From 2cf6dddb87b89dcf6aac2adafe5192cd262a6e5d Mon Sep 17 00:00:00 2001 From: Akshat Mittal Date: Fri, 16 Feb 2024 05:54:52 +0530 Subject: [PATCH 1/2] Add DN404Cloneable --- .gas-snapshot | 5 +++ src/example/DN404Cloneable.sol | 81 ++++++++++++++++++++++++++++++++++ test/DN404Cloneable.t.sol | 44 ++++++++++++++++++ 3 files changed, 130 insertions(+) create mode 100644 src/example/DN404Cloneable.sol create mode 100644 test/DN404Cloneable.t.sol diff --git a/.gas-snapshot b/.gas-snapshot index d1865c7..e24c2ea 100644 --- a/.gas-snapshot +++ b/.gas-snapshot @@ -65,6 +65,11 @@ BenchTest:testMintPandora_14() (gas: 1037484) BenchTest:testMintPandora_15() (gas: 1106967) BenchTest:testMintPandora_16() (gas: 1176473) BenchTest:test__codesize() (gas: 29290) +DN404CloneableTest:testMint() (gas: 54205) +DN404CloneableTest:testName() (gas: 12348) +DN404CloneableTest:testSetBaseURI() (gas: 41446) +DN404CloneableTest:testSymbol() (gas: 12390) +DN404CloneableTest:test__codesize() (gas: 4926) DN404CustomUnitTest:testInitializeWithZeroUnitReverts() (gas: 85821) DN404CustomUnitTest:testMint() (gas: 162679) DN404CustomUnitTest:testMintWithoutNFTs(uint256,uint256,uint256) (runs: 256, μ: 155067, ~: 162175) diff --git a/src/example/DN404Cloneable.sol b/src/example/DN404Cloneable.sol new file mode 100644 index 0000000..d11c93b --- /dev/null +++ b/src/example/DN404Cloneable.sol @@ -0,0 +1,81 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.4; + +import "../DN404.sol"; +import "../DN404Mirror.sol"; +import {Ownable} from "../../lib/solady/src/auth/Ownable.sol"; +import {LibString} from "../../lib/solady/src/utils/LibString.sol"; +import {SafeTransferLib} from "../../lib/solady/src/utils/SafeTransferLib.sol"; +import {Initializable} from "../../lib/solady/src/utils/Initializable.sol"; +import {LibClone} from "../../lib/solady/src/utils/LibClone.sol"; +import {IERC20} from "../../lib/forge-std/src/interfaces/IERC20.sol"; + +/** + * @title DN404Cloneable + * @notice Simple DN404 contract that allows clones of the contract to be created. + * Both DN404 Base and DN404Mirror are created as EIP 1167 clones. + */ +contract DN404Cloneable is DN404, Ownable, Initializable { + error MaxTokenSupplyExceeded(); + + string private _name; + string private _sym; + string private _baseURI; + + uint96 private _maxTokenSupply; + + // Immutable so clones don't inherit this and proxy calls still read the right value. + address private immutable dn404mirrorImpl = address(new DN404Mirror(address(this))); + + function initialize( + address owner_, + string calldata name_, + string calldata symbol_, + string calldata baseURI_, + address initialMintTarget_, + uint96 initialTokenSupply_, + uint96 maxTokenSupply_ + ) external payable initializer { + _initializeOwner(owner_); + + _name = name_; + _sym = symbol_; + _baseURI = baseURI_; + _maxTokenSupply = maxTokenSupply_; + + // We don't care about the constructor since address(0) is acceptable. + address mirror = LibClone.clone(dn404mirrorImpl); + + _initializeDN404(initialTokenSupply_, initialMintTarget_, mirror); + } + + function name() public view override returns (string memory) { + return _name; + } + + function symbol() public view override returns (string memory) { + return _sym; + } + + function setBaseURI(string calldata baseURI_) public onlyOwner { + _baseURI = baseURI_; + } + + function mint(address to, uint256 amount) public onlyOwner { + if (amount + totalSupply() > _maxTokenSupply) { + revert MaxTokenSupplyExceeded(); + } + + _mint(to, amount); + } + + function tokenURI(uint256 tokenId) public view override returns (string memory) { + return bytes(_baseURI).length != 0 + ? string(abi.encodePacked(_baseURI, LibString.toString(tokenId))) + : ""; + } + + function withdraw() public onlyOwner { + SafeTransferLib.safeTransferAllETH(msg.sender); + } +} diff --git a/test/DN404Cloneable.t.sol b/test/DN404Cloneable.t.sol new file mode 100644 index 0000000..e1d3c41 --- /dev/null +++ b/test/DN404Cloneable.t.sol @@ -0,0 +1,44 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.4; + +import "./utils/SoladyTest.sol"; +import {LibClone} from "../lib/solady/src/utils/LibClone.sol"; +import {DN404Cloneable} from "../src/example/DN404Cloneable.sol"; + +contract DN404CloneableTest is SoladyTest { + address immutable dnImpl = address(new DN404Cloneable()); + + DN404Cloneable dn; + address alice = address(111); + + function setUp() public { + dn = DN404Cloneable(payable(LibClone.clone(dnImpl))); + + vm.prank(alice); + dn.initialize(alice, "DN404", "DN", "", address(this), 1000, 2000); + } + + function testMint() public { + vm.prank(dn.owner()); + dn.mint(alice, 100); + assertEq(dn.totalSupply(), 1100); + + vm.prank(dn.owner()); + vm.expectRevert(); + dn.mint(alice, 1000); + } + + function testName() public { + assertEq(dn.name(), "DN404"); + } + + function testSymbol() public { + assertEq(dn.symbol(), "DN"); + } + + function testSetBaseURI() public { + vm.prank(alice); + dn.setBaseURI("https://example.com/"); + assertEq(dn.tokenURI(1), "https://example.com/1"); + } +} From be7f3216bc9a4300e97be7d7ff17e5c410cf0fae Mon Sep 17 00:00:00 2001 From: Akshat Mittal Date: Fri, 16 Feb 2024 05:59:26 +0530 Subject: [PATCH 2/2] Gas opt --- .gas-snapshot | 4 ++-- src/example/DN404Cloneable.sol | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.gas-snapshot b/.gas-snapshot index e24c2ea..5e21430 100644 --- a/.gas-snapshot +++ b/.gas-snapshot @@ -65,10 +65,10 @@ BenchTest:testMintPandora_14() (gas: 1037484) BenchTest:testMintPandora_15() (gas: 1106967) BenchTest:testMintPandora_16() (gas: 1176473) BenchTest:test__codesize() (gas: 29290) -DN404CloneableTest:testMint() (gas: 54205) +DN404CloneableTest:testMint() (gas: 54089) DN404CloneableTest:testName() (gas: 12348) DN404CloneableTest:testSetBaseURI() (gas: 41446) -DN404CloneableTest:testSymbol() (gas: 12390) +DN404CloneableTest:testSymbol() (gas: 12368) DN404CloneableTest:test__codesize() (gas: 4926) DN404CustomUnitTest:testInitializeWithZeroUnitReverts() (gas: 85821) DN404CustomUnitTest:testMint() (gas: 162679) diff --git a/src/example/DN404Cloneable.sol b/src/example/DN404Cloneable.sol index d11c93b..e332fd2 100644 --- a/src/example/DN404Cloneable.sol +++ b/src/example/DN404Cloneable.sol @@ -22,7 +22,7 @@ contract DN404Cloneable is DN404, Ownable, Initializable { string private _sym; string private _baseURI; - uint96 private _maxTokenSupply; + uint256 private _maxTokenSupply; // Immutable so clones don't inherit this and proxy calls still read the right value. address private immutable dn404mirrorImpl = address(new DN404Mirror(address(this))); @@ -33,8 +33,8 @@ contract DN404Cloneable is DN404, Ownable, Initializable { string calldata symbol_, string calldata baseURI_, address initialMintTarget_, - uint96 initialTokenSupply_, - uint96 maxTokenSupply_ + uint256 initialTokenSupply_, + uint256 maxTokenSupply_ ) external payable initializer { _initializeOwner(owner_);