OpenZepplin ERC1155
// contracts/GameItems.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.0;
import "@openzeppelin/contracts/token/ERC1155/ERC1155.sol";
contract GameItems is ERC1155 {
uint256 public constant GOLD = 0;
uint256 public constant SILVER = 1;
uint256 public constant THORS_HAMMER = 2;
uint256 public constant SWORD = 3;
uint256 public constant SHIELD = 4;
constructor() public ERC1155("https://game.example/api/item/{id}.json") {
_mint(msg.sender, GOLD, 10**18, "");
_mint(msg.sender, SILVER, 10**27, "");
_mint(msg.sender, THORS_HAMMER, 1, "");
_mint(msg.sender, SWORD, 10**9, "");
_mint(msg.sender, SHIELD, 10**9, "");
}
}
The constants on the top create different NFTs. By using the mint function you can mint those NFTs as shown in the constructor function
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;
Best Answer
The term
operator
has been first introduced by the EIP-721 to define addresses authorized (or approved) by a NFT owner to spend all of his token Ids.In EIP-1155, the
operator
is set by the token owner thanks to the following function :Operators have the ability to manage all the tokens owned by the caller of the
setApprovalForAll
method.Therefore, the
safeTransferFrom
andsafeBatchTransferFrom
methods can be called either by the token owner or one of his operators (note that an owner can have multiple operators). This statement is checked in both functions with the following line :