-
Notifications
You must be signed in to change notification settings - Fork 28
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Adds single mint contract guards (#83)
* fix tests * refactor common code * revert private * add scripts, fix tests * add 1155 single mint * make it an admin mint guard * fix mint method
- Loading branch information
Showing
9 changed files
with
272 additions
and
2 deletions.
There are no files selected for viewing
18 changes: 18 additions & 0 deletions
18
packages/manifold/contracts/single/IManifoldERC1155Single.sol
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
// SPDX-License-Identifier: MIT | ||
|
||
pragma solidity ^0.8.0; | ||
|
||
/// @author: manifold.xyz | ||
|
||
/** | ||
* Manifold ERC1155 Single Mint interface | ||
*/ | ||
interface IManifoldERC1155Single { | ||
|
||
error InvalidInput(); | ||
|
||
/** | ||
* @dev Mint a new token | ||
*/ | ||
function mint(address creatorCore, uint256 expectedTokenId, string calldata uri, address[] calldata recipients, uint256[] calldata amounts) external; | ||
} |
18 changes: 18 additions & 0 deletions
18
packages/manifold/contracts/single/IManifoldERC721Single.sol
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
// SPDX-License-Identifier: MIT | ||
|
||
pragma solidity ^0.8.0; | ||
|
||
/// @author: manifold.xyz | ||
|
||
/** | ||
* Manifold ERC721 Single Mint interface | ||
*/ | ||
interface IManifoldERC721Single { | ||
|
||
error InvalidInput(); | ||
|
||
/** | ||
* @dev Mint a token | ||
*/ | ||
function mint(address creatorCore, uint256 expectedTokenId, string calldata uri, address recipient) external; | ||
} |
35 changes: 35 additions & 0 deletions
35
packages/manifold/contracts/single/ManifoldERC1155Single.sol
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
// SPDX-License-Identifier: MIT | ||
|
||
pragma solidity ^0.8.0; | ||
|
||
/// @author: manifold.xyz | ||
|
||
import "@manifoldxyz/libraries-solidity/contracts/access/IAdminControl.sol"; | ||
import "@manifoldxyz/creator-core-solidity/contracts/core/IERC1155CreatorCore.sol"; | ||
import "./IManifoldERC1155Single.sol"; | ||
|
||
/** | ||
* Manifold ERC1155 Single Mint Implementation | ||
*/ | ||
contract ManifoldERC1155Single is IManifoldERC1155Single { | ||
|
||
/** | ||
* @dev Only allows approved admins to call the specified function | ||
*/ | ||
modifier creatorAdminRequired(address creator) { | ||
if (!IAdminControl(creator).isAdmin(msg.sender)) revert("Must be owner or admin of creator contract"); | ||
_; | ||
} | ||
|
||
/** | ||
* @dev See {IManifoldERC1155Single-mintNew}. | ||
*/ | ||
function mint(address creatorCore, uint256 expectedTokenId, string calldata uri, address[] calldata recipients, uint256[] calldata amounts) external override creatorAdminRequired(creatorCore) { | ||
string[] memory uris = new string[](1); | ||
uris[0] = uri; | ||
uint256[] memory tokenIds = IERC1155CreatorCore(creatorCore).mintBaseNew(recipients, amounts, uris); | ||
if (tokenIds.length != 1 || tokenIds[0] != expectedTokenId) { | ||
revert InvalidInput(); | ||
} | ||
} | ||
} |
33 changes: 33 additions & 0 deletions
33
packages/manifold/contracts/single/ManifoldERC721Single.sol
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
// SPDX-License-Identifier: MIT | ||
|
||
pragma solidity ^0.8.0; | ||
|
||
/// @author: manifold.xyz | ||
|
||
import "@manifoldxyz/libraries-solidity/contracts/access/IAdminControl.sol"; | ||
import "@manifoldxyz/creator-core-solidity/contracts/core/IERC721CreatorCore.sol"; | ||
import "./IManifoldERC721Single.sol"; | ||
|
||
/** | ||
* Manifold ERC721 Single Mint Implementation | ||
*/ | ||
contract ManifoldERC721Single is IManifoldERC721Single { | ||
|
||
/** | ||
* @dev Only allows approved admins to call the specified function | ||
*/ | ||
modifier creatorAdminRequired(address creator) { | ||
if (!IAdminControl(creator).isAdmin(msg.sender)) revert("Must be owner or admin of creator contract"); | ||
_; | ||
} | ||
|
||
/** | ||
* @dev See {IManifoldERC721Single-mint}. | ||
*/ | ||
function mint(address creatorCore, uint256 expectedTokenId, string calldata uri, address recipient) external override creatorAdminRequired(creatorCore) { | ||
uint256 tokenId = IERC721CreatorCore(creatorCore).mintBase(recipient, uri); | ||
if (tokenId != expectedTokenId) { | ||
revert InvalidInput(); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
// SPDX-License-Identifier: UNLICENSED | ||
pragma solidity ^0.8.13; | ||
|
||
import "forge-std/Script.sol"; | ||
import "../contracts/single/ManifoldERC1155Single.sol"; | ||
|
||
contract DeployManifoldERC1155Single is Script { | ||
function run() external { | ||
// uint256 deployerPrivateKey = pk; // uncomment this when testing on goerli | ||
uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY"); // comment this out when testing on goerli | ||
vm.startBroadcast(deployerPrivateKey); | ||
// forge script script/ManifoldERC1155Single.s.sol --optimizer-runs 1000 --rpc-url <YOUR_NODE> --broadcast | ||
// forge verify-contract --compiler-version 0.8.17 --optimizer-runs 1000 --chain sepolia <DEPLOYED_ADDRESS> contracts/single/ManifoldERC1155Single.sol:ManifoldERC1155Single --watch | ||
new ManifoldERC1155Single{salt: 0x4d616e69666f6c644552433131353553696e676c654d616e69666f6c64455243}(); | ||
vm.stopBroadcast(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
// SPDX-License-Identifier: UNLICENSED | ||
pragma solidity ^0.8.13; | ||
|
||
import "forge-std/Script.sol"; | ||
import "../contracts/single/ManifoldERC721Single.sol"; | ||
|
||
contract DeployManifoldERC721Single is Script { | ||
function run() external { | ||
// uint256 deployerPrivateKey = pk; // uncomment this when testing on goerli | ||
uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY"); // comment this out when testing on goerli | ||
vm.startBroadcast(deployerPrivateKey); | ||
// forge script script/ManifoldERC721Single.s.sol --optimizer-runs 1000 --rpc-url <YOUR_NODE> --broadcast | ||
// forge verify-contract --compiler-version 0.8.17 --optimizer-runs 1000 --chain sepolia <DEPLOYED_ADDRESS> contracts/single/ManifoldERC721Single.sol:ManifoldERC721Single --watch | ||
new ManifoldERC721Single{salt: 0x4d616e69666f6c6445524337323153696e676c654d616e69666f6c6445524337}(); | ||
vm.stopBroadcast(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
// SPDX-License-Identifier: UNLICENSED | ||
pragma solidity ^0.8.13; | ||
|
||
import "forge-std/Test.sol"; | ||
import "forge-std/console.sol"; | ||
import "../../contracts/single/ManifoldERC1155Single.sol"; | ||
import "@manifoldxyz/creator-core-solidity/contracts/ERC1155Creator.sol"; | ||
|
||
import "../mocks/Mock.sol"; | ||
|
||
contract ManifoldERC1155SingleTest is Test { | ||
ManifoldERC1155Single public example; | ||
ERC1155Creator public creatorCore; | ||
|
||
address public owner = 0x6140F00e4Ff3936702E68744f2b5978885464cbB; | ||
address public operator = 0xc78Dc443c126af6E4f6Ed540c1e740C1b5be09cd; | ||
|
||
address public zeroAddress = address(0); | ||
address public deadAddress = 0x000000000000000000000000000000000000dEaD; | ||
uint256 private constant MAX_UINT_256 = 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff; | ||
|
||
function setUp() public { | ||
vm.startPrank(owner); | ||
creatorCore = new ERC1155Creator("Token", "NFT"); | ||
|
||
example = new ManifoldERC1155Single(); | ||
|
||
creatorCore.registerExtension(address(example), ""); | ||
vm.deal(owner, 10 ether); | ||
vm.deal(operator, 10 ether); | ||
vm.stopPrank(); | ||
} | ||
|
||
function testAccess() public { | ||
address[] memory recipients = new address[](1); | ||
uint256[] memory amounts = new uint256[](1); | ||
vm.startPrank(operator); | ||
vm.expectRevert("Must be owner or admin of creator contract"); | ||
example.mint(address(creatorCore), 1, "", recipients, amounts); | ||
vm.stopPrank(); | ||
} | ||
|
||
function testMint() public { | ||
vm.startPrank(owner); | ||
creatorCore.approveAdmin(address(example)); | ||
address[] memory recipients = new address[](1); | ||
uint256[] memory amounts = new uint256[](1); | ||
recipients[0] = operator; | ||
amounts[0] = 2; | ||
example.mint(address(creatorCore), 1, "", recipients, amounts); | ||
assertEq(creatorCore.balanceOf(operator, 1), 2); | ||
// Can't mint same instance twice | ||
vm.expectRevert(IManifoldERC1155Single.InvalidInput.selector); | ||
example.mint(address(creatorCore), 1, "", recipients, amounts); | ||
vm.stopPrank(); | ||
} | ||
|
||
function testTokenURI() public { | ||
vm.startPrank(owner); | ||
creatorCore.approveAdmin(address(example)); | ||
address[] memory recipients = new address[](1); | ||
uint256[] memory amounts = new uint256[](1); | ||
recipients[0] = operator; | ||
amounts[0] = 2; | ||
example.mint(address(creatorCore), 1, "https://arweave.net/1hRadwN29sN5UDl_BBgH4RhCc2TjknMpuzGsP1t3wEM", recipients, amounts); | ||
assertEq(creatorCore.uri(1), "https://arweave.net/1hRadwN29sN5UDl_BBgH4RhCc2TjknMpuzGsP1t3wEM"); | ||
vm.stopPrank(); | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
// SPDX-License-Identifier: UNLICENSED | ||
pragma solidity ^0.8.13; | ||
|
||
import "forge-std/Test.sol"; | ||
import "forge-std/console.sol"; | ||
import "../../contracts/single/ManifoldERC721Single.sol"; | ||
import "@manifoldxyz/creator-core-solidity/contracts/ERC721Creator.sol"; | ||
|
||
import "../mocks/Mock.sol"; | ||
|
||
contract ManifoldERC721SingleTest is Test { | ||
ManifoldERC721Single public example; | ||
ERC721Creator public creatorCore; | ||
|
||
address public owner = 0x6140F00e4Ff3936702E68744f2b5978885464cbB; | ||
address public operator = 0xc78Dc443c126af6E4f6Ed540c1e740C1b5be09cd; | ||
|
||
address public zeroAddress = address(0); | ||
address public deadAddress = 0x000000000000000000000000000000000000dEaD; | ||
uint256 private constant MAX_UINT_256 = 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff; | ||
|
||
|
||
function setUp() public { | ||
vm.startPrank(owner); | ||
creatorCore = new ERC721Creator("Token", "NFT"); | ||
|
||
example = new ManifoldERC721Single(); | ||
|
||
creatorCore.registerExtension(address(example), ""); | ||
vm.deal(owner, 10 ether); | ||
vm.deal(operator, 10 ether); | ||
vm.stopPrank(); | ||
} | ||
|
||
function testAccess() public { | ||
vm.startPrank(operator); | ||
vm.expectRevert("Must be owner or admin of creator contract"); | ||
example.mint(address(creatorCore), 1, "", address(0)); | ||
vm.stopPrank(); | ||
} | ||
|
||
function testMint() public { | ||
vm.startPrank(owner); | ||
creatorCore.approveAdmin(address(example)); | ||
example.mint(address(creatorCore), 1, "", operator); | ||
assertEq(creatorCore.balanceOf(operator), 1); | ||
// Can't mint same instance twice | ||
vm.expectRevert(IManifoldERC721Single.InvalidInput.selector); | ||
example.mint(address(creatorCore), 1, "", operator); | ||
vm.stopPrank(); | ||
} | ||
|
||
function testTokenURI() public { | ||
vm.startPrank(owner); | ||
creatorCore.approveAdmin(address(example)); | ||
example.mint(address(creatorCore), 1, "https://arweave.net/1hRadwN29sN5UDl_BBgH4RhCc2TjknMpuzGsP1t3wEM", operator); | ||
assertEq(creatorCore.balanceOf(operator), 1); | ||
assertEq(creatorCore.tokenURI(1), "https://arweave.net/1hRadwN29sN5UDl_BBgH4RhCc2TjknMpuzGsP1t3wEM"); | ||
vm.stopPrank(); | ||
} | ||
|
||
} |