With ERC721, there's the 'ownerOf' function that takes a non-fungible token's id and returns the owner address, but ERC1155 doesn't officially require that a function like that be implemented. I made an ERC1155 contract through rarible.com, and I can't find a function implemented there either. Both rarible.com and Opensea.io marketplaces show the owners of ERC1155 NFTs, so I know it's possible, but I can't figure it out.
[Ethereum] How to get a list of all owners of an ERC1155 NFT by using a web3 call
erc-1155nftweb3js
Related Solutions
Lazy minting or "Gas Free" minting can be done using both the ERC1155 standard or the ERC721 standard. There is certainly nothing preventing OpenSea and other marketplaces from using an ERC721 for lazy minting.
The reason ERC1155 is becoming the popular choice for lazy minting is because:
- You have the ability to create Fungible and Non-Fungible assets
- ERC1155s uses ID substitution pattern in the
uri()
function. This allows for easy linkage to the metadata with just the tokenId which makes it easier to lazy mint. - There is a large reduction in gas cost when using ERC1155 that increases the users experience.
Using the two basic examples below from OpenZeppelin we can see the gas savings:
- Minting with an ERC721 costs 96,073
- Safe Transfer for ERC721 costs 61,542
- Minting with an ERC1155 costs 51,935
- Safe Transfer for ERC1155 costs 53,492
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.3;
import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/token/ERC1155/ERC1155.sol";
contract MyERC721 is ERC721, ERC721URIStorage, Ownable {
constructor() ERC721("MyToken", "MTK") {}
function safeMint(address to, uint256 tokenId, string memory uri)
public
onlyOwner
{
_safeMint(to, tokenId);
_setTokenURI(tokenId, uri);
}
// The following functions are overrides required by Solidity.
function _burn(uint256 tokenId) internal override(ERC721, ERC721URIStorage) {
super._burn(tokenId);
}
function tokenURI(uint256 tokenId)
public
view
override(ERC721, ERC721URIStorage)
returns (string memory)
{
return super.tokenURI(tokenId);
}
}
contract MyERC1155 is ERC1155, Ownable {
constructor() ERC1155("") {}
function setURI(string memory newuri) public onlyOwner {
_setURI(newuri);
}
function mint(address account, uint256 id, uint256 amount, bytes memory data)
public
onlyOwner
{
_mint(account, id, amount, data);
}
function mintBatch(address to, uint256[] memory ids, uint256[] memory amounts, bytes memory data)
public
onlyOwner
{
_mintBatch(to, ids, amounts, data);
}
}
How can ERC1155 help with low gas fees?
ERC1155 helps with low gas fees even with basic transfer transactions because it stores data more efficiently inside the contract. If you look inside the OpenZeppelin ERC1155 contract you will see that you only need to update two mappings to transfer the token.
_balances[id][from] = fromBalance - amount;
_balances[id][to] += amount;
But for the ERC721 you have to update 3 mappings which raises the gas cost
_balances[from] -= 1;
_balances[to] += 1;
_owners[tokenId] = to;
As Julissa noted, in Solidity this is only achievable if the owners of the NFTs are saved in the contract.
But if you are looking to get all the holders of an NFT collection off-chain then it's fairly easy.
ERC-721 tokens emit an Transfer
event when a NFT is transferred. So you can loop over all the Transfer
events and keep track of which address holds which NFT.
With the web3.js getPastEvents
function you can get all the past Transfer
events.
The docs for this function are here.
Best Answer
UPDATE: Now you can use the Moralis API
/nft/{token_address}/owners
to get this directly.This is quite difficult, as Anupam pointed out you would have to go through all the transfer events and save them to some sort of database. And this takes a lot of effort when you want to do it with a lot of big NFTs. I've never found an easy solution myself.
Full disclosure: I work at Moralis, and we've gotten a lot of these requests. And we're currently building this functionality, so hopefully in a few weeks you will be able to get this with only one line of code through the moralis SDK.
I'll edit this post once I know the full specification of this.
TheGraph is also an option, but it's a little bit cumbersome.