From 507d44213c900f999dad4be2e7174d7e48a55174 Mon Sep 17 00:00:00 2001 From: eugenioclrc Date: Tue, 29 Aug 2023 00:12:47 -0300 Subject: [PATCH] refacto, gas is bad --- foundry.toml | 4 ++-- script/Deploy.s.sol | 5 ++--- src/Huffplug.huff | 30 ++++++++++++++---------------- src/Ownable.sol | 33 +++++++++++++++++++++++++++++++++ src/TokenRenderer.sol | 32 ++++++++++++++++++-------------- test/E2E.t.sol | 2 +- test/Huffplug.t.sol | 19 +++++++++++-------- test/TokenRenderer.t.sol | 4 ++-- 8 files changed, 83 insertions(+), 46 deletions(-) create mode 100644 src/Ownable.sol diff --git a/foundry.toml b/foundry.toml index dd32706..5423e1a 100644 --- a/foundry.toml +++ b/foundry.toml @@ -6,8 +6,8 @@ libs = ["lib"] solc = "0.8.21" evm_version = 'shanghai' -optimize = true -optimize_runs = 20000 +#optimize = true // no need to optimaze (will produce bigger bytecode) +#optimize_runs = 1 ffi=true diff --git a/script/Deploy.s.sol b/script/Deploy.s.sol index 99c0a16..e74d11f 100644 --- a/script/Deploy.s.sol +++ b/script/Deploy.s.sol @@ -12,7 +12,7 @@ using {compile} for Vm; contract HuffDeployScript is Script { address constant DEPLOYER2 = 0x4e59b44847b379578588920cA78FbF26c0B4956C; - IHuffplug constant huffplug = IHuffplug(0xBe0768c32D3AEda087c5064e6f402D91cB9d466A); + IHuffplug constant huffplug = IHuffplug(0xC27a5a9193ab37f646F21C120110315Baa26806A); bytes32 constant MERKLE_ROOT = 0x51496785f4dd04d525b568df7fa6f1057799bc21f7e76c26ee77d2f569b40601; @@ -22,12 +22,11 @@ contract HuffDeployScript is Script { require(tx.origin == owner, "deployer should be 0xC0FFE"); vm.startBroadcast(); - TokenRenderer renderer = new TokenRenderer("ipfs://bafybeia7h7n6osru3b4mvivjb3h2fkonvmotobvboqw3k3v4pvyv5oyzse/"); + TokenRenderer renderer = new TokenRenderer("ipfs://bafybeibtkqysjtgxmcegh7rjnpi3hbfn4chy3yxuav4jbiawwvutxerw64/", "uri"); // @TODO upload contract uro to ipfs bytes32 _saltDeploy = 0x09286b392f541f94d0afab741157bd9f766292f732021a1be9ad86bc28b1be42; bytes memory bytecode = vm.compile(address(renderer), MERKLE_ROOT); // send owner to the constructor - bytecode = bytes.concat(bytecode, abi.encode(owner)); _saltDeploy = 0xcfbbb05e4e07ccd909806657fd780c32d4c4c76931df8394e91d2aa76fc351d1; (bool success, bytes memory ret) = DEPLOYER2.call(bytes.concat(_saltDeploy, bytecode)); diff --git a/src/Huffplug.huff b/src/Huffplug.huff index 2dec74a..34a17cb 100644 --- a/src/Huffplug.huff +++ b/src/Huffplug.huff @@ -7,8 +7,6 @@ #include "./Plugger.huff" #include "huffmate/tokens/ERC721.huff" -// @dev Owner pattern is only use to gain access to the Opensea collection admin functions -#include "huffmate/auth/Owned.huff" // @dev this is for import the macro STATICCALL() #include "huffmate/utils/Calls.huff" @@ -38,6 +36,8 @@ #define function currentDifficulty() view returns (uint256) #define function totalMinted() view returns (uint256) #define function salt() view returns (bytes32) +#define function contractURI() view returns (string) +#define function owner() view returns (address) // ************************************************************* // *** Macros *** @@ -63,18 +63,17 @@ 0x60 0x00 return } -#define macro TOKEN_URI() = takes (0) { +#define macro DELEGATE_TOKENRENDERER() = takes (0) { // tokenURI SIG + token id 0x24 0x00 0x00 calldatacopy // STATICCALL(ret_size,ret_offset,arg_size,arg_offset,to,maxgas) STATICCALL(0x00,0x00,0x24,0x00,TOKEN_RENDERER,gas) - // we dont care if this revert // Revert if call is unsuccessful - // cont jumpi - // 0x00 0x00 revert - // cont: + cont jumpi + 0x00 0x00 revert + cont: returndatasize 0x00 0x00 returndatacopy // Load the result @@ -95,7 +94,6 @@ // ************************************************************* #define macro CONSTRUCTOR() = takes (0) returns (0) { - OWNED_CONSTRUCTOR() CONSTRUCTOR_PLUGGER() // this will setup the immutable and return de code with the immutable @@ -113,7 +111,7 @@ NON_PAYABLE() // [] dup1 __FUNC_SIG(mint) eq mint jumpi - dup1 __FUNC_SIG(mintWithMerkle) eq mintWithMerkle jumpi + dup1 __FUNC_SIG(mintWithMerkle) eq mintWithMerkle jumpi dup1 __FUNC_SIG(approve) eq approve jumpi dup1 __FUNC_SIG(setApprovalForAll) eq setApprovalForAll jumpi @@ -123,8 +121,12 @@ dup1 __FUNC_SIG(name) eq name jumpi dup1 __FUNC_SIG(symbol) eq symbol jumpi - dup1 __FUNC_SIG(tokenURI) eq tokenURI jumpi dup1 __FUNC_SIG(supportsInterface) eq supportsInterface jumpi + + /// @dev this functions are delegate to the TokenRenderer + dup1 __FUNC_SIG(tokenURI) eq delegateTokenRenderer jumpi + dup1 __FUNC_SIG(contractURI) eq delegateTokenRenderer jumpi + dup1 __FUNC_SIG(owner) eq delegateTokenRenderer jumpi dup1 __FUNC_SIG(getApproved) eq getApproved jumpi dup1 __FUNC_SIG(isApprovedForAll) eq isApprovedForAll jumpi @@ -137,10 +139,6 @@ dup1 __FUNC_SIG(totalSupply) eq totalSupply jumpi dup1 __FUNC_SIG(totalMinted) eq totalMinted jumpi - /// @dev owner is only used to admin opensea collection page - // owned functions dispatcher - OWNED_MAIN() - dup1 __FUNC_SIG(claimed) eq claimed jumpi dup1 __FUNC_SIG(salt) eq salt jumpi // last one doesnt need dup1 @@ -190,8 +188,8 @@ NAME() symbol: SYMBOL() - tokenURI: - TOKEN_URI() + delegateTokenRenderer: + DELEGATE_TOKENRENDERER() supportsInterface: SUPPORTS_INTERFACE() diff --git a/src/Ownable.sol b/src/Ownable.sol new file mode 100644 index 0000000..bb470c2 --- /dev/null +++ b/src/Ownable.sol @@ -0,0 +1,33 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.21; + +// @dev this is base on the solady implementation +// https://github.com/Vectorized/solady/blob/main/src/auth/Ownable.sol + +abstract contract Ownable { + address public owner; + + /// @dev The caller is not authorized to call the function. + error Unauthorized(); + + constructor() { + owner = msg.sender; + } + + /// @dev Marks a function as only callable by the owner. + modifier onlyOwner() { + _checkOwner(); + _; + } + + /// @dev Throws if the sender is not the owner. + function _checkOwner() internal view { + if (msg.sender != owner) { + revert Unauthorized(); + } + } + + function transferOwnership(address newOwner) external payable onlyOwner() { + owner = newOwner; + } +} \ No newline at end of file diff --git a/src/TokenRenderer.sol b/src/TokenRenderer.sol index 55bd7c5..0d77b0a 100644 --- a/src/TokenRenderer.sol +++ b/src/TokenRenderer.sol @@ -4,28 +4,32 @@ pragma solidity 0.8.21; // Render contract for the Huffplugs // source code: https://github.com/webtresclub/huffplug // mint on goerli: https://buttplug-homepage.vercel.app/ - -import {Owned} from "solmate/auth/Owned.sol"; import {LibString} from "solmate/utils/LibString.sol"; +import {Ownable} from "./Ownable.sol"; -contract TokenRenderer is Owned(msg.sender) { - string public baseurl; - - event UpdateBaseurl(string baseurl); +contract TokenRenderer is Ownable { + string private _baseurl; + string public contractURI; - constructor(string memory _baseurl) { - baseurl = _baseurl; - emit UpdateBaseurl(_baseurl); + constructor(string memory baseurl_, string memory contractURI_) payable { + owner = msg.sender; + _baseurl = baseurl_; + contractURI = contractURI_; } /// @dev just in case we need to update the collection, owner should renounceOwnership after everything is ok - function changeBaseurl(string memory newBaseurl) external onlyOwner { - baseurl = newBaseurl; - emit UpdateBaseurl(newBaseurl); + function changeBaseurl(string memory baseurl_) external payable onlyOwner { + _baseurl = baseurl_; + } + /// @dev just in case we need to update the collection, owner should renounceOwnership after everything is ok + function changeContractUri(string memory contractURI_) external payable onlyOwner { + contractURI = contractURI_; } function tokenURI(uint256 id) external view returns (string memory url) { - require(id > 0 && id < 1025, "invalid token"); - url = string.concat(baseurl, LibString.toString(id), ".json"); + unchecked { + if ((id-1) > 1024) revert("invalid token id"); + } + url = string.concat(_baseurl, LibString.toString(id), ".json"); } } diff --git a/test/E2E.t.sol b/test/E2E.t.sol index 8dc9009..84a7892 100644 --- a/test/E2E.t.sol +++ b/test/E2E.t.sol @@ -23,7 +23,7 @@ contract E2ETest is Test { vm.createSelectFork("https://ethereum-goerli.publicnode.com"); vm.startPrank(owner); - TokenRenderer renderer = new TokenRenderer("ipfs://bafybeia7h7n6osru3b4mvivjb3h2fkonvmotobvboqw3k3v4pvyv5oyzse/"); + TokenRenderer renderer = new TokenRenderer("ipfs://bafybeia7h7n6osru3b4mvivjb3h2fkonvmotobvboqw3k3v4pvyv5oyzse/", "contract uri"); bytes memory bytecode = vm.compile(address(renderer), MERKLE_ROOT); // send owner to the constructor diff --git a/test/Huffplug.t.sol b/test/Huffplug.t.sol index b2eb7b1..8c7cd92 100644 --- a/test/Huffplug.t.sol +++ b/test/Huffplug.t.sol @@ -12,24 +12,27 @@ using {compile} for Vm; contract ButtplugTest is Test { IHuffplug public huffplug; + TokenRenderer public tokenRenderer; - bytes32 SALT_SLOT = bytes32(uint256(0x01)); - bytes32 TOTAL_MINTED_SLOT = bytes32(uint256(0x02)); + bytes32 SALT_SLOT = bytes32(uint256(0x00)); + bytes32 TOTAL_MINTED_SLOT = bytes32(uint256(0x01)); address public user = makeAddr("user"); address public owner = makeAddr("owner"); address public minter = makeAddr("minter"); string baseUrl = "ipfs://bafybeia7h7n6osru3b4mvivjb3h2fkonvmotobvboqw3k3v4pvyv5oyzse/"; + string contractURI = "ipfs://CONTRACTURI/"; function setUp() public { vm.warp(1000000); - TokenRenderer renderer = new TokenRenderer(baseUrl); + vm.prank(owner); + TokenRenderer renderer = new TokenRenderer(baseUrl, contractURI); bytes memory bytecode = vm.compile(address(renderer), 0x51496785f4dd04d525b568df7fa6f1057799bc21f7e76c26ee77d2f569b40601); // send owner to the constructor, owner is only for opensea main page admin - bytecode = bytes.concat(bytecode, abi.encode(owner)); + bytecode = bytes.concat(bytecode); address deployed; assembly { @@ -213,7 +216,7 @@ contract ButtplugTest is Test { function testRendererFuzz(uint256 id) public { - /* + if (id == 0 || id > 1024) { vm.expectRevert(); huffplug.tokenURI(id); @@ -221,7 +224,7 @@ contract ButtplugTest is Test { string memory expected = string.concat(baseUrl, LibString.toString(id), ".json"); assertEq(huffplug.tokenURI(id), expected); } - */ + id = bound(id, 1, 1024); string memory expected = string.concat(baseUrl, LibString.toString(id), ".json"); assertEq(huffplug.tokenURI(id), expected); @@ -254,11 +257,11 @@ contract ButtplugTest is Test { vm.prank(new_owner); vm.expectRevert(); - huffplug.setOwner(new_owner); + tokenRenderer.transferOwnership(new_owner); assertEq(owner, huffplug.owner()); vm.prank(owner); - huffplug.setOwner(new_owner); + tokenRenderer.transferOwnership(new_owner); assertEq(new_owner, huffplug.owner()); } } diff --git a/test/TokenRenderer.t.sol b/test/TokenRenderer.t.sol index 3e189e0..afb70d7 100644 --- a/test/TokenRenderer.t.sol +++ b/test/TokenRenderer.t.sol @@ -10,8 +10,8 @@ contract RendererTest is Test { TokenRenderer renderer2; function setUp() public { - renderer1 = new TokenRenderer("https://huffplug1.com/"); - renderer2 = new TokenRenderer("https://huffplug2.com/"); + renderer1 = new TokenRenderer("https://huffplug1.com/", "contracturi1"); + renderer2 = new TokenRenderer("https://huffplug2.com/", "contracturi2"); } function testRenderer1(uint256 tokenId) public {