From cbc1c50719cabdeb940a5a2a61082d933991cb39 Mon Sep 17 00:00:00 2001 From: Andrew Richardson Date: Fri, 1 Mar 2024 23:49:49 -0500 Subject: [PATCH 1/2] Update to latest OpenZeppelin base contracts Signed-off-by: Andrew Richardson --- samples/solidity/contracts/ERC1155MixedFungible.sol | 5 ++--- samples/solidity/package-lock.json | 8 ++++---- samples/solidity/package.json | 2 +- samples/solidity/test/ERC1155MixedFungible.ts | 4 ++-- 4 files changed, 9 insertions(+), 10 deletions(-) diff --git a/samples/solidity/contracts/ERC1155MixedFungible.sol b/samples/solidity/contracts/ERC1155MixedFungible.sol index 44c3649..e526c1e 100644 --- a/samples/solidity/contracts/ERC1155MixedFungible.sol +++ b/samples/solidity/contracts/ERC1155MixedFungible.sol @@ -3,7 +3,6 @@ pragma solidity ^0.8.0; import '@openzeppelin/contracts/token/ERC1155/ERC1155.sol'; import '@openzeppelin/contracts/utils/Context.sol'; -import '@openzeppelin/contracts/utils/math/SafeMath.sol'; import './IERC1155MixedFungible.sol'; /** @@ -114,7 +113,7 @@ contract ERC1155MixedFungible is Context, ERC1155, IERC1155MixedFungible { // Indexes are 1-based. uint256 index = maxIndex[type_id] + 1; - maxIndex[type_id] = SafeMath.add(to.length, maxIndex[type_id]); + maxIndex[type_id] = to.length + maxIndex[type_id]; for (uint256 i = 0; i < to.length; ++i) { _mint(to[i], type_id | (index + i), 1, data); @@ -134,7 +133,7 @@ contract ERC1155MixedFungible is Context, ERC1155, IERC1155MixedFungible { // Indexes are 1-based. uint256 index = maxIndex[type_id] + 1; - maxIndex[type_id] = SafeMath.add(to.length, maxIndex[type_id]); + maxIndex[type_id] = to.length + maxIndex[type_id]; for (uint256 i = 0; i < to.length; ++i) { uint256 id = type_id | (index + i); diff --git a/samples/solidity/package-lock.json b/samples/solidity/package-lock.json index 548ce43..0133df1 100644 --- a/samples/solidity/package-lock.json +++ b/samples/solidity/package-lock.json @@ -8,7 +8,7 @@ "name": "@hyperledger/firefly-tokens-erc1155-contracts", "version": "0.0.2", "dependencies": { - "@openzeppelin/contracts": "^4.5.0" + "@openzeppelin/contracts": "^5.0.2" }, "devDependencies": { "@nomicfoundation/hardhat-toolbox": "^4.0.0", @@ -1493,9 +1493,9 @@ } }, "node_modules/@openzeppelin/contracts": { - "version": "4.9.5", - "resolved": "https://registry.npmjs.org/@openzeppelin/contracts/-/contracts-4.9.5.tgz", - "integrity": "sha512-ZK+W5mVhRppff9BE6YdR8CC52C8zAvsVAiWhEtQ5+oNxFE6h1WdeWo+FJSF8KKvtxxVYZ7MTP/5KoVpAU3aSWg==" + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@openzeppelin/contracts/-/contracts-5.0.2.tgz", + "integrity": "sha512-ytPc6eLGcHHnapAZ9S+5qsdomhjo6QBHTDRRBFfTxXIpsicMhVPouPgmUPebZZZGX7vt9USA+Z+0M0dSVtSUEA==" }, "node_modules/@scure/base": { "version": "1.1.5", diff --git a/samples/solidity/package.json b/samples/solidity/package.json index 9c26882..c6fccc7 100644 --- a/samples/solidity/package.json +++ b/samples/solidity/package.json @@ -6,7 +6,7 @@ "test": "hardhat test --network hardhat" }, "dependencies": { - "@openzeppelin/contracts": "^4.5.0" + "@openzeppelin/contracts": "^5.0.2" }, "devDependencies": { "@nomicfoundation/hardhat-toolbox": "^4.0.0", diff --git a/samples/solidity/test/ERC1155MixedFungible.ts b/samples/solidity/test/ERC1155MixedFungible.ts index e616575..e36c6ce 100644 --- a/samples/solidity/test/ERC1155MixedFungible.ts +++ b/samples/solidity/test/ERC1155MixedFungible.ts @@ -241,7 +241,7 @@ describe('ERC1155MixedFungible - Unit Tests', () => { 1, '0x00', ), - ).to.be.revertedWith('ERC1155: caller is not token owner or approved'); + ).to.be.revertedWithCustomError(deployedERC1155, 'ERC1155MissingApprovalForAll'); expect( await deployedERC1155 .connect(deployerSignerA) @@ -371,7 +371,7 @@ describe('ERC1155MixedFungible - Unit Tests', () => { 1, '0x00', ), - ).to.be.revertedWith('ERC1155: caller is not token owner or approved'); + ).to.be.revertedWithCustomError(deployedERC1155, 'ERC1155MissingApprovalForAll'); expect( await deployedERC1155 .connect(deployerSignerA) From 0ba24c2b518490f14f4a088cb8b70cf79becaf3e Mon Sep 17 00:00:00 2001 From: Andrew Richardson Date: Mon, 4 Mar 2024 08:41:58 -0500 Subject: [PATCH 2/2] Extend ERC1155URIStorage This makes the contracts more consistent with OpenZeppelin examples. No signatures are changed, but there is one slight change in behavior: if you specify a "base URI", then individual token URIs are always understood to be a suffix for that base URI. The previous contract would ignore the base URI when a token URI was specified. Signed-off-by: Andrew Richardson --- .../contracts/ERC1155MixedFungible.sol | 47 ++++++++----------- .../contracts/IERC1155MixedFungible.sol | 5 +- 2 files changed, 22 insertions(+), 30 deletions(-) diff --git a/samples/solidity/contracts/ERC1155MixedFungible.sol b/samples/solidity/contracts/ERC1155MixedFungible.sol index e526c1e..6d43535 100644 --- a/samples/solidity/contracts/ERC1155MixedFungible.sol +++ b/samples/solidity/contracts/ERC1155MixedFungible.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.0; -import '@openzeppelin/contracts/token/ERC1155/ERC1155.sol'; +import '@openzeppelin/contracts/token/ERC1155/extensions/ERC1155URIStorage.sol'; import '@openzeppelin/contracts/utils/Context.sol'; import './IERC1155MixedFungible.sol'; @@ -27,7 +27,7 @@ import './IERC1155MixedFungible.sol'; * Remember to always consult best practices from other communities and examples (such as OpenZeppelin) * when crafting your token logic, rather than relying on the FireFly community alone. Happy minting! */ -contract ERC1155MixedFungible is Context, ERC1155, IERC1155MixedFungible { +contract ERC1155MixedFungible is Context, ERC1155URIStorage, IERC1155MixedFungible { // Use a split bit implementation: // - Bit 255: type flag (0 = fungible, 1 = non-fungible) // - Bits 255-128: type id @@ -44,10 +44,6 @@ contract ERC1155MixedFungible is Context, ERC1155, IERC1155MixedFungible { // inherited ERC1155 `_uri` is private, so need our own within this contract string private _baseTokenURI; - // mapping from type ID | index => custom token URIs for non-fungible tokens - // fallback behavior if missing is to use the default base URI - mapping(uint256 => string) private _nfTokenURIs; - function isFungible(uint256 id) internal pure returns (bool) { return id & TYPE_NF_BIT == 0; } @@ -89,18 +85,6 @@ contract ERC1155MixedFungible is Context, ERC1155, IERC1155MixedFungible { ); } - function _setNonFungibleURI( - uint256 type_id, - uint256 id, - string memory _uri - ) private creatorOnly(type_id) { - require( - isNonFungible(type_id), - 'ERC1155MixedFungible: id does not represent a non-fungible type' - ); - _nfTokenURIs[id] = _uri; - } - function mintNonFungible( uint256 type_id, address[] calldata to, @@ -138,7 +122,7 @@ contract ERC1155MixedFungible is Context, ERC1155, IERC1155MixedFungible { for (uint256 i = 0; i < to.length; ++i) { uint256 id = type_id | (index + i); _mint(to[i], id, 1, data); - _setNonFungibleURI(type_id, id, _uri); + _setURI(id, _uri); } } @@ -185,15 +169,22 @@ contract ERC1155MixedFungible is Context, ERC1155, IERC1155MixedFungible { function uri( uint256 id - ) public view virtual override(IERC1155MixedFungible, ERC1155) returns (string memory) { - string memory _tokenUri = _nfTokenURIs[id]; - bytes memory tempURITest = bytes(_tokenUri); - - if (tempURITest.length == 0) { - return _baseTokenURI; - } else { - return _tokenUri; - } + ) + public + view + virtual + override(IERC1155MixedFungible, ERC1155URIStorage) + returns (string memory) + { + return super.uri(id); + } + + function _setURI(uint256 id, string memory tokenURI) internal virtual override { + require( + isNonFungible(id), + 'ERC1155MixedFungible: id does not represent a non-fungible type' + ); + super._setURI(id, tokenURI); } function baseTokenUri() public view virtual override returns (string memory) { diff --git a/samples/solidity/contracts/IERC1155MixedFungible.sol b/samples/solidity/contracts/IERC1155MixedFungible.sol index 79c4360..fb80520 100644 --- a/samples/solidity/contracts/IERC1155MixedFungible.sol +++ b/samples/solidity/contracts/IERC1155MixedFungible.sol @@ -2,6 +2,7 @@ pragma solidity ^0.8.0; +import '@openzeppelin/contracts/token/ERC1155/extensions/IERC1155MetadataURI.sol'; import '@openzeppelin/contracts/utils/introspection/IERC165.sol'; import './IERC1155Factory.sol'; @@ -9,7 +10,7 @@ import './IERC1155Factory.sol'; * ERC1155 interface with mint, burn, and attached data support for fungible & non-fungible tokens. * Non-fungible tokens also have support for custom URI's. */ -interface IERC1155MixedFungible is IERC165, IERC1155Factory { +interface IERC1155MixedFungible is IERC165, IERC1155Factory, IERC1155MetadataURI { function create(bool is_fungible, bytes calldata data) external override; function mintNonFungible(uint256 type_id, address[] calldata to, bytes calldata data) external; @@ -36,7 +37,7 @@ interface IERC1155MixedFungible is IERC165, IERC1155Factory { bytes calldata data ) external; - function uri(uint256 id) external returns (string memory); + function uri(uint256 id) external view returns (string memory); function baseTokenUri() external returns (string memory); }