What I want to achieve:
A user should be able to transfer ERC1155 tokens from my contract address to his account.
I've tried two approaches:
- Deploy ERC1155 contract, then pass its address to the constructor of the second contract which handles transfers.
This works. Users are able to call buyItems() without any errors.
pragma solidity ^0.8.0;
import '@openzeppelin/contracts/token/ERC1155/IERC1155.sol';
import '@openzeppelin/contracts/token/ERC1155/utils/ERC1155Holder.sol';
import '@openzeppelin/contracts/token/ERC1155/presets/ERC1155PresetMinterPauser.sol';
contract ERC1155Preset is ERC1155PresetMinterPauser {
constructor() ERC1155PresetMinterPauser("https://token-cdn-domain/{id}.json") {}
}
contract testContract is ERC1155Holder {
IERC1155 private _IERC1155;
constructor(IERC1155 ERC1155Address) {
_IERC1155 = ERC1155Address;
}
function buyItems(uint256 _itemId, uint256 _amount) external {
require(_IERC1155.balanceOf(address(this), _itemId) >= _amount);
_IERC1155.safeTransferFrom(address(this), msg.sender, _itemId, _amount, "");
}
}
- Deploy only one contract for ERC1155 and transfers.
This doesn't work. When a user calls buyItems(), I get this error: execution reverted: ERC1155: caller is not owner nor approved
pragma solidity ^0.8.0;
import '@openzeppelin/contracts/token/ERC1155/utils/ERC1155Holder.sol';
import '@openzeppelin/contracts/token/ERC1155/presets/ERC1155PresetMinterPauser.sol';
contract testContract2 is ERC1155PresetMinterPauser, ERC1155Holder {
constructor() ERC1155PresetMinterPauser("https://token-cdn-domain/{id}.json") {}
function supportsInterface(bytes4 interfaceId) public view virtual override(ERC1155PresetMinterPauser, ERC1155Receiver) returns (bool) {
return interfaceId == type(IERC1155).interfaceId
|| interfaceId == type(IERC1155Receiver).interfaceId
|| super.supportsInterface(interfaceId);
}
function buyItems(uint256 _itemId, uint256 _amount) external {
require(balanceOf(address(this), _itemId) >= _amount);
safeTransferFrom(address(this), msg.sender, _itemId, _amount, "");
}
}
My question: Why does the first approach work, and why not the second one?
Best Answer
Could you look into the documentation on openzepplin? I've linked it here, particularly pertaining to ERC1155PresetMinterPauser.There's a dependency that I don't see mentioned here, namely, Access Control.
The address you are using, the caller in this case, is not registered as either an
owner
or otherwiseapproved
, hence the error.