From a874e4d53e6d0c8fcb8ba01a15da50c2189064fa Mon Sep 17 00:00:00 2001 From: Yash Date: Tue, 19 Mar 2024 00:39:09 +0530 Subject: [PATCH 01/30] Airdrop --- .../prebuilts/unaudited/airdrop/Airdrop.sol | 279 ++++++++++++++++++ 1 file changed, 279 insertions(+) create mode 100644 contracts/prebuilts/unaudited/airdrop/Airdrop.sol diff --git a/contracts/prebuilts/unaudited/airdrop/Airdrop.sol b/contracts/prebuilts/unaudited/airdrop/Airdrop.sol new file mode 100644 index 000000000..9efa4cedd --- /dev/null +++ b/contracts/prebuilts/unaudited/airdrop/Airdrop.sol @@ -0,0 +1,279 @@ +// SPDX-License-Identifier: Apache-2.0 +pragma solidity ^0.8.11; + +/// @author thirdweb + +// $$\ $$\ $$\ $$\ $$\ +// $$ | $$ | \__| $$ | $$ | +// $$$$$$\ $$$$$$$\ $$\ $$$$$$\ $$$$$$$ |$$\ $$\ $$\ $$$$$$\ $$$$$$$\ +// \_$$ _| $$ __$$\ $$ |$$ __$$\ $$ __$$ |$$ | $$ | $$ |$$ __$$\ $$ __$$\ +// $$ | $$ | $$ |$$ |$$ | \__|$$ / $$ |$$ | $$ | $$ |$$$$$$$$ |$$ | $$ | +// $$ |$$\ $$ | $$ |$$ |$$ | $$ | $$ |$$ | $$ | $$ |$$ ____|$$ | $$ | +// \$$$$ |$$ | $$ |$$ |$$ | \$$$$$$$ |\$$$$$\$$$$ |\$$$$$$$\ $$$$$$$ | +// \____/ \__| \__|\__|\__| \_______| \_____\____/ \_______|\_______/ + +import { Initializable } from "../../../extension/Initializable.sol"; +import { Ownable } from "../../../extension/Ownable.sol"; + +import "../../../eip/interface/IERC721.sol"; +import "../../../eip/interface/IERC1155.sol"; +import "../../../lib/MerkleProof.sol"; +import "../../../lib/CurrencyTransferLib.sol"; + +contract Airdrop is Initializable, Ownable { + /*/////////////////////////////////////////////////////////////// + State & structs + //////////////////////////////////////////////////////////////*/ + + // ERC20 claimable + address public tokenAddress20; + mapping(address => bytes32) public merkleRoot20; + mapping(address => bool) public claimed20; + + // Native token claimable + bytes32 public merkleRootETH; + mapping(address => bool) public claimedETH; + + // ERC721 claimable + address public tokenAddress721; + mapping(address => bytes32) public merkleRoot721; + mapping(uint256 => bool) public claimed721; + + // ERC1155 claimable + address public tokenAddress1155; + mapping(address => bytes32) public merkleRoot1155; + mapping(uint256 => mapping(address => bool)) public claimed1155; + + struct AirdropContent20 { + address recipient; + uint256 amount; + } + + struct AirdropContent721 { + address recipient; + uint256 tokenId; + } + + struct AirdropContent1155 { + address recipient; + uint256 tokenId; + uint256 amount; + } + + /*/////////////////////////////////////////////////////////////// + Errors + //////////////////////////////////////////////////////////////*/ + + error AirdropInvalidProof(); + error AirdropFailed(); + error AirdropNoMerkleRoot(); + error AirdropValueMismatch(); + + /*/////////////////////////////////////////////////////////////// + Constructor + //////////////////////////////////////////////////////////////*/ + + constructor() { + _disableInitializers(); + } + + function initialize(address _defaultAdmin) external initializer { + _setupOwner(_defaultAdmin); + } + + /*/////////////////////////////////////////////////////////////// + Airdrop Push + //////////////////////////////////////////////////////////////*/ + + function airdropERC20(address _tokenAddress, AirdropContent20[] calldata _contents) external { + address _from = msg.sender; + uint256 len = _contents.length; + + for (uint256 i = 0; i < len; ) { + CurrencyTransferLib.transferCurrency(_tokenAddress, _from, _contents[i].recipient, _contents[i].amount); + + unchecked { + i += 1; + } + } + } + + function airdropNativeToken(AirdropContent20[] calldata _contents) external payable { + uint256 len = _contents.length; + + uint256 nativeTokenAmount; + uint256 refundAmount; + + for (uint256 i = 0; i < len; ) { + nativeTokenAmount += _contents[i].amount; + + if (nativeTokenAmount > msg.value) { + revert AirdropValueMismatch(); + } + + (bool success, ) = _contents[i].recipient.call{ value: _contents[i].amount }(""); + + if (!success) { + refundAmount += _contents[i].amount; + } + + unchecked { + i += 1; + } + } + + if (nativeTokenAmount != msg.value) { + revert AirdropValueMismatch(); + } + + if (refundAmount > 0) { + // refund failed payments' amount to sender address + // solhint-disable avoid-low-level-calls + // slither-disable-next-line low-level-calls + (bool refundSuccess, ) = msg.sender.call{ value: refundAmount }(""); + } + } + + function airdrop721(address _tokenAddress, AirdropContent721[] calldata _contents) external { + address _from = msg.sender; + + uint256 len = _contents.length; + + for (uint256 i = 0; i < len; ) { + IERC721(_tokenAddress).safeTransferFrom(_from, _contents[i].recipient, _contents[i].tokenId); + + unchecked { + i += 1; + } + } + } + + function airdropERC1155(address _tokenAddress, AirdropContent1155[] calldata _contents) external { + address _from = msg.sender; + + uint256 len = _contents.length; + + for (uint256 i = 0; i < len; ) { + IERC1155(_tokenAddress).safeTransferFrom( + _from, + _contents[i].recipient, + _contents[i].tokenId, + _contents[i].amount, + "" + ); + + unchecked { + i += 1; + } + } + } + + /*/////////////////////////////////////////////////////////////// + Airdrop Claimable + //////////////////////////////////////////////////////////////*/ + + function claim20(address _token, address _receiver, uint256 _quantity, bytes32[] calldata _proofs) external { + bytes32 _merkleRoot = merkleRoot20[_token]; + + if (_merkleRoot == bytes32(0)) { + revert AirdropNoMerkleRoot(); + } + + bool valid; + (valid, ) = MerkleProof.verify(_proofs, _merkleRoot, keccak256(abi.encodePacked(msg.sender, _quantity))); + + if (!valid) { + revert AirdropInvalidProof(); + } + + claimed20[msg.sender] = true; + + CurrencyTransferLib.transferCurrency(tokenAddress20, owner(), _receiver, _quantity); + } + + function claimETH(address _receiver, uint256 _quantity, bytes32[] calldata _proofs) external { + bool valid; + (valid, ) = MerkleProof.verify(_proofs, merkleRootETH, keccak256(abi.encodePacked(msg.sender, _quantity))); + + if (!valid) { + revert AirdropInvalidProof(); + } + + claimedETH[msg.sender] = true; + + (bool success, ) = _receiver.call{ value: _quantity }(""); + if (!success) revert AirdropFailed(); + } + + function claim721(address _token, address _receiver, uint256 _tokenId, bytes32[] calldata _proofs) external { + bytes32 _merkleRoot = merkleRoot721[_token]; + + if (_merkleRoot == bytes32(0)) { + revert AirdropNoMerkleRoot(); + } + + bool valid; + (valid, ) = MerkleProof.verify(_proofs, _merkleRoot, keccak256(abi.encodePacked(msg.sender, _tokenId))); + + if (!valid) { + revert AirdropInvalidProof(); + } + + claimed721[_tokenId] = true; + + IERC721(tokenAddress721).safeTransferFrom(owner(), _receiver, _tokenId); + } + + function claim1155( + address _token, + address _receiver, + uint256 _tokenId, + uint256 _quantity, + bytes32[] calldata _proofs + ) external { + bytes32 _merkleRoot = merkleRoot1155[_token]; + + if (_merkleRoot == bytes32(0)) { + revert AirdropNoMerkleRoot(); + } + + bool valid; + (valid, ) = MerkleProof.verify(_proofs, _merkleRoot, keccak256(abi.encodePacked(msg.sender, _quantity))); + + if (!valid) { + revert AirdropInvalidProof(); + } + + claimed1155[_tokenId][msg.sender] = true; + + IERC1155(tokenAddress1155).safeTransferFrom(owner(), _receiver, _tokenId, _quantity, ""); + } + + /*/////////////////////////////////////////////////////////////// + Setter functions + //////////////////////////////////////////////////////////////*/ + + function setMerkleRoot20(address _token, bytes32 _merkleRoot) external onlyOwner { + merkleRoot20[_token] = _merkleRoot; + } + + function setMerkleRootETH(bytes32 _merkleRoot) external onlyOwner { + merkleRootETH = _merkleRoot; + } + + function setMerkleRoot721(address _token, bytes32 _merkleRoot) external onlyOwner { + merkleRoot721[_token] = _merkleRoot; + } + + function setMerkleRoot1155(address _token, bytes32 _merkleRoot) external onlyOwner { + merkleRoot1155[_token] = _merkleRoot; + } + + /*/////////////////////////////////////////////////////////////// + Miscellaneous + //////////////////////////////////////////////////////////////*/ + + function _canSetOwner() internal view virtual override returns (bool) { + return msg.sender == owner(); + } +} From 1ed800a1568e7c67de00d96d292cbea8b91b3ca5 Mon Sep 17 00:00:00 2001 From: Yash Date: Tue, 19 Mar 2024 11:04:34 +0530 Subject: [PATCH 02/30] airdrop with signature --- .gitmodules | 3 + .../prebuilts/unaudited/airdrop/Airdrop.sol | 276 +++++++++++++++++- foundry.toml | 1 + lib/solady | 1 + 4 files changed, 271 insertions(+), 10 deletions(-) create mode 160000 lib/solady diff --git a/.gitmodules b/.gitmodules index 7872f5e50..6cf023db0 100644 --- a/.gitmodules +++ b/.gitmodules @@ -22,3 +22,6 @@ [submodule "lib/dynamic-contracts"] path = lib/dynamic-contracts url = https://github.com/thirdweb-dev/dynamic-contracts +[submodule "lib/solady"] + path = lib/solady + url = https://github.com/vectorized/solady diff --git a/contracts/prebuilts/unaudited/airdrop/Airdrop.sol b/contracts/prebuilts/unaudited/airdrop/Airdrop.sol index 9efa4cedd..364fa2056 100644 --- a/contracts/prebuilts/unaudited/airdrop/Airdrop.sol +++ b/contracts/prebuilts/unaudited/airdrop/Airdrop.sol @@ -12,6 +12,10 @@ pragma solidity ^0.8.11; // \$$$$ |$$ | $$ |$$ |$$ | \$$$$$$$ |\$$$$$\$$$$ |\$$$$$$$\ $$$$$$$ | // \____/ \__| \__|\__|\__| \_______| \_____\____/ \_______|\_______/ +import "@solady/src/utils/MerkleProofLib.sol"; +import "@solady/src/utils/ECDSA.sol"; +import "@solady/src/utils/EIP712.sol"; + import { Initializable } from "../../../extension/Initializable.sol"; import { Ownable } from "../../../extension/Ownable.sol"; @@ -20,9 +24,11 @@ import "../../../eip/interface/IERC1155.sol"; import "../../../lib/MerkleProof.sol"; import "../../../lib/CurrencyTransferLib.sol"; -contract Airdrop is Initializable, Ownable { +contract Airdrop is EIP712, Initializable, Ownable { + using ECDSA for bytes32; + /*/////////////////////////////////////////////////////////////// - State & structs + State, constants & structs //////////////////////////////////////////////////////////////*/ // ERC20 claimable @@ -44,6 +50,9 @@ contract Airdrop is Initializable, Ownable { mapping(address => bytes32) public merkleRoot1155; mapping(uint256 => mapping(address => bool)) public claimed1155; + /// @dev Mapping from request UID => whether the request is processed. + mapping(bytes32 => bool) private processed; + struct AirdropContent20 { address recipient; uint256 amount; @@ -60,6 +69,47 @@ contract Airdrop is Initializable, Ownable { uint256 amount; } + struct AirdropRequest20 { + bytes32 uid; + address tokenAddress; + uint256 expirationTimestamp; + AirdropContent20[] contents; + } + + struct AirdropRequest721 { + bytes32 uid; + address tokenAddress; + uint256 expirationTimestamp; + AirdropContent721[] contents; + } + + struct AirdropRequest1155 { + bytes32 uid; + address tokenAddress; + uint256 expirationTimestamp; + AirdropContent1155[] contents; + } + + bytes32 private constant CONTENT_TYPEHASH_ERC20 = keccak256("AirdropContent20(address recipient,uint256 amount)"); + bytes32 private constant REQUEST_TYPEHASH_ERC20 = + keccak256( + "AirdropRequest20(bytes32 uid,address tokenAddress,uint256 expirationTimestamp,AirdropContent20[] contents)AirdropContent20(address recipient,uint256 amount)" + ); + + bytes32 private constant CONTENT_TYPEHASH_ERC721 = + keccak256("AirdropContent721(address recipient,uint256 tokenId)"); + bytes32 private constant REQUEST_TYPEHASH_ERC721 = + keccak256( + "AirdropRequest721(bytes32 uid,address tokenAddress,uint256 expirationTimestamp,AirdropContent721[] contents)AirdropContent721(address recipient,uint256 tokenId)" + ); + + bytes32 private constant CONTENT_TYPEHASH_ERC1155 = + keccak256("AirdropContent1155(address recipient,uint256 tokenId,uint256 amount)"); + bytes32 private constant REQUEST_TYPEHASH_ERC1155 = + keccak256( + "AirdropRequest1155(bytes32 uid,address tokenAddress,uint256 expirationTimestamp,AirdropContent1155[] contents)AirdropContent1155(address recipient,uint256 tokenId,uint256 amount)" + ); + /*/////////////////////////////////////////////////////////////// Errors //////////////////////////////////////////////////////////////*/ @@ -68,6 +118,9 @@ contract Airdrop is Initializable, Ownable { error AirdropFailed(); error AirdropNoMerkleRoot(); error AirdropValueMismatch(); + error AirdropRequestExpired(uint256 expirationTimestamp); + error AirdropVerificationFailed(); + error AirdropInvalidTokenAddress(); /*/////////////////////////////////////////////////////////////// Constructor @@ -168,6 +221,141 @@ contract Airdrop is Initializable, Ownable { } } + /*/////////////////////////////////////////////////////////////// + Airdrop With Signature + //////////////////////////////////////////////////////////////*/ + + function airdropERC20WithSignature(AirdropRequest20 calldata req, bytes calldata signature) external { + // verify expiration timestamp + if (req.expirationTimestamp < block.timestamp) { + revert AirdropRequestExpired(req.expirationTimestamp); + } + + // verify data + if (!_verifyReqERC20(req, signature)) { + revert AirdropVerificationFailed(); + } + + address _from = owner(); + uint256 len = req.contents.length; + + for (uint256 i = 0; i < len; ) { + CurrencyTransferLib.transferCurrency( + req.tokenAddress, + _from, + req.contents[i].recipient, + req.contents[i].amount + ); + + unchecked { + i += 1; + } + } + } + + function airdropNativeTokenWithSignature(AirdropRequest20 calldata req, bytes calldata signature) external payable { + // verify expiration timestamp + if (req.expirationTimestamp < block.timestamp) { + revert AirdropRequestExpired(req.expirationTimestamp); + } + + if (req.tokenAddress != address(0)) { + revert AirdropInvalidTokenAddress(); + } + + // verify data + if (!_verifyReqERC20(req, signature)) { + revert AirdropVerificationFailed(); + } + + address _from = owner(); + uint256 len = req.contents.length; + + uint256 nativeTokenAmount; + uint256 refundAmount; + + for (uint256 i = 0; i < len; ) { + nativeTokenAmount += req.contents[i].amount; + + if (nativeTokenAmount > msg.value) { + revert AirdropValueMismatch(); + } + + (bool success, ) = req.contents[i].recipient.call{ value: req.contents[i].amount }(""); + + if (!success) { + refundAmount += req.contents[i].amount; + } + + unchecked { + i += 1; + } + } + + if (nativeTokenAmount != msg.value) { + revert AirdropValueMismatch(); + } + + if (refundAmount > 0) { + // refund failed payments' amount to sender address + // solhint-disable avoid-low-level-calls + // slither-disable-next-line low-level-calls + (bool refundSuccess, ) = _from.call{ value: refundAmount }(""); + } + } + + function airdrop721WithSignature(AirdropRequest721 calldata req, bytes calldata signature) external { + // verify expiration timestamp + if (req.expirationTimestamp < block.timestamp) { + revert AirdropRequestExpired(req.expirationTimestamp); + } + + // verify data + if (!_verifyReqERC721(req, signature)) { + revert AirdropVerificationFailed(); + } + + address _from = owner(); + uint256 len = req.contents.length; + + for (uint256 i = 0; i < len; ) { + IERC721(req.tokenAddress).safeTransferFrom(_from, req.contents[i].recipient, req.contents[i].tokenId); + + unchecked { + i += 1; + } + } + } + + function airdropERC1155WithSignature(AirdropRequest1155 calldata req, bytes calldata signature) external { + // verify expiration timestamp + if (req.expirationTimestamp < block.timestamp) { + revert AirdropRequestExpired(req.expirationTimestamp); + } + + // verify data + if (!_verifyReqERC1155(req, signature)) { + revert AirdropVerificationFailed(); + } + + address _from = owner(); + uint256 len = req.contents.length; + + for (uint256 i = 0; i < len; ) { + IERC1155(req.tokenAddress).safeTransferFrom( + _from, + req.contents[i].recipient, + req.contents[i].tokenId, + req.contents[i].amount, + "" + ); + + unchecked { + i += 1; + } + } + } + /*/////////////////////////////////////////////////////////////// Airdrop Claimable //////////////////////////////////////////////////////////////*/ @@ -179,8 +367,7 @@ contract Airdrop is Initializable, Ownable { revert AirdropNoMerkleRoot(); } - bool valid; - (valid, ) = MerkleProof.verify(_proofs, _merkleRoot, keccak256(abi.encodePacked(msg.sender, _quantity))); + bool valid = MerkleProofLib.verify(_proofs, _merkleRoot, keccak256(abi.encodePacked(msg.sender, _quantity))); if (!valid) { revert AirdropInvalidProof(); @@ -192,8 +379,7 @@ contract Airdrop is Initializable, Ownable { } function claimETH(address _receiver, uint256 _quantity, bytes32[] calldata _proofs) external { - bool valid; - (valid, ) = MerkleProof.verify(_proofs, merkleRootETH, keccak256(abi.encodePacked(msg.sender, _quantity))); + bool valid = MerkleProofLib.verify(_proofs, merkleRootETH, keccak256(abi.encodePacked(msg.sender, _quantity))); if (!valid) { revert AirdropInvalidProof(); @@ -212,8 +398,7 @@ contract Airdrop is Initializable, Ownable { revert AirdropNoMerkleRoot(); } - bool valid; - (valid, ) = MerkleProof.verify(_proofs, _merkleRoot, keccak256(abi.encodePacked(msg.sender, _tokenId))); + bool valid = MerkleProofLib.verify(_proofs, _merkleRoot, keccak256(abi.encodePacked(msg.sender, _tokenId))); if (!valid) { revert AirdropInvalidProof(); @@ -237,8 +422,7 @@ contract Airdrop is Initializable, Ownable { revert AirdropNoMerkleRoot(); } - bool valid; - (valid, ) = MerkleProof.verify(_proofs, _merkleRoot, keccak256(abi.encodePacked(msg.sender, _quantity))); + bool valid = MerkleProofLib.verify(_proofs, _merkleRoot, keccak256(abi.encodePacked(msg.sender, _quantity))); if (!valid) { revert AirdropInvalidProof(); @@ -276,4 +460,76 @@ contract Airdrop is Initializable, Ownable { function _canSetOwner() internal view virtual override returns (bool) { return msg.sender == owner(); } + + function _domainNameAndVersion() internal pure override returns (string memory name, string memory version) { + name = "Airdrop"; + version = "1"; + } + + function _hashContentInfo20(AirdropContent20[] calldata contents) private pure returns (bytes32) { + bytes32[] memory contentHashes = new bytes32[](contents.length); + for (uint i = 0; i < contents.length; i++) { + contentHashes[i] = keccak256(abi.encode(CONTENT_TYPEHASH_ERC20, contents[i].recipient, contents[i].amount)); + } + return keccak256(abi.encodePacked(contentHashes)); + } + + function _hashContentInfo721(AirdropContent721[] calldata contents) private pure returns (bytes32) { + bytes32[] memory contentHashes = new bytes32[](contents.length); + for (uint i = 0; i < contents.length; i++) { + contentHashes[i] = keccak256( + abi.encode(CONTENT_TYPEHASH_ERC721, contents[i].recipient, contents[i].tokenId) + ); + } + return keccak256(abi.encodePacked(contentHashes)); + } + + function _hashContentInfo1155(AirdropContent1155[] calldata contents) private pure returns (bytes32) { + bytes32[] memory contentHashes = new bytes32[](contents.length); + for (uint i = 0; i < contents.length; i++) { + contentHashes[i] = keccak256( + abi.encode(CONTENT_TYPEHASH_ERC1155, contents[i].recipient, contents[i].tokenId, contents[i].amount) + ); + } + return keccak256(abi.encodePacked(contentHashes)); + } + + function _verifyReqERC20(AirdropRequest20 calldata req, bytes calldata signature) private view returns (bool) { + bytes32 contentHash = _hashContentInfo20(req.contents); + bytes32 structHash = keccak256( + abi.encode(REQUEST_TYPEHASH_ERC20, req.uid, req.tokenAddress, req.expirationTimestamp, contentHash) + ); + + bytes32 digest = _hashTypedData(structHash); + address recovered = digest.recover(signature); + bool valid = recovered == owner() && !processed[req.uid]; + + return valid; + } + + function _verifyReqERC721(AirdropRequest721 calldata req, bytes calldata signature) private view returns (bool) { + bytes32 contentHash = _hashContentInfo721(req.contents); + bytes32 structHash = keccak256( + abi.encode(REQUEST_TYPEHASH_ERC721, req.uid, req.tokenAddress, req.expirationTimestamp, contentHash) + ); + + bytes32 digest = _hashTypedData(structHash); + address recovered = digest.recover(signature); + bool valid = recovered == owner() && !processed[req.uid]; + + return valid; + } + + function _verifyReqERC1155(AirdropRequest1155 calldata req, bytes calldata signature) private view returns (bool) { + bytes32 contentHash = _hashContentInfo1155(req.contents); + bytes32 structHash = keccak256( + abi.encode(REQUEST_TYPEHASH_ERC1155, req.uid, req.tokenAddress, req.expirationTimestamp, contentHash) + ); + + bytes32 digest = _hashTypedData(structHash); + address recovered = digest.recover(signature); + bool valid = recovered == owner() && !processed[req.uid]; + + return valid; + } } diff --git a/foundry.toml b/foundry.toml index a86fc9b13..1512dadaa 100644 --- a/foundry.toml +++ b/foundry.toml @@ -39,6 +39,7 @@ remappings = [ 'erc721a/=lib/ERC721A/', '@thirdweb-dev/dynamic-contracts/=lib/dynamic-contracts/', 'lib/sstore2=lib/dynamic-contracts/lib/sstore2/', + '@solady/=lib/solady/', ] fs_permissions = [{ access = "read-write", path = "./src/test/smart-wallet/utils"}] src = 'contracts' diff --git a/lib/solady b/lib/solady new file mode 160000 index 000000000..c6738e402 --- /dev/null +++ b/lib/solady @@ -0,0 +1 @@ +Subproject commit c6738e40225288842ce890cd265a305684e52c3d From 6fae75a5655d3496f64a6172924394d70abb2c20 Mon Sep 17 00:00:00 2001 From: Yash Date: Tue, 19 Mar 2024 14:10:43 +0530 Subject: [PATCH 03/30] benchmark tests --- .../prebuilts/unaudited/airdrop/Airdrop.sol | 11 +- gasreport.txt | 378 ++++++----- package.json | 2 +- src/test/benchmark/AirdropBenchmark.t.sol | 621 ++++++++++++++++++ .../utils/AABenchmarkArtifacts.sol | 4 +- 5 files changed, 832 insertions(+), 184 deletions(-) create mode 100644 src/test/benchmark/AirdropBenchmark.t.sol diff --git a/contracts/prebuilts/unaudited/airdrop/Airdrop.sol b/contracts/prebuilts/unaudited/airdrop/Airdrop.sol index 364fa2056..1c9c1f7fe 100644 --- a/contracts/prebuilts/unaudited/airdrop/Airdrop.sol +++ b/contracts/prebuilts/unaudited/airdrop/Airdrop.sol @@ -138,7 +138,7 @@ contract Airdrop is EIP712, Initializable, Ownable { Airdrop Push //////////////////////////////////////////////////////////////*/ - function airdropERC20(address _tokenAddress, AirdropContent20[] calldata _contents) external { + function airdrop20(address _tokenAddress, AirdropContent20[] calldata _contents) external { address _from = msg.sender; uint256 len = _contents.length; @@ -201,7 +201,7 @@ contract Airdrop is EIP712, Initializable, Ownable { } } - function airdropERC1155(address _tokenAddress, AirdropContent1155[] calldata _contents) external { + function airdrop1155(address _tokenAddress, AirdropContent1155[] calldata _contents) external { address _from = msg.sender; uint256 len = _contents.length; @@ -225,7 +225,7 @@ contract Airdrop is EIP712, Initializable, Ownable { Airdrop With Signature //////////////////////////////////////////////////////////////*/ - function airdropERC20WithSignature(AirdropRequest20 calldata req, bytes calldata signature) external { + function airdrop20WithSignature(AirdropRequest20 calldata req, bytes calldata signature) external { // verify expiration timestamp if (req.expirationTimestamp < block.timestamp) { revert AirdropRequestExpired(req.expirationTimestamp); @@ -327,7 +327,7 @@ contract Airdrop is EIP712, Initializable, Ownable { } } - function airdropERC1155WithSignature(AirdropRequest1155 calldata req, bytes calldata signature) external { + function airdrop1155WithSignature(AirdropRequest1155 calldata req, bytes calldata signature) external { // verify expiration timestamp if (req.expirationTimestamp < block.timestamp) { revert AirdropRequestExpired(req.expirationTimestamp); @@ -438,6 +438,7 @@ contract Airdrop is EIP712, Initializable, Ownable { //////////////////////////////////////////////////////////////*/ function setMerkleRoot20(address _token, bytes32 _merkleRoot) external onlyOwner { + tokenAddress20 = _token; merkleRoot20[_token] = _merkleRoot; } @@ -446,10 +447,12 @@ contract Airdrop is EIP712, Initializable, Ownable { } function setMerkleRoot721(address _token, bytes32 _merkleRoot) external onlyOwner { + tokenAddress721 = _token; merkleRoot721[_token] = _merkleRoot; } function setMerkleRoot1155(address _token, bytes32 _merkleRoot) external onlyOwner { + tokenAddress1155 = _token; merkleRoot1155[_token] = _merkleRoot; } diff --git a/gasreport.txt b/gasreport.txt index ea8d57ffc..149430dfc 100644 --- a/gasreport.txt +++ b/gasreport.txt @@ -1,181 +1,205 @@ No files changed, compilation skipped -Running 2 tests for src/test/benchmark/MultiwrapBenchmark.t.sol:MultiwrapBenchmarkTest -[PASS] test_benchmark_multiwrap_unwrap() (gas: 88950) -[PASS] test_benchmark_multiwrap_wrap() (gas: 473462) -Test result: ok. 2 passed; 0 failed; 0 skipped; finished in 236.08ms - -Running 3 tests for src/test/benchmark/EditionStakeBenchmark.t.sol:EditionStakeBenchmarkTest -[PASS] test_benchmark_editionStake_claimRewards() (gas: 65081) -[PASS] test_benchmark_editionStake_stake() (gas: 185144) -[PASS] test_benchmark_editionStake_withdraw() (gas: 46364) -Test result: ok. 3 passed; 0 failed; 0 skipped; finished in 238.67ms - -Running 3 tests for src/test/benchmark/TokenStakeBenchmark.t.sol:TokenStakeBenchmarkTest -[PASS] test_benchmark_tokenStake_claimRewards() (gas: 67554) -[PASS] test_benchmark_tokenStake_stake() (gas: 177180) -[PASS] test_benchmark_tokenStake_withdraw() (gas: 47396) -Test result: ok. 3 passed; 0 failed; 0 skipped; finished in 241.12ms - -Running 4 tests for src/test/benchmark/TokenERC1155Benchmark.t.sol:TokenERC1155BenchmarkTest -[PASS] test_benchmark_tokenERC1155_burn() (gas: 5728) -[PASS] test_benchmark_tokenERC1155_mintTo() (gas: 122286) -[PASS] test_benchmark_tokenERC1155_mintWithSignature_pay_with_ERC20() (gas: 267175) -[PASS] test_benchmark_tokenERC1155_mintWithSignature_pay_with_native_token() (gas: 296172) -Test result: ok. 4 passed; 0 failed; 0 skipped; finished in 240.92ms - -Running 1 test for src/test/benchmark/AirdropERC1155Benchmark.t.sol:AirdropERC1155BenchmarkTest -[PASS] test_benchmark_airdropERC1155_airdrop() (gas: 38083572) -Test result: ok. 1 passed; 0 failed; 0 skipped; finished in 269.27ms - -Running 1 test for src/test/benchmark/AirdropERC20Benchmark.t.sol:AirdropERC20BenchmarkTest -[PASS] test_benchmark_airdropERC20_airdrop() (gas: 32068413) -Test result: ok. 1 passed; 0 failed; 0 skipped; finished in 270.94ms - -Running 1 test for src/test/smart-wallet/utils/AABenchmarkPrepare.sol:AABenchmarkPrepare -[PASS] test_prepareBenchmarkFile() (gas: 2926370) -Test result: ok. 1 passed; 0 failed; 0 skipped; finished in 272.43ms - -Running 1 test for src/test/benchmark/AirdropERC721Benchmark.t.sol:AirdropERC721BenchmarkTest -[PASS] test_benchmark_airdropERC721_airdrop() (gas: 41912536) -Test result: ok. 1 passed; 0 failed; 0 skipped; finished in 297.69ms - -Running 4 tests for src/test/benchmark/TokenERC721Benchmark.t.sol:TokenERC721BenchmarkTest -[PASS] test_benchmark_tokenERC721_burn() (gas: 8954) -[PASS] test_benchmark_tokenERC721_mintTo() (gas: 151552) -[PASS] test_benchmark_tokenERC721_mintWithSignature_pay_with_ERC20() (gas: 262344) -[PASS] test_benchmark_tokenERC721_mintWithSignature_pay_with_native_token() (gas: 286914) -Test result: ok. 4 passed; 0 failed; 0 skipped; finished in 242.17ms - -Running 3 tests for src/test/benchmark/NFTStakeBenchmark.t.sol:NFTStakeBenchmarkTest -[PASS] test_benchmark_nftStake_claimRewards() (gas: 68287) -[PASS] test_benchmark_nftStake_stake_five_tokens() (gas: 539145) -[PASS] test_benchmark_nftStake_withdraw() (gas: 38076) -Test result: ok. 3 passed; 0 failed; 0 skipped; finished in 279.71ms - -Running 5 tests for src/test/benchmark/SignatureDropBenchmark.t.sol:SignatureDropBenchmarkTest -[PASS] test_benchmark_signatureDrop_claim_five_tokens() (gas: 140517) -[PASS] test_benchmark_signatureDrop_lazyMint() (gas: 124311) -[PASS] test_benchmark_signatureDrop_lazyMint_for_delayed_reveal() (gas: 225891) -[PASS] test_benchmark_signatureDrop_reveal() (gas: 10647) -[PASS] test_benchmark_signatureDrop_setClaimConditions() (gas: 73699) -Test result: ok. 5 passed; 0 failed; 0 skipped; finished in 251.39ms - -Running 3 tests for src/test/benchmark/TokenERC20Benchmark.t.sol:TokenERC20BenchmarkTest -[PASS] test_benchmark_tokenERC20_mintTo() (gas: 118586) -[PASS] test_benchmark_tokenERC20_mintWithSignature_pay_with_ERC20() (gas: 183032) -[PASS] test_benchmark_tokenERC20_mintWithSignature_pay_with_native_token() (gas: 207694) -Test result: ok. 3 passed; 0 failed; 0 skipped; finished in 287.73ms - -Running 14 tests for src/test/benchmark/AccountBenchmark.t.sol:AccountBenchmarkTest -[PASS] test_state_accountReceivesNativeTokens() (gas: 11037) -[PASS] test_state_addAndWithdrawDeposit() (gas: 83332) -[PASS] test_state_contractMetadata() (gas: 56507) -[PASS] test_state_createAccount_viaEntrypoint() (gas: 432040) -[PASS] test_state_createAccount_viaFactory() (gas: 334122) -[PASS] test_state_executeBatchTransaction() (gas: 39874) -[PASS] test_state_executeBatchTransaction_viaAccountSigner() (gas: 392782) -[PASS] test_state_executeBatchTransaction_viaEntrypoint() (gas: 82915) -[PASS] test_state_executeTransaction() (gas: 35735) -[PASS] test_state_executeTransaction_viaAccountSigner() (gas: 378632) -[PASS] test_state_executeTransaction_viaEntrypoint() (gas: 75593) -[PASS] test_state_receiveERC1155NFT() (gas: 39343) -[PASS] test_state_receiveERC721NFT() (gas: 78624) -[PASS] test_state_transferOutsNativeTokens() (gas: 81713) -Test result: ok. 14 passed; 0 failed; 0 skipped; finished in 364.96ms - -Running 3 tests for src/test/benchmark/PackBenchmark.t.sol:PackBenchmarkTest -[PASS] test_benchmark_pack_addPackContents() (gas: 219188) -[PASS] test_benchmark_pack_createPack() (gas: 1412868) -[PASS] test_benchmark_pack_openPack() (gas: 141860) -Test result: ok. 3 passed; 0 failed; 0 skipped; finished in 258.39ms - -Running 3 tests for src/test/benchmark/PackVRFDirectBenchmark.t.sol:PackVRFDirectBenchmarkTest -[PASS] test_benchmark_packvrf_createPack() (gas: 1379604) -[PASS] test_benchmark_packvrf_openPack() (gas: 119953) +Ran 5 tests for src/test/benchmark/SignatureDropBenchmark.t.sol:SignatureDropBenchmarkTest +[PASS] test_benchmark_signatureDrop_claim_five_tokens() (gas: 185688) +[PASS] test_benchmark_signatureDrop_lazyMint() (gas: 147153) +[PASS] test_benchmark_signatureDrop_lazyMint_for_delayed_reveal() (gas: 249057) +[PASS] test_benchmark_signatureDrop_reveal() (gas: 49802) +[PASS] test_benchmark_signatureDrop_setClaimConditions() (gas: 100719) +Suite result: ok. 5 passed; 0 failed; 0 skipped; finished in 368.34ms (798.50µs CPU time) + +Ran 14 tests for src/test/benchmark/AccountBenchmark.t.sol:AccountBenchmarkTest +[PASS] test_state_accountReceivesNativeTokens() (gas: 34537) +[PASS] test_state_addAndWithdrawDeposit() (gas: 148780) +[PASS] test_state_contractMetadata() (gas: 114307) +[PASS] test_state_createAccount_viaEntrypoint() (gas: 458192) +[PASS] test_state_createAccount_viaFactory() (gas: 355822) +[PASS] test_state_executeBatchTransaction() (gas: 76066) +[PASS] test_state_executeBatchTransaction_viaAccountSigner() (gas: 488470) +[PASS] test_state_executeBatchTransaction_viaEntrypoint() (gas: 138443) +[PASS] test_state_executeTransaction() (gas: 68891) +[PASS] test_state_executeTransaction_viaAccountSigner() (gas: 471272) +[PASS] test_state_executeTransaction_viaEntrypoint() (gas: 128073) +[PASS] test_state_receiveERC1155NFT() (gas: 66043) +[PASS] test_state_receiveERC721NFT() (gas: 100196) +[PASS] test_state_transferOutsNativeTokens() (gas: 133673) +Suite result: ok. 14 passed; 0 failed; 0 skipped; finished in 393.82ms (23.99ms CPU time) + +Ran 1 test for src/test/benchmark/AirdropERC721Benchmark.t.sol:AirdropERC721BenchmarkTest +[PASS] test_benchmark_airdropERC721_airdrop() (gas: 42241588) +Suite result: ok. 1 passed; 0 failed; 0 skipped; finished in 417.61ms (15.88ms CPU time) + +Ran 3 tests for src/test/benchmark/EditionStakeBenchmark.t.sol:EditionStakeBenchmarkTest +[PASS] test_benchmark_editionStake_claimRewards() (gas: 98765) +[PASS] test_benchmark_editionStake_stake() (gas: 203676) +[PASS] test_benchmark_editionStake_withdraw() (gas: 94296) +Suite result: ok. 3 passed; 0 failed; 0 skipped; finished in 419.06ms (660.96µs CPU time) + +Ran 1 test for src/test/smart-wallet/utils/AABenchmarkPrepare.sol:AABenchmarkPrepare +[PASS] test_prepareBenchmarkFile() (gas: 2955770) +Suite result: ok. 1 passed; 0 failed; 0 skipped; finished in 420.21ms (13.23ms CPU time) + +Ran 1 test for src/test/benchmark/AirdropERC20Benchmark.t.sol:AirdropERC20BenchmarkTest +[PASS] test_benchmark_airdropERC20_airdrop() (gas: 32443785) +Suite result: ok. 1 passed; 0 failed; 0 skipped; finished in 425.50ms (15.60ms CPU time) + +Ran 3 tests for src/test/benchmark/NFTStakeBenchmark.t.sol:NFTStakeBenchmarkTest +[PASS] test_benchmark_nftStake_claimRewards() (gas: 99831) +[PASS] test_benchmark_nftStake_stake_five_tokens() (gas: 553577) +[PASS] test_benchmark_nftStake_withdraw() (gas: 96144) +Suite result: ok. 3 passed; 0 failed; 0 skipped; finished in 450.72ms (858.67µs CPU time) + +Ran 4 tests for src/test/benchmark/TokenERC721Benchmark.t.sol:TokenERC721BenchmarkTest +[PASS] test_benchmark_tokenERC721_burn() (gas: 40392) +[PASS] test_benchmark_tokenERC721_mintTo() (gas: 172834) +[PASS] test_benchmark_tokenERC721_mintWithSignature_pay_with_ERC20() (gas: 301844) +[PASS] test_benchmark_tokenERC721_mintWithSignature_pay_with_native_token() (gas: 308814) +Suite result: ok. 4 passed; 0 failed; 0 skipped; finished in 178.08ms (1.53ms CPU time) + +Ran 2 tests for src/test/benchmark/MultiwrapBenchmark.t.sol:MultiwrapBenchmarkTest +[PASS] test_benchmark_multiwrap_unwrap() (gas: 152040) +[PASS] test_benchmark_multiwrap_wrap() (gas: 480722) +Suite result: ok. 2 passed; 0 failed; 0 skipped; finished in 188.11ms (726.04µs CPU time) + +Ran 3 tests for src/test/benchmark/PackBenchmark.t.sol:PackBenchmarkTest +[PASS] test_benchmark_pack_addPackContents() (gas: 312595) +[PASS] test_benchmark_pack_createPack() (gas: 1419379) +[PASS] test_benchmark_pack_openPack() (gas: 306658) +Suite result: ok. 3 passed; 0 failed; 0 skipped; finished in 193.93ms (2.61ms CPU time) + +Ran 3 tests for src/test/benchmark/TokenERC20Benchmark.t.sol:TokenERC20BenchmarkTest +[PASS] test_benchmark_tokenERC20_mintTo() (gas: 139513) +[PASS] test_benchmark_tokenERC20_mintWithSignature_pay_with_ERC20() (gas: 221724) +[PASS] test_benchmark_tokenERC20_mintWithSignature_pay_with_native_token() (gas: 228786) +Suite result: ok. 3 passed; 0 failed; 0 skipped; finished in 221.96ms (1.41ms CPU time) + +Ran 4 tests for src/test/benchmark/TokenERC1155Benchmark.t.sol:TokenERC1155BenchmarkTest +[PASS] test_benchmark_tokenERC1155_burn() (gas: 30352) +[PASS] test_benchmark_tokenERC1155_mintTo() (gas: 144229) +[PASS] test_benchmark_tokenERC1155_mintWithSignature_pay_with_ERC20() (gas: 307291) +[PASS] test_benchmark_tokenERC1155_mintWithSignature_pay_with_native_token() (gas: 318712) +Suite result: ok. 4 passed; 0 failed; 0 skipped; finished in 247.98ms (1.60ms CPU time) + +Ran 1 test for src/test/benchmark/AirdropERC1155Benchmark.t.sol:AirdropERC1155BenchmarkTest +[PASS] test_benchmark_airdropERC1155_airdrop() (gas: 38536544) +Suite result: ok. 1 passed; 0 failed; 0 skipped; finished in 220.05ms (26.46ms CPU time) + +Ran 3 tests for src/test/benchmark/DropERC1155Benchmark.t.sol:DropERC1155BenchmarkTest +[PASS] test_benchmark_dropERC1155_claim() (gas: 245552) +[PASS] test_benchmark_dropERC1155_lazyMint() (gas: 146425) +[PASS] test_benchmark_dropERC1155_setClaimConditions_five_conditions() (gas: 525725) +Suite result: ok. 3 passed; 0 failed; 0 skipped; finished in 828.71ms (822.94ms CPU time) + +Ran 3 tests for src/test/benchmark/PackVRFDirectBenchmark.t.sol:PackVRFDirectBenchmarkTest +[PASS] test_benchmark_packvrf_createPack() (gas: 1392387) +[PASS] test_benchmark_packvrf_openPack() (gas: 150677) [PASS] test_benchmark_packvrf_openPackAndClaimRewards() (gas: 3621) -Test result: ok. 3 passed; 0 failed; 0 skipped; finished in 285.64ms - -Running 3 tests for src/test/benchmark/DropERC1155Benchmark.t.sol:DropERC1155BenchmarkTest -[PASS] test_benchmark_dropERC1155_claim() (gas: 185032) -[PASS] test_benchmark_dropERC1155_lazyMint() (gas: 123913) -[PASS] test_benchmark_dropERC1155_setClaimConditions_five_conditions() (gas: 492121) -Test result: ok. 3 passed; 0 failed; 0 skipped; finished in 735.56ms - -Running 5 tests for src/test/benchmark/DropERC721Benchmark.t.sol:DropERC721BenchmarkTest -[PASS] test_benchmark_dropERC721_claim_five_tokens() (gas: 210967) -[PASS] test_benchmark_dropERC721_lazyMint() (gas: 124540) -[PASS] test_benchmark_dropERC721_lazyMint_for_delayed_reveal() (gas: 226149) -[PASS] test_benchmark_dropERC721_reveal() (gas: 13732) -[PASS] test_benchmark_dropERC721_setClaimConditions_five_conditions() (gas: 500494) -Test result: ok. 5 passed; 0 failed; 0 skipped; finished in 742.03ms - -Running 2 tests for src/test/benchmark/DropERC20Benchmark.t.sol:DropERC20BenchmarkTest -[PASS] test_benchmark_dropERC20_claim() (gas: 230505) -[PASS] test_benchmark_dropERC20_setClaimConditions_five_conditions() (gas: 500858) -Test result: ok. 2 passed; 0 failed; 0 skipped; finished in 1.12s - - -Ran 18 test suites: 61 tests passed, 0 failed, 0 skipped (61 total tests) -test_state_accountReceivesNativeTokens() (gas: 0 (0.000%)) -test_state_addAndWithdrawDeposit() (gas: 0 (0.000%)) -test_state_contractMetadata() (gas: 0 (0.000%)) -test_state_createAccount_viaEntrypoint() (gas: 0 (0.000%)) -test_state_createAccount_viaFactory() (gas: 0 (0.000%)) -test_state_executeBatchTransaction() (gas: 0 (0.000%)) -test_state_executeBatchTransaction_viaAccountSigner() (gas: 0 (0.000%)) -test_state_executeBatchTransaction_viaEntrypoint() (gas: 0 (0.000%)) -test_state_executeTransaction() (gas: 0 (0.000%)) -test_state_executeTransaction_viaAccountSigner() (gas: 0 (0.000%)) -test_state_executeTransaction_viaEntrypoint() (gas: 0 (0.000%)) -test_state_receiveERC1155NFT() (gas: 0 (0.000%)) -test_state_receiveERC721NFT() (gas: 0 (0.000%)) -test_state_transferOutsNativeTokens() (gas: 0 (0.000%)) -test_benchmark_airdropERC1155_airdrop() (gas: 0 (0.000%)) -test_benchmark_airdropERC20_airdrop() (gas: 0 (0.000%)) -test_benchmark_airdropERC721_airdrop() (gas: 0 (0.000%)) -test_benchmark_dropERC1155_claim() (gas: 0 (0.000%)) -test_benchmark_dropERC1155_lazyMint() (gas: 0 (0.000%)) -test_benchmark_dropERC1155_setClaimConditions_five_conditions() (gas: 0 (0.000%)) -test_benchmark_dropERC20_claim() (gas: 0 (0.000%)) -test_benchmark_dropERC20_setClaimConditions_five_conditions() (gas: 0 (0.000%)) -test_benchmark_dropERC721_claim_five_tokens() (gas: 0 (0.000%)) -test_benchmark_dropERC721_lazyMint() (gas: 0 (0.000%)) -test_benchmark_dropERC721_lazyMint_for_delayed_reveal() (gas: 0 (0.000%)) -test_benchmark_dropERC721_reveal() (gas: 0 (0.000%)) -test_benchmark_dropERC721_setClaimConditions_five_conditions() (gas: 0 (0.000%)) -test_benchmark_editionStake_claimRewards() (gas: 0 (0.000%)) -test_benchmark_editionStake_stake() (gas: 0 (0.000%)) -test_benchmark_editionStake_withdraw() (gas: 0 (0.000%)) -test_benchmark_multiwrap_unwrap() (gas: 0 (0.000%)) -test_benchmark_multiwrap_wrap() (gas: 0 (0.000%)) -test_benchmark_nftStake_claimRewards() (gas: 0 (0.000%)) -test_benchmark_nftStake_stake_five_tokens() (gas: 0 (0.000%)) -test_benchmark_nftStake_withdraw() (gas: 0 (0.000%)) -test_benchmark_pack_addPackContents() (gas: 0 (0.000%)) -test_benchmark_pack_createPack() (gas: 0 (0.000%)) -test_benchmark_pack_openPack() (gas: 0 (0.000%)) -test_benchmark_packvrf_createPack() (gas: 0 (0.000%)) -test_benchmark_packvrf_openPack() (gas: 0 (0.000%)) +Suite result: ok. 3 passed; 0 failed; 0 skipped; finished in 217.00ms (2.23ms CPU time) + +Ran 3 tests for src/test/benchmark/TokenStakeBenchmark.t.sol:TokenStakeBenchmarkTest +[PASS] test_benchmark_tokenStake_claimRewards() (gas: 101098) +[PASS] test_benchmark_tokenStake_stake() (gas: 195556) +[PASS] test_benchmark_tokenStake_withdraw() (gas: 104792) +Suite result: ok. 3 passed; 0 failed; 0 skipped; finished in 234.37ms (634.83µs CPU time) + +Ran 21 tests for src/test/benchmark/AirdropBenchmark.t.sol:AirdropBenchmarkTest +[PASS] test_benchmark_airdropClaim_erc1155() (gas: 103438) +[PASS] test_benchmark_airdropClaim_erc20() (gas: 108822) +[PASS] test_benchmark_airdropClaim_erc721() (gas: 107287) +[PASS] test_benchmark_airdropPush_erc1155_10() (gas: 367151) +[PASS] test_benchmark_airdropPush_erc1155_100() (gas: 3263016) +[PASS] test_benchmark_airdropPush_erc1155_1000() (gas: 32342317) +[PASS] test_benchmark_airdropPush_erc20_10() (gas: 358522) +[PASS] test_benchmark_airdropPush_erc20_100() (gas: 3134977) +[PASS] test_benchmark_airdropPush_erc20_1000() (gas: 31084435) +[PASS] test_benchmark_airdropPush_erc721_10() (gas: 423587) +[PASS] test_benchmark_airdropPush_erc721_100() (gas: 3833981) +[PASS] test_benchmark_airdropPush_erc721_1000() (gas: 38101966) +[PASS] test_benchmark_airdropSignature_erc115_10() (gas: 395262) +[PASS] test_benchmark_airdropSignature_erc115_100() (gas: 3436291) +[PASS] test_benchmark_airdropSignature_erc115_1000() (gas: 34308834) +[PASS] test_benchmark_airdropSignature_erc20_10() (gas: 384336) +[PASS] test_benchmark_airdropSignature_erc20_100() (gas: 3281632) +[PASS] test_benchmark_airdropSignature_erc20_1000() (gas: 32840926) +[PASS] test_benchmark_airdropSignature_erc721_10() (gas: 448563) +[PASS] test_benchmark_airdropSignature_erc721_100() (gas: 3987657) +[PASS] test_benchmark_airdropSignature_erc721_1000() (gas: 39666524) +Suite result: ok. 21 passed; 0 failed; 0 skipped; finished in 1.00s (1.31s CPU time) + +Ran 2 tests for src/test/benchmark/DropERC20Benchmark.t.sol:DropERC20BenchmarkTest +[PASS] test_benchmark_dropERC20_claim() (gas: 291508) +[PASS] test_benchmark_dropERC20_setClaimConditions_five_conditions() (gas: 530026) +Suite result: ok. 2 passed; 0 failed; 0 skipped; finished in 1.08s (708.25ms CPU time) + +Ran 5 tests for src/test/benchmark/DropERC721Benchmark.t.sol:DropERC721BenchmarkTest +[PASS] test_benchmark_dropERC721_claim_five_tokens() (gas: 273303) +[PASS] test_benchmark_dropERC721_lazyMint() (gas: 147052) +[PASS] test_benchmark_dropERC721_lazyMint_for_delayed_reveal() (gas: 248985) +[PASS] test_benchmark_dropERC721_reveal() (gas: 49433) +[PASS] test_benchmark_dropERC721_setClaimConditions_five_conditions() (gas: 529470) +Suite result: ok. 5 passed; 0 failed; 0 skipped; finished in 474.66ms (495.93ms CPU time) + + +Ran 19 test suites in 1.22s (7.98s CPU time): 82 tests passed, 0 failed, 0 skipped (82 total tests) test_benchmark_packvrf_openPackAndClaimRewards() (gas: 0 (0.000%)) -test_benchmark_signatureDrop_claim_five_tokens() (gas: 0 (0.000%)) -test_benchmark_signatureDrop_lazyMint() (gas: 0 (0.000%)) -test_benchmark_signatureDrop_lazyMint_for_delayed_reveal() (gas: 0 (0.000%)) -test_benchmark_signatureDrop_reveal() (gas: 0 (0.000%)) -test_benchmark_signatureDrop_setClaimConditions() (gas: 0 (0.000%)) -test_benchmark_tokenERC1155_burn() (gas: 0 (0.000%)) -test_benchmark_tokenERC1155_mintTo() (gas: 0 (0.000%)) -test_benchmark_tokenERC1155_mintWithSignature_pay_with_ERC20() (gas: 0 (0.000%)) -test_benchmark_tokenERC1155_mintWithSignature_pay_with_native_token() (gas: 0 (0.000%)) -test_benchmark_tokenERC20_mintTo() (gas: 0 (0.000%)) -test_benchmark_tokenERC20_mintWithSignature_pay_with_ERC20() (gas: 0 (0.000%)) -test_benchmark_tokenERC20_mintWithSignature_pay_with_native_token() (gas: 0 (0.000%)) -test_benchmark_tokenERC721_burn() (gas: 0 (0.000%)) -test_benchmark_tokenERC721_mintTo() (gas: 0 (0.000%)) -test_benchmark_tokenERC721_mintWithSignature_pay_with_ERC20() (gas: 0 (0.000%)) -test_benchmark_tokenERC721_mintWithSignature_pay_with_native_token() (gas: 0 (0.000%)) -test_benchmark_tokenStake_claimRewards() (gas: 0 (0.000%)) -test_benchmark_tokenStake_stake() (gas: 0 (0.000%)) -test_benchmark_tokenStake_withdraw() (gas: 0 (0.000%)) -test_prepareBenchmarkFile() (gas: 0 (0.000%)) -Overall gas change: 0 (0.000%) +test_benchmark_pack_createPack() (gas: 6511 (0.461%)) +test_benchmark_airdropERC721_airdrop() (gas: 329052 (0.785%)) +test_benchmark_packvrf_createPack() (gas: 12783 (0.927%)) +test_prepareBenchmarkFile() (gas: 29400 (1.005%)) +test_benchmark_airdropERC20_airdrop() (gas: 375372 (1.171%)) +test_benchmark_airdropERC1155_airdrop() (gas: 452972 (1.189%)) +test_benchmark_multiwrap_wrap() (gas: 7260 (1.533%)) +test_benchmark_nftStake_stake_five_tokens() (gas: 14432 (2.677%)) +test_benchmark_dropERC721_setClaimConditions_five_conditions() (gas: 28976 (5.789%)) +test_benchmark_dropERC20_setClaimConditions_five_conditions() (gas: 29168 (5.824%)) +test_state_createAccount_viaEntrypoint() (gas: 26152 (6.053%)) +test_state_createAccount_viaFactory() (gas: 21700 (6.495%)) +test_benchmark_dropERC1155_setClaimConditions_five_conditions() (gas: 33604 (6.828%)) +test_benchmark_tokenERC1155_mintWithSignature_pay_with_native_token() (gas: 22540 (7.610%)) +test_benchmark_tokenERC721_mintWithSignature_pay_with_native_token() (gas: 21900 (7.633%)) +test_benchmark_editionStake_stake() (gas: 18532 (10.010%)) +test_benchmark_dropERC721_lazyMint_for_delayed_reveal() (gas: 22836 (10.098%)) +test_benchmark_tokenERC20_mintWithSignature_pay_with_native_token() (gas: 21092 (10.155%)) +test_benchmark_signatureDrop_lazyMint_for_delayed_reveal() (gas: 23166 (10.255%)) +test_benchmark_tokenStake_stake() (gas: 18376 (10.371%)) +test_benchmark_tokenERC721_mintTo() (gas: 21282 (14.043%)) +test_benchmark_tokenERC1155_mintWithSignature_pay_with_ERC20() (gas: 40116 (15.015%)) +test_benchmark_tokenERC721_mintWithSignature_pay_with_ERC20() (gas: 39500 (15.057%)) +test_benchmark_tokenERC20_mintTo() (gas: 20927 (17.647%)) +test_benchmark_tokenERC1155_mintTo() (gas: 21943 (17.944%)) +test_benchmark_dropERC721_lazyMint() (gas: 22512 (18.076%)) +test_benchmark_dropERC1155_lazyMint() (gas: 22512 (18.168%)) +test_benchmark_signatureDrop_lazyMint() (gas: 22842 (18.375%)) +test_benchmark_tokenERC20_mintWithSignature_pay_with_ERC20() (gas: 38692 (21.139%)) +test_state_executeBatchTransaction_viaAccountSigner() (gas: 95688 (24.362%)) +test_state_executeTransaction_viaAccountSigner() (gas: 92640 (24.467%)) +test_benchmark_packvrf_openPack() (gas: 30724 (25.613%)) +test_benchmark_dropERC20_claim() (gas: 61003 (26.465%)) +test_state_receiveERC721NFT() (gas: 21572 (27.437%)) +test_benchmark_dropERC721_claim_five_tokens() (gas: 62336 (29.548%)) +test_benchmark_signatureDrop_claim_five_tokens() (gas: 45171 (32.146%)) +test_benchmark_dropERC1155_claim() (gas: 60520 (32.708%)) +test_benchmark_signatureDrop_setClaimConditions() (gas: 27020 (36.663%)) +test_benchmark_pack_addPackContents() (gas: 93407 (42.615%)) +test_benchmark_nftStake_claimRewards() (gas: 31544 (46.193%)) +test_benchmark_tokenStake_claimRewards() (gas: 33544 (49.655%)) +test_benchmark_editionStake_claimRewards() (gas: 33684 (51.757%)) +test_state_transferOutsNativeTokens() (gas: 51960 (63.588%)) +test_state_executeBatchTransaction_viaEntrypoint() (gas: 55528 (66.970%)) +test_state_receiveERC1155NFT() (gas: 26700 (67.865%)) +test_state_executeTransaction_viaEntrypoint() (gas: 52480 (69.424%)) +test_benchmark_multiwrap_unwrap() (gas: 63090 (70.927%)) +test_state_addAndWithdrawDeposit() (gas: 65448 (78.539%)) +test_state_executeBatchTransaction() (gas: 36192 (90.766%)) +test_state_executeTransaction() (gas: 33156 (92.783%)) +test_state_contractMetadata() (gas: 57800 (102.288%)) +test_benchmark_editionStake_withdraw() (gas: 47932 (103.382%)) +test_benchmark_pack_openPack() (gas: 164798 (116.169%)) +test_benchmark_tokenStake_withdraw() (gas: 57396 (121.099%)) +test_benchmark_nftStake_withdraw() (gas: 58068 (152.506%)) +test_state_accountReceivesNativeTokens() (gas: 23500 (212.920%)) +test_benchmark_dropERC721_reveal() (gas: 35701 (259.984%)) +test_benchmark_tokenERC721_burn() (gas: 31438 (351.106%)) +test_benchmark_signatureDrop_reveal() (gas: 39155 (367.756%)) +test_benchmark_tokenERC1155_burn() (gas: 24624 (429.888%)) +Overall gas change: 3379969 (2.656%) diff --git a/package.json b/package.json index 01a2151a7..8a2326845 100644 --- a/package.json +++ b/package.json @@ -57,7 +57,7 @@ "build": "yarn clean && yarn compile", "forge:build": "forge build", "forge:test": "forge test", - "gas": "forge snapshot --mc Benchmark --gas-report --diff .gas-snapshot > gasreport.txt", + "gas": "forge snapshot --isolate --mc Benchmark --gas-report --diff .gas-snapshot > gasreport.txt", "forge:snapshot": "forge snapshot --check", "aabenchmark": "forge test --mc AABenchmarkPrepare && forge test --mc ProfileThirdwebAccount -vvv" } diff --git a/src/test/benchmark/AirdropBenchmark.t.sol b/src/test/benchmark/AirdropBenchmark.t.sol new file mode 100644 index 000000000..5061500f7 --- /dev/null +++ b/src/test/benchmark/AirdropBenchmark.t.sol @@ -0,0 +1,621 @@ +// SPDX-License-Identifier: Apache-2.0 +pragma solidity ^0.8.0; + +import { Airdrop } from "contracts/prebuilts/unaudited/airdrop/Airdrop.sol"; + +// Test imports +import { TWProxy } from "contracts/infra/TWProxy.sol"; +import "../utils/BaseTest.sol"; + +contract AirdropBenchmarkTest is BaseTest { + Airdrop internal airdrop; + + bytes32 private constant CONTENT_TYPEHASH_ERC20 = keccak256("AirdropContent20(address recipient,uint256 amount)"); + bytes32 private constant REQUEST_TYPEHASH_ERC20 = + keccak256( + "AirdropRequest20(bytes32 uid,address tokenAddress,uint256 expirationTimestamp,AirdropContent20[] contents)AirdropContent20(address recipient,uint256 amount)" + ); + + bytes32 private constant CONTENT_TYPEHASH_ERC721 = + keccak256("AirdropContent721(address recipient,uint256 tokenId)"); + bytes32 private constant REQUEST_TYPEHASH_ERC721 = + keccak256( + "AirdropRequest721(bytes32 uid,address tokenAddress,uint256 expirationTimestamp,AirdropContent721[] contents)AirdropContent721(address recipient,uint256 tokenId)" + ); + + bytes32 private constant CONTENT_TYPEHASH_ERC1155 = + keccak256("AirdropContent1155(address recipient,uint256 tokenId,uint256 amount)"); + bytes32 private constant REQUEST_TYPEHASH_ERC1155 = + keccak256( + "AirdropRequest1155(bytes32 uid,address tokenAddress,uint256 expirationTimestamp,AirdropContent1155[] contents)AirdropContent1155(address recipient,uint256 tokenId,uint256 amount)" + ); + + bytes32 private constant NAME_HASH = keccak256(bytes("Airdrop")); + bytes32 private constant VERSION_HASH = keccak256(bytes("1")); + bytes32 private constant TYPE_HASH_EIP712 = + keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"); + + bytes32 internal domainSeparator; + + function setUp() public override { + super.setUp(); + + address impl = address(new Airdrop()); + + airdrop = Airdrop(address(new TWProxy(impl, abi.encodeCall(Airdrop.initialize, (signer))))); + + domainSeparator = keccak256( + abi.encode(TYPE_HASH_EIP712, NAME_HASH, VERSION_HASH, block.chainid, address(airdrop)) + ); + } + + function _getContentsERC20(uint256 length) internal pure returns (Airdrop.AirdropContent20[] memory contents) { + contents = new Airdrop.AirdropContent20[](length); + for (uint256 i = 0; i < length; i++) { + contents[i].recipient = address(uint160(i + 10)); + contents[i].amount = i + 10; + } + } + + function _getContentsERC721(uint256 length) internal pure returns (Airdrop.AirdropContent721[] memory contents) { + contents = new Airdrop.AirdropContent721[](length); + for (uint256 i = 0; i < length; i++) { + contents[i].recipient = address(uint160(i + 10)); + contents[i].tokenId = i; + } + } + + function _getContentsERC1155(uint256 length) internal pure returns (Airdrop.AirdropContent1155[] memory contents) { + contents = new Airdrop.AirdropContent1155[](length); + for (uint256 i = 0; i < length; i++) { + contents[i].recipient = address(uint160(i + 10)); + contents[i].tokenId = 0; + contents[i].amount = i + 10; + } + } + + function _signReqERC20( + Airdrop.AirdropRequest20 memory req, + uint256 privateKey + ) internal view returns (bytes memory signature) { + bytes32[] memory contentHashes = new bytes32[](req.contents.length); + for (uint i = 0; i < req.contents.length; i++) { + contentHashes[i] = keccak256( + abi.encode(CONTENT_TYPEHASH_ERC20, req.contents[i].recipient, req.contents[i].amount) + ); + } + bytes32 contentHash = keccak256(abi.encodePacked(contentHashes)); + + bytes memory dataToHash; + { + dataToHash = abi.encode( + REQUEST_TYPEHASH_ERC20, + req.uid, + req.tokenAddress, + req.expirationTimestamp, + contentHash + ); + } + + { + bytes32 _structHash = keccak256(dataToHash); + bytes32 typedDataHash = keccak256(abi.encodePacked("\x19\x01", domainSeparator, _structHash)); + (uint8 v, bytes32 r, bytes32 s) = vm.sign(privateKey, typedDataHash); + + signature = abi.encodePacked(r, s, v); + } + } + + function _signReqERC721( + Airdrop.AirdropRequest721 memory req, + uint256 privateKey + ) internal view returns (bytes memory signature) { + bytes32[] memory contentHashes = new bytes32[](req.contents.length); + for (uint i = 0; i < req.contents.length; i++) { + contentHashes[i] = keccak256( + abi.encode(CONTENT_TYPEHASH_ERC721, req.contents[i].recipient, req.contents[i].tokenId) + ); + } + bytes32 contentHash = keccak256(abi.encodePacked(contentHashes)); + + bytes memory dataToHash; + { + dataToHash = abi.encode( + REQUEST_TYPEHASH_ERC721, + req.uid, + req.tokenAddress, + req.expirationTimestamp, + contentHash + ); + } + + { + bytes32 _structHash = keccak256(dataToHash); + bytes32 typedDataHash = keccak256(abi.encodePacked("\x19\x01", domainSeparator, _structHash)); + (uint8 v, bytes32 r, bytes32 s) = vm.sign(privateKey, typedDataHash); + + signature = abi.encodePacked(r, s, v); + } + } + + function _signReqERC1155( + Airdrop.AirdropRequest1155 memory req, + uint256 privateKey + ) internal view returns (bytes memory signature) { + bytes32[] memory contentHashes = new bytes32[](req.contents.length); + for (uint i = 0; i < req.contents.length; i++) { + contentHashes[i] = keccak256( + abi.encode( + CONTENT_TYPEHASH_ERC1155, + req.contents[i].recipient, + req.contents[i].tokenId, + req.contents[i].amount + ) + ); + } + bytes32 contentHash = keccak256(abi.encodePacked(contentHashes)); + + bytes memory dataToHash; + { + dataToHash = abi.encode( + REQUEST_TYPEHASH_ERC1155, + req.uid, + req.tokenAddress, + req.expirationTimestamp, + contentHash + ); + } + + { + bytes32 _structHash = keccak256(dataToHash); + bytes32 typedDataHash = keccak256(abi.encodePacked("\x19\x01", domainSeparator, _structHash)); + (uint8 v, bytes32 r, bytes32 s) = vm.sign(privateKey, typedDataHash); + + signature = abi.encodePacked(r, s, v); + } + } + + /*/////////////////////////////////////////////////////////////// + Benchmark: Airdrop Push ERC20 + //////////////////////////////////////////////////////////////*/ + + function test_benchmark_airdropPush_erc20_10() public { + vm.pauseGasMetering(); + + erc20.mint(signer, 100 ether); + vm.prank(signer); + erc20.approve(address(airdrop), 100 ether); + + Airdrop.AirdropContent20[] memory contents = _getContentsERC20(10); + + vm.prank(signer); + vm.resumeGasMetering(); + airdrop.airdrop20(address(erc20), contents); + } + + function test_benchmark_airdropPush_erc20_100() public { + vm.pauseGasMetering(); + + erc20.mint(signer, 100 ether); + vm.prank(signer); + erc20.approve(address(airdrop), 100 ether); + + Airdrop.AirdropContent20[] memory contents = _getContentsERC20(100); + + vm.prank(signer); + vm.resumeGasMetering(); + airdrop.airdrop20(address(erc20), contents); + } + + function test_benchmark_airdropPush_erc20_1000() public { + vm.pauseGasMetering(); + + erc20.mint(signer, 100 ether); + vm.prank(signer); + erc20.approve(address(airdrop), 100 ether); + + Airdrop.AirdropContent20[] memory contents = _getContentsERC20(1000); + + vm.prank(signer); + vm.resumeGasMetering(); + airdrop.airdrop20(address(erc20), contents); + } + + /*/////////////////////////////////////////////////////////////// + Benchmark: Airdrop Signature ERC20 + //////////////////////////////////////////////////////////////*/ + + function test_benchmark_airdropSignature_erc20_10() public { + vm.pauseGasMetering(); + + erc20.mint(signer, 100 ether); + vm.prank(signer); + erc20.approve(address(airdrop), 100 ether); + + Airdrop.AirdropContent20[] memory contents = _getContentsERC20(10); + Airdrop.AirdropRequest20 memory req = Airdrop.AirdropRequest20({ + uid: bytes32(uint256(1)), + tokenAddress: address(erc20), + expirationTimestamp: 1000, + contents: contents + }); + bytes memory signature = _signReqERC20(req, privateKey); + + vm.prank(signer); + vm.resumeGasMetering(); + airdrop.airdrop20WithSignature(req, signature); + } + + function test_benchmark_airdropSignature_erc20_100() public { + vm.pauseGasMetering(); + + erc20.mint(signer, 100 ether); + vm.prank(signer); + erc20.approve(address(airdrop), 100 ether); + + Airdrop.AirdropContent20[] memory contents = _getContentsERC20(100); + Airdrop.AirdropRequest20 memory req = Airdrop.AirdropRequest20({ + uid: bytes32(uint256(1)), + tokenAddress: address(erc20), + expirationTimestamp: 1000, + contents: contents + }); + bytes memory signature = _signReqERC20(req, privateKey); + + vm.prank(signer); + vm.resumeGasMetering(); + airdrop.airdrop20WithSignature(req, signature); + } + + function test_benchmark_airdropSignature_erc20_1000() public { + vm.pauseGasMetering(); + + erc20.mint(signer, 100 ether); + vm.prank(signer); + erc20.approve(address(airdrop), 100 ether); + + Airdrop.AirdropContent20[] memory contents = _getContentsERC20(1000); + Airdrop.AirdropRequest20 memory req = Airdrop.AirdropRequest20({ + uid: bytes32(uint256(1)), + tokenAddress: address(erc20), + expirationTimestamp: 1000, + contents: contents + }); + bytes memory signature = _signReqERC20(req, privateKey); + + vm.prank(signer); + vm.resumeGasMetering(); + airdrop.airdrop20WithSignature(req, signature); + } + + /*/////////////////////////////////////////////////////////////// + Benchmark: Airdrop Claim ERC20 + //////////////////////////////////////////////////////////////*/ + + function test_benchmark_airdropClaim_erc20() public { + vm.pauseGasMetering(); + + erc20.mint(signer, 100 ether); + vm.prank(signer); + erc20.approve(address(airdrop), 100 ether); + + string[] memory inputs = new string[](3); + inputs[0] = "node"; + inputs[1] = "src/test/scripts/generateRootAirdrop.ts"; + inputs[2] = Strings.toString(uint256(5)); + bytes memory result = vm.ffi(inputs); + bytes32 root = abi.decode(result, (bytes32)); + + // set merkle root + vm.prank(signer); + airdrop.setMerkleRoot20(address(erc20), root); + + // generate proof + inputs[1] = "src/test/scripts/getProofAirdrop.ts"; + result = vm.ffi(inputs); + bytes32[] memory proofs = abi.decode(result, (bytes32[])); + + address receiver = address(0xDDdDddDdDdddDDddDDddDDDDdDdDDdDDdDDDDDDd); + uint256 quantity = 5; + + vm.prank(receiver); + vm.resumeGasMetering(); + airdrop.claim20(address(erc20), receiver, quantity, proofs); + } + + /*/////////////////////////////////////////////////////////////// + Benchmark: Airdrop Push ERC721 + //////////////////////////////////////////////////////////////*/ + + function test_benchmark_airdropPush_erc721_10() public { + vm.pauseGasMetering(); + + erc721.mint(signer, 100); + vm.prank(signer); + erc721.setApprovalForAll(address(airdrop), true); + + Airdrop.AirdropContent721[] memory contents = _getContentsERC721(10); + + vm.prank(signer); + vm.resumeGasMetering(); + airdrop.airdrop721(address(erc721), contents); + } + + function test_benchmark_airdropPush_erc721_100() public { + vm.pauseGasMetering(); + + erc721.mint(signer, 100); + vm.prank(signer); + erc721.setApprovalForAll(address(airdrop), true); + + Airdrop.AirdropContent721[] memory contents = _getContentsERC721(100); + + vm.prank(signer); + vm.resumeGasMetering(); + airdrop.airdrop721(address(erc721), contents); + } + + function test_benchmark_airdropPush_erc721_1000() public { + vm.pauseGasMetering(); + + erc721.mint(signer, 1000); + vm.prank(signer); + erc721.setApprovalForAll(address(airdrop), true); + + Airdrop.AirdropContent721[] memory contents = _getContentsERC721(1000); + + vm.prank(signer); + vm.resumeGasMetering(); + airdrop.airdrop721(address(erc721), contents); + } + + /*/////////////////////////////////////////////////////////////// + Benchmark: Airdrop Signature ERC721 + //////////////////////////////////////////////////////////////*/ + + function test_benchmark_airdropSignature_erc721_10() public { + vm.pauseGasMetering(); + + erc721.mint(signer, 1000); + vm.prank(signer); + erc721.setApprovalForAll(address(airdrop), true); + + Airdrop.AirdropContent721[] memory contents = _getContentsERC721(10); + Airdrop.AirdropRequest721 memory req = Airdrop.AirdropRequest721({ + uid: bytes32(uint256(1)), + tokenAddress: address(erc721), + expirationTimestamp: 1000, + contents: contents + }); + bytes memory signature = _signReqERC721(req, privateKey); + + vm.prank(signer); + vm.resumeGasMetering(); + airdrop.airdrop721WithSignature(req, signature); + } + + function test_benchmark_airdropSignature_erc721_100() public { + vm.pauseGasMetering(); + + erc721.mint(signer, 1000); + vm.prank(signer); + erc721.setApprovalForAll(address(airdrop), true); + + Airdrop.AirdropContent721[] memory contents = _getContentsERC721(100); + Airdrop.AirdropRequest721 memory req = Airdrop.AirdropRequest721({ + uid: bytes32(uint256(1)), + tokenAddress: address(erc721), + expirationTimestamp: 1000, + contents: contents + }); + bytes memory signature = _signReqERC721(req, privateKey); + + vm.prank(signer); + vm.resumeGasMetering(); + airdrop.airdrop721WithSignature(req, signature); + } + + function test_benchmark_airdropSignature_erc721_1000() public { + vm.pauseGasMetering(); + + erc721.mint(signer, 1000); + vm.prank(signer); + erc721.setApprovalForAll(address(airdrop), true); + + Airdrop.AirdropContent721[] memory contents = _getContentsERC721(1000); + Airdrop.AirdropRequest721 memory req = Airdrop.AirdropRequest721({ + uid: bytes32(uint256(1)), + tokenAddress: address(erc721), + expirationTimestamp: 1000, + contents: contents + }); + bytes memory signature = _signReqERC721(req, privateKey); + + vm.prank(signer); + vm.resumeGasMetering(); + airdrop.airdrop721WithSignature(req, signature); + } + + /*/////////////////////////////////////////////////////////////// + Benchmark: Airdrop Claim ERC721 + //////////////////////////////////////////////////////////////*/ + + function test_benchmark_airdropClaim_erc721() public { + vm.pauseGasMetering(); + + erc721.mint(signer, 100); + vm.prank(signer); + erc721.setApprovalForAll(address(airdrop), true); + + string[] memory inputs = new string[](3); + inputs[0] = "node"; + inputs[1] = "src/test/scripts/generateRootAirdrop.ts"; + inputs[2] = Strings.toString(uint256(5)); + bytes memory result = vm.ffi(inputs); + bytes32 root = abi.decode(result, (bytes32)); + + // set merkle root + vm.prank(signer); + airdrop.setMerkleRoot721(address(erc721), root); + + // generate proof + inputs[1] = "src/test/scripts/getProofAirdrop.ts"; + result = vm.ffi(inputs); + bytes32[] memory proofs = abi.decode(result, (bytes32[])); + + address receiver = address(0xDDdDddDdDdddDDddDDddDDDDdDdDDdDDdDDDDDDd); + uint256 tokenId = 5; + + vm.prank(receiver); + vm.resumeGasMetering(); + airdrop.claim721(address(erc721), receiver, tokenId, proofs); + } + + /*/////////////////////////////////////////////////////////////// + Benchmark: Airdrop Push ERC1155 + //////////////////////////////////////////////////////////////*/ + + function test_benchmark_airdropPush_erc1155_10() public { + vm.pauseGasMetering(); + + erc1155.mint(signer, 0, 100 ether); + vm.prank(signer); + erc1155.setApprovalForAll(address(airdrop), true); + + Airdrop.AirdropContent1155[] memory contents = _getContentsERC1155(10); + + vm.prank(signer); + vm.resumeGasMetering(); + airdrop.airdrop1155(address(erc1155), contents); + } + + function test_benchmark_airdropPush_erc1155_100() public { + vm.pauseGasMetering(); + + erc1155.mint(signer, 0, 100 ether); + vm.prank(signer); + erc1155.setApprovalForAll(address(airdrop), true); + + Airdrop.AirdropContent1155[] memory contents = _getContentsERC1155(100); + + vm.prank(signer); + vm.resumeGasMetering(); + airdrop.airdrop1155(address(erc1155), contents); + } + + function test_benchmark_airdropPush_erc1155_1000() public { + vm.pauseGasMetering(); + + erc1155.mint(signer, 0, 100 ether); + vm.prank(signer); + erc1155.setApprovalForAll(address(airdrop), true); + + Airdrop.AirdropContent1155[] memory contents = _getContentsERC1155(1000); + + vm.prank(signer); + vm.resumeGasMetering(); + airdrop.airdrop1155(address(erc1155), contents); + } + + /*/////////////////////////////////////////////////////////////// + Benchmark: Airdrop Signature ERC1155 + //////////////////////////////////////////////////////////////*/ + + function test_benchmark_airdropSignature_erc115_10() public { + vm.pauseGasMetering(); + + erc1155.mint(signer, 0, 100 ether); + vm.prank(signer); + erc1155.setApprovalForAll(address(airdrop), true); + + Airdrop.AirdropContent1155[] memory contents = _getContentsERC1155(10); + Airdrop.AirdropRequest1155 memory req = Airdrop.AirdropRequest1155({ + uid: bytes32(uint256(1)), + tokenAddress: address(erc1155), + expirationTimestamp: 1000, + contents: contents + }); + bytes memory signature = _signReqERC1155(req, privateKey); + + vm.prank(signer); + vm.resumeGasMetering(); + airdrop.airdrop1155WithSignature(req, signature); + } + + function test_benchmark_airdropSignature_erc115_100() public { + vm.pauseGasMetering(); + + erc1155.mint(signer, 0, 100 ether); + vm.prank(signer); + erc1155.setApprovalForAll(address(airdrop), true); + + Airdrop.AirdropContent1155[] memory contents = _getContentsERC1155(100); + Airdrop.AirdropRequest1155 memory req = Airdrop.AirdropRequest1155({ + uid: bytes32(uint256(1)), + tokenAddress: address(erc1155), + expirationTimestamp: 1000, + contents: contents + }); + bytes memory signature = _signReqERC1155(req, privateKey); + + vm.prank(signer); + vm.resumeGasMetering(); + airdrop.airdrop1155WithSignature(req, signature); + } + + function test_benchmark_airdropSignature_erc115_1000() public { + vm.pauseGasMetering(); + + erc1155.mint(signer, 0, 100 ether); + vm.prank(signer); + erc1155.setApprovalForAll(address(airdrop), true); + + Airdrop.AirdropContent1155[] memory contents = _getContentsERC1155(1000); + Airdrop.AirdropRequest1155 memory req = Airdrop.AirdropRequest1155({ + uid: bytes32(uint256(1)), + tokenAddress: address(erc1155), + expirationTimestamp: 1000, + contents: contents + }); + bytes memory signature = _signReqERC1155(req, privateKey); + + vm.prank(signer); + vm.resumeGasMetering(); + airdrop.airdrop1155WithSignature(req, signature); + } + + /*/////////////////////////////////////////////////////////////// + Benchmark: Airdrop Claim ERC1155 + //////////////////////////////////////////////////////////////*/ + + function test_benchmark_airdropClaim_erc1155() public { + vm.pauseGasMetering(); + + erc1155.mint(signer, 0, 100 ether); + vm.prank(signer); + erc1155.setApprovalForAll(address(airdrop), true); + + string[] memory inputs = new string[](3); + inputs[0] = "node"; + inputs[1] = "src/test/scripts/generateRootAirdrop.ts"; + inputs[2] = Strings.toString(uint256(5)); + bytes memory result = vm.ffi(inputs); + bytes32 root = abi.decode(result, (bytes32)); + + // set merkle root + vm.prank(signer); + airdrop.setMerkleRoot1155(address(erc1155), root); + + // generate proof + inputs[1] = "src/test/scripts/getProofAirdrop.ts"; + result = vm.ffi(inputs); + bytes32[] memory proofs = abi.decode(result, (bytes32[])); + + address receiver = address(0xDDdDddDdDdddDDddDDddDDDDdDdDDdDDdDDDDDDd); + uint256 quantity = 5; + + vm.prank(receiver); + vm.resumeGasMetering(); + airdrop.claim1155(address(erc1155), receiver, 0, quantity, proofs); + } +} diff --git a/src/test/smart-wallet/utils/AABenchmarkArtifacts.sol b/src/test/smart-wallet/utils/AABenchmarkArtifacts.sol index 049b16036..69107bb0c 100644 --- a/src/test/smart-wallet/utils/AABenchmarkArtifacts.sol +++ b/src/test/smart-wallet/utils/AABenchmarkArtifacts.sol @@ -9,6 +9,6 @@ interface ThirdwebAccount { } address constant THIRDWEB_ACCOUNT_FACTORY_ADDRESS = 0x2e234DAe75C793f67A35089C9d99245E1C58470b; address constant THIRDWEB_ACCOUNT_IMPL_ADDRESS = 0xffD4505B3452Dc22f8473616d50503bA9E1710Ac; -bytes constant THIRDWEB_ACCOUNT_FACTORY_BYTECODE = hex"608060405234801561001057600080fd5b50600436106101285760003560e01c806308e93d0a1461012d5780630b61e12b1461014b5780630e6254fd1461016057806311464fbe14610173578063248a9ca3146101b25780632f2ff15d146101d357806336568abe146101e657806358451f97146101f957806383a03f8c146102015780638878ed33146102145780639010d07c1461022757806391d148541461023a5780639387a3801461025d578063938e3d7b14610270578063a217fddf14610283578063a32fa5b31461028b578063a65d69d41461029e578063ac9650d8146102c5578063c3c5a547146102e5578063ca15c873146102f8578063d547741f1461030b578063d8fd8f441461031e578063e68a7c3b14610331578063e8a3d48514610344575b600080fd5b610135610359565b6040516101429190611945565b60405180910390f35b61015e6101593660046119ae565b61036a565b005b61013561016e3660046119d8565b61040b565b61019a7f000000000000000000000000ffd4505b3452dc22f8473616d50503ba9e1710ac81565b6040516001600160a01b039091168152602001610142565b6101c56101c03660046119f3565b610435565b604051908152602001610142565b61015e6101e1366004611a0c565b610453565b61015e6101f4366004611a0c565b6104fd565b6101c561055c565b61015e61020f3660046119f3565b610568565b61019a610222366004611a38565b6105b6565b61019a610235366004611aba565b610630565b61024d610248366004611a0c565b61073e565b6040519015158152602001610142565b61015e61026b3660046119ae565b610772565b61015e61027e366004611af2565b610809565b6101c5600081565b61024d610299366004611a0c565b61085a565b61019a7f0000000000000000000000005ff137d4b0fdcd49dca30c7cf57e578a026d278981565b6102d86102d3366004611ba2565b6108bd565b6040516101429190611c66565b61024d6102f33660046119d8565b610a19565b6101c56103063660046119f3565b610a25565b61015e610319366004611a0c565b610ac2565b61019a61032c366004611a38565b610acd565b61013561033f366004611aba565b610c18565b61034c610d49565b6040516101429190611cca565b60606103656000610de1565b905090565b336103758183610dee565b61039a5760405162461bcd60e51b815260040161039190611cdd565b60405180910390fd5b6001600160a01b03831660009081526002602052604081206103bc9083610e32565b9050801561040557836001600160a01b0316826001600160a01b03167f12146497b3b826918ec47f0cac7272a09ed06b30c16c030e99ec48ff5dd60b4760405160405180910390a35b50505050565b6001600160a01b038116600090815260026020526040902060609061042f90610de1565b92915050565b600061043f610e47565b600092835260010160205250604090205490565b61047761045e610e47565b6000848152600191909101602052604090205433610e6b565b61047f610e47565b6000838152602091825260408082206001600160a01b0385168352909252205460ff16156104ef5760405162461bcd60e51b815260206004820152601d60248201527f43616e206f6e6c79206772616e7420746f206e6f6e20686f6c646572730000006044820152606401610391565b6104f98282610ef0565b5050565b336001600160a01b038216146105525760405162461bcd60e51b815260206004820152601a60248201527921b0b71037b7363c903932b737bab731b2903337b91039b2b63360311b6044820152606401610391565b6104f98282610f04565b60006103656000610f18565b336105738183610dee565b61058f5760405162461bcd60e51b815260040161039190611cdd565b61059a600082610e32565b6104f95760405162461bcd60e51b815260040161039190611d14565b6000806105f98585858080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250610f2292505050565b90506106257f000000000000000000000000ffd4505b3452dc22f8473616d50503ba9e1710ac82610f55565b9150505b9392505050565b60008061063b610fb5565b600085815260209190915260408120549150805b82811015610735576000610661610fb5565b60008881526020918252604080822085835260010190925220546001600160a01b0316146106d9578482036106c757610698610fb5565b600087815260209182526040808220938252600190930190915220546001600160a01b0316925061042f915050565b6106d2600183611d74565b9150610723565b6106e486600061073e565b801561071057506106f3610fb5565b600087815260209182526040808220828052600201909252205481145b1561072357610720600183611d74565b91505b61072e600182611d74565b905061064f565b50505092915050565b6000610748610e47565b6000938452602090815260408085206001600160a01b039490941685529290525090205460ff1690565b3361077d8183610dee565b6107995760405162461bcd60e51b815260040161039190611cdd565b6001600160a01b03831660009081526002602052604081206107bb9083610fbf565b9050801561040557836001600160a01b0316826001600160a01b03167f98d1ebbe00ae92a5de96a0f49742a8afa89f42363592bc2e7cfaaed68b45e7a660405160405180910390a350505050565b610811610fd4565b61084e5760405162461bcd60e51b815260206004820152600e60248201526d139bdd08185d5d1a1bdc9a5e995960921b6044820152606401610391565b61085781610fe0565b50565b6000610864610e47565b600084815260209182526040808220828052909252205460ff166108b45761088a610e47565b6000848152602091825260408082206001600160a01b0386168352909252205460ff16905061042f565b50600192915050565b6060816001600160401b038111156108d7576108d7611adc565b60405190808252806020026020018201604052801561090a57816020015b60608152602001906001900390816108f55790505b509050336000805b848110156107355781156109915761096f3087878481811061093657610936611d87565b90506020028101906109489190611d9d565b8660405160200161095b93929190611dea565b6040516020818303038152906040526110c7565b84828151811061098157610981611d87565b6020026020010181905250610a11565b6109f3308787848181106109a7576109a7611d87565b90506020028101906109b99190611d9d565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506110c792505050565b848281518110610a0557610a05611d87565b60200260200101819052505b600101610912565b600061042f81836110ec565b600080610a30610fb5565b6000848152602091909152604081205491505b81811015610a9d576000610a55610fb5565b60008681526020918252604080822085835260010190925220546001600160a01b031614610a8b57610a88600184611d74565b92505b610a96600182611d74565b9050610a43565b50610aa983600061073e565b15610abc57610ab9600183611d74565b91505b50919050565b61055261045e610e47565b6000807f000000000000000000000000ffd4505b3452dc22f8473616d50503ba9e1710ac90506000610b358686868080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250610f2292505050565b90506000610b438383610f55565b90506001600160a01b0381163b15610b5f579250610629915050565b610b69838361110e565b9050336001600160a01b037f0000000000000000000000005ff137d4b0fdcd49dca30c7cf57e578a026d27891614610bc257610ba6600082610e32565b610bc25760405162461bcd60e51b815260040161039190611d14565b610bce818888886111a5565b866001600160a01b0316816001600160a01b03167fac631f3001b55ea1509cf3d7e74898f85392a61a76e8149181ae1259622dabc860405160405180910390a39695505050505050565b60608183108015610c325750610c2e6000610f18565b8211155b610c8a5760405162461bcd60e51b815260206004820152602360248201527f426173654163636f756e74466163746f72793a20696e76616c696420696e646960448201526263657360e81b6064820152608401610391565b6000610c968484611e0b565b9050610ca28484611e0b565b6001600160401b03811115610cb957610cb9611adc565b604051908082528060200260200182016040528015610ce2578160200160208202803683370190505b50915060005b81811015610d4157610d05610cfd8683611d74565b60009061120d565b838281518110610d1757610d17611d87565b6001600160a01b0390921660209283029190910190910152610d3a600182611d74565b9050610ce8565b505092915050565b6060610d53611219565b8054610d5e90611e1e565b80601f0160208091040260200160405190810160405280929190818152602001828054610d8a90611e1e565b8015610dd75780601f10610dac57610100808354040283529160200191610dd7565b820191906000526020600020905b815481529060010190602001808311610dba57829003601f168201915b5050505050905090565b606060006106298361123d565b600080610e1b7f000000000000000000000000ffd4505b3452dc22f8473616d50503ba9e1710ac84610f55565b6001600160a01b0385811691161491505092915050565b6000610629836001600160a01b038416611299565b7f0a7b0f5c59907924802379ebe98cdc23e2ee7820f63d30126e10b3752010e50090565b610e73610e47565b6000838152602091825260408082206001600160a01b0385168352909252205460ff166104f957610eae816001600160a01b031660146112e8565b610eb98360206112e8565b604051602001610eca929190611e52565b60408051601f198184030181529082905262461bcd60e51b825261039191600401611cca565b610efa8282611483565b6104f982826114ec565b610f0e82826115ab565b6104f98282611614565b600061042f825490565b60008282604051602001610f37929190611ebf565b60405160208183030381529060405280519060200120905092915050565b6040513060388201526f5af43d82803e903d91602b57fd5bf3ff602482015260148101839052733d602d80600a3d3981f3363d3d373d3d3d363d738152605881018290526037600c82012060788201526055604390910120600090610629565b60006103656116a3565b6000610629836001600160a01b038416611705565b6000610365813361073e565b6000610fea611219565b8054610ff590611e1e565b80601f016020809104026020016040519081016040528092919081815260200182805461102190611e1e565b801561106e5780601f106110435761010080835404028352916020019161106e565b820191906000526020600020905b81548152906001019060200180831161105157829003601f168201915b505050505090508161107e611219565b906110899082611f34565b507fc9c7c3fe08b88b4df9d4d47ef47d2c43d55c025a0ba88ca442580ed9e7348a1681836040516110bb929190611ff3565b60405180910390a15050565b606061062983836040518060600160405280602781526020016120b9602791396117f8565b6001600160a01b03811660009081526001830160205260408120541515610629565b6000763d602d80600a3d3981f3363d3d373d3d3d363d730000008360601b60e81c176000526e5af43d82803e903d91602b57fd5bf38360781b1760205281603760096000f590506001600160a01b03811661042f5760405162461bcd60e51b8152602060048201526017602482015276115490cc4c4d8dce8818dc99585d194c8819985a5b1959604a1b6044820152606401610391565b60405163347d5e2560e21b81526001600160a01b0385169063d1f57894906111d590869086908690600401612018565b600060405180830381600087803b1580156111ef57600080fd5b505af1158015611203573d6000803e3d6000fd5b5050505050505050565b60006106298383611870565b7f4bc804ba64359c0e35e5ed5d90ee596ecaa49a3a930ddcb1470ea0dd625da90090565b60608160000180548060200260200160405190810160405280929190818152602001828054801561128d57602002820191906000526020600020905b815481526020019060010190808311611279575b50505050509050919050565b60008181526001830160205260408120546112e05750815460018181018455600084815260208082209093018490558454848252828601909352604090209190915561042f565b50600061042f565b606060006112f7836002612058565b611302906002611d74565b6001600160401b0381111561131957611319611adc565b6040519080825280601f01601f191660200182016040528015611343576020820181803683370190505b509050600360fc1b8160008151811061135e5761135e611d87565b60200101906001600160f81b031916908160001a905350600f60fb1b8160018151811061138d5761138d611d87565b60200101906001600160f81b031916908160001a90535060006113b1846002612058565b6113bc906001611d74565b90505b6001811115611434576f181899199a1a9b1b9c1cb0b131b232b360811b85600f16601081106113f0576113f0611d87565b1a60f81b82828151811061140657611406611d87565b60200101906001600160f81b031916908160001a90535060049490941c9361142d8161206f565b90506113bf565b5083156106295760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152606401610391565b600161148d610e47565b6000848152602091825260408082206001600160a01b0386168084529352808220805460ff1916941515949094179093559151339285917f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d9190a45050565b60006114f6610fb5565b6000848152602091909152604090205490506001611512610fb5565b6000858152602091909152604081208054909190611531908490611d74565b90915550829050611540610fb5565b6000858152602091825260408082208583526001019092522080546001600160a01b0319166001600160a01b039290921691909117905580611580610fb5565b6000948552602090815260408086206001600160a01b03909516865260029094019052919092205550565b6115b58282610e6b565b6115bd610e47565b6000838152602091825260408082206001600160a01b0385168084529352808220805460ff191690555133929185917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b600061161e610fb5565b6000848152602091825260408082206001600160a01b03861683526002019092522054905061164b610fb5565b6000848152602091825260408082208483526001019092522080546001600160a01b031916905561167a610fb5565b6000938452602090815260408085206001600160a01b0390941685526002909301905250812055565b60008060ff196116d460017f0c4ba382c0009cf238e4c1ca1a52f51c61e6248a70bdfb34e5ed49d5578a5c0c611e0b565b6040516020016116e691815260200190565b60408051601f1981840301815291905280516020909101201692915050565b600081815260018301602052604081205480156117ee576000611729600183611e0b565b855490915060009061173d90600190611e0b565b90508181146117a257600086600001828154811061175d5761175d611d87565b906000526020600020015490508087600001848154811061178057611780611d87565b6000918252602080832090910192909255918252600188019052604090208390555b85548690806117b3576117b3612086565b60019003818190600052602060002001600090559055856001016000868152602001908152602001600020600090556001935050505061042f565b600091505061042f565b6060600080856001600160a01b031685604051611815919061209c565b600060405180830381855af49150503d8060008114611850576040519150601f19603f3d011682016040523d82523d6000602084013e611855565b606091505b50915091506118668683838761189a565b9695505050505050565b600082600001828154811061188757611887611d87565b9060005260206000200154905092915050565b60608315611909578251600003611902576001600160a01b0385163b6119025760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610391565b5081611913565b611913838361191b565b949350505050565b81511561192b5781518083602001fd5b8060405162461bcd60e51b81526004016103919190611cca565b6020808252825182820181905260009190848201906040850190845b818110156119865783516001600160a01b031683529284019291840191600101611961565b50909695505050505050565b80356001600160a01b03811681146119a957600080fd5b919050565b600080604083850312156119c157600080fd5b6119ca83611992565b946020939093013593505050565b6000602082840312156119ea57600080fd5b61062982611992565b600060208284031215611a0557600080fd5b5035919050565b60008060408385031215611a1f57600080fd5b82359150611a2f60208401611992565b90509250929050565b600080600060408486031215611a4d57600080fd5b611a5684611992565b925060208401356001600160401b0380821115611a7257600080fd5b818601915086601f830112611a8657600080fd5b813581811115611a9557600080fd5b876020828501011115611aa757600080fd5b6020830194508093505050509250925092565b60008060408385031215611acd57600080fd5b50508035926020909101359150565b634e487b7160e01b600052604160045260246000fd5b600060208284031215611b0457600080fd5b81356001600160401b0380821115611b1b57600080fd5b818401915084601f830112611b2f57600080fd5b813581811115611b4157611b41611adc565b604051601f8201601f19908116603f01168101908382118183101715611b6957611b69611adc565b81604052828152876020848701011115611b8257600080fd5b826020860160208301376000928101602001929092525095945050505050565b60008060208385031215611bb557600080fd5b82356001600160401b0380821115611bcc57600080fd5b818501915085601f830112611be057600080fd5b813581811115611bef57600080fd5b8660208260051b8501011115611c0457600080fd5b60209290920196919550909350505050565b60005b83811015611c31578181015183820152602001611c19565b50506000910152565b60008151808452611c52816020860160208601611c16565b601f01601f19169290920160200192915050565b600060208083016020845280855180835260408601915060408160051b87010192506020870160005b82811015611cbd57603f19888603018452611cab858351611c3a565b94509285019290850190600101611c8f565b5092979650505050505050565b6020815260006106296020830184611c3a565b6020808252601f908201527f4163636f756e74466163746f72793a206e6f7420616e206163636f756e742e00604082015260600190565b6020808252602a908201527f4163636f756e74466163746f72793a206163636f756e7420616c7265616479206040820152691c9959da5cdd195c995960b21b606082015260800190565b634e487b7160e01b600052601160045260246000fd5b8082018082111561042f5761042f611d5e565b634e487b7160e01b600052603260045260246000fd5b6000808335601e19843603018112611db457600080fd5b8301803591506001600160401b03821115611dce57600080fd5b602001915036819003821315611de357600080fd5b9250929050565b8284823760609190911b6001600160601b0319169101908152601401919050565b8181038181111561042f5761042f611d5e565b600181811c90821680611e3257607f821691505b602082108103610abc57634e487b7160e01b600052602260045260246000fd5b7402832b936b4b9b9b4b7b7399d1030b1b1b7bab73a1605d1b815260008351611e82816015850160208801611c16565b7001034b99036b4b9b9b4b733903937b6329607d1b6015918401918201528351611eb3816026840160208801611c16565b01602601949350505050565b6001600160a01b038316815260406020820181905260009061191390830184611c3a565b601f821115611f2f576000816000526020600020601f850160051c81016020861015611f0c5750805b601f850160051c820191505b81811015611f2b57828155600101611f18565b5050505b505050565b81516001600160401b03811115611f4d57611f4d611adc565b611f6181611f5b8454611e1e565b84611ee3565b602080601f831160018114611f965760008415611f7e5750858301515b600019600386901b1c1916600185901b178555611f2b565b600085815260208120601f198616915b82811015611fc557888601518255948401946001909101908401611fa6565b5085821015611fe35787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6040815260006120066040830185611c3a565b82810360208401526106258185611c3a565b6001600160a01b03841681526040602082018190528101829052818360608301376000818301606090810191909152601f909201601f1916010192915050565b808202811582820484141761042f5761042f611d5e565b60008161207e5761207e611d5e565b506000190190565b634e487b7160e01b600052603160045260246000fd5b600082516120ae818460208701611c16565b919091019291505056fe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a26469706673582212206d4165d1cf7ceea1ef7ae2a59f35cbdcc072abf82553dfe8d4b217752d7a1b3c64736f6c63430008170033"; -bytes constant THIRDWEB_ACCOUNT_IMPL_BYTECODE = hex"60806040526004361061014b5760003560e01c806301ffc9a7146101575780630a1028c41461018c578063150b7a02146101ba5780631626ba7e146101f35780631dd756c51461021357806324d7806c146102335780633a871cdd1461025357806347e1da2a146102735780634a58db19146102955780634d44560d1461029d5780635892e236146102bd5780637dff5a79146102dd5780638b52d723146102fd578063938e3d7b1461031f578063a9082d841461033f578063ac9650d81461037e578063b0d691fe146103ab578063b61d27f6146103cd578063b76464d5146103ed578063bc197c811461040d578063c45a015514610439578063d087d2881461046d578063d1f5789414610482578063d42f2f35146104a2578063e8a3d485146104b7578063e9523c97146104d9578063f15d424e146104fb578063f23a6e611461052857600080fd5b3661015257005b600080fd5b34801561016357600080fd5b50610177610172366004612d91565b610554565b60405190151581526020015b60405180910390f35b34801561019857600080fd5b506101ac6101a7366004612e78565b61059a565b604051908152602001610183565b3480156101c657600080fd5b506101da6101d5366004612ed1565b61063e565b6040516001600160e01b03199091168152602001610183565b3480156101ff57600080fd5b506101da61020e366004612f3c565b61064f565b34801561021f57600080fd5b5061017761022e366004612f9b565b61078f565b34801561023f57600080fd5b5061017761024e366004612fe0565b610a53565b34801561025f57600080fd5b506101ac61026e366004612ffd565b610a82565b34801561027f57600080fd5b5061029361028e36600461308e565b610aa8565b005b610293610c0f565b3480156102a957600080fd5b506102936102b8366004613127565b610c77565b3480156102c957600080fd5b506102936102d8366004613194565b610cea565b3480156102e957600080fd5b506101776102f8366004612fe0565b6110a7565b34801561030957600080fd5b50610312611160565b60405161018391906132a7565b34801561032b57600080fd5b5061029361033a36600461330b565b6113a7565b34801561034b57600080fd5b5061035f61035a366004613194565b6113f8565b6040805192151583526001600160a01b03909116602083015201610183565b34801561038a57600080fd5b5061039e610399366004613353565b61144f565b60405161018391906133e4565b3480156103b757600080fd5b506103c06115b4565b604051610183919061343b565b3480156103d957600080fd5b506102936103e836600461344f565b6115fd565b3480156103f957600080fd5b50610293610408366004612fe0565b61168d565b34801561041957600080fd5b506101da61042836600461353c565b63bc197c8160e01b95945050505050565b34801561044557600080fd5b506103c07f0000000000000000000000002e234dae75c793f67a35089c9d99245e1c58470b81565b34801561047957600080fd5b506101ac6116bf565b34801561048e57600080fd5b5061029361049d3660046135e9565b61173f565b3480156104ae57600080fd5b506103126118f7565b3480156104c357600080fd5b506104cc611a68565b6040516101839190613630565b3480156104e557600080fd5b506104ee611b00565b6040516101839190613643565b34801561050757600080fd5b5061051b610516366004612fe0565b611b12565b6040516101839190613690565b34801561053457600080fd5b506101da6105433660046136a3565b63f23a6e6160e01b95945050505050565b60006001600160e01b03198216630271189760e51b148061058557506001600160e01b03198216630a85bd0160e11b145b80610594575061059482611bea565b92915050565b6000807f82cac545155fcbf147f2a9013809613677ac7d65498556e6d19ce43bcbf6c28483805190602001206040516020016105e0929190918252602082015260400190565b604051602081830303815290604052805190602001209050610600611c1f565b60405161190160f01b602082015260228101919091526042810182905260620160405160208183030381529060405280519060200120915050919050565b630a85bd0160e11b5b949350505050565b60008061067c8460405160200161066891815260200190565b60405160208183030381529060405261059a565b9050600061068a8285611d46565b905061069581610a53565b156106ac5750630b135d3f60e11b91506105949050565b3360006106b7611d6a565b6001600160a01b03841660009081526006919091016020526040902090506106df8183611d8e565b8061070f57506106ee81611db0565b600114801561070f575060006107048282611dba565b6001600160a01b0316145b61076c5760405162461bcd60e51b8152602060048201526024808201527f4163636f756e743a2063616c6c6572206e6f7420617070726f7665642074617260448201526333b2ba1760e11b60648201526084015b60405180910390fd5b610775836110a7565b1561078557630b135d3f60e11b94505b5050505092915050565b6000610799611d6a565b6001600160a01b0384166000908152600491909101602052604090205460ff16156107c657506001610594565b60006107d0611d6a565b6001600160a01b0385166000908152600591909101602090815260408083208151606081018352815481526001909101546001600160801b0380821694830194909452600160801b900490921690820152915061082b611d6a565b6006016000866001600160a01b03166001600160a01b0316815260200190815260200160002090504282602001516001600160801b0316118061087b575081604001516001600160801b03164210155b8061088c575061088a81611db0565b155b1561089c57600092505050610594565b60006108b36108ae606087018761370b565b611dc6565b905060006108c083611db0565b60011480156108e1575060006108d68482611dba565b6001600160a01b0316145b90506324f16c0560e11b6001600160e01b03198316016109585760008061091361090e60608a018a61370b565b611e00565b9150915082610939576109268583611d8e565b6109395760009650505050505050610594565b85518111156109515760009650505050505050610594565b5050610a46565b635c0f12eb60e11b6001600160e01b0319831601610a395760008061098861098360608a018a61370b565b611e65565b5091509150826109e85760005b82518110156109e6576109ca8382815181106109b3576109b3613751565b602002602001015187611d8e90919063ffffffff16565b6109de576000975050505050505050610594565b600101610995565b505b60005b8251811015610a3157818181518110610a0657610a06613751565b602002602001015187600001511015610a29576000975050505050505050610594565b6001016109eb565b505050610a46565b6000945050505050610594565b5060019695505050505050565b6000610a5d611d6a565b6001600160a01b03909216600090815260049290920160205250604090205460ff1690565b6000610a8c611eb2565b610a968484611f1b565b9050610aa182612060565b9392505050565b610ab06115b4565b6001600160a01b0316336001600160a01b03161480610ad35750610ad333610a53565b610aef5760405162461bcd60e51b815260040161076390613767565b610af76120ad565b8481148015610b0557508483145b610b515760405162461bcd60e51b815260206004820152601d60248201527f4163636f756e743a2077726f6e67206172726179206c656e677468732e0000006044820152606401610763565b60005b85811015610c0657610bfd878783818110610b7157610b71613751565b9050602002016020810190610b869190612fe0565b868684818110610b9857610b98613751565b90506020020135858585818110610bb157610bb1613751565b9050602002810190610bc3919061370b565b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061219392505050565b50600101610b54565b50505050505050565b610c176115b4565b6001600160a01b031663b760faf934306040518363ffffffff1660e01b8152600401610c43919061343b565b6000604051808303818588803b158015610c5c57600080fd5b505af1158015610c70573d6000803e3d6000fd5b5050505050565b610c7f612204565b610c876115b4565b6001600160a01b031663205c287883836040518363ffffffff1660e01b8152600401610cb49291906137a8565b600060405180830381600087803b158015610cce57600080fd5b505af1158015610ce2573d6000803e3d6000fd5b505050505050565b6000610cf96020850185612fe0565b905042610d0c60e0860160c087016137d8565b6001600160801b031611158015610d3b5750610d2f610100850160e086016137d8565b6001600160801b031642105b610d715760405162461bcd60e51b8152602060048201526007602482015266085c195c9a5bd960ca1b6044820152606401610763565b600080610d7f8686866113f8565b9150915081610db95760405162461bcd60e51b8152600401610763906020808252600490820152632173696760e01b604082015260600190565b6001610dc3611d6a565b610100880135600090815260079190910160209081526040808320805460ff1916941515949094179093559091610dff91908901908901613804565b60ff161115610e2c576000610e1a6040880160208901613804565b60ff166001149050610c068482612242565b610e3583610a53565b15610e6a5760405162461bcd60e51b815260206004820152600560248201526430b236b4b760d91b6044820152606401610763565b610e7f83610e76611d6a565b60020190612317565b50604051806060016040528087606001358152602001876080016020810190610ea891906137d8565b6001600160801b03168152602001610ec660c0890160a08a016137d8565b6001600160801b03169052610ed9611d6a565b6001600160a01b03851660009081526005919091016020908152604080832084518155918401519301516001600160801b03908116600160801b02931692909217600190920191909155610f4f610f2e611d6a565b6001600160a01b03861660009081526006919091016020526040902061232c565b805190915060005b81811015610fb957610fa6838281518110610f7457610f74613751565b6020026020010151610f84611d6a565b6001600160a01b03891660009081526006919091016020526040902090612339565b50610fb2600182613835565b9050610f57565b50610fc76040890189613848565b9050905060005b8181101561104857611035610fe660408b018b613848565b83818110610ff657610ff6613751565b905060200201602081019061100b9190612fe0565b611013611d6a565b6001600160a01b03891660009081526006919091016020526040902090612317565b50611041600182613835565b9050610fce565b506110528861234e565b846001600160a01b0316836001600160a01b03167ff21d10c26e35863a8df291aca54181ee8c4a3bc8e00246c3f7a5a14b69d826a78a6040516110959190613922565b60405180910390a35050505050505050565b6000806110b2611d6a565b6001600160a01b038416600090815260059190910160209081526040918290208251606081018452815481526001909101546001600160801b03808216938301849052600160801b90910416928101929092529091504210801590611123575080604001516001600160801b031642105b8015610aa157506000611158611137611d6a565b6001600160a01b038616600090815260069190910160205260409020611db0565b119392505050565b6060600061117761116f611d6a565b60020161232c565b80519091506000805b82811015611208576111aa84828151811061119d5761119d613751565b60200260200101516110a7565b156111c157816111b981613a0d565b9250506111f6565b60008482815181106111d5576111d5613751565b60200260200101906001600160a01b031690816001600160a01b0316815250505b611201600182613835565b9050611180565b50806001600160401b0381111561122157611221612dbb565b60405190808252806020026020018201604052801561125a57816020015b611247612d47565b81526020019060019003908161123f5790505b5093506000805b8381101561139f5760006001600160a01b031685828151811061128657611286613751565b60200260200101516001600160a01b03161461138d5760008582815181106112b0576112b0613751565b6020026020010151905060006112c4611d6a565b6001600160a01b038316600081815260059290920160209081526040928390208351606081018552815481526001909101546001600160801b0380821683850152600160801b9091041681850152835160a08101909452918352909250810161132e610f2e611d6a565b81526020018260000151815260200182602001516001600160801b0316815260200182604001516001600160801b031681525088858061136d90613a0d565b96508151811061137f5761137f613751565b602002602001018190525050505b611398600182613835565b9050611261565b505050505090565b6113af6123e3565b6113ec5760405162461bcd60e51b815260206004820152600e60248201526d139bdd08185d5d1a1bdc9a5e995960921b6044820152606401610763565b6113f5816123fb565b50565b60008061140e611407866124e2565b8585612626565b9050611418611d6a565b6101008601356000908152600791909101602052604090205460ff16158015611445575061144581610a53565b9150935093915050565b6060816001600160401b0381111561146957611469612dbb565b60405190808252806020026020018201604052801561149c57816020015b60608152602001906001900390816114875790505b509050336000805b848110156115ab57811561152357611501308787848181106114c8576114c8613751565b90506020028101906114da919061370b565b866040516020016114ed93929190613a26565b604051602081830303815290604052612678565b84828151811061151357611513613751565b60200260200101819052506115a3565b6115853087878481811061153957611539613751565b905060200281019061154b919061370b565b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061267892505050565b84828151811061159757611597613751565b60200260200101819052505b6001016114a4565b50505092915050565b6000806115bf61269d565b546001600160a01b0316905080156115d657919050565b7f0000000000000000000000005ff137d4b0fdcd49dca30c7cf57e578a026d278991505090565b6116056115b4565b6001600160a01b0316336001600160a01b03161480611628575061162833610a53565b6116445760405162461bcd60e51b815260040161076390613767565b61164c6120ad565b610c70848484848080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061219392505050565b611695612204565b8061169e61269d565b80546001600160a01b0319166001600160a01b039290921691909117905550565b60006116c96115b4565b604051631aab3f0d60e11b8152306004820152600060248201526001600160a01b0391909116906335567e1a90604401602060405180830381865afa158015611716573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061173a9190613a47565b905090565b60006117496126c1565b5460ff16905060006117596126c1565b54610100900460ff1690508015808015611776575060018360ff16105b806117955750611785306126e5565b15801561179557508260ff166001145b6117f85760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610763565b60016118026126c1565b805460ff191660ff92909216919091179055801561183b5760016118246126c1565b80549115156101000261ff00199092169190911790555b61187b8686868080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506126f492505050565b61188361269d565b60010181905550611895866001612242565b8015610ce25760006118a56126c1565b80549115156101000261ff0019909216919091179055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a1505050505050565b6060600061190661116f611d6a565b8051909150806001600160401b0381111561192357611923612dbb565b60405190808252806020026020018201604052801561195c57816020015b611949612d47565b8152602001906001900390816119415790505b50925060005b81811015611a6257600083828151811061197e5761197e613751565b602002602001015190506000611992611d6a565b6001600160a01b038316600081815260059290920160209081526040928390208351606081018552815481526001909101546001600160801b0380821683850152600160801b9091041681850152835160a0810190945291835290925081016119fc610f2e611d6a565b81526020018260000151815260200182602001516001600160801b0316815260200182604001516001600160801b0316815250868481518110611a4157611a41613751565b60200260200101819052505050600181611a5b9190613835565b9050611962565b50505090565b6060611a72612727565b8054611a7d90613a60565b80601f0160208091040260200160405190810160405280929190818152602001828054611aa990613a60565b8015611af65780601f10611acb57610100808354040283529160200191611af6565b820191906000526020600020905b815481529060010190602001808311611ad957829003601f168201915b5050505050905090565b606061173a611b0d611d6a565b61232c565b611b1a612d47565b6000611b24611d6a565b6001600160a01b038416600081815260059290920160209081526040928390208351606081018552815481526001909101546001600160801b0380821683850152600160801b9091041681850152835160a081019094529183529092508101611baf611b8e611d6a565b6001600160a01b03871660009081526006919091016020526040902061232c565b81526020018260000151815260200182602001516001600160801b0316815260200182604001516001600160801b0316815250915050919050565b60006001600160e01b03198216630271189760e51b148061059457506301ffc9a760e01b6001600160e01b0319831614610594565b6000306001600160a01b037f000000000000000000000000ffd4505b3452dc22f8473616d50503ba9e1710ac16148015611c7857507f0000000000000000000000000000000000000000000000000000000000007a6946145b15611ca257507fbcdadf6444930a967ffda04923d78c49b3dd65df3ed39abb04a1e3eb1190553790565b50604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f6020808301919091527ff0729608244859f656d32ae4cbc6b0367695d68d8e941a28f5e2d33c6d5182dd828401527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608301524660808301523060a0808401919091528351808403909101815260c0909201909252805191012090565b6000806000611d55858561274b565b91509150611d6281612790565b509392505050565b7f3181e78fc1b109bc611fd2406150bf06e33faa75f71cba12c3e1fd670f2def0090565b6001600160a01b03811660009081526001830160205260408120541515610aa1565b6000610594825490565b6000610aa183836128d5565b60006004821015611de95760405162461bcd60e51b815260040161076390613a94565b611df7600460008486613ab3565b610aa191613add565b6000806044831015611e245760405162461bcd60e51b815260040161076390613a94565b611e32602460048587613ab3565b810190611e3f9190612fe0565b9150611e4f604460248587613ab3565b810190611e5c9190613b0d565b90509250929050565b606080806064841015611e8a5760405162461bcd60e51b815260040161076390613a94565b611e978460048188613ab3565b810190611ea49190613ba5565b919790965090945092505050565b611eba6115b4565b6001600160a01b0316336001600160a01b031614611f195760405162461bcd60e51b815260206004820152601c60248201527b1858d8dbdd5b9d0e881b9bdd08199c9bdb48115b9d1c9e541bda5b9d60221b6044820152606401610763565b565b7b0ca2ba3432b932bab69029b4b3b732b21026b2b9b9b0b3b29d05199960211b6000908152601c829052603c81206000611f99611f5c61014087018761370b565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152508693925050611d469050565b9050611fa5818661078f565b611fb457600192505050610594565b6000611fbe611d6a565b6001600160a01b03929092166000908152600590920160209081526040808420815160608082018452825482526001909201546001600160801b0380821683870152600160801b8204908116928501929092528351928301845295825265ffffffffffff8087169483019490945292831691015260d09290921b6001600160d01b03191660a09290921b65ffffffffffff60a01b169190911795945050505050565b80156113f557604051600090339060001990849084818181858888f193505050503d8060008114610c70576040519150601f19603f3d011682016040523d82523d6000602084013e610c70565b60405163c3c5a54760e01b81527f0000000000000000000000002e234dae75c793f67a35089c9d99245e1c58470b906001600160a01b0382169063c3c5a547906120fb90309060040161343b565b602060405180830381865afa158015612118573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061213c9190613c8a565b6113f557806001600160a01b03166383a03f8c61215761269d565b600101546040518263ffffffff1660e01b815260040161217991815260200190565b600060405180830381600087803b158015610c5c57600080fd5b60606000846001600160a01b031684846040516121b09190613cac565b60006040518083038185875af1925050503d80600081146121ed576040519150601f19603f3d011682016040523d82523d6000602084013e6121f2565b606091505b509250905080611d6257815160208301fd5b61220d33610a53565b611f195760405162461bcd60e51b815260206004820152600660248201526510b0b236b4b760d11b6044820152606401610763565b61224c82826128ff565b6001600160a01b037f0000000000000000000000002e234dae75c793f67a35089c9d99245e1c58470b163b156123135780156122db577f0000000000000000000000002e234dae75c793f67a35089c9d99245e1c58470b6001600160a01b0316630b61e12b836122ba61269d565b600101546040518363ffffffff1660e01b8152600401610cb49291906137a8565b7f0000000000000000000000002e234dae75c793f67a35089c9d99245e1c58470b6001600160a01b0316639387a380836122ba61269d565b5050565b6000610aa1836001600160a01b0384166129ae565b60606000610aa1836129fd565b6000610aa1836001600160a01b038416612a59565b6001600160a01b037f0000000000000000000000002e234dae75c793f67a35089c9d99245e1c58470b163b156113f5576001600160a01b037f0000000000000000000000002e234dae75c793f67a35089c9d99245e1c58470b16630b61e12b6123ba6020840184612fe0565b6123c261269d565b600101546040518363ffffffff1660e01b81526004016121799291906137a8565b60006123ee33610a53565b8061173a57505030331490565b6000612405612727565b805461241090613a60565b80601f016020809104026020016040519081016040528092919081815260200182805461243c90613a60565b80156124895780601f1061245e57610100808354040283529160200191612489565b820191906000526020600020905b81548152906001019060200180831161246c57829003601f168201915b5050505050905081612499612727565b906124a49082613d15565b507fc9c7c3fe08b88b4df9d4d47ef47d2c43d55c025a0ba88ca442580ed9e7348a1681836040516124d6929190613dd4565b60405180910390a15050565b60607f3fd4a1a1a267c84185e3b7eecd57c68783c0581d538b9d6e5f23e4670497c1e96125126020840184612fe0565b6125226040850160208601613804565b61252f6040860186613848565b604051602001612540929190613e02565b60408051601f198184030181529190528051602090910120606086013561256d60a08801608089016137d8565b61257d60c0890160a08a016137d8565b61258d60e08a0160c08b016137d8565b61259e6101008b0160e08c016137d8565b60408051602081019a909a526001600160a01b039098169789019790975260ff9095166060880152608087019390935260a08601919091526001600160801b0390811660c086015290811660e0850152908116610100848101919091529116610120830152830135610140820152610160016040516020818303038152906040529050919050565b600061064783838080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250508751602089012061267292509050612b4c565b90611d46565b6060610aa18383604051806060016040528060278152602001613ea860279139612b79565b7f036f52c1827dab135f7fd44ca0bddde297e2f659c710e0ec53e975f22b54830090565b7f322cf19c484104d3b1a9c2982ebae869ede3fa5f6c4703ca41b9a48c76ee030090565b6001600160a01b03163b151590565b60008282604051602001612709929190613e44565b60405160208183030381529060405280519060200120905092915050565b7f4bc804ba64359c0e35e5ed5d90ee596ecaa49a3a930ddcb1470ea0dd625da90090565b60008082516041036127815760208301516040840151606085015160001a61277587828585612bf1565b94509450505050612789565b506000905060025b9250929050565b60008160048111156127a4576127a4613e68565b036127ac5750565b60018160048111156127c0576127c0613e68565b036128085760405162461bcd60e51b815260206004820152601860248201527745434453413a20696e76616c6964207369676e617475726560401b6044820152606401610763565b600281600481111561281c5761281c613e68565b036128695760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e677468006044820152606401610763565b600381600481111561287d5761287d613e68565b036113f55760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604482015261756560f01b6064820152608401610763565b60008260000182815481106128ec576128ec613751565b9060005260206000200154905092915050565b80612908611d6a565b6001600160a01b038416600090815260049190910160205260409020805460ff191691151591909117905580156129515761294b82612945611d6a565b90612317565b50612965565b6129638261295d611d6a565b90612339565b505b816001600160a01b03167f235bc17e7930760029e9f4d860a2a8089976de5b381cf8380fc11c1d88a11133826040516129a2911515815260200190565b60405180910390a25050565b60008181526001830160205260408120546129f557508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610594565b506000610594565b606081600001805480602002602001604051908101604052809291908181526020018280548015612a4d57602002820191906000526020600020905b815481526020019060010190808311612a39575b50505050509050919050565b60008181526001830160205260408120548015612b42576000612a7d600183613e7e565b8554909150600090612a9190600190613e7e565b9050818114612af6576000866000018281548110612ab157612ab1613751565b9060005260206000200154905080876000018481548110612ad457612ad4613751565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080612b0757612b07613e91565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050610594565b6000915050610594565b6000610594612b59611c1f565b8360405161190160f01b8152600281019290925260228201526042902090565b6060600080856001600160a01b031685604051612b969190613cac565b600060405180830381855af49150503d8060008114612bd1576040519150601f19603f3d011682016040523d82523d6000602084013e612bd6565b606091505b5091509150612be786838387612cab565b9695505050505050565b6000806fa2a8918ca85bafe22016d0b997e4df60600160ff1b03831115612c1e5750600090506003612ca2565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa158015612c72573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116612c9b57600060019250925050612ca2565b9150600090505b94509492505050565b60608315612d18578251600003612d1157612cc5856126e5565b612d115760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610763565b5081610647565b6106478383815115612d2d5781518083602001fd5b8060405162461bcd60e51b81526004016107639190613630565b6040518060a0016040528060006001600160a01b03168152602001606081526020016000815260200160006001600160801b0316815260200160006001600160801b031681525090565b600060208284031215612da357600080fd5b81356001600160e01b031981168114610aa157600080fd5b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b0381118282101715612df957612df9612dbb565b604052919050565b60006001600160401b03831115612e1a57612e1a612dbb565b612e2d601f8401601f1916602001612dd1565b9050828152838383011115612e4157600080fd5b828260208301376000602084830101529392505050565b600082601f830112612e6957600080fd5b610aa183833560208501612e01565b600060208284031215612e8a57600080fd5b81356001600160401b03811115612ea057600080fd5b61064784828501612e58565b6001600160a01b03811681146113f557600080fd5b8035612ecc81612eac565b919050565b60008060008060808587031215612ee757600080fd5b8435612ef281612eac565b93506020850135612f0281612eac565b92506040850135915060608501356001600160401b03811115612f2457600080fd5b612f3087828801612e58565b91505092959194509250565b60008060408385031215612f4f57600080fd5b8235915060208301356001600160401b03811115612f6c57600080fd5b612f7885828601612e58565b9150509250929050565b60006101608284031215612f9557600080fd5b50919050565b60008060408385031215612fae57600080fd5b8235612fb981612eac565b915060208301356001600160401b03811115612fd457600080fd5b612f7885828601612f82565b600060208284031215612ff257600080fd5b8135610aa181612eac565b60008060006060848603121561301257600080fd5b83356001600160401b0381111561302857600080fd5b61303486828701612f82565b9660208601359650604090950135949350505050565b60008083601f84011261305c57600080fd5b5081356001600160401b0381111561307357600080fd5b6020830191508360208260051b850101111561278957600080fd5b600080600080600080606087890312156130a757600080fd5b86356001600160401b03808211156130be57600080fd5b6130ca8a838b0161304a565b909850965060208901359150808211156130e357600080fd5b6130ef8a838b0161304a565b9096509450604089013591508082111561310857600080fd5b5061311589828a0161304a565b979a9699509497509295939492505050565b6000806040838503121561313a57600080fd5b823561314581612eac565b946020939093013593505050565b60008083601f84011261316557600080fd5b5081356001600160401b0381111561317c57600080fd5b60208301915083602082850101111561278957600080fd5b6000806000604084860312156131a957600080fd5b83356001600160401b03808211156131c057600080fd5b9085019061012082880312156131d557600080fd5b909350602085013590808211156131eb57600080fd5b506131f886828701613153565b9497909650939450505050565b6001600160801b03169052565b80516001600160a01b03908116835260208083015160a082860181905281519086018190526000939183019290849060c08801905b8083101561326957855185168252948301946001929092019190830190613247565b5060408701516040890152606087015194506132886060890186613205565b6080870151945061329c6080890186613205565b979650505050505050565b600060208083016020845280855180835260408601915060408160051b87010192506020870160005b828110156132fe57603f198886030184526132ec858351613212565b945092850192908501906001016132d0565b5092979650505050505050565b60006020828403121561331d57600080fd5b81356001600160401b0381111561333357600080fd5b8201601f8101841361334457600080fd5b61064784823560208401612e01565b6000806020838503121561336657600080fd5b82356001600160401b0381111561337c57600080fd5b6133888582860161304a565b90969095509350505050565b60005b838110156133af578181015183820152602001613397565b50506000910152565b600081518084526133d0816020860160208601613394565b601f01601f19169290920160200192915050565b600060208083016020845280855180835260408601915060408160051b87010192506020870160005b828110156132fe57603f198886030184526134298583516133b8565b9450928501929085019060010161340d565b6001600160a01b0391909116815260200190565b6000806000806060858703121561346557600080fd5b843561347081612eac565b93506020850135925060408501356001600160401b0381111561349257600080fd5b61349e87828801613153565b95989497509550505050565b60006001600160401b038211156134c3576134c3612dbb565b5060051b60200190565b600082601f8301126134de57600080fd5b813560206134f36134ee836134aa565b612dd1565b8083825260208201915060208460051b87010193508684111561351557600080fd5b602086015b84811015613531578035835291830191830161351a565b509695505050505050565b600080600080600060a0868803121561355457600080fd5b853561355f81612eac565b9450602086013561356f81612eac565b935060408601356001600160401b038082111561358b57600080fd5b61359789838a016134cd565b945060608801359150808211156135ad57600080fd5b6135b989838a016134cd565b935060808801359150808211156135cf57600080fd5b506135dc88828901612e58565b9150509295509295909350565b6000806000604084860312156135fe57600080fd5b833561360981612eac565b925060208401356001600160401b0381111561362457600080fd5b6131f886828701613153565b602081526000610aa160208301846133b8565b6020808252825182820181905260009190848201906040850190845b818110156136845783516001600160a01b03168352928401929184019160010161365f565b50909695505050505050565b602081526000610aa16020830184613212565b600080600080600060a086880312156136bb57600080fd5b85356136c681612eac565b945060208601356136d681612eac565b9350604086013592506060860135915060808601356001600160401b038111156136ff57600080fd5b6135dc88828901612e58565b6000808335601e1984360301811261372257600080fd5b8301803591506001600160401b0382111561373c57600080fd5b60200191503681900382131561278957600080fd5b634e487b7160e01b600052603260045260246000fd5b60208082526021908201527f4163636f756e743a206e6f742061646d696e206f7220456e747279506f696e746040820152601760f91b606082015260800190565b6001600160a01b03929092168252602082015260400190565b80356001600160801b0381168114612ecc57600080fd5b6000602082840312156137ea57600080fd5b610aa1826137c1565b803560ff81168114612ecc57600080fd5b60006020828403121561381657600080fd5b610aa1826137f3565b634e487b7160e01b600052601160045260246000fd5b808201808211156105945761059461381f565b6000808335601e1984360301811261385f57600080fd5b8301803591506001600160401b0382111561387957600080fd5b6020019150600581901b360382131561278957600080fd5b6000808335601e198436030181126138a857600080fd5b83016020810192503590506001600160401b038111156138c757600080fd5b8060051b360382131561278957600080fd5b8183526000602080850194508260005b858110156139175781356138fc81612eac565b6001600160a01b0316875295820195908201906001016138e9565b509495945050505050565b602081526139436020820161393684612ec1565b6001600160a01b03169052565b6000613951602084016137f3565b60ff81166040840152506139686040840184613891565b610120806060860152613980610140860183856138d9565b925060608601356080860152613998608087016137c1565b91506139a760a0860183613205565b6139b360a087016137c1565b91506139c260c0860183613205565b6139ce60c087016137c1565b91506139dd60e0860183613205565b6139e960e087016137c1565b91506101006139fa81870184613205565b9590950135939094019290925250919050565b600060018201613a1f57613a1f61381f565b5060010190565b8284823760609190911b6001600160601b0319169101908152601401919050565b600060208284031215613a5957600080fd5b5051919050565b600181811c90821680613a7457607f821691505b602082108103612f9557634e487b7160e01b600052602260045260246000fd5b602080825260059082015264214461746160d81b604082015260600190565b60008085851115613ac357600080fd5b83861115613ad057600080fd5b5050820193919092039150565b6001600160e01b03198135818116916004851015613b055780818660040360031b1b83161692505b505092915050565b600060208284031215613b1f57600080fd5b5035919050565b600082601f830112613b3757600080fd5b81356020613b476134ee836134aa565b82815260059290921b84018101918181019086841115613b6657600080fd5b8286015b848110156135315780356001600160401b03811115613b895760008081fd5b613b978986838b0101612e58565b845250918301918301613b6a565b600080600060608486031215613bba57600080fd5b83356001600160401b0380821115613bd157600080fd5b818601915086601f830112613be557600080fd5b81356020613bf56134ee836134aa565b82815260059290921b8401810191818101908a841115613c1457600080fd5b948201945b83861015613c3b578535613c2c81612eac565b82529482019490820190613c19565b97505087013592505080821115613c5157600080fd5b613c5d878388016134cd565b93506040860135915080821115613c7357600080fd5b50613c8086828701613b26565b9150509250925092565b600060208284031215613c9c57600080fd5b81518015158114610aa157600080fd5b60008251613cbe818460208701613394565b9190910192915050565b601f821115613d10576000816000526020600020601f850160051c81016020861015613cf15750805b601f850160051c820191505b81811015610ce257828155600101613cfd565b505050565b81516001600160401b03811115613d2e57613d2e612dbb565b613d4281613d3c8454613a60565b84613cc8565b602080601f831160018114613d775760008415613d5f5750858301515b600019600386901b1c1916600185901b178555610ce2565b600085815260208120601f198616915b82811015613da657888601518255948401946001909101908401613d87565b5085821015613dc45787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b604081526000613de760408301856133b8565b8281036020840152613df981856133b8565b95945050505050565b60008184825b85811015613e39578135613e1b81612eac565b6001600160a01b031683526020928301929190910190600101613e08565b509095945050505050565b6001600160a01b0383168152604060208201819052600090610647908301846133b8565b634e487b7160e01b600052602160045260246000fd5b818103818111156105945761059461381f565b634e487b7160e01b600052603160045260246000fdfe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a264697066735822122019cc7525a78289009afc67e3df01d951420e7390ef0e5a1ac3e7ae9c26de3c6564736f6c63430008170033"; +bytes constant THIRDWEB_ACCOUNT_FACTORY_BYTECODE = hex"608060405234801561001057600080fd5b50600436106101285760003560e01c806308e93d0a1461012d5780630b61e12b1461014b5780630e6254fd1461016057806311464fbe14610173578063248a9ca3146101b25780632f2ff15d146101d357806336568abe146101e657806358451f97146101f957806383a03f8c146102015780638878ed33146102145780639010d07c1461022757806391d148541461023a5780639387a3801461025d578063938e3d7b14610270578063a217fddf14610283578063a32fa5b31461028b578063a65d69d41461029e578063ac9650d8146102c5578063c3c5a547146102e5578063ca15c873146102f8578063d547741f1461030b578063d8fd8f441461031e578063e68a7c3b14610331578063e8a3d48514610344575b600080fd5b610135610359565b6040516101429190611945565b60405180910390f35b61015e6101593660046119ae565b61036a565b005b61013561016e3660046119d8565b61040b565b61019a7f000000000000000000000000ffd4505b3452dc22f8473616d50503ba9e1710ac81565b6040516001600160a01b039091168152602001610142565b6101c56101c03660046119f3565b610435565b604051908152602001610142565b61015e6101e1366004611a0c565b610453565b61015e6101f4366004611a0c565b6104fd565b6101c561055c565b61015e61020f3660046119f3565b610568565b61019a610222366004611a38565b6105b6565b61019a610235366004611aba565b610630565b61024d610248366004611a0c565b61073e565b6040519015158152602001610142565b61015e61026b3660046119ae565b610772565b61015e61027e366004611af2565b610809565b6101c5600081565b61024d610299366004611a0c565b61085a565b61019a7f0000000000000000000000005ff137d4b0fdcd49dca30c7cf57e578a026d278981565b6102d86102d3366004611ba2565b6108bd565b6040516101429190611c66565b61024d6102f33660046119d8565b610a19565b6101c56103063660046119f3565b610a25565b61015e610319366004611a0c565b610ac2565b61019a61032c366004611a38565b610acd565b61013561033f366004611aba565b610c18565b61034c610d49565b6040516101429190611cca565b60606103656000610de1565b905090565b336103758183610dee565b61039a5760405162461bcd60e51b815260040161039190611cdd565b60405180910390fd5b6001600160a01b03831660009081526002602052604081206103bc9083610e32565b9050801561040557836001600160a01b0316826001600160a01b03167f12146497b3b826918ec47f0cac7272a09ed06b30c16c030e99ec48ff5dd60b4760405160405180910390a35b50505050565b6001600160a01b038116600090815260026020526040902060609061042f90610de1565b92915050565b600061043f610e47565b600092835260010160205250604090205490565b61047761045e610e47565b6000848152600191909101602052604090205433610e6b565b61047f610e47565b6000838152602091825260408082206001600160a01b0385168352909252205460ff16156104ef5760405162461bcd60e51b815260206004820152601d60248201527f43616e206f6e6c79206772616e7420746f206e6f6e20686f6c646572730000006044820152606401610391565b6104f98282610ef0565b5050565b336001600160a01b038216146105525760405162461bcd60e51b815260206004820152601a60248201527921b0b71037b7363c903932b737bab731b2903337b91039b2b63360311b6044820152606401610391565b6104f98282610f04565b60006103656000610f18565b336105738183610dee565b61058f5760405162461bcd60e51b815260040161039190611cdd565b61059a600082610e32565b6104f95760405162461bcd60e51b815260040161039190611d14565b6000806105f98585858080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250610f2292505050565b90506106257f000000000000000000000000ffd4505b3452dc22f8473616d50503ba9e1710ac82610f55565b9150505b9392505050565b60008061063b610fb5565b600085815260209190915260408120549150805b82811015610735576000610661610fb5565b60008881526020918252604080822085835260010190925220546001600160a01b0316146106d9578482036106c757610698610fb5565b600087815260209182526040808220938252600190930190915220546001600160a01b0316925061042f915050565b6106d2600183611d74565b9150610723565b6106e486600061073e565b801561071057506106f3610fb5565b600087815260209182526040808220828052600201909252205481145b1561072357610720600183611d74565b91505b61072e600182611d74565b905061064f565b50505092915050565b6000610748610e47565b6000938452602090815260408085206001600160a01b039490941685529290525090205460ff1690565b3361077d8183610dee565b6107995760405162461bcd60e51b815260040161039190611cdd565b6001600160a01b03831660009081526002602052604081206107bb9083610fbf565b9050801561040557836001600160a01b0316826001600160a01b03167f98d1ebbe00ae92a5de96a0f49742a8afa89f42363592bc2e7cfaaed68b45e7a660405160405180910390a350505050565b610811610fd4565b61084e5760405162461bcd60e51b815260206004820152600e60248201526d139bdd08185d5d1a1bdc9a5e995960921b6044820152606401610391565b61085781610fe0565b50565b6000610864610e47565b600084815260209182526040808220828052909252205460ff166108b45761088a610e47565b6000848152602091825260408082206001600160a01b0386168352909252205460ff16905061042f565b50600192915050565b6060816001600160401b038111156108d7576108d7611adc565b60405190808252806020026020018201604052801561090a57816020015b60608152602001906001900390816108f55790505b509050336000805b848110156107355781156109915761096f3087878481811061093657610936611d87565b90506020028101906109489190611d9d565b8660405160200161095b93929190611dea565b6040516020818303038152906040526110c7565b84828151811061098157610981611d87565b6020026020010181905250610a11565b6109f3308787848181106109a7576109a7611d87565b90506020028101906109b99190611d9d565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506110c792505050565b848281518110610a0557610a05611d87565b60200260200101819052505b600101610912565b600061042f81836110ec565b600080610a30610fb5565b6000848152602091909152604081205491505b81811015610a9d576000610a55610fb5565b60008681526020918252604080822085835260010190925220546001600160a01b031614610a8b57610a88600184611d74565b92505b610a96600182611d74565b9050610a43565b50610aa983600061073e565b15610abc57610ab9600183611d74565b91505b50919050565b61055261045e610e47565b6000807f000000000000000000000000ffd4505b3452dc22f8473616d50503ba9e1710ac90506000610b358686868080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250610f2292505050565b90506000610b438383610f55565b90506001600160a01b0381163b15610b5f579250610629915050565b610b69838361110e565b9050336001600160a01b037f0000000000000000000000005ff137d4b0fdcd49dca30c7cf57e578a026d27891614610bc257610ba6600082610e32565b610bc25760405162461bcd60e51b815260040161039190611d14565b610bce818888886111a5565b866001600160a01b0316816001600160a01b03167fac631f3001b55ea1509cf3d7e74898f85392a61a76e8149181ae1259622dabc860405160405180910390a39695505050505050565b60608183108015610c325750610c2e6000610f18565b8211155b610c8a5760405162461bcd60e51b815260206004820152602360248201527f426173654163636f756e74466163746f72793a20696e76616c696420696e646960448201526263657360e81b6064820152608401610391565b6000610c968484611e0b565b9050610ca28484611e0b565b6001600160401b03811115610cb957610cb9611adc565b604051908082528060200260200182016040528015610ce2578160200160208202803683370190505b50915060005b81811015610d4157610d05610cfd8683611d74565b60009061120d565b838281518110610d1757610d17611d87565b6001600160a01b0390921660209283029190910190910152610d3a600182611d74565b9050610ce8565b505092915050565b6060610d53611219565b8054610d5e90611e1e565b80601f0160208091040260200160405190810160405280929190818152602001828054610d8a90611e1e565b8015610dd75780601f10610dac57610100808354040283529160200191610dd7565b820191906000526020600020905b815481529060010190602001808311610dba57829003601f168201915b5050505050905090565b606060006106298361123d565b600080610e1b7f000000000000000000000000ffd4505b3452dc22f8473616d50503ba9e1710ac84610f55565b6001600160a01b0385811691161491505092915050565b6000610629836001600160a01b038416611299565b7f0a7b0f5c59907924802379ebe98cdc23e2ee7820f63d30126e10b3752010e50090565b610e73610e47565b6000838152602091825260408082206001600160a01b0385168352909252205460ff166104f957610eae816001600160a01b031660146112e8565b610eb98360206112e8565b604051602001610eca929190611e52565b60408051601f198184030181529082905262461bcd60e51b825261039191600401611cca565b610efa8282611483565b6104f982826114ec565b610f0e82826115ab565b6104f98282611614565b600061042f825490565b60008282604051602001610f37929190611ebf565b60405160208183030381529060405280519060200120905092915050565b6040513060388201526f5af43d82803e903d91602b57fd5bf3ff602482015260148101839052733d602d80600a3d3981f3363d3d373d3d3d363d738152605881018290526037600c82012060788201526055604390910120600090610629565b60006103656116a3565b6000610629836001600160a01b038416611705565b6000610365813361073e565b6000610fea611219565b8054610ff590611e1e565b80601f016020809104026020016040519081016040528092919081815260200182805461102190611e1e565b801561106e5780601f106110435761010080835404028352916020019161106e565b820191906000526020600020905b81548152906001019060200180831161105157829003601f168201915b505050505090508161107e611219565b906110899082611f34565b507fc9c7c3fe08b88b4df9d4d47ef47d2c43d55c025a0ba88ca442580ed9e7348a1681836040516110bb929190611ff3565b60405180910390a15050565b606061062983836040518060600160405280602781526020016120b9602791396117f8565b6001600160a01b03811660009081526001830160205260408120541515610629565b6000763d602d80600a3d3981f3363d3d373d3d3d363d730000008360601b60e81c176000526e5af43d82803e903d91602b57fd5bf38360781b1760205281603760096000f590506001600160a01b03811661042f5760405162461bcd60e51b8152602060048201526017602482015276115490cc4c4d8dce8818dc99585d194c8819985a5b1959604a1b6044820152606401610391565b60405163347d5e2560e21b81526001600160a01b0385169063d1f57894906111d590869086908690600401612018565b600060405180830381600087803b1580156111ef57600080fd5b505af1158015611203573d6000803e3d6000fd5b5050505050505050565b60006106298383611870565b7f4bc804ba64359c0e35e5ed5d90ee596ecaa49a3a930ddcb1470ea0dd625da90090565b60608160000180548060200260200160405190810160405280929190818152602001828054801561128d57602002820191906000526020600020905b815481526020019060010190808311611279575b50505050509050919050565b60008181526001830160205260408120546112e05750815460018181018455600084815260208082209093018490558454848252828601909352604090209190915561042f565b50600061042f565b606060006112f7836002612058565b611302906002611d74565b6001600160401b0381111561131957611319611adc565b6040519080825280601f01601f191660200182016040528015611343576020820181803683370190505b509050600360fc1b8160008151811061135e5761135e611d87565b60200101906001600160f81b031916908160001a905350600f60fb1b8160018151811061138d5761138d611d87565b60200101906001600160f81b031916908160001a90535060006113b1846002612058565b6113bc906001611d74565b90505b6001811115611434576f181899199a1a9b1b9c1cb0b131b232b360811b85600f16601081106113f0576113f0611d87565b1a60f81b82828151811061140657611406611d87565b60200101906001600160f81b031916908160001a90535060049490941c9361142d8161206f565b90506113bf565b5083156106295760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152606401610391565b600161148d610e47565b6000848152602091825260408082206001600160a01b0386168084529352808220805460ff1916941515949094179093559151339285917f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d9190a45050565b60006114f6610fb5565b6000848152602091909152604090205490506001611512610fb5565b6000858152602091909152604081208054909190611531908490611d74565b90915550829050611540610fb5565b6000858152602091825260408082208583526001019092522080546001600160a01b0319166001600160a01b039290921691909117905580611580610fb5565b6000948552602090815260408086206001600160a01b03909516865260029094019052919092205550565b6115b58282610e6b565b6115bd610e47565b6000838152602091825260408082206001600160a01b0385168084529352808220805460ff191690555133929185917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b600061161e610fb5565b6000848152602091825260408082206001600160a01b03861683526002019092522054905061164b610fb5565b6000848152602091825260408082208483526001019092522080546001600160a01b031916905561167a610fb5565b6000938452602090815260408085206001600160a01b0390941685526002909301905250812055565b60008060ff196116d460017f0c4ba382c0009cf238e4c1ca1a52f51c61e6248a70bdfb34e5ed49d5578a5c0c611e0b565b6040516020016116e691815260200190565b60408051601f1981840301815291905280516020909101201692915050565b600081815260018301602052604081205480156117ee576000611729600183611e0b565b855490915060009061173d90600190611e0b565b90508181146117a257600086600001828154811061175d5761175d611d87565b906000526020600020015490508087600001848154811061178057611780611d87565b6000918252602080832090910192909255918252600188019052604090208390555b85548690806117b3576117b3612086565b60019003818190600052602060002001600090559055856001016000868152602001908152602001600020600090556001935050505061042f565b600091505061042f565b6060600080856001600160a01b031685604051611815919061209c565b600060405180830381855af49150503d8060008114611850576040519150601f19603f3d011682016040523d82523d6000602084013e611855565b606091505b50915091506118668683838761189a565b9695505050505050565b600082600001828154811061188757611887611d87565b9060005260206000200154905092915050565b60608315611909578251600003611902576001600160a01b0385163b6119025760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610391565b5081611913565b611913838361191b565b949350505050565b81511561192b5781518083602001fd5b8060405162461bcd60e51b81526004016103919190611cca565b6020808252825182820181905260009190848201906040850190845b818110156119865783516001600160a01b031683529284019291840191600101611961565b50909695505050505050565b80356001600160a01b03811681146119a957600080fd5b919050565b600080604083850312156119c157600080fd5b6119ca83611992565b946020939093013593505050565b6000602082840312156119ea57600080fd5b61062982611992565b600060208284031215611a0557600080fd5b5035919050565b60008060408385031215611a1f57600080fd5b82359150611a2f60208401611992565b90509250929050565b600080600060408486031215611a4d57600080fd5b611a5684611992565b925060208401356001600160401b0380821115611a7257600080fd5b818601915086601f830112611a8657600080fd5b813581811115611a9557600080fd5b876020828501011115611aa757600080fd5b6020830194508093505050509250925092565b60008060408385031215611acd57600080fd5b50508035926020909101359150565b634e487b7160e01b600052604160045260246000fd5b600060208284031215611b0457600080fd5b81356001600160401b0380821115611b1b57600080fd5b818401915084601f830112611b2f57600080fd5b813581811115611b4157611b41611adc565b604051601f8201601f19908116603f01168101908382118183101715611b6957611b69611adc565b81604052828152876020848701011115611b8257600080fd5b826020860160208301376000928101602001929092525095945050505050565b60008060208385031215611bb557600080fd5b82356001600160401b0380821115611bcc57600080fd5b818501915085601f830112611be057600080fd5b813581811115611bef57600080fd5b8660208260051b8501011115611c0457600080fd5b60209290920196919550909350505050565b60005b83811015611c31578181015183820152602001611c19565b50506000910152565b60008151808452611c52816020860160208601611c16565b601f01601f19169290920160200192915050565b600060208083016020845280855180835260408601915060408160051b87010192506020870160005b82811015611cbd57603f19888603018452611cab858351611c3a565b94509285019290850190600101611c8f565b5092979650505050505050565b6020815260006106296020830184611c3a565b6020808252601f908201527f4163636f756e74466163746f72793a206e6f7420616e206163636f756e742e00604082015260600190565b6020808252602a908201527f4163636f756e74466163746f72793a206163636f756e7420616c7265616479206040820152691c9959da5cdd195c995960b21b606082015260800190565b634e487b7160e01b600052601160045260246000fd5b8082018082111561042f5761042f611d5e565b634e487b7160e01b600052603260045260246000fd5b6000808335601e19843603018112611db457600080fd5b8301803591506001600160401b03821115611dce57600080fd5b602001915036819003821315611de357600080fd5b9250929050565b8284823760609190911b6001600160601b0319169101908152601401919050565b8181038181111561042f5761042f611d5e565b600181811c90821680611e3257607f821691505b602082108103610abc57634e487b7160e01b600052602260045260246000fd5b7402832b936b4b9b9b4b7b7399d1030b1b1b7bab73a1605d1b815260008351611e82816015850160208801611c16565b7001034b99036b4b9b9b4b733903937b6329607d1b6015918401918201528351611eb3816026840160208801611c16565b01602601949350505050565b6001600160a01b038316815260406020820181905260009061191390830184611c3a565b601f821115611f2f576000816000526020600020601f850160051c81016020861015611f0c5750805b601f850160051c820191505b81811015611f2b57828155600101611f18565b5050505b505050565b81516001600160401b03811115611f4d57611f4d611adc565b611f6181611f5b8454611e1e565b84611ee3565b602080601f831160018114611f965760008415611f7e5750858301515b600019600386901b1c1916600185901b178555611f2b565b600085815260208120601f198616915b82811015611fc557888601518255948401946001909101908401611fa6565b5085821015611fe35787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6040815260006120066040830185611c3a565b82810360208401526106258185611c3a565b6001600160a01b03841681526040602082018190528101829052818360608301376000818301606090810191909152601f909201601f1916010192915050565b808202811582820484141761042f5761042f611d5e565b60008161207e5761207e611d5e565b506000190190565b634e487b7160e01b600052603160045260246000fd5b600082516120ae818460208701611c16565b919091019291505056fe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a26469706673582212208fee46949383576f28224ce9e6b6a4b07519741c4de38b0c75218e600dce91e564736f6c63430008170033"; +bytes constant THIRDWEB_ACCOUNT_IMPL_BYTECODE = hex"60806040526004361061014b5760003560e01c806301ffc9a714610157578063150b7a021461018c5780631626ba7e146101c55780631dd756c5146101e557806324d7806c14610205578063399b77da146102255780633a871cdd1461025357806347e1da2a146102735780634a58db19146102955780634d44560d1461029d5780635892e236146102bd5780637dff5a79146102dd5780638b52d723146102fd578063938e3d7b1461031f578063a9082d841461033f578063ac9650d81461037e578063b0d691fe146103ab578063b61d27f6146103cd578063b76464d5146103ed578063bc197c811461040d578063c45a015514610439578063d087d2881461046d578063d1f5789414610482578063d42f2f35146104a2578063e8a3d485146104b7578063e9523c97146104d9578063f15d424e146104fb578063f23a6e611461052857600080fd5b3661015257005b600080fd5b34801561016357600080fd5b50610177610172366004612d97565b610554565b60405190151581526020015b60405180910390f35b34801561019857600080fd5b506101ac6101a7366004612ea3565b61059a565b6040516001600160e01b03199091168152602001610183565b3480156101d157600080fd5b506101ac6101e0366004612f0e565b6105ab565b3480156101f157600080fd5b50610177610200366004612f6d565b6106ca565b34801561021157600080fd5b50610177610220366004612fb2565b61098e565b34801561023157600080fd5b50610245610240366004612fcf565b6109bd565b604051908152602001610183565b34801561025f57600080fd5b5061024561026e366004612fe8565b610a88565b34801561027f57600080fd5b5061029361028e366004613079565b610aae565b005b610293610c15565b3480156102a957600080fd5b506102936102b8366004613112565b610c7d565b3480156102c957600080fd5b506102936102d836600461317f565b610cf0565b3480156102e957600080fd5b506101776102f8366004612fb2565b6110ad565b34801561030957600080fd5b50610312611166565b6040516101839190613292565b34801561032b57600080fd5b5061029361033a3660046132f6565b6113ad565b34801561034b57600080fd5b5061035f61035a36600461317f565b6113fe565b6040805192151583526001600160a01b03909116602083015201610183565b34801561038a57600080fd5b5061039e61039936600461333e565b611455565b60405161018391906133cf565b3480156103b757600080fd5b506103c06115ba565b6040516101839190613426565b3480156103d957600080fd5b506102936103e836600461343a565b611603565b3480156103f957600080fd5b50610293610408366004612fb2565b611693565b34801561041957600080fd5b506101ac610428366004613527565b63bc197c8160e01b95945050505050565b34801561044557600080fd5b506103c07f0000000000000000000000002e234dae75c793f67a35089c9d99245e1c58470b81565b34801561047957600080fd5b506102456116c5565b34801561048e57600080fd5b5061029361049d3660046135d4565b611745565b3480156104ae57600080fd5b506103126118fd565b3480156104c357600080fd5b506104cc611a6e565b604051610183919061361b565b3480156104e557600080fd5b506104ee611b06565b604051610183919061362e565b34801561050757600080fd5b5061051b610516366004612fb2565b611b18565b604051610183919061367b565b34801561053457600080fd5b506101ac61054336600461368e565b63f23a6e6160e01b95945050505050565b60006001600160e01b03198216630271189760e51b148061058557506001600160e01b03198216630a85bd0160e11b145b80610594575061059482611bf0565b92915050565b630a85bd0160e11b5b949350505050565b6000806105b7846109bd565b905060006105c58285611c25565b90506105d08161098e565b156105e75750630b135d3f60e11b91506105949050565b3360006105f2611c49565b6001600160a01b038416600090815260069190910160205260409020905061061a8183611c6d565b8061064a575061062981611c8f565b600114801561064a5750600061063f8282611c99565b6001600160a01b0316145b6106a75760405162461bcd60e51b8152602060048201526024808201527f4163636f756e743a2063616c6c6572206e6f7420617070726f7665642074617260448201526333b2ba1760e11b60648201526084015b60405180910390fd5b6106b0836110ad565b156106c057630b135d3f60e11b94505b5050505092915050565b60006106d4611c49565b6001600160a01b0384166000908152600491909101602052604090205460ff161561070157506001610594565b600061070b611c49565b6001600160a01b0385166000908152600591909101602090815260408083208151606081018352815481526001909101546001600160801b0380821694830194909452600160801b9004909216908201529150610766611c49565b6006016000866001600160a01b03166001600160a01b0316815260200190815260200160002090504282602001516001600160801b031611806107b6575081604001516001600160801b03164210155b806107c757506107c581611c8f565b155b156107d757600092505050610594565b60006107ee6107e960608701876136f6565b611ca5565b905060006107fb83611c8f565b600114801561081c575060006108118482611c99565b6001600160a01b0316145b90506324f16c0560e11b6001600160e01b03198316016108935760008061084e61084960608a018a6136f6565b611cdf565b9150915082610874576108618583611c6d565b6108745760009650505050505050610594565b855181111561088c5760009650505050505050610594565b5050610981565b635c0f12eb60e11b6001600160e01b0319831601610974576000806108c36108be60608a018a6136f6565b611d44565b5091509150826109235760005b8251811015610921576109058382815181106108ee576108ee61373c565b602002602001015187611c6d90919063ffffffff16565b610919576000975050505050505050610594565b6001016108d0565b505b60005b825181101561096c578181815181106109415761094161373c565b602002602001015187600001511015610964576000975050505050505050610594565b600101610926565b505050610981565b6000945050505050610594565b5060019695505050505050565b6000610998611c49565b6001600160a01b03909216600090815260049290920160205250604090205460ff1690565b600080826040516020016109d391815260200190565b60405160208183030381529060405280519060200120905060007f82cac545155fcbf147f2a9013809613677ac7d65498556e6d19ce43bcbf6c28482604051602001610a29929190918252602082015260400190565b604051602081830303815290604052805190602001209050610a49611d91565b60405161190160f01b60208201526022810191909152604281018290526062016040516020818303038152906040528051906020012092505050919050565b6000610a92611eb8565b610a9c8484611f21565b9050610aa782612066565b9392505050565b610ab66115ba565b6001600160a01b0316336001600160a01b03161480610ad95750610ad93361098e565b610af55760405162461bcd60e51b815260040161069e90613752565b610afd6120b3565b8481148015610b0b57508483145b610b575760405162461bcd60e51b815260206004820152601d60248201527f4163636f756e743a2077726f6e67206172726179206c656e677468732e000000604482015260640161069e565b60005b85811015610c0c57610c03878783818110610b7757610b7761373c565b9050602002016020810190610b8c9190612fb2565b868684818110610b9e57610b9e61373c565b90506020020135858585818110610bb757610bb761373c565b9050602002810190610bc991906136f6565b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061219992505050565b50600101610b5a565b50505050505050565b610c1d6115ba565b6001600160a01b031663b760faf934306040518363ffffffff1660e01b8152600401610c499190613426565b6000604051808303818588803b158015610c6257600080fd5b505af1158015610c76573d6000803e3d6000fd5b5050505050565b610c8561220a565b610c8d6115ba565b6001600160a01b031663205c287883836040518363ffffffff1660e01b8152600401610cba929190613793565b600060405180830381600087803b158015610cd457600080fd5b505af1158015610ce8573d6000803e3d6000fd5b505050505050565b6000610cff6020850185612fb2565b905042610d1260e0860160c087016137c3565b6001600160801b031611158015610d415750610d35610100850160e086016137c3565b6001600160801b031642105b610d775760405162461bcd60e51b8152602060048201526007602482015266085c195c9a5bd960ca1b604482015260640161069e565b600080610d858686866113fe565b9150915081610dbf5760405162461bcd60e51b815260040161069e906020808252600490820152632173696760e01b604082015260600190565b6001610dc9611c49565b610100880135600090815260079190910160209081526040808320805460ff1916941515949094179093559091610e05919089019089016137ef565b60ff161115610e32576000610e2060408801602089016137ef565b60ff166001149050610c0c8482612248565b610e3b8361098e565b15610e705760405162461bcd60e51b815260206004820152600560248201526430b236b4b760d91b604482015260640161069e565b610e8583610e7c611c49565b6002019061231d565b50604051806060016040528087606001358152602001876080016020810190610eae91906137c3565b6001600160801b03168152602001610ecc60c0890160a08a016137c3565b6001600160801b03169052610edf611c49565b6001600160a01b03851660009081526005919091016020908152604080832084518155918401519301516001600160801b03908116600160801b02931692909217600190920191909155610f55610f34611c49565b6001600160a01b038616600090815260069190910160205260409020612332565b805190915060005b81811015610fbf57610fac838281518110610f7a57610f7a61373c565b6020026020010151610f8a611c49565b6001600160a01b0389166000908152600691909101602052604090209061233f565b50610fb8600182613820565b9050610f5d565b50610fcd6040890189613833565b9050905060005b8181101561104e5761103b610fec60408b018b613833565b83818110610ffc57610ffc61373c565b90506020020160208101906110119190612fb2565b611019611c49565b6001600160a01b0389166000908152600691909101602052604090209061231d565b50611047600182613820565b9050610fd4565b5061105888612354565b846001600160a01b0316836001600160a01b03167ff21d10c26e35863a8df291aca54181ee8c4a3bc8e00246c3f7a5a14b69d826a78a60405161109b919061390d565b60405180910390a35050505050505050565b6000806110b8611c49565b6001600160a01b038416600090815260059190910160209081526040918290208251606081018452815481526001909101546001600160801b03808216938301849052600160801b90910416928101929092529091504210801590611129575080604001516001600160801b031642105b8015610aa75750600061115e61113d611c49565b6001600160a01b038616600090815260069190910160205260409020611c8f565b119392505050565b6060600061117d611175611c49565b600201612332565b80519091506000805b8281101561120e576111b08482815181106111a3576111a361373c565b60200260200101516110ad565b156111c757816111bf816139f8565b9250506111fc565b60008482815181106111db576111db61373c565b60200260200101906001600160a01b031690816001600160a01b0316815250505b611207600182613820565b9050611186565b50806001600160401b0381111561122757611227612de6565b60405190808252806020026020018201604052801561126057816020015b61124d612d4d565b8152602001906001900390816112455790505b5093506000805b838110156113a55760006001600160a01b031685828151811061128c5761128c61373c565b60200260200101516001600160a01b0316146113935760008582815181106112b6576112b661373c565b6020026020010151905060006112ca611c49565b6001600160a01b038316600081815260059290920160209081526040928390208351606081018552815481526001909101546001600160801b0380821683850152600160801b9091041681850152835160a081019094529183529092508101611334610f34611c49565b81526020018260000151815260200182602001516001600160801b0316815260200182604001516001600160801b0316815250888580611373906139f8565b9650815181106113855761138561373c565b602002602001018190525050505b61139e600182613820565b9050611267565b505050505090565b6113b56123e9565b6113f25760405162461bcd60e51b815260206004820152600e60248201526d139bdd08185d5d1a1bdc9a5e995960921b604482015260640161069e565b6113fb81612401565b50565b60008061141461140d866124e8565b858561262c565b905061141e611c49565b6101008601356000908152600791909101602052604090205460ff1615801561144b575061144b8161098e565b9150935093915050565b6060816001600160401b0381111561146f5761146f612de6565b6040519080825280602002602001820160405280156114a257816020015b606081526020019060019003908161148d5790505b509050336000805b848110156115b157811561152957611507308787848181106114ce576114ce61373c565b90506020028101906114e091906136f6565b866040516020016114f393929190613a11565b60405160208183030381529060405261267e565b8482815181106115195761151961373c565b60200260200101819052506115a9565b61158b3087878481811061153f5761153f61373c565b905060200281019061155191906136f6565b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061267e92505050565b84828151811061159d5761159d61373c565b60200260200101819052505b6001016114aa565b50505092915050565b6000806115c56126a3565b546001600160a01b0316905080156115dc57919050565b7f0000000000000000000000005ff137d4b0fdcd49dca30c7cf57e578a026d278991505090565b61160b6115ba565b6001600160a01b0316336001600160a01b0316148061162e575061162e3361098e565b61164a5760405162461bcd60e51b815260040161069e90613752565b6116526120b3565b610c76848484848080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061219992505050565b61169b61220a565b806116a46126a3565b80546001600160a01b0319166001600160a01b039290921691909117905550565b60006116cf6115ba565b604051631aab3f0d60e11b8152306004820152600060248201526001600160a01b0391909116906335567e1a90604401602060405180830381865afa15801561171c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117409190613a32565b905090565b600061174f6126c7565b5460ff169050600061175f6126c7565b54610100900460ff169050801580801561177c575060018360ff16105b8061179b575061178b306126eb565b15801561179b57508260ff166001145b6117fe5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b606482015260840161069e565b60016118086126c7565b805460ff191660ff92909216919091179055801561184157600161182a6126c7565b80549115156101000261ff00199092169190911790555b6118818686868080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506126fa92505050565b6118896126a3565b6001018190555061189b866001612248565b8015610ce85760006118ab6126c7565b80549115156101000261ff0019909216919091179055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a1505050505050565b6060600061190c611175611c49565b8051909150806001600160401b0381111561192957611929612de6565b60405190808252806020026020018201604052801561196257816020015b61194f612d4d565b8152602001906001900390816119475790505b50925060005b81811015611a685760008382815181106119845761198461373c565b602002602001015190506000611998611c49565b6001600160a01b038316600081815260059290920160209081526040928390208351606081018552815481526001909101546001600160801b0380821683850152600160801b9091041681850152835160a081019094529183529092508101611a02610f34611c49565b81526020018260000151815260200182602001516001600160801b0316815260200182604001516001600160801b0316815250868481518110611a4757611a4761373c565b60200260200101819052505050600181611a619190613820565b9050611968565b50505090565b6060611a7861272d565b8054611a8390613a4b565b80601f0160208091040260200160405190810160405280929190818152602001828054611aaf90613a4b565b8015611afc5780601f10611ad157610100808354040283529160200191611afc565b820191906000526020600020905b815481529060010190602001808311611adf57829003601f168201915b5050505050905090565b6060611740611b13611c49565b612332565b611b20612d4d565b6000611b2a611c49565b6001600160a01b038416600081815260059290920160209081526040928390208351606081018552815481526001909101546001600160801b0380821683850152600160801b9091041681850152835160a081019094529183529092508101611bb5611b94611c49565b6001600160a01b038716600090815260069190910160205260409020612332565b81526020018260000151815260200182602001516001600160801b0316815260200182604001516001600160801b0316815250915050919050565b60006001600160e01b03198216630271189760e51b148061059457506301ffc9a760e01b6001600160e01b0319831614610594565b6000806000611c348585612751565b91509150611c4181612796565b509392505050565b7f3181e78fc1b109bc611fd2406150bf06e33faa75f71cba12c3e1fd670f2def0090565b6001600160a01b03811660009081526001830160205260408120541515610aa7565b6000610594825490565b6000610aa783836128db565b60006004821015611cc85760405162461bcd60e51b815260040161069e90613a7f565b611cd6600460008486613a9e565b610aa791613ac8565b6000806044831015611d035760405162461bcd60e51b815260040161069e90613a7f565b611d11602460048587613a9e565b810190611d1e9190612fb2565b9150611d2e604460248587613a9e565b810190611d3b9190612fcf565b90509250929050565b606080806064841015611d695760405162461bcd60e51b815260040161069e90613a7f565b611d768460048188613a9e565b810190611d839190613b77565b919790965090945092505050565b6000306001600160a01b037f000000000000000000000000ffd4505b3452dc22f8473616d50503ba9e1710ac16148015611dea57507f0000000000000000000000000000000000000000000000000000000000007a6946145b15611e1457507fbcdadf6444930a967ffda04923d78c49b3dd65df3ed39abb04a1e3eb1190553790565b50604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f6020808301919091527ff0729608244859f656d32ae4cbc6b0367695d68d8e941a28f5e2d33c6d5182dd828401527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608301524660808301523060a0808401919091528351808403909101815260c0909201909252805191012090565b611ec06115ba565b6001600160a01b0316336001600160a01b031614611f1f5760405162461bcd60e51b815260206004820152601c60248201527b1858d8dbdd5b9d0e881b9bdd08199c9bdb48115b9d1c9e541bda5b9d60221b604482015260640161069e565b565b7b0ca2ba3432b932bab69029b4b3b732b21026b2b9b9b0b3b29d05199960211b6000908152601c829052603c81206000611f9f611f626101408701876136f6565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152508693925050611c259050565b9050611fab81866106ca565b611fba57600192505050610594565b6000611fc4611c49565b6001600160a01b03929092166000908152600590920160209081526040808420815160608082018452825482526001909201546001600160801b0380821683870152600160801b8204908116928501929092528351928301845295825265ffffffffffff8087169483019490945292831691015260d09290921b6001600160d01b03191660a09290921b65ffffffffffff60a01b169190911795945050505050565b80156113fb57604051600090339060001990849084818181858888f193505050503d8060008114610c76576040519150601f19603f3d011682016040523d82523d6000602084013e610c76565b60405163c3c5a54760e01b81527f0000000000000000000000002e234dae75c793f67a35089c9d99245e1c58470b906001600160a01b0382169063c3c5a54790612101903090600401613426565b602060405180830381865afa15801561211e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121429190613c5c565b6113fb57806001600160a01b03166383a03f8c61215d6126a3565b600101546040518263ffffffff1660e01b815260040161217f91815260200190565b600060405180830381600087803b158015610c6257600080fd5b60606000846001600160a01b031684846040516121b69190613c7e565b60006040518083038185875af1925050503d80600081146121f3576040519150601f19603f3d011682016040523d82523d6000602084013e6121f8565b606091505b509250905080611c4157815160208301fd5b6122133361098e565b611f1f5760405162461bcd60e51b815260206004820152600660248201526510b0b236b4b760d11b604482015260640161069e565b6122528282612905565b6001600160a01b037f0000000000000000000000002e234dae75c793f67a35089c9d99245e1c58470b163b156123195780156122e1577f0000000000000000000000002e234dae75c793f67a35089c9d99245e1c58470b6001600160a01b0316630b61e12b836122c06126a3565b600101546040518363ffffffff1660e01b8152600401610cba929190613793565b7f0000000000000000000000002e234dae75c793f67a35089c9d99245e1c58470b6001600160a01b0316639387a380836122c06126a3565b5050565b6000610aa7836001600160a01b0384166129b4565b60606000610aa783612a03565b6000610aa7836001600160a01b038416612a5f565b6001600160a01b037f0000000000000000000000002e234dae75c793f67a35089c9d99245e1c58470b163b156113fb576001600160a01b037f0000000000000000000000002e234dae75c793f67a35089c9d99245e1c58470b16630b61e12b6123c06020840184612fb2565b6123c86126a3565b600101546040518363ffffffff1660e01b815260040161217f929190613793565b60006123f43361098e565b8061174057505030331490565b600061240b61272d565b805461241690613a4b565b80601f016020809104026020016040519081016040528092919081815260200182805461244290613a4b565b801561248f5780601f106124645761010080835404028352916020019161248f565b820191906000526020600020905b81548152906001019060200180831161247257829003601f168201915b505050505090508161249f61272d565b906124aa9082613ce7565b507fc9c7c3fe08b88b4df9d4d47ef47d2c43d55c025a0ba88ca442580ed9e7348a1681836040516124dc929190613da6565b60405180910390a15050565b60607f3fd4a1a1a267c84185e3b7eecd57c68783c0581d538b9d6e5f23e4670497c1e96125186020840184612fb2565b61252860408501602086016137ef565b6125356040860186613833565b604051602001612546929190613dd4565b60408051601f198184030181529190528051602090910120606086013561257360a08801608089016137c3565b61258360c0890160a08a016137c3565b61259360e08a0160c08b016137c3565b6125a46101008b0160e08c016137c3565b60408051602081019a909a526001600160a01b039098169789019790975260ff9095166060880152608087019390935260a08601919091526001600160801b0390811660c086015290811660e0850152908116610100848101919091529116610120830152830135610140820152610160016040516020818303038152906040529050919050565b60006105a383838080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250508751602089012061267892509050612b52565b90611c25565b6060610aa78383604051806060016040528060278152602001613e7a60279139612b7f565b7f036f52c1827dab135f7fd44ca0bddde297e2f659c710e0ec53e975f22b54830090565b7f322cf19c484104d3b1a9c2982ebae869ede3fa5f6c4703ca41b9a48c76ee030090565b6001600160a01b03163b151590565b6000828260405160200161270f929190613e16565b60405160208183030381529060405280519060200120905092915050565b7f4bc804ba64359c0e35e5ed5d90ee596ecaa49a3a930ddcb1470ea0dd625da90090565b60008082516041036127875760208301516040840151606085015160001a61277b87828585612bf7565b9450945050505061278f565b506000905060025b9250929050565b60008160048111156127aa576127aa613e3a565b036127b25750565b60018160048111156127c6576127c6613e3a565b0361280e5760405162461bcd60e51b815260206004820152601860248201527745434453413a20696e76616c6964207369676e617475726560401b604482015260640161069e565b600281600481111561282257612822613e3a565b0361286f5760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e67746800604482015260640161069e565b600381600481111561288357612883613e3a565b036113fb5760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604482015261756560f01b606482015260840161069e565b60008260000182815481106128f2576128f261373c565b9060005260206000200154905092915050565b8061290e611c49565b6001600160a01b038416600090815260049190910160205260409020805460ff19169115159190911790558015612957576129518261294b611c49565b9061231d565b5061296b565b61296982612963611c49565b9061233f565b505b816001600160a01b03167f235bc17e7930760029e9f4d860a2a8089976de5b381cf8380fc11c1d88a11133826040516129a8911515815260200190565b60405180910390a25050565b60008181526001830160205260408120546129fb57508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610594565b506000610594565b606081600001805480602002602001604051908101604052809291908181526020018280548015612a5357602002820191906000526020600020905b815481526020019060010190808311612a3f575b50505050509050919050565b60008181526001830160205260408120548015612b48576000612a83600183613e50565b8554909150600090612a9790600190613e50565b9050818114612afc576000866000018281548110612ab757612ab761373c565b9060005260206000200154905080876000018481548110612ada57612ada61373c565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080612b0d57612b0d613e63565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050610594565b6000915050610594565b6000610594612b5f611d91565b8360405161190160f01b8152600281019290925260228201526042902090565b6060600080856001600160a01b031685604051612b9c9190613c7e565b600060405180830381855af49150503d8060008114612bd7576040519150601f19603f3d011682016040523d82523d6000602084013e612bdc565b606091505b5091509150612bed86838387612cb1565b9695505050505050565b6000806fa2a8918ca85bafe22016d0b997e4df60600160ff1b03831115612c245750600090506003612ca8565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa158015612c78573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116612ca157600060019250925050612ca8565b9150600090505b94509492505050565b60608315612d1e578251600003612d1757612ccb856126eb565b612d175760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640161069e565b50816105a3565b6105a38383815115612d335781518083602001fd5b8060405162461bcd60e51b815260040161069e919061361b565b6040518060a0016040528060006001600160a01b03168152602001606081526020016000815260200160006001600160801b0316815260200160006001600160801b031681525090565b600060208284031215612da957600080fd5b81356001600160e01b031981168114610aa757600080fd5b6001600160a01b03811681146113fb57600080fd5b8035612de181612dc1565b919050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b0381118282101715612e2457612e24612de6565b604052919050565b60006001600160401b03831115612e4557612e45612de6565b612e58601f8401601f1916602001612dfc565b9050828152838383011115612e6c57600080fd5b828260208301376000602084830101529392505050565b600082601f830112612e9457600080fd5b610aa783833560208501612e2c565b60008060008060808587031215612eb957600080fd5b8435612ec481612dc1565b93506020850135612ed481612dc1565b92506040850135915060608501356001600160401b03811115612ef657600080fd5b612f0287828801612e83565b91505092959194509250565b60008060408385031215612f2157600080fd5b8235915060208301356001600160401b03811115612f3e57600080fd5b612f4a85828601612e83565b9150509250929050565b60006101608284031215612f6757600080fd5b50919050565b60008060408385031215612f8057600080fd5b8235612f8b81612dc1565b915060208301356001600160401b03811115612fa657600080fd5b612f4a85828601612f54565b600060208284031215612fc457600080fd5b8135610aa781612dc1565b600060208284031215612fe157600080fd5b5035919050565b600080600060608486031215612ffd57600080fd5b83356001600160401b0381111561301357600080fd5b61301f86828701612f54565b9660208601359650604090950135949350505050565b60008083601f84011261304757600080fd5b5081356001600160401b0381111561305e57600080fd5b6020830191508360208260051b850101111561278f57600080fd5b6000806000806000806060878903121561309257600080fd5b86356001600160401b03808211156130a957600080fd5b6130b58a838b01613035565b909850965060208901359150808211156130ce57600080fd5b6130da8a838b01613035565b909650945060408901359150808211156130f357600080fd5b5061310089828a01613035565b979a9699509497509295939492505050565b6000806040838503121561312557600080fd5b823561313081612dc1565b946020939093013593505050565b60008083601f84011261315057600080fd5b5081356001600160401b0381111561316757600080fd5b60208301915083602082850101111561278f57600080fd5b60008060006040848603121561319457600080fd5b83356001600160401b03808211156131ab57600080fd5b9085019061012082880312156131c057600080fd5b909350602085013590808211156131d657600080fd5b506131e38682870161313e565b9497909650939450505050565b6001600160801b03169052565b80516001600160a01b03908116835260208083015160a082860181905281519086018190526000939183019290849060c08801905b8083101561325457855185168252948301946001929092019190830190613232565b50604087015160408901526060870151945061327360608901866131f0565b6080870151945061328760808901866131f0565b979650505050505050565b600060208083016020845280855180835260408601915060408160051b87010192506020870160005b828110156132e957603f198886030184526132d78583516131fd565b945092850192908501906001016132bb565b5092979650505050505050565b60006020828403121561330857600080fd5b81356001600160401b0381111561331e57600080fd5b8201601f8101841361332f57600080fd5b6105a384823560208401612e2c565b6000806020838503121561335157600080fd5b82356001600160401b0381111561336757600080fd5b61337385828601613035565b90969095509350505050565b60005b8381101561339a578181015183820152602001613382565b50506000910152565b600081518084526133bb81602086016020860161337f565b601f01601f19169290920160200192915050565b600060208083016020845280855180835260408601915060408160051b87010192506020870160005b828110156132e957603f198886030184526134148583516133a3565b945092850192908501906001016133f8565b6001600160a01b0391909116815260200190565b6000806000806060858703121561345057600080fd5b843561345b81612dc1565b93506020850135925060408501356001600160401b0381111561347d57600080fd5b6134898782880161313e565b95989497509550505050565b60006001600160401b038211156134ae576134ae612de6565b5060051b60200190565b600082601f8301126134c957600080fd5b813560206134de6134d983613495565b612dfc565b8083825260208201915060208460051b87010193508684111561350057600080fd5b602086015b8481101561351c5780358352918301918301613505565b509695505050505050565b600080600080600060a0868803121561353f57600080fd5b853561354a81612dc1565b9450602086013561355a81612dc1565b935060408601356001600160401b038082111561357657600080fd5b61358289838a016134b8565b9450606088013591508082111561359857600080fd5b6135a489838a016134b8565b935060808801359150808211156135ba57600080fd5b506135c788828901612e83565b9150509295509295909350565b6000806000604084860312156135e957600080fd5b83356135f481612dc1565b925060208401356001600160401b0381111561360f57600080fd5b6131e38682870161313e565b602081526000610aa760208301846133a3565b6020808252825182820181905260009190848201906040850190845b8181101561366f5783516001600160a01b03168352928401929184019160010161364a565b50909695505050505050565b602081526000610aa760208301846131fd565b600080600080600060a086880312156136a657600080fd5b85356136b181612dc1565b945060208601356136c181612dc1565b9350604086013592506060860135915060808601356001600160401b038111156136ea57600080fd5b6135c788828901612e83565b6000808335601e1984360301811261370d57600080fd5b8301803591506001600160401b0382111561372757600080fd5b60200191503681900382131561278f57600080fd5b634e487b7160e01b600052603260045260246000fd5b60208082526021908201527f4163636f756e743a206e6f742061646d696e206f7220456e747279506f696e746040820152601760f91b606082015260800190565b6001600160a01b03929092168252602082015260400190565b80356001600160801b0381168114612de157600080fd5b6000602082840312156137d557600080fd5b610aa7826137ac565b803560ff81168114612de157600080fd5b60006020828403121561380157600080fd5b610aa7826137de565b634e487b7160e01b600052601160045260246000fd5b808201808211156105945761059461380a565b6000808335601e1984360301811261384a57600080fd5b8301803591506001600160401b0382111561386457600080fd5b6020019150600581901b360382131561278f57600080fd5b6000808335601e1984360301811261389357600080fd5b83016020810192503590506001600160401b038111156138b257600080fd5b8060051b360382131561278f57600080fd5b8183526000602080850194508260005b858110156139025781356138e781612dc1565b6001600160a01b0316875295820195908201906001016138d4565b509495945050505050565b6020815261392e6020820161392184612dd6565b6001600160a01b03169052565b600061393c602084016137de565b60ff8116604084015250613953604084018461387c565b61012080606086015261396b610140860183856138c4565b925060608601356080860152613983608087016137ac565b915061399260a08601836131f0565b61399e60a087016137ac565b91506139ad60c08601836131f0565b6139b960c087016137ac565b91506139c860e08601836131f0565b6139d460e087016137ac565b91506101006139e5818701846131f0565b9590950135939094019290925250919050565b600060018201613a0a57613a0a61380a565b5060010190565b8284823760609190911b6001600160601b0319169101908152601401919050565b600060208284031215613a4457600080fd5b5051919050565b600181811c90821680613a5f57607f821691505b602082108103612f6757634e487b7160e01b600052602260045260246000fd5b602080825260059082015264214461746160d81b604082015260600190565b60008085851115613aae57600080fd5b83861115613abb57600080fd5b5050820193919092039150565b6001600160e01b03198135818116916004851015613af05780818660040360031b1b83161692505b505092915050565b600082601f830112613b0957600080fd5b81356020613b196134d983613495565b82815260059290921b84018101918181019086841115613b3857600080fd5b8286015b8481101561351c5780356001600160401b03811115613b5b5760008081fd5b613b698986838b0101612e83565b845250918301918301613b3c565b600080600060608486031215613b8c57600080fd5b83356001600160401b0380821115613ba357600080fd5b818601915086601f830112613bb757600080fd5b81356020613bc76134d983613495565b82815260059290921b8401810191818101908a841115613be657600080fd5b948201945b83861015613c0d578535613bfe81612dc1565b82529482019490820190613beb565b97505087013592505080821115613c2357600080fd5b613c2f878388016134b8565b93506040860135915080821115613c4557600080fd5b50613c5286828701613af8565b9150509250925092565b600060208284031215613c6e57600080fd5b81518015158114610aa757600080fd5b60008251613c9081846020870161337f565b9190910192915050565b601f821115613ce2576000816000526020600020601f850160051c81016020861015613cc35750805b601f850160051c820191505b81811015610ce857828155600101613ccf565b505050565b81516001600160401b03811115613d0057613d00612de6565b613d1481613d0e8454613a4b565b84613c9a565b602080601f831160018114613d495760008415613d315750858301515b600019600386901b1c1916600185901b178555610ce8565b600085815260208120601f198616915b82811015613d7857888601518255948401946001909101908401613d59565b5085821015613d965787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b604081526000613db960408301856133a3565b8281036020840152613dcb81856133a3565b95945050505050565b60008184825b85811015613e0b578135613ded81612dc1565b6001600160a01b031683526020928301929190910190600101613dda565b509095945050505050565b6001600160a01b03831681526040602082018190526000906105a3908301846133a3565b634e487b7160e01b600052602160045260246000fd5b818103818111156105945761059461380a565b634e487b7160e01b600052603160045260246000fdfe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a2646970667358221220247c9feadcfb4aa67bba286fdc86b80cc167fce1383f2afbc218bf965fb6bc3264736f6c63430008170033"; From 0b84c841aa5029b749032a9ed429caf0b55f065a Mon Sep 17 00:00:00 2001 From: Jake Loo <2171134+jakeloo@users.noreply.github.com> Date: Wed, 20 Mar 2024 19:27:00 +0000 Subject: [PATCH 04/30] Partial changes --- .../prebuilts/unaudited/airdrop/Airdrop.sol | 71 ++++++++++++++----- 1 file changed, 54 insertions(+), 17 deletions(-) diff --git a/contracts/prebuilts/unaudited/airdrop/Airdrop.sol b/contracts/prebuilts/unaudited/airdrop/Airdrop.sol index 1c9c1f7fe..c95846b44 100644 --- a/contracts/prebuilts/unaudited/airdrop/Airdrop.sol +++ b/contracts/prebuilts/unaudited/airdrop/Airdrop.sol @@ -31,6 +31,14 @@ contract Airdrop is EIP712, Initializable, Ownable { State, constants & structs //////////////////////////////////////////////////////////////*/ + // token contract address => merkle root + mapping(address => bytes32) public merkleRoot; + // hash(claimer address || token address || token id [1155]) => has claimed + mapping(bytes32 => bool) private claimed; + mapping(bytes32 => bool) private processed; + + // ---------------------- + // ERC20 claimable address public tokenAddress20; mapping(address => bytes32) public merkleRoot20; @@ -115,6 +123,7 @@ contract Airdrop is EIP712, Initializable, Ownable { //////////////////////////////////////////////////////////////*/ error AirdropInvalidProof(); + error AirdropAlreadyClaimed(); error AirdropFailed(); error AirdropNoMerkleRoot(); error AirdropValueMismatch(); @@ -160,12 +169,7 @@ contract Airdrop is EIP712, Initializable, Ownable { for (uint256 i = 0; i < len; ) { nativeTokenAmount += _contents[i].amount; - if (nativeTokenAmount > msg.value) { - revert AirdropValueMismatch(); - } - (bool success, ) = _contents[i].recipient.call{ value: _contents[i].amount }(""); - if (!success) { refundAmount += _contents[i].amount; } @@ -189,7 +193,6 @@ contract Airdrop is EIP712, Initializable, Ownable { function airdrop721(address _tokenAddress, AirdropContent721[] calldata _contents) external { address _from = msg.sender; - uint256 len = _contents.length; for (uint256 i = 0; i < len; ) { @@ -360,8 +363,18 @@ contract Airdrop is EIP712, Initializable, Ownable { Airdrop Claimable //////////////////////////////////////////////////////////////*/ - function claim20(address _token, address _receiver, uint256 _quantity, bytes32[] calldata _proofs) external { - bytes32 _merkleRoot = merkleRoot20[_token]; + function claim20( + address _token, + address _receiver, + uint256 _quantity, + bytes32[] calldata _proofs + ) external { + bytes32 claimHash = getClaimHashERC20(msg.sender, _token); + if (claimed[claimHash]) { + revert AirdropAlreadyClaimed(); + } + + bytes32 _merkleRoot = merkleRoot[_token]; if (_merkleRoot == bytes32(0)) { revert AirdropNoMerkleRoot(); @@ -373,12 +386,32 @@ contract Airdrop is EIP712, Initializable, Ownable { revert AirdropInvalidProof(); } - claimed20[msg.sender] = true; + claimed[claimHash] = true; - CurrencyTransferLib.transferCurrency(tokenAddress20, owner(), _receiver, _quantity); + CurrencyTransferLib.transferCurrency(_token, owner(), _receiver, _quantity); } - function claimETH(address _receiver, uint256 _quantity, bytes32[] calldata _proofs) external { + function getClaimHashERC20(address _sender, address _token) private view returns (bytes32) { + return keccak256(abi.encodePacked(_sender, _token)); + } + + function getClaimHashERC721(address _sender, address _token) private view returns (bytes32) { + return keccak256(abi.encodePacked(_sender, _token)); + } + + function getClaimHashERC1155( + address _sender, + address _token, + uint256 _tokenId + ) private view returns (bytes32) { + return keccak256(abi.encodePacked(_sender, _token, _tokenId)); + } + + function claimETH( + address _receiver, + uint256 _quantity, + bytes32[] calldata _proofs + ) external { bool valid = MerkleProofLib.verify(_proofs, merkleRootETH, keccak256(abi.encodePacked(msg.sender, _quantity))); if (!valid) { @@ -391,7 +424,12 @@ contract Airdrop is EIP712, Initializable, Ownable { if (!success) revert AirdropFailed(); } - function claim721(address _token, address _receiver, uint256 _tokenId, bytes32[] calldata _proofs) external { + function claim721( + address _token, + address _receiver, + uint256 _tokenId, + bytes32[] calldata _proofs + ) external { bytes32 _merkleRoot = merkleRoot721[_token]; if (_merkleRoot == bytes32(0)) { @@ -438,8 +476,7 @@ contract Airdrop is EIP712, Initializable, Ownable { //////////////////////////////////////////////////////////////*/ function setMerkleRoot20(address _token, bytes32 _merkleRoot) external onlyOwner { - tokenAddress20 = _token; - merkleRoot20[_token] = _merkleRoot; + merkleRoot[_token] = _merkleRoot; } function setMerkleRootETH(bytes32 _merkleRoot) external onlyOwner { @@ -471,7 +508,7 @@ contract Airdrop is EIP712, Initializable, Ownable { function _hashContentInfo20(AirdropContent20[] calldata contents) private pure returns (bytes32) { bytes32[] memory contentHashes = new bytes32[](contents.length); - for (uint i = 0; i < contents.length; i++) { + for (uint256 i = 0; i < contents.length; i++) { contentHashes[i] = keccak256(abi.encode(CONTENT_TYPEHASH_ERC20, contents[i].recipient, contents[i].amount)); } return keccak256(abi.encodePacked(contentHashes)); @@ -479,7 +516,7 @@ contract Airdrop is EIP712, Initializable, Ownable { function _hashContentInfo721(AirdropContent721[] calldata contents) private pure returns (bytes32) { bytes32[] memory contentHashes = new bytes32[](contents.length); - for (uint i = 0; i < contents.length; i++) { + for (uint256 i = 0; i < contents.length; i++) { contentHashes[i] = keccak256( abi.encode(CONTENT_TYPEHASH_ERC721, contents[i].recipient, contents[i].tokenId) ); @@ -489,7 +526,7 @@ contract Airdrop is EIP712, Initializable, Ownable { function _hashContentInfo1155(AirdropContent1155[] calldata contents) private pure returns (bytes32) { bytes32[] memory contentHashes = new bytes32[](contents.length); - for (uint i = 0; i < contents.length; i++) { + for (uint256 i = 0; i < contents.length; i++) { contentHashes[i] = keccak256( abi.encode(CONTENT_TYPEHASH_ERC1155, contents[i].recipient, contents[i].tokenId, contents[i].amount) ); From aa163a555b1d1be7f932ed5c1bf0153d04f11112 Mon Sep 17 00:00:00 2001 From: Yash Date: Thu, 21 Mar 2024 06:16:45 +0530 Subject: [PATCH 05/30] remove unused --- .../prebuilts/unaudited/airdrop/Airdrop.sol | 92 ++++++------------- package.json | 3 + src/test/benchmark/AirdropBenchmark.t.sol | 6 +- yarn.lock | 38 ++++++++ 4 files changed, 71 insertions(+), 68 deletions(-) diff --git a/contracts/prebuilts/unaudited/airdrop/Airdrop.sol b/contracts/prebuilts/unaudited/airdrop/Airdrop.sol index c95846b44..15ee56447 100644 --- a/contracts/prebuilts/unaudited/airdrop/Airdrop.sol +++ b/contracts/prebuilts/unaudited/airdrop/Airdrop.sol @@ -31,33 +31,13 @@ contract Airdrop is EIP712, Initializable, Ownable { State, constants & structs //////////////////////////////////////////////////////////////*/ + bytes32 public merkleRootETH; + mapping(address => bool) public claimedETH; + // token contract address => merkle root mapping(address => bytes32) public merkleRoot; // hash(claimer address || token address || token id [1155]) => has claimed mapping(bytes32 => bool) private claimed; - mapping(bytes32 => bool) private processed; - - // ---------------------- - - // ERC20 claimable - address public tokenAddress20; - mapping(address => bytes32) public merkleRoot20; - mapping(address => bool) public claimed20; - - // Native token claimable - bytes32 public merkleRootETH; - mapping(address => bool) public claimedETH; - - // ERC721 claimable - address public tokenAddress721; - mapping(address => bytes32) public merkleRoot721; - mapping(uint256 => bool) public claimed721; - - // ERC1155 claimable - address public tokenAddress1155; - mapping(address => bytes32) public merkleRoot1155; - mapping(uint256 => mapping(address => bool)) public claimed1155; - /// @dev Mapping from request UID => whether the request is processed. mapping(bytes32 => bool) private processed; @@ -363,13 +343,8 @@ contract Airdrop is EIP712, Initializable, Ownable { Airdrop Claimable //////////////////////////////////////////////////////////////*/ - function claim20( - address _token, - address _receiver, - uint256 _quantity, - bytes32[] calldata _proofs - ) external { - bytes32 claimHash = getClaimHashERC20(msg.sender, _token); + function claim20(address _token, address _receiver, uint256 _quantity, bytes32[] calldata _proofs) external { + bytes32 claimHash = _getClaimHashERC20(msg.sender, _token); if (claimed[claimHash]) { revert AirdropAlreadyClaimed(); } @@ -391,27 +366,19 @@ contract Airdrop is EIP712, Initializable, Ownable { CurrencyTransferLib.transferCurrency(_token, owner(), _receiver, _quantity); } - function getClaimHashERC20(address _sender, address _token) private view returns (bytes32) { + function _getClaimHashERC20(address _sender, address _token) private view returns (bytes32) { return keccak256(abi.encodePacked(_sender, _token)); } - function getClaimHashERC721(address _sender, address _token) private view returns (bytes32) { + function _getClaimHashERC721(address _sender, address _token) private view returns (bytes32) { return keccak256(abi.encodePacked(_sender, _token)); } - function getClaimHashERC1155( - address _sender, - address _token, - uint256 _tokenId - ) private view returns (bytes32) { + function _getClaimHashERC1155(address _sender, address _token, uint256 _tokenId) private view returns (bytes32) { return keccak256(abi.encodePacked(_sender, _token, _tokenId)); } - function claimETH( - address _receiver, - uint256 _quantity, - bytes32[] calldata _proofs - ) external { + function claimETH(address _receiver, uint256 _quantity, bytes32[] calldata _proofs) external { bool valid = MerkleProofLib.verify(_proofs, merkleRootETH, keccak256(abi.encodePacked(msg.sender, _quantity))); if (!valid) { @@ -424,13 +391,13 @@ contract Airdrop is EIP712, Initializable, Ownable { if (!success) revert AirdropFailed(); } - function claim721( - address _token, - address _receiver, - uint256 _tokenId, - bytes32[] calldata _proofs - ) external { - bytes32 _merkleRoot = merkleRoot721[_token]; + function claim721(address _token, address _receiver, uint256 _tokenId, bytes32[] calldata _proofs) external { + bytes32 claimHash = _getClaimHashERC721(msg.sender, _token); + if (claimed[claimHash]) { + revert AirdropAlreadyClaimed(); + } + + bytes32 _merkleRoot = merkleRoot[_token]; if (_merkleRoot == bytes32(0)) { revert AirdropNoMerkleRoot(); @@ -442,9 +409,9 @@ contract Airdrop is EIP712, Initializable, Ownable { revert AirdropInvalidProof(); } - claimed721[_tokenId] = true; + claimed[claimHash] = true; - IERC721(tokenAddress721).safeTransferFrom(owner(), _receiver, _tokenId); + IERC721(_token).safeTransferFrom(owner(), _receiver, _tokenId); } function claim1155( @@ -454,7 +421,12 @@ contract Airdrop is EIP712, Initializable, Ownable { uint256 _quantity, bytes32[] calldata _proofs ) external { - bytes32 _merkleRoot = merkleRoot1155[_token]; + bytes32 claimHash = _getClaimHashERC1155(msg.sender, _token, _tokenId); + if (claimed[claimHash]) { + revert AirdropAlreadyClaimed(); + } + + bytes32 _merkleRoot = merkleRoot[_token]; if (_merkleRoot == bytes32(0)) { revert AirdropNoMerkleRoot(); @@ -466,16 +438,16 @@ contract Airdrop is EIP712, Initializable, Ownable { revert AirdropInvalidProof(); } - claimed1155[_tokenId][msg.sender] = true; + claimed[claimHash] = true; - IERC1155(tokenAddress1155).safeTransferFrom(owner(), _receiver, _tokenId, _quantity, ""); + IERC1155(_token).safeTransferFrom(owner(), _receiver, _tokenId, _quantity, ""); } /*/////////////////////////////////////////////////////////////// Setter functions //////////////////////////////////////////////////////////////*/ - function setMerkleRoot20(address _token, bytes32 _merkleRoot) external onlyOwner { + function setMerkleRoot(address _token, bytes32 _merkleRoot) external onlyOwner { merkleRoot[_token] = _merkleRoot; } @@ -483,16 +455,6 @@ contract Airdrop is EIP712, Initializable, Ownable { merkleRootETH = _merkleRoot; } - function setMerkleRoot721(address _token, bytes32 _merkleRoot) external onlyOwner { - tokenAddress721 = _token; - merkleRoot721[_token] = _merkleRoot; - } - - function setMerkleRoot1155(address _token, bytes32 _merkleRoot) external onlyOwner { - tokenAddress1155 = _token; - merkleRoot1155[_token] = _merkleRoot; - } - /*/////////////////////////////////////////////////////////////// Miscellaneous //////////////////////////////////////////////////////////////*/ diff --git a/package.json b/package.json index 34a5cdbda..adec1dd03 100644 --- a/package.json +++ b/package.json @@ -57,5 +57,8 @@ "gas": "forge snapshot --isolate --mc Benchmark --gas-report --diff .gas-snapshot > gasreport.txt", "forge:snapshot": "forge snapshot --check", "aabenchmark": "forge test --mc AABenchmarkPrepare && forge test --mc ProfileThirdwebAccount -vvv" + }, + "dependencies": { + "@thirdweb-dev/merkletree": "^0.2.1" } } diff --git a/src/test/benchmark/AirdropBenchmark.t.sol b/src/test/benchmark/AirdropBenchmark.t.sol index 5061500f7..07261822b 100644 --- a/src/test/benchmark/AirdropBenchmark.t.sol +++ b/src/test/benchmark/AirdropBenchmark.t.sol @@ -308,7 +308,7 @@ contract AirdropBenchmarkTest is BaseTest { // set merkle root vm.prank(signer); - airdrop.setMerkleRoot20(address(erc20), root); + airdrop.setMerkleRoot(address(erc20), root); // generate proof inputs[1] = "src/test/scripts/getProofAirdrop.ts"; @@ -456,7 +456,7 @@ contract AirdropBenchmarkTest is BaseTest { // set merkle root vm.prank(signer); - airdrop.setMerkleRoot721(address(erc721), root); + airdrop.setMerkleRoot(address(erc721), root); // generate proof inputs[1] = "src/test/scripts/getProofAirdrop.ts"; @@ -604,7 +604,7 @@ contract AirdropBenchmarkTest is BaseTest { // set merkle root vm.prank(signer); - airdrop.setMerkleRoot1155(address(erc1155), root); + airdrop.setMerkleRoot(address(erc1155), root); // generate proof inputs[1] = "src/test/scripts/getProofAirdrop.ts"; diff --git a/yarn.lock b/yarn.lock index 599a1533c..92d7be0c9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -486,6 +486,11 @@ "@jridgewell/resolve-uri" "^3.1.0" "@jridgewell/sourcemap-codec" "^1.4.14" +"@noble/hashes@^1.3.2": + version "1.4.0" + resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.4.0.tgz#45814aa329f30e4fe0ba49426f49dfccdd066426" + integrity sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg== + "@nodelib/fs.scandir@2.1.5": version "2.1.5" resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" @@ -534,11 +539,29 @@ resolved "https://registry.yarnpkg.com/@solidity-parser/parser/-/parser-0.17.0.tgz#52a2fcc97ff609f72011014e4c5b485ec52243ef" integrity sha512-Nko8R0/kUo391jsEHHxrGM07QFdnPGvlmox4rmH0kNiNAashItAilhy4Mv4pK5gQmW5f4sXAF58fwJbmlkGcVw== +"@thirdweb-dev/crypto@0.2.1": + version "0.2.1" + resolved "https://registry.yarnpkg.com/@thirdweb-dev/crypto/-/crypto-0.2.1.tgz#7643c91c9d87e4d51a77163b87f6bff547e9506c" + integrity sha512-SYEkdtdhTOAcgGklqPrKgyIftA2x0WBTtpAEyJBTLCL1z+2IKvExWZyZn3Mx2cZ8skO3iAfGzC4Si2ORWBcS2g== + dependencies: + "@noble/hashes" "^1.3.2" + js-sha3 "^0.9.2" + "@thirdweb-dev/dynamic-contracts@^1.2.4": version "1.2.5" resolved "https://registry.yarnpkg.com/@thirdweb-dev/dynamic-contracts/-/dynamic-contracts-1.2.5.tgz#f9735c0d46198e7bf2f98c277f0a9a79c54da1e8" integrity sha512-YVsz+jUWbwj+6aF2eTZGMfyw47a1HRmgNl4LQ3gW9gwYL5y5+OX/yOzv6aV5ibvoqCk/k10aIVK2eFrcpMubQA== +"@thirdweb-dev/merkletree@^0.2.1": + version "0.2.1" + resolved "https://registry.yarnpkg.com/@thirdweb-dev/merkletree/-/merkletree-0.2.1.tgz#1604e238a921fe520520e18b63312ca049376707" + integrity sha512-NQEo+KlwQFWr0z4+OlD5WJ9GZEFOrVufvjG2zcn2eylFZacJq5GvRz04Yan9eMR844M7LNx5godA5B7DAinqKg== + dependencies: + "@thirdweb-dev/crypto" "0.2.1" + buffer "^6.0.3" + buffer-reverse "^1.0.1" + treeify "^1.1.0" + "@tsconfig/node10@^1.0.7": version "1.0.9" resolved "https://registry.yarnpkg.com/@tsconfig/node10/-/node10-1.0.9.tgz#df4907fc07a886922637b15e02d4cebc4c0021b2" @@ -894,6 +917,11 @@ browser-stdout@1.3.1: resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.1.tgz#baa559ee14ced73452229bad7326467c61fabd60" integrity sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw== +buffer-reverse@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/buffer-reverse/-/buffer-reverse-1.0.1.tgz#49283c8efa6f901bc01fa3304d06027971ae2f60" + integrity sha512-M87YIUBsZ6N924W57vDwT/aOu8hw7ZgdByz6ijksLjmHJELBASmYTTlNHRgjE+pTsT9oJXGaDSgqqwfdHotDUg== + buffer@^6.0.3: version "6.0.3" resolved "https://registry.yarnpkg.com/buffer/-/buffer-6.0.3.tgz#2ace578459cc8fbe2a70aaa8f52ee63b6a74c6c6" @@ -1845,6 +1873,11 @@ js-sha3@0.8.0, js-sha3@^0.8.0: resolved "https://registry.yarnpkg.com/js-sha3/-/js-sha3-0.8.0.tgz#b9b7a5da73afad7dedd0f8c463954cbde6818840" integrity sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q== +js-sha3@^0.9.2: + version "0.9.3" + resolved "https://registry.yarnpkg.com/js-sha3/-/js-sha3-0.9.3.tgz#f0209432b23a66a0f6c7af592c26802291a75c2a" + integrity sha512-BcJPCQeLg6WjEx3FE591wVAevlli8lxsxm9/FzV4HXkV49TmBH38Yvrpce6fjbADGMKFrBMGTqrVz3qPIZ88Gg== + js-tokens@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" @@ -2634,6 +2667,11 @@ tree-kill@^1.2.2: resolved "https://registry.yarnpkg.com/tree-kill/-/tree-kill-1.2.2.tgz#4ca09a9092c88b73a7cdc5e8a01b507b0790a0cc" integrity sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A== +treeify@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/treeify/-/treeify-1.1.0.tgz#4e31c6a463accd0943879f30667c4fdaff411bb8" + integrity sha512-1m4RA7xVAJrSGrrXGs0L3YTwyvBs2S8PbRHaLZAkFw7JR8oIFwYtysxlBZhYIa7xSyiYJKZ3iGrrk55cGA3i9A== + ts-command-line-args@^2.2.0: version "2.5.1" resolved "https://registry.yarnpkg.com/ts-command-line-args/-/ts-command-line-args-2.5.1.tgz#e64456b580d1d4f6d948824c274cf6fa5f45f7f0" From 556e78f0082d98e4c2b3641e956ff7a1c6491e45 Mon Sep 17 00:00:00 2001 From: Yash Date: Thu, 21 Mar 2024 06:22:07 +0530 Subject: [PATCH 06/30] remove failsafe and refund from eth airdrop --- .../prebuilts/unaudited/airdrop/Airdrop.sol | 21 ++----------------- 1 file changed, 2 insertions(+), 19 deletions(-) diff --git a/contracts/prebuilts/unaudited/airdrop/Airdrop.sol b/contracts/prebuilts/unaudited/airdrop/Airdrop.sol index 15ee56447..6fca75786 100644 --- a/contracts/prebuilts/unaudited/airdrop/Airdrop.sol +++ b/contracts/prebuilts/unaudited/airdrop/Airdrop.sol @@ -144,14 +144,13 @@ contract Airdrop is EIP712, Initializable, Ownable { uint256 len = _contents.length; uint256 nativeTokenAmount; - uint256 refundAmount; for (uint256 i = 0; i < len; ) { nativeTokenAmount += _contents[i].amount; (bool success, ) = _contents[i].recipient.call{ value: _contents[i].amount }(""); if (!success) { - refundAmount += _contents[i].amount; + revert AirdropFailed(); } unchecked { @@ -162,13 +161,6 @@ contract Airdrop is EIP712, Initializable, Ownable { if (nativeTokenAmount != msg.value) { revert AirdropValueMismatch(); } - - if (refundAmount > 0) { - // refund failed payments' amount to sender address - // solhint-disable avoid-low-level-calls - // slither-disable-next-line low-level-calls - (bool refundSuccess, ) = msg.sender.call{ value: refundAmount }(""); - } } function airdrop721(address _tokenAddress, AirdropContent721[] calldata _contents) external { @@ -251,11 +243,9 @@ contract Airdrop is EIP712, Initializable, Ownable { revert AirdropVerificationFailed(); } - address _from = owner(); uint256 len = req.contents.length; uint256 nativeTokenAmount; - uint256 refundAmount; for (uint256 i = 0; i < len; ) { nativeTokenAmount += req.contents[i].amount; @@ -267,7 +257,7 @@ contract Airdrop is EIP712, Initializable, Ownable { (bool success, ) = req.contents[i].recipient.call{ value: req.contents[i].amount }(""); if (!success) { - refundAmount += req.contents[i].amount; + revert AirdropFailed(); } unchecked { @@ -278,13 +268,6 @@ contract Airdrop is EIP712, Initializable, Ownable { if (nativeTokenAmount != msg.value) { revert AirdropValueMismatch(); } - - if (refundAmount > 0) { - // refund failed payments' amount to sender address - // solhint-disable avoid-low-level-calls - // slither-disable-next-line low-level-calls - (bool refundSuccess, ) = _from.call{ value: refundAmount }(""); - } } function airdrop721WithSignature(AirdropRequest721 calldata req, bytes calldata signature) external { From 65dd7cf4b69454805e1cf5f1e87677e446e1d011 Mon Sep 17 00:00:00 2001 From: Yash Date: Thu, 21 Mar 2024 06:29:18 +0530 Subject: [PATCH 07/30] reorg --- .../prebuilts/unaudited/airdrop/Airdrop.sol | 85 ++++++++----------- 1 file changed, 35 insertions(+), 50 deletions(-) diff --git a/contracts/prebuilts/unaudited/airdrop/Airdrop.sol b/contracts/prebuilts/unaudited/airdrop/Airdrop.sol index 6fca75786..897df67a1 100644 --- a/contracts/prebuilts/unaudited/airdrop/Airdrop.sol +++ b/contracts/prebuilts/unaudited/airdrop/Airdrop.sol @@ -127,34 +127,31 @@ contract Airdrop is EIP712, Initializable, Ownable { Airdrop Push //////////////////////////////////////////////////////////////*/ - function airdrop20(address _tokenAddress, AirdropContent20[] calldata _contents) external { + function airdrop20(address _tokenAddress, AirdropContent20[] calldata _contents) external payable { address _from = msg.sender; uint256 len = _contents.length; - - for (uint256 i = 0; i < len; ) { - CurrencyTransferLib.transferCurrency(_tokenAddress, _from, _contents[i].recipient, _contents[i].amount); - - unchecked { - i += 1; - } - } - } - - function airdropNativeToken(AirdropContent20[] calldata _contents) external payable { - uint256 len = _contents.length; - uint256 nativeTokenAmount; - for (uint256 i = 0; i < len; ) { - nativeTokenAmount += _contents[i].amount; + if (_tokenAddress == CurrencyTransferLib.NATIVE_TOKEN) { + for (uint256 i = 0; i < len; ) { + nativeTokenAmount += _contents[i].amount; - (bool success, ) = _contents[i].recipient.call{ value: _contents[i].amount }(""); - if (!success) { - revert AirdropFailed(); + (bool success, ) = _contents[i].recipient.call{ value: _contents[i].amount }(""); + if (!success) { + revert AirdropFailed(); + } + + unchecked { + i += 1; + } } + } else { + for (uint256 i = 0; i < len; ) { + CurrencyTransferLib.transferCurrency(_tokenAddress, _from, _contents[i].recipient, _contents[i].amount); - unchecked { - i += 1; + unchecked { + i += 1; + } } } @@ -346,32 +343,12 @@ contract Airdrop is EIP712, Initializable, Ownable { claimed[claimHash] = true; - CurrencyTransferLib.transferCurrency(_token, owner(), _receiver, _quantity); - } - - function _getClaimHashERC20(address _sender, address _token) private view returns (bytes32) { - return keccak256(abi.encodePacked(_sender, _token)); - } - - function _getClaimHashERC721(address _sender, address _token) private view returns (bytes32) { - return keccak256(abi.encodePacked(_sender, _token)); - } - - function _getClaimHashERC1155(address _sender, address _token, uint256 _tokenId) private view returns (bytes32) { - return keccak256(abi.encodePacked(_sender, _token, _tokenId)); - } - - function claimETH(address _receiver, uint256 _quantity, bytes32[] calldata _proofs) external { - bool valid = MerkleProofLib.verify(_proofs, merkleRootETH, keccak256(abi.encodePacked(msg.sender, _quantity))); - - if (!valid) { - revert AirdropInvalidProof(); + if (_token == CurrencyTransferLib.NATIVE_TOKEN) { + (bool success, ) = _receiver.call{ value: _quantity }(""); + if (!success) revert AirdropFailed(); + } else { + CurrencyTransferLib.transferCurrency(_token, owner(), _receiver, _quantity); } - - claimedETH[msg.sender] = true; - - (bool success, ) = _receiver.call{ value: _quantity }(""); - if (!success) revert AirdropFailed(); } function claim721(address _token, address _receiver, uint256 _tokenId, bytes32[] calldata _proofs) external { @@ -434,10 +411,6 @@ contract Airdrop is EIP712, Initializable, Ownable { merkleRoot[_token] = _merkleRoot; } - function setMerkleRootETH(bytes32 _merkleRoot) external onlyOwner { - merkleRootETH = _merkleRoot; - } - /*/////////////////////////////////////////////////////////////// Miscellaneous //////////////////////////////////////////////////////////////*/ @@ -451,6 +424,18 @@ contract Airdrop is EIP712, Initializable, Ownable { version = "1"; } + function _getClaimHashERC20(address _sender, address _token) private view returns (bytes32) { + return keccak256(abi.encodePacked(_sender, _token)); + } + + function _getClaimHashERC721(address _sender, address _token) private view returns (bytes32) { + return keccak256(abi.encodePacked(_sender, _token)); + } + + function _getClaimHashERC1155(address _sender, address _token, uint256 _tokenId) private view returns (bytes32) { + return keccak256(abi.encodePacked(_sender, _token, _tokenId)); + } + function _hashContentInfo20(AirdropContent20[] calldata contents) private pure returns (bytes32) { bytes32[] memory contentHashes = new bytes32[](contents.length); for (uint256 i = 0; i < contents.length; i++) { From 14553e2cb7894971bb6c477ffa13017a764fc4ef Mon Sep 17 00:00:00 2001 From: Yash Date: Thu, 21 Mar 2024 06:34:22 +0530 Subject: [PATCH 08/30] no sig airdrop for eth --- .../prebuilts/unaudited/airdrop/Airdrop.sol | 45 +------------------ 1 file changed, 2 insertions(+), 43 deletions(-) diff --git a/contracts/prebuilts/unaudited/airdrop/Airdrop.sol b/contracts/prebuilts/unaudited/airdrop/Airdrop.sol index 897df67a1..3258514c0 100644 --- a/contracts/prebuilts/unaudited/airdrop/Airdrop.sol +++ b/contracts/prebuilts/unaudited/airdrop/Airdrop.sol @@ -208,9 +208,10 @@ contract Airdrop is EIP712, Initializable, Ownable { revert AirdropVerificationFailed(); } - address _from = owner(); uint256 len = req.contents.length; + address _from = owner(); + for (uint256 i = 0; i < len; ) { CurrencyTransferLib.transferCurrency( req.tokenAddress, @@ -225,48 +226,6 @@ contract Airdrop is EIP712, Initializable, Ownable { } } - function airdropNativeTokenWithSignature(AirdropRequest20 calldata req, bytes calldata signature) external payable { - // verify expiration timestamp - if (req.expirationTimestamp < block.timestamp) { - revert AirdropRequestExpired(req.expirationTimestamp); - } - - if (req.tokenAddress != address(0)) { - revert AirdropInvalidTokenAddress(); - } - - // verify data - if (!_verifyReqERC20(req, signature)) { - revert AirdropVerificationFailed(); - } - - uint256 len = req.contents.length; - - uint256 nativeTokenAmount; - - for (uint256 i = 0; i < len; ) { - nativeTokenAmount += req.contents[i].amount; - - if (nativeTokenAmount > msg.value) { - revert AirdropValueMismatch(); - } - - (bool success, ) = req.contents[i].recipient.call{ value: req.contents[i].amount }(""); - - if (!success) { - revert AirdropFailed(); - } - - unchecked { - i += 1; - } - } - - if (nativeTokenAmount != msg.value) { - revert AirdropValueMismatch(); - } - } - function airdrop721WithSignature(AirdropRequest721 calldata req, bytes calldata signature) external { // verify expiration timestamp if (req.expirationTimestamp < block.timestamp) { From 0b51a7f3c1a9c1bc6ab71159775f8b5eb143c65b Mon Sep 17 00:00:00 2001 From: Yash Date: Thu, 21 Mar 2024 06:54:03 +0530 Subject: [PATCH 09/30] claim condition id and reset --- .../prebuilts/unaudited/airdrop/Airdrop.sol | 34 ++++++++++++------- src/test/benchmark/AirdropBenchmark.t.sol | 6 ++-- 2 files changed, 24 insertions(+), 16 deletions(-) diff --git a/contracts/prebuilts/unaudited/airdrop/Airdrop.sol b/contracts/prebuilts/unaudited/airdrop/Airdrop.sol index 3258514c0..6dc3b6703 100644 --- a/contracts/prebuilts/unaudited/airdrop/Airdrop.sol +++ b/contracts/prebuilts/unaudited/airdrop/Airdrop.sol @@ -31,13 +31,12 @@ contract Airdrop is EIP712, Initializable, Ownable { State, constants & structs //////////////////////////////////////////////////////////////*/ - bytes32 public merkleRootETH; - mapping(address => bool) public claimedETH; - - // token contract address => merkle root + /// @dev token contract address => conditionId + mapping(address => bytes32) public conditionIdForToken; + /// @dev token contract address => merkle root mapping(address => bytes32) public merkleRoot; - // hash(claimer address || token address || token id [1155]) => has claimed - mapping(bytes32 => bool) private claimed; + /// @dev conditionId => hash(claimer address, token address, token id [1155]) => has claimed + mapping(bytes32 => mapping(bytes32 => bool)) private claimed; /// @dev Mapping from request UID => whether the request is processed. mapping(bytes32 => bool) private processed; @@ -284,7 +283,9 @@ contract Airdrop is EIP712, Initializable, Ownable { function claim20(address _token, address _receiver, uint256 _quantity, bytes32[] calldata _proofs) external { bytes32 claimHash = _getClaimHashERC20(msg.sender, _token); - if (claimed[claimHash]) { + bytes32 conditionId = conditionIdForToken[_token]; + + if (claimed[conditionId][claimHash]) { revert AirdropAlreadyClaimed(); } @@ -300,7 +301,7 @@ contract Airdrop is EIP712, Initializable, Ownable { revert AirdropInvalidProof(); } - claimed[claimHash] = true; + claimed[conditionId][claimHash] = true; if (_token == CurrencyTransferLib.NATIVE_TOKEN) { (bool success, ) = _receiver.call{ value: _quantity }(""); @@ -312,7 +313,9 @@ contract Airdrop is EIP712, Initializable, Ownable { function claim721(address _token, address _receiver, uint256 _tokenId, bytes32[] calldata _proofs) external { bytes32 claimHash = _getClaimHashERC721(msg.sender, _token); - if (claimed[claimHash]) { + bytes32 conditionId = conditionIdForToken[_token]; + + if (claimed[conditionId][claimHash]) { revert AirdropAlreadyClaimed(); } @@ -328,7 +331,7 @@ contract Airdrop is EIP712, Initializable, Ownable { revert AirdropInvalidProof(); } - claimed[claimHash] = true; + claimed[conditionId][claimHash] = true; IERC721(_token).safeTransferFrom(owner(), _receiver, _tokenId); } @@ -341,7 +344,9 @@ contract Airdrop is EIP712, Initializable, Ownable { bytes32[] calldata _proofs ) external { bytes32 claimHash = _getClaimHashERC1155(msg.sender, _token, _tokenId); - if (claimed[claimHash]) { + bytes32 conditionId = conditionIdForToken[_token]; + + if (claimed[conditionId][claimHash]) { revert AirdropAlreadyClaimed(); } @@ -357,7 +362,7 @@ contract Airdrop is EIP712, Initializable, Ownable { revert AirdropInvalidProof(); } - claimed[claimHash] = true; + claimed[conditionId][claimHash] = true; IERC1155(_token).safeTransferFrom(owner(), _receiver, _tokenId, _quantity, ""); } @@ -366,7 +371,10 @@ contract Airdrop is EIP712, Initializable, Ownable { Setter functions //////////////////////////////////////////////////////////////*/ - function setMerkleRoot(address _token, bytes32 _merkleRoot) external onlyOwner { + function setMerkleRoot(address _token, bytes32 _merkleRoot, bool _resetClaimStatus) external onlyOwner { + if (_resetClaimStatus || conditionIdForToken[_token] == bytes32(0)) { + conditionIdForToken[_token] = keccak256(abi.encodePacked(_token, block.number)); + } merkleRoot[_token] = _merkleRoot; } diff --git a/src/test/benchmark/AirdropBenchmark.t.sol b/src/test/benchmark/AirdropBenchmark.t.sol index 07261822b..af1b40285 100644 --- a/src/test/benchmark/AirdropBenchmark.t.sol +++ b/src/test/benchmark/AirdropBenchmark.t.sol @@ -308,7 +308,7 @@ contract AirdropBenchmarkTest is BaseTest { // set merkle root vm.prank(signer); - airdrop.setMerkleRoot(address(erc20), root); + airdrop.setMerkleRoot(address(erc20), root, true); // generate proof inputs[1] = "src/test/scripts/getProofAirdrop.ts"; @@ -456,7 +456,7 @@ contract AirdropBenchmarkTest is BaseTest { // set merkle root vm.prank(signer); - airdrop.setMerkleRoot(address(erc721), root); + airdrop.setMerkleRoot(address(erc721), root, true); // generate proof inputs[1] = "src/test/scripts/getProofAirdrop.ts"; @@ -604,7 +604,7 @@ contract AirdropBenchmarkTest is BaseTest { // set merkle root vm.prank(signer); - airdrop.setMerkleRoot(address(erc1155), root); + airdrop.setMerkleRoot(address(erc1155), root, true); // generate proof inputs[1] = "src/test/scripts/getProofAirdrop.ts"; From bfbb38519491baa9268ddafef028b20a00ee703d Mon Sep 17 00:00:00 2001 From: Yash Date: Thu, 21 Mar 2024 11:51:12 +0530 Subject: [PATCH 10/30] cleanup --- .../prebuilts/unaudited/airdrop/Airdrop.sol | 42 +---- gasreport.txt | 170 +++++++++--------- 2 files changed, 92 insertions(+), 120 deletions(-) diff --git a/contracts/prebuilts/unaudited/airdrop/Airdrop.sol b/contracts/prebuilts/unaudited/airdrop/Airdrop.sol index 6dc3b6703..76bdc54ca 100644 --- a/contracts/prebuilts/unaudited/airdrop/Airdrop.sol +++ b/contracts/prebuilts/unaudited/airdrop/Airdrop.sol @@ -132,25 +132,17 @@ contract Airdrop is EIP712, Initializable, Ownable { uint256 nativeTokenAmount; if (_tokenAddress == CurrencyTransferLib.NATIVE_TOKEN) { - for (uint256 i = 0; i < len; ) { + for (uint256 i = 0; i < len; i++) { nativeTokenAmount += _contents[i].amount; (bool success, ) = _contents[i].recipient.call{ value: _contents[i].amount }(""); if (!success) { revert AirdropFailed(); } - - unchecked { - i += 1; - } } } else { - for (uint256 i = 0; i < len; ) { + for (uint256 i = 0; i < len; i++) { CurrencyTransferLib.transferCurrency(_tokenAddress, _from, _contents[i].recipient, _contents[i].amount); - - unchecked { - i += 1; - } } } @@ -163,12 +155,8 @@ contract Airdrop is EIP712, Initializable, Ownable { address _from = msg.sender; uint256 len = _contents.length; - for (uint256 i = 0; i < len; ) { + for (uint256 i = 0; i < len; i++) { IERC721(_tokenAddress).safeTransferFrom(_from, _contents[i].recipient, _contents[i].tokenId); - - unchecked { - i += 1; - } } } @@ -177,7 +165,7 @@ contract Airdrop is EIP712, Initializable, Ownable { uint256 len = _contents.length; - for (uint256 i = 0; i < len; ) { + for (uint256 i = 0; i < len; i++) { IERC1155(_tokenAddress).safeTransferFrom( _from, _contents[i].recipient, @@ -185,10 +173,6 @@ contract Airdrop is EIP712, Initializable, Ownable { _contents[i].amount, "" ); - - unchecked { - i += 1; - } } } @@ -211,17 +195,13 @@ contract Airdrop is EIP712, Initializable, Ownable { address _from = owner(); - for (uint256 i = 0; i < len; ) { + for (uint256 i = 0; i < len; i++) { CurrencyTransferLib.transferCurrency( req.tokenAddress, _from, req.contents[i].recipient, req.contents[i].amount ); - - unchecked { - i += 1; - } } } @@ -239,12 +219,8 @@ contract Airdrop is EIP712, Initializable, Ownable { address _from = owner(); uint256 len = req.contents.length; - for (uint256 i = 0; i < len; ) { + for (uint256 i = 0; i < len; i++) { IERC721(req.tokenAddress).safeTransferFrom(_from, req.contents[i].recipient, req.contents[i].tokenId); - - unchecked { - i += 1; - } } } @@ -262,7 +238,7 @@ contract Airdrop is EIP712, Initializable, Ownable { address _from = owner(); uint256 len = req.contents.length; - for (uint256 i = 0; i < len; ) { + for (uint256 i = 0; i < len; i++) { IERC1155(req.tokenAddress).safeTransferFrom( _from, req.contents[i].recipient, @@ -270,10 +246,6 @@ contract Airdrop is EIP712, Initializable, Ownable { req.contents[i].amount, "" ); - - unchecked { - i += 1; - } } } diff --git a/gasreport.txt b/gasreport.txt index 149430dfc..16642e3cb 100644 --- a/gasreport.txt +++ b/gasreport.txt @@ -1,12 +1,42 @@ No files changed, compilation skipped +Ran 3 tests for src/test/benchmark/EditionStakeBenchmark.t.sol:EditionStakeBenchmarkTest +[PASS] test_benchmark_editionStake_claimRewards() (gas: 98765) +[PASS] test_benchmark_editionStake_stake() (gas: 203676) +[PASS] test_benchmark_editionStake_withdraw() (gas: 94296) +Suite result: ok. 3 passed; 0 failed; 0 skipped; finished in 652.02ms (715.83µs CPU time) + +Ran 3 tests for src/test/benchmark/PackBenchmark.t.sol:PackBenchmarkTest +[PASS] test_benchmark_pack_addPackContents() (gas: 312595) +[PASS] test_benchmark_pack_createPack() (gas: 1419379) +[PASS] test_benchmark_pack_openPack() (gas: 306658) +Suite result: ok. 3 passed; 0 failed; 0 skipped; finished in 660.31ms (3.57ms CPU time) + Ran 5 tests for src/test/benchmark/SignatureDropBenchmark.t.sol:SignatureDropBenchmarkTest [PASS] test_benchmark_signatureDrop_claim_five_tokens() (gas: 185688) [PASS] test_benchmark_signatureDrop_lazyMint() (gas: 147153) [PASS] test_benchmark_signatureDrop_lazyMint_for_delayed_reveal() (gas: 249057) [PASS] test_benchmark_signatureDrop_reveal() (gas: 49802) [PASS] test_benchmark_signatureDrop_setClaimConditions() (gas: 100719) -Suite result: ok. 5 passed; 0 failed; 0 skipped; finished in 368.34ms (798.50µs CPU time) +Suite result: ok. 5 passed; 0 failed; 0 skipped; finished in 667.52ms (808.25µs CPU time) + +Ran 3 tests for src/test/benchmark/NFTStakeBenchmark.t.sol:NFTStakeBenchmarkTest +[PASS] test_benchmark_nftStake_claimRewards() (gas: 99831) +[PASS] test_benchmark_nftStake_stake_five_tokens() (gas: 553577) +[PASS] test_benchmark_nftStake_withdraw() (gas: 96144) +Suite result: ok. 3 passed; 0 failed; 0 skipped; finished in 670.59ms (846.13µs CPU time) + +Ran 1 test for src/test/smart-wallet/utils/AABenchmarkPrepare.sol:AABenchmarkPrepare +[PASS] test_prepareBenchmarkFile() (gas: 2955770) +Suite result: ok. 1 passed; 0 failed; 0 skipped; finished in 672.41ms (20.88ms CPU time) + +Ran 1 test for src/test/benchmark/AirdropERC20Benchmark.t.sol:AirdropERC20BenchmarkTest +[PASS] test_benchmark_airdropERC20_airdrop() (gas: 32443785) +Suite result: ok. 1 passed; 0 failed; 0 skipped; finished in 676.87ms (15.63ms CPU time) + +Ran 1 test for src/test/benchmark/AirdropERC721Benchmark.t.sol:AirdropERC721BenchmarkTest +[PASS] test_benchmark_airdropERC721_airdrop() (gas: 42241588) +Suite result: ok. 1 passed; 0 failed; 0 skipped; finished in 685.01ms (16.22ms CPU time) Ran 14 tests for src/test/benchmark/AccountBenchmark.t.sol:AccountBenchmarkTest [PASS] test_state_accountReceivesNativeTokens() (gas: 34537) @@ -23,113 +53,83 @@ Ran 14 tests for src/test/benchmark/AccountBenchmark.t.sol:AccountBenchmarkTest [PASS] test_state_receiveERC1155NFT() (gas: 66043) [PASS] test_state_receiveERC721NFT() (gas: 100196) [PASS] test_state_transferOutsNativeTokens() (gas: 133673) -Suite result: ok. 14 passed; 0 failed; 0 skipped; finished in 393.82ms (23.99ms CPU time) - -Ran 1 test for src/test/benchmark/AirdropERC721Benchmark.t.sol:AirdropERC721BenchmarkTest -[PASS] test_benchmark_airdropERC721_airdrop() (gas: 42241588) -Suite result: ok. 1 passed; 0 failed; 0 skipped; finished in 417.61ms (15.88ms CPU time) - -Ran 3 tests for src/test/benchmark/EditionStakeBenchmark.t.sol:EditionStakeBenchmarkTest -[PASS] test_benchmark_editionStake_claimRewards() (gas: 98765) -[PASS] test_benchmark_editionStake_stake() (gas: 203676) -[PASS] test_benchmark_editionStake_withdraw() (gas: 94296) -Suite result: ok. 3 passed; 0 failed; 0 skipped; finished in 419.06ms (660.96µs CPU time) - -Ran 1 test for src/test/smart-wallet/utils/AABenchmarkPrepare.sol:AABenchmarkPrepare -[PASS] test_prepareBenchmarkFile() (gas: 2955770) -Suite result: ok. 1 passed; 0 failed; 0 skipped; finished in 420.21ms (13.23ms CPU time) - -Ran 1 test for src/test/benchmark/AirdropERC20Benchmark.t.sol:AirdropERC20BenchmarkTest -[PASS] test_benchmark_airdropERC20_airdrop() (gas: 32443785) -Suite result: ok. 1 passed; 0 failed; 0 skipped; finished in 425.50ms (15.60ms CPU time) - -Ran 3 tests for src/test/benchmark/NFTStakeBenchmark.t.sol:NFTStakeBenchmarkTest -[PASS] test_benchmark_nftStake_claimRewards() (gas: 99831) -[PASS] test_benchmark_nftStake_stake_five_tokens() (gas: 553577) -[PASS] test_benchmark_nftStake_withdraw() (gas: 96144) -Suite result: ok. 3 passed; 0 failed; 0 skipped; finished in 450.72ms (858.67µs CPU time) - -Ran 4 tests for src/test/benchmark/TokenERC721Benchmark.t.sol:TokenERC721BenchmarkTest -[PASS] test_benchmark_tokenERC721_burn() (gas: 40392) -[PASS] test_benchmark_tokenERC721_mintTo() (gas: 172834) -[PASS] test_benchmark_tokenERC721_mintWithSignature_pay_with_ERC20() (gas: 301844) -[PASS] test_benchmark_tokenERC721_mintWithSignature_pay_with_native_token() (gas: 308814) -Suite result: ok. 4 passed; 0 failed; 0 skipped; finished in 178.08ms (1.53ms CPU time) +Suite result: ok. 14 passed; 0 failed; 0 skipped; finished in 738.85ms (21.33ms CPU time) Ran 2 tests for src/test/benchmark/MultiwrapBenchmark.t.sol:MultiwrapBenchmarkTest [PASS] test_benchmark_multiwrap_unwrap() (gas: 152040) [PASS] test_benchmark_multiwrap_wrap() (gas: 480722) -Suite result: ok. 2 passed; 0 failed; 0 skipped; finished in 188.11ms (726.04µs CPU time) +Suite result: ok. 2 passed; 0 failed; 0 skipped; finished in 222.28ms (685.96µs CPU time) -Ran 3 tests for src/test/benchmark/PackBenchmark.t.sol:PackBenchmarkTest -[PASS] test_benchmark_pack_addPackContents() (gas: 312595) -[PASS] test_benchmark_pack_createPack() (gas: 1419379) -[PASS] test_benchmark_pack_openPack() (gas: 306658) -Suite result: ok. 3 passed; 0 failed; 0 skipped; finished in 193.93ms (2.61ms CPU time) - -Ran 3 tests for src/test/benchmark/TokenERC20Benchmark.t.sol:TokenERC20BenchmarkTest -[PASS] test_benchmark_tokenERC20_mintTo() (gas: 139513) -[PASS] test_benchmark_tokenERC20_mintWithSignature_pay_with_ERC20() (gas: 221724) -[PASS] test_benchmark_tokenERC20_mintWithSignature_pay_with_native_token() (gas: 228786) -Suite result: ok. 3 passed; 0 failed; 0 skipped; finished in 221.96ms (1.41ms CPU time) +Ran 3 tests for src/test/benchmark/PackVRFDirectBenchmark.t.sol:PackVRFDirectBenchmarkTest +[PASS] test_benchmark_packvrf_createPack() (gas: 1392387) +[PASS] test_benchmark_packvrf_openPack() (gas: 150677) +[PASS] test_benchmark_packvrf_openPackAndClaimRewards() (gas: 3621) +Suite result: ok. 3 passed; 0 failed; 0 skipped; finished in 217.48ms (1.99ms CPU time) Ran 4 tests for src/test/benchmark/TokenERC1155Benchmark.t.sol:TokenERC1155BenchmarkTest [PASS] test_benchmark_tokenERC1155_burn() (gas: 30352) [PASS] test_benchmark_tokenERC1155_mintTo() (gas: 144229) [PASS] test_benchmark_tokenERC1155_mintWithSignature_pay_with_ERC20() (gas: 307291) [PASS] test_benchmark_tokenERC1155_mintWithSignature_pay_with_native_token() (gas: 318712) -Suite result: ok. 4 passed; 0 failed; 0 skipped; finished in 247.98ms (1.60ms CPU time) +Suite result: ok. 4 passed; 0 failed; 0 skipped; finished in 229.46ms (1.60ms CPU time) + +Ran 3 tests for src/test/benchmark/TokenERC20Benchmark.t.sol:TokenERC20BenchmarkTest +[PASS] test_benchmark_tokenERC20_mintTo() (gas: 139513) +[PASS] test_benchmark_tokenERC20_mintWithSignature_pay_with_ERC20() (gas: 221724) +[PASS] test_benchmark_tokenERC20_mintWithSignature_pay_with_native_token() (gas: 228786) +Suite result: ok. 3 passed; 0 failed; 0 skipped; finished in 229.79ms (1.31ms CPU time) Ran 1 test for src/test/benchmark/AirdropERC1155Benchmark.t.sol:AirdropERC1155BenchmarkTest [PASS] test_benchmark_airdropERC1155_airdrop() (gas: 38536544) -Suite result: ok. 1 passed; 0 failed; 0 skipped; finished in 220.05ms (26.46ms CPU time) - -Ran 3 tests for src/test/benchmark/DropERC1155Benchmark.t.sol:DropERC1155BenchmarkTest -[PASS] test_benchmark_dropERC1155_claim() (gas: 245552) -[PASS] test_benchmark_dropERC1155_lazyMint() (gas: 146425) -[PASS] test_benchmark_dropERC1155_setClaimConditions_five_conditions() (gas: 525725) -Suite result: ok. 3 passed; 0 failed; 0 skipped; finished in 828.71ms (822.94ms CPU time) - -Ran 3 tests for src/test/benchmark/PackVRFDirectBenchmark.t.sol:PackVRFDirectBenchmarkTest -[PASS] test_benchmark_packvrf_createPack() (gas: 1392387) -[PASS] test_benchmark_packvrf_openPack() (gas: 150677) -[PASS] test_benchmark_packvrf_openPackAndClaimRewards() (gas: 3621) -Suite result: ok. 3 passed; 0 failed; 0 skipped; finished in 217.00ms (2.23ms CPU time) +Suite result: ok. 1 passed; 0 failed; 0 skipped; finished in 262.58ms (18.95ms CPU time) Ran 3 tests for src/test/benchmark/TokenStakeBenchmark.t.sol:TokenStakeBenchmarkTest [PASS] test_benchmark_tokenStake_claimRewards() (gas: 101098) [PASS] test_benchmark_tokenStake_stake() (gas: 195556) [PASS] test_benchmark_tokenStake_withdraw() (gas: 104792) -Suite result: ok. 3 passed; 0 failed; 0 skipped; finished in 234.37ms (634.83µs CPU time) +Suite result: ok. 3 passed; 0 failed; 0 skipped; finished in 205.37ms (599.46µs CPU time) + +Ran 4 tests for src/test/benchmark/TokenERC721Benchmark.t.sol:TokenERC721BenchmarkTest +[PASS] test_benchmark_tokenERC721_burn() (gas: 40392) +[PASS] test_benchmark_tokenERC721_mintTo() (gas: 172834) +[PASS] test_benchmark_tokenERC721_mintWithSignature_pay_with_ERC20() (gas: 301844) +[PASS] test_benchmark_tokenERC721_mintWithSignature_pay_with_native_token() (gas: 308814) +Suite result: ok. 4 passed; 0 failed; 0 skipped; finished in 303.02ms (1.56ms CPU time) Ran 21 tests for src/test/benchmark/AirdropBenchmark.t.sol:AirdropBenchmarkTest -[PASS] test_benchmark_airdropClaim_erc1155() (gas: 103438) -[PASS] test_benchmark_airdropClaim_erc20() (gas: 108822) -[PASS] test_benchmark_airdropClaim_erc721() (gas: 107287) -[PASS] test_benchmark_airdropPush_erc1155_10() (gas: 367151) -[PASS] test_benchmark_airdropPush_erc1155_100() (gas: 3263016) -[PASS] test_benchmark_airdropPush_erc1155_1000() (gas: 32342317) -[PASS] test_benchmark_airdropPush_erc20_10() (gas: 358522) -[PASS] test_benchmark_airdropPush_erc20_100() (gas: 3134977) -[PASS] test_benchmark_airdropPush_erc20_1000() (gas: 31084435) -[PASS] test_benchmark_airdropPush_erc721_10() (gas: 423587) -[PASS] test_benchmark_airdropPush_erc721_100() (gas: 3833981) -[PASS] test_benchmark_airdropPush_erc721_1000() (gas: 38101966) -[PASS] test_benchmark_airdropSignature_erc115_10() (gas: 395262) -[PASS] test_benchmark_airdropSignature_erc115_100() (gas: 3436291) -[PASS] test_benchmark_airdropSignature_erc115_1000() (gas: 34308834) -[PASS] test_benchmark_airdropSignature_erc20_10() (gas: 384336) -[PASS] test_benchmark_airdropSignature_erc20_100() (gas: 3281632) -[PASS] test_benchmark_airdropSignature_erc20_1000() (gas: 32840926) -[PASS] test_benchmark_airdropSignature_erc721_10() (gas: 448563) -[PASS] test_benchmark_airdropSignature_erc721_100() (gas: 3987657) -[PASS] test_benchmark_airdropSignature_erc721_1000() (gas: 39666524) -Suite result: ok. 21 passed; 0 failed; 0 skipped; finished in 1.00s (1.31s CPU time) +[PASS] test_benchmark_airdropClaim_erc1155() (gas: 103778) +[PASS] test_benchmark_airdropClaim_erc20() (gas: 109548) +[PASS] test_benchmark_airdropClaim_erc721() (gas: 107657) +[PASS] test_benchmark_airdropPush_erc1155_10() (gas: 366949) +[PASS] test_benchmark_airdropPush_erc1155_100() (gas: 3263174) +[PASS] test_benchmark_airdropPush_erc1155_1000() (gas: 32346075) +[PASS] test_benchmark_airdropPush_erc20_10() (gas: 358772) +[PASS] test_benchmark_airdropPush_erc20_100() (gas: 3137837) +[PASS] test_benchmark_airdropPush_erc20_1000() (gas: 31113395) +[PASS] test_benchmark_airdropPush_erc721_10() (gas: 423341) +[PASS] test_benchmark_airdropPush_erc721_100() (gas: 3834095) +[PASS] test_benchmark_airdropPush_erc721_1000() (gas: 38105680) +[PASS] test_benchmark_airdropSignature_erc115_10() (gas: 395103) +[PASS] test_benchmark_airdropSignature_erc115_100() (gas: 3436492) +[PASS] test_benchmark_airdropSignature_erc115_1000() (gas: 34312635) +[PASS] test_benchmark_airdropSignature_erc20_10() (gas: 384317) +[PASS] test_benchmark_airdropSignature_erc20_100() (gas: 3284223) +[PASS] test_benchmark_airdropSignature_erc20_1000() (gas: 32869617) +[PASS] test_benchmark_airdropSignature_erc721_10() (gas: 448536) +[PASS] test_benchmark_airdropSignature_erc721_100() (gas: 3987990) +[PASS] test_benchmark_airdropSignature_erc721_1000() (gas: 39670457) +Suite result: ok. 21 passed; 0 failed; 0 skipped; finished in 1.30s (1.14s CPU time) Ran 2 tests for src/test/benchmark/DropERC20Benchmark.t.sol:DropERC20BenchmarkTest [PASS] test_benchmark_dropERC20_claim() (gas: 291508) [PASS] test_benchmark_dropERC20_setClaimConditions_five_conditions() (gas: 530026) -Suite result: ok. 2 passed; 0 failed; 0 skipped; finished in 1.08s (708.25ms CPU time) +Suite result: ok. 2 passed; 0 failed; 0 skipped; finished in 444.21ms (516.94ms CPU time) + +Ran 3 tests for src/test/benchmark/DropERC1155Benchmark.t.sol:DropERC1155BenchmarkTest +[PASS] test_benchmark_dropERC1155_claim() (gas: 245552) +[PASS] test_benchmark_dropERC1155_lazyMint() (gas: 146425) +[PASS] test_benchmark_dropERC1155_setClaimConditions_five_conditions() (gas: 525725) +Suite result: ok. 3 passed; 0 failed; 0 skipped; finished in 1.31s (677.77ms CPU time) Ran 5 tests for src/test/benchmark/DropERC721Benchmark.t.sol:DropERC721BenchmarkTest [PASS] test_benchmark_dropERC721_claim_five_tokens() (gas: 273303) @@ -137,10 +137,10 @@ Ran 5 tests for src/test/benchmark/DropERC721Benchmark.t.sol:DropERC721Benchmark [PASS] test_benchmark_dropERC721_lazyMint_for_delayed_reveal() (gas: 248985) [PASS] test_benchmark_dropERC721_reveal() (gas: 49433) [PASS] test_benchmark_dropERC721_setClaimConditions_five_conditions() (gas: 529470) -Suite result: ok. 5 passed; 0 failed; 0 skipped; finished in 474.66ms (495.93ms CPU time) +Suite result: ok. 5 passed; 0 failed; 0 skipped; finished in 429.81ms (520.49ms CPU time) -Ran 19 test suites in 1.22s (7.98s CPU time): 82 tests passed, 0 failed, 0 skipped (82 total tests) +Ran 19 test suites in 1.52s (10.57s CPU time): 82 tests passed, 0 failed, 0 skipped (82 total tests) test_benchmark_packvrf_openPackAndClaimRewards() (gas: 0 (0.000%)) test_benchmark_pack_createPack() (gas: 6511 (0.461%)) test_benchmark_airdropERC721_airdrop() (gas: 329052 (0.785%)) From ed78b5cdcddc15af11fd091bdb41c1e68c7297f9 Mon Sep 17 00:00:00 2001 From: Jake Loo <2171134+jakeloo@users.noreply.github.com> Date: Thu, 21 Mar 2024 19:24:14 +0000 Subject: [PATCH 11/30] prefix ERC --- .../prebuilts/unaudited/airdrop/Airdrop.sol | 107 ++++++++---------- 1 file changed, 50 insertions(+), 57 deletions(-) diff --git a/contracts/prebuilts/unaudited/airdrop/Airdrop.sol b/contracts/prebuilts/unaudited/airdrop/Airdrop.sol index 76bdc54ca..cd0e7500a 100644 --- a/contracts/prebuilts/unaudited/airdrop/Airdrop.sol +++ b/contracts/prebuilts/unaudited/airdrop/Airdrop.sol @@ -16,8 +16,8 @@ import "@solady/src/utils/MerkleProofLib.sol"; import "@solady/src/utils/ECDSA.sol"; import "@solady/src/utils/EIP712.sol"; -import { Initializable } from "../../../extension/Initializable.sol"; -import { Ownable } from "../../../extension/Ownable.sol"; +import {Initializable} from "../../../extension/Initializable.sol"; +import {Ownable} from "../../../extension/Ownable.sol"; import "../../../eip/interface/IERC721.sol"; import "../../../eip/interface/IERC1155.sol"; @@ -40,62 +40,59 @@ contract Airdrop is EIP712, Initializable, Ownable { /// @dev Mapping from request UID => whether the request is processed. mapping(bytes32 => bool) private processed; - struct AirdropContent20 { + struct AirdropContentERC20 { address recipient; uint256 amount; } - struct AirdropContent721 { + struct AirdropContentERC721 { address recipient; uint256 tokenId; } - struct AirdropContent1155 { + struct AirdropContentERC1155 { address recipient; uint256 tokenId; uint256 amount; } - struct AirdropRequest20 { + struct AirdropRequestERC20 { bytes32 uid; address tokenAddress; uint256 expirationTimestamp; - AirdropContent20[] contents; + AirdropContentERC20[] contents; } - struct AirdropRequest721 { + struct AirdropRequestERC721 { bytes32 uid; address tokenAddress; uint256 expirationTimestamp; - AirdropContent721[] contents; + AirdropContentERC721[] contents; } - struct AirdropRequest1155 { + struct AirdropRequestERC1155 { bytes32 uid; address tokenAddress; uint256 expirationTimestamp; - AirdropContent1155[] contents; + AirdropContentERC1155[] contents; } - bytes32 private constant CONTENT_TYPEHASH_ERC20 = keccak256("AirdropContent20(address recipient,uint256 amount)"); - bytes32 private constant REQUEST_TYPEHASH_ERC20 = - keccak256( - "AirdropRequest20(bytes32 uid,address tokenAddress,uint256 expirationTimestamp,AirdropContent20[] contents)AirdropContent20(address recipient,uint256 amount)" - ); + bytes32 private constant CONTENT_TYPEHASH_ERC20 = keccak256("AirdropContentERC20(address recipient,uint256 amount)"); + bytes32 private constant REQUEST_TYPEHASH_ERC20 = keccak256( + "AirdropRequestERC20(bytes32 uid,address tokenAddress,uint256 expirationTimestamp,AirdropContentERC20[] contents)AirdropContentERC20(address recipient,uint256 amount)" + ); bytes32 private constant CONTENT_TYPEHASH_ERC721 = - keccak256("AirdropContent721(address recipient,uint256 tokenId)"); - bytes32 private constant REQUEST_TYPEHASH_ERC721 = - keccak256( - "AirdropRequest721(bytes32 uid,address tokenAddress,uint256 expirationTimestamp,AirdropContent721[] contents)AirdropContent721(address recipient,uint256 tokenId)" - ); + keccak256("AirdropContentERC721(address recipient,uint256 tokenId)"); + bytes32 private constant REQUEST_TYPEHASH_ERC721 = keccak256( + "AirdropRequestERC721(bytes32 uid,address tokenAddress,uint256 expirationTimestamp,AirdropContentERC721[] contents)AirdropContentERC721(address recipient,uint256 tokenId)" + ); bytes32 private constant CONTENT_TYPEHASH_ERC1155 = - keccak256("AirdropContent1155(address recipient,uint256 tokenId,uint256 amount)"); - bytes32 private constant REQUEST_TYPEHASH_ERC1155 = - keccak256( - "AirdropRequest1155(bytes32 uid,address tokenAddress,uint256 expirationTimestamp,AirdropContent1155[] contents)AirdropContent1155(address recipient,uint256 tokenId,uint256 amount)" - ); + keccak256("AirdropContentERC1155(address recipient,uint256 tokenId,uint256 amount)"); + bytes32 private constant REQUEST_TYPEHASH_ERC1155 = keccak256( + "AirdropRequestERC1155(bytes32 uid,address tokenAddress,uint256 expirationTimestamp,AirdropContentERC1155[] contents)AirdropContentERC1155(address recipient,uint256 tokenId,uint256 amount)" + ); /*/////////////////////////////////////////////////////////////// Errors @@ -126,7 +123,7 @@ contract Airdrop is EIP712, Initializable, Ownable { Airdrop Push //////////////////////////////////////////////////////////////*/ - function airdrop20(address _tokenAddress, AirdropContent20[] calldata _contents) external payable { + function airdrop20(address _tokenAddress, AirdropContentERC20[] calldata _contents) external payable { address _from = msg.sender; uint256 len = _contents.length; uint256 nativeTokenAmount; @@ -135,7 +132,7 @@ contract Airdrop is EIP712, Initializable, Ownable { for (uint256 i = 0; i < len; i++) { nativeTokenAmount += _contents[i].amount; - (bool success, ) = _contents[i].recipient.call{ value: _contents[i].amount }(""); + (bool success,) = _contents[i].recipient.call{value: _contents[i].amount}(""); if (!success) { revert AirdropFailed(); } @@ -151,7 +148,7 @@ contract Airdrop is EIP712, Initializable, Ownable { } } - function airdrop721(address _tokenAddress, AirdropContent721[] calldata _contents) external { + function airdrop721(address _tokenAddress, AirdropContentERC721[] calldata _contents) external { address _from = msg.sender; uint256 len = _contents.length; @@ -160,18 +157,14 @@ contract Airdrop is EIP712, Initializable, Ownable { } } - function airdrop1155(address _tokenAddress, AirdropContent1155[] calldata _contents) external { + function airdrop1155(address _tokenAddress, AirdropContentERC1155[] calldata _contents) external { address _from = msg.sender; uint256 len = _contents.length; for (uint256 i = 0; i < len; i++) { IERC1155(_tokenAddress).safeTransferFrom( - _from, - _contents[i].recipient, - _contents[i].tokenId, - _contents[i].amount, - "" + _from, _contents[i].recipient, _contents[i].tokenId, _contents[i].amount, "" ); } } @@ -180,7 +173,7 @@ contract Airdrop is EIP712, Initializable, Ownable { Airdrop With Signature //////////////////////////////////////////////////////////////*/ - function airdrop20WithSignature(AirdropRequest20 calldata req, bytes calldata signature) external { + function airdrop20WithSignature(AirdropRequestERC20 calldata req, bytes calldata signature) external { // verify expiration timestamp if (req.expirationTimestamp < block.timestamp) { revert AirdropRequestExpired(req.expirationTimestamp); @@ -197,15 +190,12 @@ contract Airdrop is EIP712, Initializable, Ownable { for (uint256 i = 0; i < len; i++) { CurrencyTransferLib.transferCurrency( - req.tokenAddress, - _from, - req.contents[i].recipient, - req.contents[i].amount + req.tokenAddress, _from, req.contents[i].recipient, req.contents[i].amount ); } } - function airdrop721WithSignature(AirdropRequest721 calldata req, bytes calldata signature) external { + function airdrop721WithSignature(AirdropRequestERC721 calldata req, bytes calldata signature) external { // verify expiration timestamp if (req.expirationTimestamp < block.timestamp) { revert AirdropRequestExpired(req.expirationTimestamp); @@ -224,7 +214,7 @@ contract Airdrop is EIP712, Initializable, Ownable { } } - function airdrop1155WithSignature(AirdropRequest1155 calldata req, bytes calldata signature) external { + function airdrop1155WithSignature(AirdropRequestERC1155 calldata req, bytes calldata signature) external { // verify expiration timestamp if (req.expirationTimestamp < block.timestamp) { revert AirdropRequestExpired(req.expirationTimestamp); @@ -240,11 +230,7 @@ contract Airdrop is EIP712, Initializable, Ownable { for (uint256 i = 0; i < len; i++) { IERC1155(req.tokenAddress).safeTransferFrom( - _from, - req.contents[i].recipient, - req.contents[i].tokenId, - req.contents[i].amount, - "" + _from, req.contents[i].recipient, req.contents[i].tokenId, req.contents[i].amount, "" ); } } @@ -276,7 +262,7 @@ contract Airdrop is EIP712, Initializable, Ownable { claimed[conditionId][claimHash] = true; if (_token == CurrencyTransferLib.NATIVE_TOKEN) { - (bool success, ) = _receiver.call{ value: _quantity }(""); + (bool success,) = _receiver.call{value: _quantity}(""); if (!success) revert AirdropFailed(); } else { CurrencyTransferLib.transferCurrency(_token, owner(), _receiver, _quantity); @@ -375,7 +361,7 @@ contract Airdrop is EIP712, Initializable, Ownable { return keccak256(abi.encodePacked(_sender, _token, _tokenId)); } - function _hashContentInfo20(AirdropContent20[] calldata contents) private pure returns (bytes32) { + function _hashContentInfo20(AirdropContentERC20[] calldata contents) private pure returns (bytes32) { bytes32[] memory contentHashes = new bytes32[](contents.length); for (uint256 i = 0; i < contents.length; i++) { contentHashes[i] = keccak256(abi.encode(CONTENT_TYPEHASH_ERC20, contents[i].recipient, contents[i].amount)); @@ -383,17 +369,16 @@ contract Airdrop is EIP712, Initializable, Ownable { return keccak256(abi.encodePacked(contentHashes)); } - function _hashContentInfo721(AirdropContent721[] calldata contents) private pure returns (bytes32) { + function _hashContentInfo721(AirdropContentERC721[] calldata contents) private pure returns (bytes32) { bytes32[] memory contentHashes = new bytes32[](contents.length); for (uint256 i = 0; i < contents.length; i++) { - contentHashes[i] = keccak256( - abi.encode(CONTENT_TYPEHASH_ERC721, contents[i].recipient, contents[i].tokenId) - ); + contentHashes[i] = + keccak256(abi.encode(CONTENT_TYPEHASH_ERC721, contents[i].recipient, contents[i].tokenId)); } return keccak256(abi.encodePacked(contentHashes)); } - function _hashContentInfo1155(AirdropContent1155[] calldata contents) private pure returns (bytes32) { + function _hashContentInfo1155(AirdropContentERC1155[] calldata contents) private pure returns (bytes32) { bytes32[] memory contentHashes = new bytes32[](contents.length); for (uint256 i = 0; i < contents.length; i++) { contentHashes[i] = keccak256( @@ -403,7 +388,7 @@ contract Airdrop is EIP712, Initializable, Ownable { return keccak256(abi.encodePacked(contentHashes)); } - function _verifyReqERC20(AirdropRequest20 calldata req, bytes calldata signature) private view returns (bool) { + function _verifyReqERC20(AirdropRequestERC20 calldata req, bytes calldata signature) private view returns (bool) { bytes32 contentHash = _hashContentInfo20(req.contents); bytes32 structHash = keccak256( abi.encode(REQUEST_TYPEHASH_ERC20, req.uid, req.tokenAddress, req.expirationTimestamp, contentHash) @@ -416,7 +401,11 @@ contract Airdrop is EIP712, Initializable, Ownable { return valid; } - function _verifyReqERC721(AirdropRequest721 calldata req, bytes calldata signature) private view returns (bool) { + function _verifyReqERC721(AirdropRequestERC721 calldata req, bytes calldata signature) + private + view + returns (bool) + { bytes32 contentHash = _hashContentInfo721(req.contents); bytes32 structHash = keccak256( abi.encode(REQUEST_TYPEHASH_ERC721, req.uid, req.tokenAddress, req.expirationTimestamp, contentHash) @@ -429,7 +418,11 @@ contract Airdrop is EIP712, Initializable, Ownable { return valid; } - function _verifyReqERC1155(AirdropRequest1155 calldata req, bytes calldata signature) private view returns (bool) { + function _verifyReqERC1155(AirdropRequestERC1155 calldata req, bytes calldata signature) + private + view + returns (bool) + { bytes32 contentHash = _hashContentInfo1155(req.contents); bytes32 structHash = keccak256( abi.encode(REQUEST_TYPEHASH_ERC1155, req.uid, req.tokenAddress, req.expirationTimestamp, contentHash) From d5eb80a342ea62542e580ddb4037026d9333b5ca Mon Sep 17 00:00:00 2001 From: Yash Date: Fri, 22 Mar 2024 04:17:04 +0530 Subject: [PATCH 12/30] fix --- src/test/benchmark/AirdropBenchmark.t.sol | 87 ++++++++++++----------- 1 file changed, 45 insertions(+), 42 deletions(-) diff --git a/src/test/benchmark/AirdropBenchmark.t.sol b/src/test/benchmark/AirdropBenchmark.t.sol index af1b40285..bbd002b67 100644 --- a/src/test/benchmark/AirdropBenchmark.t.sol +++ b/src/test/benchmark/AirdropBenchmark.t.sol @@ -10,24 +10,25 @@ import "../utils/BaseTest.sol"; contract AirdropBenchmarkTest is BaseTest { Airdrop internal airdrop; - bytes32 private constant CONTENT_TYPEHASH_ERC20 = keccak256("AirdropContent20(address recipient,uint256 amount)"); + bytes32 private constant CONTENT_TYPEHASH_ERC20 = + keccak256("AirdropContentERC20(address recipient,uint256 amount)"); bytes32 private constant REQUEST_TYPEHASH_ERC20 = keccak256( - "AirdropRequest20(bytes32 uid,address tokenAddress,uint256 expirationTimestamp,AirdropContent20[] contents)AirdropContent20(address recipient,uint256 amount)" + "AirdropRequestERC20(bytes32 uid,address tokenAddress,uint256 expirationTimestamp,AirdropContentERC20[] contents)AirdropContentERC20(address recipient,uint256 amount)" ); bytes32 private constant CONTENT_TYPEHASH_ERC721 = - keccak256("AirdropContent721(address recipient,uint256 tokenId)"); + keccak256("AirdropContentERC721(address recipient,uint256 tokenId)"); bytes32 private constant REQUEST_TYPEHASH_ERC721 = keccak256( - "AirdropRequest721(bytes32 uid,address tokenAddress,uint256 expirationTimestamp,AirdropContent721[] contents)AirdropContent721(address recipient,uint256 tokenId)" + "AirdropRequestERC721(bytes32 uid,address tokenAddress,uint256 expirationTimestamp,AirdropContentERC721[] contents)AirdropContentERC721(address recipient,uint256 tokenId)" ); bytes32 private constant CONTENT_TYPEHASH_ERC1155 = - keccak256("AirdropContent1155(address recipient,uint256 tokenId,uint256 amount)"); + keccak256("AirdropContentERC1155(address recipient,uint256 tokenId,uint256 amount)"); bytes32 private constant REQUEST_TYPEHASH_ERC1155 = keccak256( - "AirdropRequest1155(bytes32 uid,address tokenAddress,uint256 expirationTimestamp,AirdropContent1155[] contents)AirdropContent1155(address recipient,uint256 tokenId,uint256 amount)" + "AirdropRequestERC1155(bytes32 uid,address tokenAddress,uint256 expirationTimestamp,AirdropContentERC1155[] contents)AirdropContentERC1155(address recipient,uint256 tokenId,uint256 amount)" ); bytes32 private constant NAME_HASH = keccak256(bytes("Airdrop")); @@ -49,24 +50,26 @@ contract AirdropBenchmarkTest is BaseTest { ); } - function _getContentsERC20(uint256 length) internal pure returns (Airdrop.AirdropContent20[] memory contents) { - contents = new Airdrop.AirdropContent20[](length); + function _getContentsERC20(uint256 length) internal pure returns (Airdrop.AirdropContentERC20[] memory contents) { + contents = new Airdrop.AirdropContentERC20[](length); for (uint256 i = 0; i < length; i++) { contents[i].recipient = address(uint160(i + 10)); contents[i].amount = i + 10; } } - function _getContentsERC721(uint256 length) internal pure returns (Airdrop.AirdropContent721[] memory contents) { - contents = new Airdrop.AirdropContent721[](length); + function _getContentsERC721(uint256 length) internal pure returns (Airdrop.AirdropContentERC721[] memory contents) { + contents = new Airdrop.AirdropContentERC721[](length); for (uint256 i = 0; i < length; i++) { contents[i].recipient = address(uint160(i + 10)); contents[i].tokenId = i; } } - function _getContentsERC1155(uint256 length) internal pure returns (Airdrop.AirdropContent1155[] memory contents) { - contents = new Airdrop.AirdropContent1155[](length); + function _getContentsERC1155( + uint256 length + ) internal pure returns (Airdrop.AirdropContentERC1155[] memory contents) { + contents = new Airdrop.AirdropContentERC1155[](length); for (uint256 i = 0; i < length; i++) { contents[i].recipient = address(uint160(i + 10)); contents[i].tokenId = 0; @@ -75,7 +78,7 @@ contract AirdropBenchmarkTest is BaseTest { } function _signReqERC20( - Airdrop.AirdropRequest20 memory req, + Airdrop.AirdropRequestERC20 memory req, uint256 privateKey ) internal view returns (bytes memory signature) { bytes32[] memory contentHashes = new bytes32[](req.contents.length); @@ -107,7 +110,7 @@ contract AirdropBenchmarkTest is BaseTest { } function _signReqERC721( - Airdrop.AirdropRequest721 memory req, + Airdrop.AirdropRequestERC721 memory req, uint256 privateKey ) internal view returns (bytes memory signature) { bytes32[] memory contentHashes = new bytes32[](req.contents.length); @@ -139,7 +142,7 @@ contract AirdropBenchmarkTest is BaseTest { } function _signReqERC1155( - Airdrop.AirdropRequest1155 memory req, + Airdrop.AirdropRequestERC1155 memory req, uint256 privateKey ) internal view returns (bytes memory signature) { bytes32[] memory contentHashes = new bytes32[](req.contents.length); @@ -186,7 +189,7 @@ contract AirdropBenchmarkTest is BaseTest { vm.prank(signer); erc20.approve(address(airdrop), 100 ether); - Airdrop.AirdropContent20[] memory contents = _getContentsERC20(10); + Airdrop.AirdropContentERC20[] memory contents = _getContentsERC20(10); vm.prank(signer); vm.resumeGasMetering(); @@ -200,7 +203,7 @@ contract AirdropBenchmarkTest is BaseTest { vm.prank(signer); erc20.approve(address(airdrop), 100 ether); - Airdrop.AirdropContent20[] memory contents = _getContentsERC20(100); + Airdrop.AirdropContentERC20[] memory contents = _getContentsERC20(100); vm.prank(signer); vm.resumeGasMetering(); @@ -214,7 +217,7 @@ contract AirdropBenchmarkTest is BaseTest { vm.prank(signer); erc20.approve(address(airdrop), 100 ether); - Airdrop.AirdropContent20[] memory contents = _getContentsERC20(1000); + Airdrop.AirdropContentERC20[] memory contents = _getContentsERC20(1000); vm.prank(signer); vm.resumeGasMetering(); @@ -232,8 +235,8 @@ contract AirdropBenchmarkTest is BaseTest { vm.prank(signer); erc20.approve(address(airdrop), 100 ether); - Airdrop.AirdropContent20[] memory contents = _getContentsERC20(10); - Airdrop.AirdropRequest20 memory req = Airdrop.AirdropRequest20({ + Airdrop.AirdropContentERC20[] memory contents = _getContentsERC20(10); + Airdrop.AirdropRequestERC20 memory req = Airdrop.AirdropRequestERC20({ uid: bytes32(uint256(1)), tokenAddress: address(erc20), expirationTimestamp: 1000, @@ -253,8 +256,8 @@ contract AirdropBenchmarkTest is BaseTest { vm.prank(signer); erc20.approve(address(airdrop), 100 ether); - Airdrop.AirdropContent20[] memory contents = _getContentsERC20(100); - Airdrop.AirdropRequest20 memory req = Airdrop.AirdropRequest20({ + Airdrop.AirdropContentERC20[] memory contents = _getContentsERC20(100); + Airdrop.AirdropRequestERC20 memory req = Airdrop.AirdropRequestERC20({ uid: bytes32(uint256(1)), tokenAddress: address(erc20), expirationTimestamp: 1000, @@ -274,8 +277,8 @@ contract AirdropBenchmarkTest is BaseTest { vm.prank(signer); erc20.approve(address(airdrop), 100 ether); - Airdrop.AirdropContent20[] memory contents = _getContentsERC20(1000); - Airdrop.AirdropRequest20 memory req = Airdrop.AirdropRequest20({ + Airdrop.AirdropContentERC20[] memory contents = _getContentsERC20(1000); + Airdrop.AirdropRequestERC20 memory req = Airdrop.AirdropRequestERC20({ uid: bytes32(uint256(1)), tokenAddress: address(erc20), expirationTimestamp: 1000, @@ -334,7 +337,7 @@ contract AirdropBenchmarkTest is BaseTest { vm.prank(signer); erc721.setApprovalForAll(address(airdrop), true); - Airdrop.AirdropContent721[] memory contents = _getContentsERC721(10); + Airdrop.AirdropContentERC721[] memory contents = _getContentsERC721(10); vm.prank(signer); vm.resumeGasMetering(); @@ -348,7 +351,7 @@ contract AirdropBenchmarkTest is BaseTest { vm.prank(signer); erc721.setApprovalForAll(address(airdrop), true); - Airdrop.AirdropContent721[] memory contents = _getContentsERC721(100); + Airdrop.AirdropContentERC721[] memory contents = _getContentsERC721(100); vm.prank(signer); vm.resumeGasMetering(); @@ -362,7 +365,7 @@ contract AirdropBenchmarkTest is BaseTest { vm.prank(signer); erc721.setApprovalForAll(address(airdrop), true); - Airdrop.AirdropContent721[] memory contents = _getContentsERC721(1000); + Airdrop.AirdropContentERC721[] memory contents = _getContentsERC721(1000); vm.prank(signer); vm.resumeGasMetering(); @@ -380,8 +383,8 @@ contract AirdropBenchmarkTest is BaseTest { vm.prank(signer); erc721.setApprovalForAll(address(airdrop), true); - Airdrop.AirdropContent721[] memory contents = _getContentsERC721(10); - Airdrop.AirdropRequest721 memory req = Airdrop.AirdropRequest721({ + Airdrop.AirdropContentERC721[] memory contents = _getContentsERC721(10); + Airdrop.AirdropRequestERC721 memory req = Airdrop.AirdropRequestERC721({ uid: bytes32(uint256(1)), tokenAddress: address(erc721), expirationTimestamp: 1000, @@ -401,8 +404,8 @@ contract AirdropBenchmarkTest is BaseTest { vm.prank(signer); erc721.setApprovalForAll(address(airdrop), true); - Airdrop.AirdropContent721[] memory contents = _getContentsERC721(100); - Airdrop.AirdropRequest721 memory req = Airdrop.AirdropRequest721({ + Airdrop.AirdropContentERC721[] memory contents = _getContentsERC721(100); + Airdrop.AirdropRequestERC721 memory req = Airdrop.AirdropRequestERC721({ uid: bytes32(uint256(1)), tokenAddress: address(erc721), expirationTimestamp: 1000, @@ -422,8 +425,8 @@ contract AirdropBenchmarkTest is BaseTest { vm.prank(signer); erc721.setApprovalForAll(address(airdrop), true); - Airdrop.AirdropContent721[] memory contents = _getContentsERC721(1000); - Airdrop.AirdropRequest721 memory req = Airdrop.AirdropRequest721({ + Airdrop.AirdropContentERC721[] memory contents = _getContentsERC721(1000); + Airdrop.AirdropRequestERC721 memory req = Airdrop.AirdropRequestERC721({ uid: bytes32(uint256(1)), tokenAddress: address(erc721), expirationTimestamp: 1000, @@ -482,7 +485,7 @@ contract AirdropBenchmarkTest is BaseTest { vm.prank(signer); erc1155.setApprovalForAll(address(airdrop), true); - Airdrop.AirdropContent1155[] memory contents = _getContentsERC1155(10); + Airdrop.AirdropContentERC1155[] memory contents = _getContentsERC1155(10); vm.prank(signer); vm.resumeGasMetering(); @@ -496,7 +499,7 @@ contract AirdropBenchmarkTest is BaseTest { vm.prank(signer); erc1155.setApprovalForAll(address(airdrop), true); - Airdrop.AirdropContent1155[] memory contents = _getContentsERC1155(100); + Airdrop.AirdropContentERC1155[] memory contents = _getContentsERC1155(100); vm.prank(signer); vm.resumeGasMetering(); @@ -510,7 +513,7 @@ contract AirdropBenchmarkTest is BaseTest { vm.prank(signer); erc1155.setApprovalForAll(address(airdrop), true); - Airdrop.AirdropContent1155[] memory contents = _getContentsERC1155(1000); + Airdrop.AirdropContentERC1155[] memory contents = _getContentsERC1155(1000); vm.prank(signer); vm.resumeGasMetering(); @@ -528,8 +531,8 @@ contract AirdropBenchmarkTest is BaseTest { vm.prank(signer); erc1155.setApprovalForAll(address(airdrop), true); - Airdrop.AirdropContent1155[] memory contents = _getContentsERC1155(10); - Airdrop.AirdropRequest1155 memory req = Airdrop.AirdropRequest1155({ + Airdrop.AirdropContentERC1155[] memory contents = _getContentsERC1155(10); + Airdrop.AirdropRequestERC1155 memory req = Airdrop.AirdropRequestERC1155({ uid: bytes32(uint256(1)), tokenAddress: address(erc1155), expirationTimestamp: 1000, @@ -549,8 +552,8 @@ contract AirdropBenchmarkTest is BaseTest { vm.prank(signer); erc1155.setApprovalForAll(address(airdrop), true); - Airdrop.AirdropContent1155[] memory contents = _getContentsERC1155(100); - Airdrop.AirdropRequest1155 memory req = Airdrop.AirdropRequest1155({ + Airdrop.AirdropContentERC1155[] memory contents = _getContentsERC1155(100); + Airdrop.AirdropRequestERC1155 memory req = Airdrop.AirdropRequestERC1155({ uid: bytes32(uint256(1)), tokenAddress: address(erc1155), expirationTimestamp: 1000, @@ -570,8 +573,8 @@ contract AirdropBenchmarkTest is BaseTest { vm.prank(signer); erc1155.setApprovalForAll(address(airdrop), true); - Airdrop.AirdropContent1155[] memory contents = _getContentsERC1155(1000); - Airdrop.AirdropRequest1155 memory req = Airdrop.AirdropRequest1155({ + Airdrop.AirdropContentERC1155[] memory contents = _getContentsERC1155(1000); + Airdrop.AirdropRequestERC1155 memory req = Airdrop.AirdropRequestERC1155({ uid: bytes32(uint256(1)), tokenAddress: address(erc1155), expirationTimestamp: 1000, From 731bda97a727635897520cd2eafbfda8853d0063 Mon Sep 17 00:00:00 2001 From: Yash Date: Fri, 22 Mar 2024 04:18:55 +0530 Subject: [PATCH 13/30] unit tests wip --- src/test/airdrop/Airdrop.t.sol | 582 +++++++++++++++++++++++++++++++++ 1 file changed, 582 insertions(+) create mode 100644 src/test/airdrop/Airdrop.t.sol diff --git a/src/test/airdrop/Airdrop.t.sol b/src/test/airdrop/Airdrop.t.sol new file mode 100644 index 000000000..40cb186f7 --- /dev/null +++ b/src/test/airdrop/Airdrop.t.sol @@ -0,0 +1,582 @@ +// SPDX-License-Identifier: Apache-2.0 +pragma solidity ^0.8.0; + +import { Airdrop } from "contracts/prebuilts/unaudited/airdrop/Airdrop.sol"; + +// Test imports +import { TWProxy } from "contracts/infra/TWProxy.sol"; +import "../utils/BaseTest.sol"; + +contract AirdropTest is BaseTest { + Airdrop internal airdrop; + + bytes32 private constant CONTENT_TYPEHASH_ERC20 = + keccak256("AirdropContentERC20(address recipient,uint256 amount)"); + bytes32 private constant REQUEST_TYPEHASH_ERC20 = + keccak256( + "AirdropRequestERC20(bytes32 uid,address tokenAddress,uint256 expirationTimestamp,AirdropContentERC20[] contents)AirdropContentERC20(address recipient,uint256 amount)" + ); + + bytes32 private constant CONTENT_TYPEHASH_ERC721 = + keccak256("AirdropContentERC721(address recipient,uint256 tokenId)"); + bytes32 private constant REQUEST_TYPEHASH_ERC721 = + keccak256( + "AirdropRequestERC721(bytes32 uid,address tokenAddress,uint256 expirationTimestamp,AirdropContentERC721[] contents)AirdropContentERC721(address recipient,uint256 tokenId)" + ); + + bytes32 private constant CONTENT_TYPEHASH_ERC1155 = + keccak256("AirdropContentERC1155(address recipient,uint256 tokenId,uint256 amount)"); + bytes32 private constant REQUEST_TYPEHASH_ERC1155 = + keccak256( + "AirdropRequestERC1155(bytes32 uid,address tokenAddress,uint256 expirationTimestamp,AirdropContentERC1155[] contents)AirdropContentERC1155(address recipient,uint256 tokenId,uint256 amount)" + ); + + bytes32 private constant NAME_HASH = keccak256(bytes("Airdrop")); + bytes32 private constant VERSION_HASH = keccak256(bytes("1")); + bytes32 private constant TYPE_HASH_EIP712 = + keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"); + + bytes32 internal domainSeparator; + + function setUp() public override { + super.setUp(); + + address impl = address(new Airdrop()); + + airdrop = Airdrop(address(new TWProxy(impl, abi.encodeCall(Airdrop.initialize, (signer))))); + + domainSeparator = keccak256( + abi.encode(TYPE_HASH_EIP712, NAME_HASH, VERSION_HASH, block.chainid, address(airdrop)) + ); + } + + function _getContentsERC20(uint256 length) internal pure returns (Airdrop.AirdropContentERC20[] memory contents) { + contents = new Airdrop.AirdropContentERC20[](length); + for (uint256 i = 0; i < length; i++) { + contents[i].recipient = address(uint160(i + 10)); + contents[i].amount = i + 10; + } + } + + function _getContentsERC721(uint256 length) internal pure returns (Airdrop.AirdropContentERC721[] memory contents) { + contents = new Airdrop.AirdropContentERC721[](length); + for (uint256 i = 0; i < length; i++) { + contents[i].recipient = address(uint160(i + 10)); + contents[i].tokenId = i; + } + } + + function _getContentsERC1155( + uint256 length + ) internal pure returns (Airdrop.AirdropContentERC1155[] memory contents) { + contents = new Airdrop.AirdropContentERC1155[](length); + for (uint256 i = 0; i < length; i++) { + contents[i].recipient = address(uint160(i + 10)); + contents[i].tokenId = 0; + contents[i].amount = i + 10; + } + } + + function _signReqERC20( + Airdrop.AirdropRequestERC20 memory req, + uint256 privateKey + ) internal view returns (bytes memory signature) { + bytes32[] memory contentHashes = new bytes32[](req.contents.length); + for (uint i = 0; i < req.contents.length; i++) { + contentHashes[i] = keccak256( + abi.encode(CONTENT_TYPEHASH_ERC20, req.contents[i].recipient, req.contents[i].amount) + ); + } + bytes32 contentHash = keccak256(abi.encodePacked(contentHashes)); + + bytes memory dataToHash; + { + dataToHash = abi.encode( + REQUEST_TYPEHASH_ERC20, + req.uid, + req.tokenAddress, + req.expirationTimestamp, + contentHash + ); + } + + { + bytes32 _structHash = keccak256(dataToHash); + bytes32 typedDataHash = keccak256(abi.encodePacked("\x19\x01", domainSeparator, _structHash)); + (uint8 v, bytes32 r, bytes32 s) = vm.sign(privateKey, typedDataHash); + + signature = abi.encodePacked(r, s, v); + } + } + + function _signReqERC721( + Airdrop.AirdropRequestERC721 memory req, + uint256 privateKey + ) internal view returns (bytes memory signature) { + bytes32[] memory contentHashes = new bytes32[](req.contents.length); + for (uint i = 0; i < req.contents.length; i++) { + contentHashes[i] = keccak256( + abi.encode(CONTENT_TYPEHASH_ERC721, req.contents[i].recipient, req.contents[i].tokenId) + ); + } + bytes32 contentHash = keccak256(abi.encodePacked(contentHashes)); + + bytes memory dataToHash; + { + dataToHash = abi.encode( + REQUEST_TYPEHASH_ERC721, + req.uid, + req.tokenAddress, + req.expirationTimestamp, + contentHash + ); + } + + { + bytes32 _structHash = keccak256(dataToHash); + bytes32 typedDataHash = keccak256(abi.encodePacked("\x19\x01", domainSeparator, _structHash)); + (uint8 v, bytes32 r, bytes32 s) = vm.sign(privateKey, typedDataHash); + + signature = abi.encodePacked(r, s, v); + } + } + + function _signReqERC1155( + Airdrop.AirdropRequestERC1155 memory req, + uint256 privateKey + ) internal view returns (bytes memory signature) { + bytes32[] memory contentHashes = new bytes32[](req.contents.length); + for (uint i = 0; i < req.contents.length; i++) { + contentHashes[i] = keccak256( + abi.encode( + CONTENT_TYPEHASH_ERC1155, + req.contents[i].recipient, + req.contents[i].tokenId, + req.contents[i].amount + ) + ); + } + bytes32 contentHash = keccak256(abi.encodePacked(contentHashes)); + + bytes memory dataToHash; + { + dataToHash = abi.encode( + REQUEST_TYPEHASH_ERC1155, + req.uid, + req.tokenAddress, + req.expirationTimestamp, + contentHash + ); + } + + { + bytes32 _structHash = keccak256(dataToHash); + bytes32 typedDataHash = keccak256(abi.encodePacked("\x19\x01", domainSeparator, _structHash)); + (uint8 v, bytes32 r, bytes32 s) = vm.sign(privateKey, typedDataHash); + + signature = abi.encodePacked(r, s, v); + } + } + + /*/////////////////////////////////////////////////////////////// + Benchmark: Airdrop Push ERC20 + //////////////////////////////////////////////////////////////*/ + + function test_benchmark_airdropPush_erc20_10() public { + erc20.mint(signer, 100 ether); + vm.prank(signer); + erc20.approve(address(airdrop), 100 ether); + + Airdrop.AirdropContentERC20[] memory contents = _getContentsERC20(10); + + vm.prank(signer); + + airdrop.airdrop20(address(erc20), contents); + } + + function test_benchmark_airdropPush_erc20_100() public { + erc20.mint(signer, 100 ether); + vm.prank(signer); + erc20.approve(address(airdrop), 100 ether); + + Airdrop.AirdropContentERC20[] memory contents = _getContentsERC20(100); + + vm.prank(signer); + + airdrop.airdrop20(address(erc20), contents); + } + + function test_benchmark_airdropPush_erc20_1000() public { + erc20.mint(signer, 100 ether); + vm.prank(signer); + erc20.approve(address(airdrop), 100 ether); + + Airdrop.AirdropContentERC20[] memory contents = _getContentsERC20(1000); + + vm.prank(signer); + + airdrop.airdrop20(address(erc20), contents); + } + + /*/////////////////////////////////////////////////////////////// + Benchmark: Airdrop Signature ERC20 + //////////////////////////////////////////////////////////////*/ + + function test_benchmark_airdropSignature_erc20_10() public { + erc20.mint(signer, 100 ether); + vm.prank(signer); + erc20.approve(address(airdrop), 100 ether); + + Airdrop.AirdropContentERC20[] memory contents = _getContentsERC20(10); + Airdrop.AirdropRequestERC20 memory req = Airdrop.AirdropRequestERC20({ + uid: bytes32(uint256(1)), + tokenAddress: address(erc20), + expirationTimestamp: 1000, + contents: contents + }); + bytes memory signature = _signReqERC20(req, privateKey); + + vm.prank(signer); + + airdrop.airdrop20WithSignature(req, signature); + } + + function test_benchmark_airdropSignature_erc20_100() public { + erc20.mint(signer, 100 ether); + vm.prank(signer); + erc20.approve(address(airdrop), 100 ether); + + Airdrop.AirdropContentERC20[] memory contents = _getContentsERC20(100); + Airdrop.AirdropRequestERC20 memory req = Airdrop.AirdropRequestERC20({ + uid: bytes32(uint256(1)), + tokenAddress: address(erc20), + expirationTimestamp: 1000, + contents: contents + }); + bytes memory signature = _signReqERC20(req, privateKey); + + vm.prank(signer); + + airdrop.airdrop20WithSignature(req, signature); + } + + function test_benchmark_airdropSignature_erc20_1000() public { + erc20.mint(signer, 100 ether); + vm.prank(signer); + erc20.approve(address(airdrop), 100 ether); + + Airdrop.AirdropContentERC20[] memory contents = _getContentsERC20(1000); + Airdrop.AirdropRequestERC20 memory req = Airdrop.AirdropRequestERC20({ + uid: bytes32(uint256(1)), + tokenAddress: address(erc20), + expirationTimestamp: 1000, + contents: contents + }); + bytes memory signature = _signReqERC20(req, privateKey); + + vm.prank(signer); + + airdrop.airdrop20WithSignature(req, signature); + } + + /*/////////////////////////////////////////////////////////////// + Benchmark: Airdrop Claim ERC20 + //////////////////////////////////////////////////////////////*/ + + function test_benchmark_airdropClaim_erc20() public { + erc20.mint(signer, 100 ether); + vm.prank(signer); + erc20.approve(address(airdrop), 100 ether); + + string[] memory inputs = new string[](3); + inputs[0] = "node"; + inputs[1] = "src/test/scripts/generateRootAirdrop.ts"; + inputs[2] = Strings.toString(uint256(5)); + bytes memory result = vm.ffi(inputs); + bytes32 root = abi.decode(result, (bytes32)); + + // set merkle root + vm.prank(signer); + airdrop.setMerkleRoot(address(erc20), root, true); + + // generate proof + inputs[1] = "src/test/scripts/getProofAirdrop.ts"; + result = vm.ffi(inputs); + bytes32[] memory proofs = abi.decode(result, (bytes32[])); + + address receiver = address(0xDDdDddDdDdddDDddDDddDDDDdDdDDdDDdDDDDDDd); + uint256 quantity = 5; + + vm.prank(receiver); + + airdrop.claim20(address(erc20), receiver, quantity, proofs); + } + + /*/////////////////////////////////////////////////////////////// + Benchmark: Airdrop Push ERC721 + //////////////////////////////////////////////////////////////*/ + + function test_benchmark_airdropPush_erc721_10() public { + erc721.mint(signer, 100); + vm.prank(signer); + erc721.setApprovalForAll(address(airdrop), true); + + Airdrop.AirdropContentERC721[] memory contents = _getContentsERC721(10); + + vm.prank(signer); + + airdrop.airdrop721(address(erc721), contents); + } + + function test_benchmark_airdropPush_erc721_100() public { + erc721.mint(signer, 100); + vm.prank(signer); + erc721.setApprovalForAll(address(airdrop), true); + + Airdrop.AirdropContentERC721[] memory contents = _getContentsERC721(100); + + vm.prank(signer); + + airdrop.airdrop721(address(erc721), contents); + } + + function test_benchmark_airdropPush_erc721_1000() public { + erc721.mint(signer, 1000); + vm.prank(signer); + erc721.setApprovalForAll(address(airdrop), true); + + Airdrop.AirdropContentERC721[] memory contents = _getContentsERC721(1000); + + vm.prank(signer); + + airdrop.airdrop721(address(erc721), contents); + } + + /*/////////////////////////////////////////////////////////////// + Benchmark: Airdrop Signature ERC721 + //////////////////////////////////////////////////////////////*/ + + function test_benchmark_airdropSignature_erc721_10() public { + erc721.mint(signer, 1000); + vm.prank(signer); + erc721.setApprovalForAll(address(airdrop), true); + + Airdrop.AirdropContentERC721[] memory contents = _getContentsERC721(10); + Airdrop.AirdropRequestERC721 memory req = Airdrop.AirdropRequestERC721({ + uid: bytes32(uint256(1)), + tokenAddress: address(erc721), + expirationTimestamp: 1000, + contents: contents + }); + bytes memory signature = _signReqERC721(req, privateKey); + + vm.prank(signer); + + airdrop.airdrop721WithSignature(req, signature); + } + + function test_benchmark_airdropSignature_erc721_100() public { + erc721.mint(signer, 1000); + vm.prank(signer); + erc721.setApprovalForAll(address(airdrop), true); + + Airdrop.AirdropContentERC721[] memory contents = _getContentsERC721(100); + Airdrop.AirdropRequestERC721 memory req = Airdrop.AirdropRequestERC721({ + uid: bytes32(uint256(1)), + tokenAddress: address(erc721), + expirationTimestamp: 1000, + contents: contents + }); + bytes memory signature = _signReqERC721(req, privateKey); + + vm.prank(signer); + + airdrop.airdrop721WithSignature(req, signature); + } + + function test_benchmark_airdropSignature_erc721_1000() public { + erc721.mint(signer, 1000); + vm.prank(signer); + erc721.setApprovalForAll(address(airdrop), true); + + Airdrop.AirdropContentERC721[] memory contents = _getContentsERC721(1000); + Airdrop.AirdropRequestERC721 memory req = Airdrop.AirdropRequestERC721({ + uid: bytes32(uint256(1)), + tokenAddress: address(erc721), + expirationTimestamp: 1000, + contents: contents + }); + bytes memory signature = _signReqERC721(req, privateKey); + + vm.prank(signer); + + airdrop.airdrop721WithSignature(req, signature); + } + + /*/////////////////////////////////////////////////////////////// + Benchmark: Airdrop Claim ERC721 + //////////////////////////////////////////////////////////////*/ + + function test_benchmark_airdropClaim_erc721() public { + erc721.mint(signer, 100); + vm.prank(signer); + erc721.setApprovalForAll(address(airdrop), true); + + string[] memory inputs = new string[](3); + inputs[0] = "node"; + inputs[1] = "src/test/scripts/generateRootAirdrop.ts"; + inputs[2] = Strings.toString(uint256(5)); + bytes memory result = vm.ffi(inputs); + bytes32 root = abi.decode(result, (bytes32)); + + // set merkle root + vm.prank(signer); + airdrop.setMerkleRoot(address(erc721), root, true); + + // generate proof + inputs[1] = "src/test/scripts/getProofAirdrop.ts"; + result = vm.ffi(inputs); + bytes32[] memory proofs = abi.decode(result, (bytes32[])); + + address receiver = address(0xDDdDddDdDdddDDddDDddDDDDdDdDDdDDdDDDDDDd); + uint256 tokenId = 5; + + vm.prank(receiver); + + airdrop.claim721(address(erc721), receiver, tokenId, proofs); + } + + /*/////////////////////////////////////////////////////////////// + Benchmark: Airdrop Push ERC1155 + //////////////////////////////////////////////////////////////*/ + + function test_benchmark_airdropPush_erc1155_10() public { + erc1155.mint(signer, 0, 100 ether); + vm.prank(signer); + erc1155.setApprovalForAll(address(airdrop), true); + + Airdrop.AirdropContentERC1155[] memory contents = _getContentsERC1155(10); + + vm.prank(signer); + + airdrop.airdrop1155(address(erc1155), contents); + } + + function test_benchmark_airdropPush_erc1155_100() public { + erc1155.mint(signer, 0, 100 ether); + vm.prank(signer); + erc1155.setApprovalForAll(address(airdrop), true); + + Airdrop.AirdropContentERC1155[] memory contents = _getContentsERC1155(100); + + vm.prank(signer); + + airdrop.airdrop1155(address(erc1155), contents); + } + + function test_benchmark_airdropPush_erc1155_1000() public { + erc1155.mint(signer, 0, 100 ether); + vm.prank(signer); + erc1155.setApprovalForAll(address(airdrop), true); + + Airdrop.AirdropContentERC1155[] memory contents = _getContentsERC1155(1000); + + vm.prank(signer); + + airdrop.airdrop1155(address(erc1155), contents); + } + + /*/////////////////////////////////////////////////////////////// + Benchmark: Airdrop Signature ERC1155 + //////////////////////////////////////////////////////////////*/ + + function test_benchmark_airdropSignature_erc115_10() public { + erc1155.mint(signer, 0, 100 ether); + vm.prank(signer); + erc1155.setApprovalForAll(address(airdrop), true); + + Airdrop.AirdropContentERC1155[] memory contents = _getContentsERC1155(10); + Airdrop.AirdropRequestERC1155 memory req = Airdrop.AirdropRequestERC1155({ + uid: bytes32(uint256(1)), + tokenAddress: address(erc1155), + expirationTimestamp: 1000, + contents: contents + }); + bytes memory signature = _signReqERC1155(req, privateKey); + + vm.prank(signer); + + airdrop.airdrop1155WithSignature(req, signature); + } + + function test_benchmark_airdropSignature_erc115_100() public { + erc1155.mint(signer, 0, 100 ether); + vm.prank(signer); + erc1155.setApprovalForAll(address(airdrop), true); + + Airdrop.AirdropContentERC1155[] memory contents = _getContentsERC1155(100); + Airdrop.AirdropRequestERC1155 memory req = Airdrop.AirdropRequestERC1155({ + uid: bytes32(uint256(1)), + tokenAddress: address(erc1155), + expirationTimestamp: 1000, + contents: contents + }); + bytes memory signature = _signReqERC1155(req, privateKey); + + vm.prank(signer); + + airdrop.airdrop1155WithSignature(req, signature); + } + + function test_benchmark_airdropSignature_erc115_1000() public { + erc1155.mint(signer, 0, 100 ether); + vm.prank(signer); + erc1155.setApprovalForAll(address(airdrop), true); + + Airdrop.AirdropContentERC1155[] memory contents = _getContentsERC1155(1000); + Airdrop.AirdropRequestERC1155 memory req = Airdrop.AirdropRequestERC1155({ + uid: bytes32(uint256(1)), + tokenAddress: address(erc1155), + expirationTimestamp: 1000, + contents: contents + }); + bytes memory signature = _signReqERC1155(req, privateKey); + + vm.prank(signer); + + airdrop.airdrop1155WithSignature(req, signature); + } + + /*/////////////////////////////////////////////////////////////// + Benchmark: Airdrop Claim ERC1155 + //////////////////////////////////////////////////////////////*/ + + function test_benchmark_airdropClaim_erc1155() public { + erc1155.mint(signer, 0, 100 ether); + vm.prank(signer); + erc1155.setApprovalForAll(address(airdrop), true); + + string[] memory inputs = new string[](3); + inputs[0] = "node"; + inputs[1] = "src/test/scripts/generateRootAirdrop.ts"; + inputs[2] = Strings.toString(uint256(5)); + bytes memory result = vm.ffi(inputs); + bytes32 root = abi.decode(result, (bytes32)); + + // set merkle root + vm.prank(signer); + airdrop.setMerkleRoot(address(erc1155), root, true); + + // generate proof + inputs[1] = "src/test/scripts/getProofAirdrop.ts"; + result = vm.ffi(inputs); + bytes32[] memory proofs = abi.decode(result, (bytes32[])); + + address receiver = address(0xDDdDddDdDdddDDddDDddDDDDdDdDDdDDdDDDDDDd); + uint256 quantity = 5; + + vm.prank(receiver); + + airdrop.claim1155(address(erc1155), receiver, 0, quantity, proofs); + } +} From 9b7f49443b8e4cf9f830ee0c2f9b884b988428fd Mon Sep 17 00:00:00 2001 From: Yash Date: Fri, 22 Mar 2024 05:30:53 +0530 Subject: [PATCH 14/30] rename --- .../prebuilts/unaudited/airdrop/Airdrop.sol | 87 +++++++++++-------- src/test/airdrop/Airdrop.t.sol | 42 ++++----- src/test/benchmark/AirdropBenchmark.t.sol | 42 ++++----- 3 files changed, 91 insertions(+), 80 deletions(-) diff --git a/contracts/prebuilts/unaudited/airdrop/Airdrop.sol b/contracts/prebuilts/unaudited/airdrop/Airdrop.sol index cd0e7500a..7fac087bb 100644 --- a/contracts/prebuilts/unaudited/airdrop/Airdrop.sol +++ b/contracts/prebuilts/unaudited/airdrop/Airdrop.sol @@ -16,8 +16,8 @@ import "@solady/src/utils/MerkleProofLib.sol"; import "@solady/src/utils/ECDSA.sol"; import "@solady/src/utils/EIP712.sol"; -import {Initializable} from "../../../extension/Initializable.sol"; -import {Ownable} from "../../../extension/Ownable.sol"; +import { Initializable } from "../../../extension/Initializable.sol"; +import { Ownable } from "../../../extension/Ownable.sol"; import "../../../eip/interface/IERC721.sol"; import "../../../eip/interface/IERC1155.sol"; @@ -77,22 +77,26 @@ contract Airdrop is EIP712, Initializable, Ownable { AirdropContentERC1155[] contents; } - bytes32 private constant CONTENT_TYPEHASH_ERC20 = keccak256("AirdropContentERC20(address recipient,uint256 amount)"); - bytes32 private constant REQUEST_TYPEHASH_ERC20 = keccak256( - "AirdropRequestERC20(bytes32 uid,address tokenAddress,uint256 expirationTimestamp,AirdropContentERC20[] contents)AirdropContentERC20(address recipient,uint256 amount)" - ); + bytes32 private constant CONTENT_TYPEHASH_ERC20 = + keccak256("AirdropContentERC20(address recipient,uint256 amount)"); + bytes32 private constant REQUEST_TYPEHASH_ERC20 = + keccak256( + "AirdropRequestERC20(bytes32 uid,address tokenAddress,uint256 expirationTimestamp,AirdropContentERC20[] contents)AirdropContentERC20(address recipient,uint256 amount)" + ); bytes32 private constant CONTENT_TYPEHASH_ERC721 = keccak256("AirdropContentERC721(address recipient,uint256 tokenId)"); - bytes32 private constant REQUEST_TYPEHASH_ERC721 = keccak256( - "AirdropRequestERC721(bytes32 uid,address tokenAddress,uint256 expirationTimestamp,AirdropContentERC721[] contents)AirdropContentERC721(address recipient,uint256 tokenId)" - ); + bytes32 private constant REQUEST_TYPEHASH_ERC721 = + keccak256( + "AirdropRequestERC721(bytes32 uid,address tokenAddress,uint256 expirationTimestamp,AirdropContentERC721[] contents)AirdropContentERC721(address recipient,uint256 tokenId)" + ); bytes32 private constant CONTENT_TYPEHASH_ERC1155 = keccak256("AirdropContentERC1155(address recipient,uint256 tokenId,uint256 amount)"); - bytes32 private constant REQUEST_TYPEHASH_ERC1155 = keccak256( - "AirdropRequestERC1155(bytes32 uid,address tokenAddress,uint256 expirationTimestamp,AirdropContentERC1155[] contents)AirdropContentERC1155(address recipient,uint256 tokenId,uint256 amount)" - ); + bytes32 private constant REQUEST_TYPEHASH_ERC1155 = + keccak256( + "AirdropRequestERC1155(bytes32 uid,address tokenAddress,uint256 expirationTimestamp,AirdropContentERC1155[] contents)AirdropContentERC1155(address recipient,uint256 tokenId,uint256 amount)" + ); /*/////////////////////////////////////////////////////////////// Errors @@ -123,7 +127,7 @@ contract Airdrop is EIP712, Initializable, Ownable { Airdrop Push //////////////////////////////////////////////////////////////*/ - function airdrop20(address _tokenAddress, AirdropContentERC20[] calldata _contents) external payable { + function airdropERC20(address _tokenAddress, AirdropContentERC20[] calldata _contents) external payable { address _from = msg.sender; uint256 len = _contents.length; uint256 nativeTokenAmount; @@ -132,7 +136,7 @@ contract Airdrop is EIP712, Initializable, Ownable { for (uint256 i = 0; i < len; i++) { nativeTokenAmount += _contents[i].amount; - (bool success,) = _contents[i].recipient.call{value: _contents[i].amount}(""); + (bool success, ) = _contents[i].recipient.call{ value: _contents[i].amount }(""); if (!success) { revert AirdropFailed(); } @@ -148,7 +152,7 @@ contract Airdrop is EIP712, Initializable, Ownable { } } - function airdrop721(address _tokenAddress, AirdropContentERC721[] calldata _contents) external { + function airdropERC721(address _tokenAddress, AirdropContentERC721[] calldata _contents) external { address _from = msg.sender; uint256 len = _contents.length; @@ -157,14 +161,18 @@ contract Airdrop is EIP712, Initializable, Ownable { } } - function airdrop1155(address _tokenAddress, AirdropContentERC1155[] calldata _contents) external { + function airdropERC1155(address _tokenAddress, AirdropContentERC1155[] calldata _contents) external { address _from = msg.sender; uint256 len = _contents.length; for (uint256 i = 0; i < len; i++) { IERC1155(_tokenAddress).safeTransferFrom( - _from, _contents[i].recipient, _contents[i].tokenId, _contents[i].amount, "" + _from, + _contents[i].recipient, + _contents[i].tokenId, + _contents[i].amount, + "" ); } } @@ -173,7 +181,7 @@ contract Airdrop is EIP712, Initializable, Ownable { Airdrop With Signature //////////////////////////////////////////////////////////////*/ - function airdrop20WithSignature(AirdropRequestERC20 calldata req, bytes calldata signature) external { + function airdropERC20WithSignature(AirdropRequestERC20 calldata req, bytes calldata signature) external { // verify expiration timestamp if (req.expirationTimestamp < block.timestamp) { revert AirdropRequestExpired(req.expirationTimestamp); @@ -190,12 +198,15 @@ contract Airdrop is EIP712, Initializable, Ownable { for (uint256 i = 0; i < len; i++) { CurrencyTransferLib.transferCurrency( - req.tokenAddress, _from, req.contents[i].recipient, req.contents[i].amount + req.tokenAddress, + _from, + req.contents[i].recipient, + req.contents[i].amount ); } } - function airdrop721WithSignature(AirdropRequestERC721 calldata req, bytes calldata signature) external { + function airdropERC721WithSignature(AirdropRequestERC721 calldata req, bytes calldata signature) external { // verify expiration timestamp if (req.expirationTimestamp < block.timestamp) { revert AirdropRequestExpired(req.expirationTimestamp); @@ -214,7 +225,7 @@ contract Airdrop is EIP712, Initializable, Ownable { } } - function airdrop1155WithSignature(AirdropRequestERC1155 calldata req, bytes calldata signature) external { + function airdropERC1155WithSignature(AirdropRequestERC1155 calldata req, bytes calldata signature) external { // verify expiration timestamp if (req.expirationTimestamp < block.timestamp) { revert AirdropRequestExpired(req.expirationTimestamp); @@ -230,7 +241,11 @@ contract Airdrop is EIP712, Initializable, Ownable { for (uint256 i = 0; i < len; i++) { IERC1155(req.tokenAddress).safeTransferFrom( - _from, req.contents[i].recipient, req.contents[i].tokenId, req.contents[i].amount, "" + _from, + req.contents[i].recipient, + req.contents[i].tokenId, + req.contents[i].amount, + "" ); } } @@ -239,7 +254,7 @@ contract Airdrop is EIP712, Initializable, Ownable { Airdrop Claimable //////////////////////////////////////////////////////////////*/ - function claim20(address _token, address _receiver, uint256 _quantity, bytes32[] calldata _proofs) external { + function claimERC20(address _token, address _receiver, uint256 _quantity, bytes32[] calldata _proofs) external { bytes32 claimHash = _getClaimHashERC20(msg.sender, _token); bytes32 conditionId = conditionIdForToken[_token]; @@ -262,14 +277,14 @@ contract Airdrop is EIP712, Initializable, Ownable { claimed[conditionId][claimHash] = true; if (_token == CurrencyTransferLib.NATIVE_TOKEN) { - (bool success,) = _receiver.call{value: _quantity}(""); + (bool success, ) = _receiver.call{ value: _quantity }(""); if (!success) revert AirdropFailed(); } else { CurrencyTransferLib.transferCurrency(_token, owner(), _receiver, _quantity); } } - function claim721(address _token, address _receiver, uint256 _tokenId, bytes32[] calldata _proofs) external { + function claimERC721(address _token, address _receiver, uint256 _tokenId, bytes32[] calldata _proofs) external { bytes32 claimHash = _getClaimHashERC721(msg.sender, _token); bytes32 conditionId = conditionIdForToken[_token]; @@ -294,7 +309,7 @@ contract Airdrop is EIP712, Initializable, Ownable { IERC721(_token).safeTransferFrom(owner(), _receiver, _tokenId); } - function claim1155( + function claimERC1155( address _token, address _receiver, uint256 _tokenId, @@ -372,8 +387,9 @@ contract Airdrop is EIP712, Initializable, Ownable { function _hashContentInfo721(AirdropContentERC721[] calldata contents) private pure returns (bytes32) { bytes32[] memory contentHashes = new bytes32[](contents.length); for (uint256 i = 0; i < contents.length; i++) { - contentHashes[i] = - keccak256(abi.encode(CONTENT_TYPEHASH_ERC721, contents[i].recipient, contents[i].tokenId)); + contentHashes[i] = keccak256( + abi.encode(CONTENT_TYPEHASH_ERC721, contents[i].recipient, contents[i].tokenId) + ); } return keccak256(abi.encodePacked(contentHashes)); } @@ -401,11 +417,7 @@ contract Airdrop is EIP712, Initializable, Ownable { return valid; } - function _verifyReqERC721(AirdropRequestERC721 calldata req, bytes calldata signature) - private - view - returns (bool) - { + function _verifyReqERC721(AirdropRequestERC721 calldata req, bytes calldata signature) private view returns (bool) { bytes32 contentHash = _hashContentInfo721(req.contents); bytes32 structHash = keccak256( abi.encode(REQUEST_TYPEHASH_ERC721, req.uid, req.tokenAddress, req.expirationTimestamp, contentHash) @@ -418,11 +430,10 @@ contract Airdrop is EIP712, Initializable, Ownable { return valid; } - function _verifyReqERC1155(AirdropRequestERC1155 calldata req, bytes calldata signature) - private - view - returns (bool) - { + function _verifyReqERC1155( + AirdropRequestERC1155 calldata req, + bytes calldata signature + ) private view returns (bool) { bytes32 contentHash = _hashContentInfo1155(req.contents); bytes32 structHash = keccak256( abi.encode(REQUEST_TYPEHASH_ERC1155, req.uid, req.tokenAddress, req.expirationTimestamp, contentHash) diff --git a/src/test/airdrop/Airdrop.t.sol b/src/test/airdrop/Airdrop.t.sol index 40cb186f7..f4c34f3a2 100644 --- a/src/test/airdrop/Airdrop.t.sol +++ b/src/test/airdrop/Airdrop.t.sol @@ -191,7 +191,7 @@ contract AirdropTest is BaseTest { vm.prank(signer); - airdrop.airdrop20(address(erc20), contents); + airdrop.airdropERC20(address(erc20), contents); } function test_benchmark_airdropPush_erc20_100() public { @@ -203,7 +203,7 @@ contract AirdropTest is BaseTest { vm.prank(signer); - airdrop.airdrop20(address(erc20), contents); + airdrop.airdropERC20(address(erc20), contents); } function test_benchmark_airdropPush_erc20_1000() public { @@ -215,7 +215,7 @@ contract AirdropTest is BaseTest { vm.prank(signer); - airdrop.airdrop20(address(erc20), contents); + airdrop.airdropERC20(address(erc20), contents); } /*/////////////////////////////////////////////////////////////// @@ -238,7 +238,7 @@ contract AirdropTest is BaseTest { vm.prank(signer); - airdrop.airdrop20WithSignature(req, signature); + airdrop.airdropERC20WithSignature(req, signature); } function test_benchmark_airdropSignature_erc20_100() public { @@ -257,7 +257,7 @@ contract AirdropTest is BaseTest { vm.prank(signer); - airdrop.airdrop20WithSignature(req, signature); + airdrop.airdropERC20WithSignature(req, signature); } function test_benchmark_airdropSignature_erc20_1000() public { @@ -276,7 +276,7 @@ contract AirdropTest is BaseTest { vm.prank(signer); - airdrop.airdrop20WithSignature(req, signature); + airdrop.airdropERC20WithSignature(req, signature); } /*/////////////////////////////////////////////////////////////// @@ -309,7 +309,7 @@ contract AirdropTest is BaseTest { vm.prank(receiver); - airdrop.claim20(address(erc20), receiver, quantity, proofs); + airdrop.claimERC20(address(erc20), receiver, quantity, proofs); } /*/////////////////////////////////////////////////////////////// @@ -325,7 +325,7 @@ contract AirdropTest is BaseTest { vm.prank(signer); - airdrop.airdrop721(address(erc721), contents); + airdrop.airdropERC721(address(erc721), contents); } function test_benchmark_airdropPush_erc721_100() public { @@ -337,7 +337,7 @@ contract AirdropTest is BaseTest { vm.prank(signer); - airdrop.airdrop721(address(erc721), contents); + airdrop.airdropERC721(address(erc721), contents); } function test_benchmark_airdropPush_erc721_1000() public { @@ -349,7 +349,7 @@ contract AirdropTest is BaseTest { vm.prank(signer); - airdrop.airdrop721(address(erc721), contents); + airdrop.airdropERC721(address(erc721), contents); } /*/////////////////////////////////////////////////////////////// @@ -372,7 +372,7 @@ contract AirdropTest is BaseTest { vm.prank(signer); - airdrop.airdrop721WithSignature(req, signature); + airdrop.airdropERC721WithSignature(req, signature); } function test_benchmark_airdropSignature_erc721_100() public { @@ -391,7 +391,7 @@ contract AirdropTest is BaseTest { vm.prank(signer); - airdrop.airdrop721WithSignature(req, signature); + airdrop.airdropERC721WithSignature(req, signature); } function test_benchmark_airdropSignature_erc721_1000() public { @@ -410,7 +410,7 @@ contract AirdropTest is BaseTest { vm.prank(signer); - airdrop.airdrop721WithSignature(req, signature); + airdrop.airdropERC721WithSignature(req, signature); } /*/////////////////////////////////////////////////////////////// @@ -443,7 +443,7 @@ contract AirdropTest is BaseTest { vm.prank(receiver); - airdrop.claim721(address(erc721), receiver, tokenId, proofs); + airdrop.claimERC721(address(erc721), receiver, tokenId, proofs); } /*/////////////////////////////////////////////////////////////// @@ -459,7 +459,7 @@ contract AirdropTest is BaseTest { vm.prank(signer); - airdrop.airdrop1155(address(erc1155), contents); + airdrop.airdropERC1155(address(erc1155), contents); } function test_benchmark_airdropPush_erc1155_100() public { @@ -471,7 +471,7 @@ contract AirdropTest is BaseTest { vm.prank(signer); - airdrop.airdrop1155(address(erc1155), contents); + airdrop.airdropERC1155(address(erc1155), contents); } function test_benchmark_airdropPush_erc1155_1000() public { @@ -483,7 +483,7 @@ contract AirdropTest is BaseTest { vm.prank(signer); - airdrop.airdrop1155(address(erc1155), contents); + airdrop.airdropERC1155(address(erc1155), contents); } /*/////////////////////////////////////////////////////////////// @@ -506,7 +506,7 @@ contract AirdropTest is BaseTest { vm.prank(signer); - airdrop.airdrop1155WithSignature(req, signature); + airdrop.airdropERC1155WithSignature(req, signature); } function test_benchmark_airdropSignature_erc115_100() public { @@ -525,7 +525,7 @@ contract AirdropTest is BaseTest { vm.prank(signer); - airdrop.airdrop1155WithSignature(req, signature); + airdrop.airdropERC1155WithSignature(req, signature); } function test_benchmark_airdropSignature_erc115_1000() public { @@ -544,7 +544,7 @@ contract AirdropTest is BaseTest { vm.prank(signer); - airdrop.airdrop1155WithSignature(req, signature); + airdrop.airdropERC1155WithSignature(req, signature); } /*/////////////////////////////////////////////////////////////// @@ -577,6 +577,6 @@ contract AirdropTest is BaseTest { vm.prank(receiver); - airdrop.claim1155(address(erc1155), receiver, 0, quantity, proofs); + airdrop.claimERC1155(address(erc1155), receiver, 0, quantity, proofs); } } diff --git a/src/test/benchmark/AirdropBenchmark.t.sol b/src/test/benchmark/AirdropBenchmark.t.sol index bbd002b67..15cde879d 100644 --- a/src/test/benchmark/AirdropBenchmark.t.sol +++ b/src/test/benchmark/AirdropBenchmark.t.sol @@ -193,7 +193,7 @@ contract AirdropBenchmarkTest is BaseTest { vm.prank(signer); vm.resumeGasMetering(); - airdrop.airdrop20(address(erc20), contents); + airdrop.airdropERC20(address(erc20), contents); } function test_benchmark_airdropPush_erc20_100() public { @@ -207,7 +207,7 @@ contract AirdropBenchmarkTest is BaseTest { vm.prank(signer); vm.resumeGasMetering(); - airdrop.airdrop20(address(erc20), contents); + airdrop.airdropERC20(address(erc20), contents); } function test_benchmark_airdropPush_erc20_1000() public { @@ -221,7 +221,7 @@ contract AirdropBenchmarkTest is BaseTest { vm.prank(signer); vm.resumeGasMetering(); - airdrop.airdrop20(address(erc20), contents); + airdrop.airdropERC20(address(erc20), contents); } /*/////////////////////////////////////////////////////////////// @@ -246,7 +246,7 @@ contract AirdropBenchmarkTest is BaseTest { vm.prank(signer); vm.resumeGasMetering(); - airdrop.airdrop20WithSignature(req, signature); + airdrop.airdropERC20WithSignature(req, signature); } function test_benchmark_airdropSignature_erc20_100() public { @@ -267,7 +267,7 @@ contract AirdropBenchmarkTest is BaseTest { vm.prank(signer); vm.resumeGasMetering(); - airdrop.airdrop20WithSignature(req, signature); + airdrop.airdropERC20WithSignature(req, signature); } function test_benchmark_airdropSignature_erc20_1000() public { @@ -288,7 +288,7 @@ contract AirdropBenchmarkTest is BaseTest { vm.prank(signer); vm.resumeGasMetering(); - airdrop.airdrop20WithSignature(req, signature); + airdrop.airdropERC20WithSignature(req, signature); } /*/////////////////////////////////////////////////////////////// @@ -323,7 +323,7 @@ contract AirdropBenchmarkTest is BaseTest { vm.prank(receiver); vm.resumeGasMetering(); - airdrop.claim20(address(erc20), receiver, quantity, proofs); + airdrop.claimERC20(address(erc20), receiver, quantity, proofs); } /*/////////////////////////////////////////////////////////////// @@ -341,7 +341,7 @@ contract AirdropBenchmarkTest is BaseTest { vm.prank(signer); vm.resumeGasMetering(); - airdrop.airdrop721(address(erc721), contents); + airdrop.airdropERC721(address(erc721), contents); } function test_benchmark_airdropPush_erc721_100() public { @@ -355,7 +355,7 @@ contract AirdropBenchmarkTest is BaseTest { vm.prank(signer); vm.resumeGasMetering(); - airdrop.airdrop721(address(erc721), contents); + airdrop.airdropERC721(address(erc721), contents); } function test_benchmark_airdropPush_erc721_1000() public { @@ -369,7 +369,7 @@ contract AirdropBenchmarkTest is BaseTest { vm.prank(signer); vm.resumeGasMetering(); - airdrop.airdrop721(address(erc721), contents); + airdrop.airdropERC721(address(erc721), contents); } /*/////////////////////////////////////////////////////////////// @@ -394,7 +394,7 @@ contract AirdropBenchmarkTest is BaseTest { vm.prank(signer); vm.resumeGasMetering(); - airdrop.airdrop721WithSignature(req, signature); + airdrop.airdropERC721WithSignature(req, signature); } function test_benchmark_airdropSignature_erc721_100() public { @@ -415,7 +415,7 @@ contract AirdropBenchmarkTest is BaseTest { vm.prank(signer); vm.resumeGasMetering(); - airdrop.airdrop721WithSignature(req, signature); + airdrop.airdropERC721WithSignature(req, signature); } function test_benchmark_airdropSignature_erc721_1000() public { @@ -436,7 +436,7 @@ contract AirdropBenchmarkTest is BaseTest { vm.prank(signer); vm.resumeGasMetering(); - airdrop.airdrop721WithSignature(req, signature); + airdrop.airdropERC721WithSignature(req, signature); } /*/////////////////////////////////////////////////////////////// @@ -471,7 +471,7 @@ contract AirdropBenchmarkTest is BaseTest { vm.prank(receiver); vm.resumeGasMetering(); - airdrop.claim721(address(erc721), receiver, tokenId, proofs); + airdrop.claimERC721(address(erc721), receiver, tokenId, proofs); } /*/////////////////////////////////////////////////////////////// @@ -489,7 +489,7 @@ contract AirdropBenchmarkTest is BaseTest { vm.prank(signer); vm.resumeGasMetering(); - airdrop.airdrop1155(address(erc1155), contents); + airdrop.airdropERC1155(address(erc1155), contents); } function test_benchmark_airdropPush_erc1155_100() public { @@ -503,7 +503,7 @@ contract AirdropBenchmarkTest is BaseTest { vm.prank(signer); vm.resumeGasMetering(); - airdrop.airdrop1155(address(erc1155), contents); + airdrop.airdropERC1155(address(erc1155), contents); } function test_benchmark_airdropPush_erc1155_1000() public { @@ -517,7 +517,7 @@ contract AirdropBenchmarkTest is BaseTest { vm.prank(signer); vm.resumeGasMetering(); - airdrop.airdrop1155(address(erc1155), contents); + airdrop.airdropERC1155(address(erc1155), contents); } /*/////////////////////////////////////////////////////////////// @@ -542,7 +542,7 @@ contract AirdropBenchmarkTest is BaseTest { vm.prank(signer); vm.resumeGasMetering(); - airdrop.airdrop1155WithSignature(req, signature); + airdrop.airdropERC1155WithSignature(req, signature); } function test_benchmark_airdropSignature_erc115_100() public { @@ -563,7 +563,7 @@ contract AirdropBenchmarkTest is BaseTest { vm.prank(signer); vm.resumeGasMetering(); - airdrop.airdrop1155WithSignature(req, signature); + airdrop.airdropERC1155WithSignature(req, signature); } function test_benchmark_airdropSignature_erc115_1000() public { @@ -584,7 +584,7 @@ contract AirdropBenchmarkTest is BaseTest { vm.prank(signer); vm.resumeGasMetering(); - airdrop.airdrop1155WithSignature(req, signature); + airdrop.airdropERC1155WithSignature(req, signature); } /*/////////////////////////////////////////////////////////////// @@ -619,6 +619,6 @@ contract AirdropBenchmarkTest is BaseTest { vm.prank(receiver); vm.resumeGasMetering(); - airdrop.claim1155(address(erc1155), receiver, 0, quantity, proofs); + airdrop.claimERC1155(address(erc1155), receiver, 0, quantity, proofs); } } From c205d93c0327350ce00124597e7a0665a1ec14c7 Mon Sep 17 00:00:00 2001 From: Yash Date: Fri, 22 Mar 2024 06:49:23 +0530 Subject: [PATCH 15/30] update tests --- src/test/airdrop/Airdrop.t.sol | 230 ++++++--------------------------- 1 file changed, 41 insertions(+), 189 deletions(-) diff --git a/src/test/airdrop/Airdrop.t.sol b/src/test/airdrop/Airdrop.t.sol index f4c34f3a2..423df6473 100644 --- a/src/test/airdrop/Airdrop.t.sol +++ b/src/test/airdrop/Airdrop.t.sol @@ -182,7 +182,7 @@ contract AirdropTest is BaseTest { Benchmark: Airdrop Push ERC20 //////////////////////////////////////////////////////////////*/ - function test_benchmark_airdropPush_erc20_10() public { + function test_state_airdropPush_erc20() public { erc20.mint(signer, 100 ether); vm.prank(signer); erc20.approve(address(airdrop), 100 ether); @@ -192,37 +192,20 @@ contract AirdropTest is BaseTest { vm.prank(signer); airdrop.airdropERC20(address(erc20), contents); - } - - function test_benchmark_airdropPush_erc20_100() public { - erc20.mint(signer, 100 ether); - vm.prank(signer); - erc20.approve(address(airdrop), 100 ether); - - Airdrop.AirdropContentERC20[] memory contents = _getContentsERC20(100); - - vm.prank(signer); - - airdrop.airdropERC20(address(erc20), contents); - } - function test_benchmark_airdropPush_erc20_1000() public { - erc20.mint(signer, 100 ether); - vm.prank(signer); - erc20.approve(address(airdrop), 100 ether); - - Airdrop.AirdropContentERC20[] memory contents = _getContentsERC20(1000); - - vm.prank(signer); - - airdrop.airdropERC20(address(erc20), contents); + uint256 totalAmount; + for (uint256 i = 0; i < contents.length; i++) { + totalAmount += contents[i].amount; + assertEq(erc20.balanceOf(contents[i].recipient), contents[i].amount); + } + assertEq(erc20.balanceOf(signer), 100 ether - totalAmount); } /*/////////////////////////////////////////////////////////////// Benchmark: Airdrop Signature ERC20 //////////////////////////////////////////////////////////////*/ - function test_benchmark_airdropSignature_erc20_10() public { + function test_state_airdropSignature_erc20() public { erc20.mint(signer, 100 ether); vm.prank(signer); erc20.approve(address(airdrop), 100 ether); @@ -239,51 +222,20 @@ contract AirdropTest is BaseTest { vm.prank(signer); airdrop.airdropERC20WithSignature(req, signature); - } - - function test_benchmark_airdropSignature_erc20_100() public { - erc20.mint(signer, 100 ether); - vm.prank(signer); - erc20.approve(address(airdrop), 100 ether); - - Airdrop.AirdropContentERC20[] memory contents = _getContentsERC20(100); - Airdrop.AirdropRequestERC20 memory req = Airdrop.AirdropRequestERC20({ - uid: bytes32(uint256(1)), - tokenAddress: address(erc20), - expirationTimestamp: 1000, - contents: contents - }); - bytes memory signature = _signReqERC20(req, privateKey); - - vm.prank(signer); - - airdrop.airdropERC20WithSignature(req, signature); - } - - function test_benchmark_airdropSignature_erc20_1000() public { - erc20.mint(signer, 100 ether); - vm.prank(signer); - erc20.approve(address(airdrop), 100 ether); - Airdrop.AirdropContentERC20[] memory contents = _getContentsERC20(1000); - Airdrop.AirdropRequestERC20 memory req = Airdrop.AirdropRequestERC20({ - uid: bytes32(uint256(1)), - tokenAddress: address(erc20), - expirationTimestamp: 1000, - contents: contents - }); - bytes memory signature = _signReqERC20(req, privateKey); - - vm.prank(signer); - - airdrop.airdropERC20WithSignature(req, signature); + uint256 totalAmount; + for (uint256 i = 0; i < contents.length; i++) { + totalAmount += contents[i].amount; + assertEq(erc20.balanceOf(contents[i].recipient), contents[i].amount); + } + assertEq(erc20.balanceOf(signer), 100 ether - totalAmount); } /*/////////////////////////////////////////////////////////////// Benchmark: Airdrop Claim ERC20 //////////////////////////////////////////////////////////////*/ - function test_benchmark_airdropClaim_erc20() public { + function test_state_airdropClaim_erc20() public { erc20.mint(signer, 100 ether); vm.prank(signer); erc20.approve(address(airdrop), 100 ether); @@ -310,13 +262,16 @@ contract AirdropTest is BaseTest { vm.prank(receiver); airdrop.claimERC20(address(erc20), receiver, quantity, proofs); + + assertEq(erc20.balanceOf(receiver), quantity); + assertEq(erc20.balanceOf(signer), 100 ether - quantity); } /*/////////////////////////////////////////////////////////////// Benchmark: Airdrop Push ERC721 //////////////////////////////////////////////////////////////*/ - function test_benchmark_airdropPush_erc721_10() public { + function test_state_airdropPush_erc721() public { erc721.mint(signer, 100); vm.prank(signer); erc721.setApprovalForAll(address(airdrop), true); @@ -326,37 +281,17 @@ contract AirdropTest is BaseTest { vm.prank(signer); airdrop.airdropERC721(address(erc721), contents); - } - - function test_benchmark_airdropPush_erc721_100() public { - erc721.mint(signer, 100); - vm.prank(signer); - erc721.setApprovalForAll(address(airdrop), true); - - Airdrop.AirdropContentERC721[] memory contents = _getContentsERC721(100); - - vm.prank(signer); - airdrop.airdropERC721(address(erc721), contents); - } - - function test_benchmark_airdropPush_erc721_1000() public { - erc721.mint(signer, 1000); - vm.prank(signer); - erc721.setApprovalForAll(address(airdrop), true); - - Airdrop.AirdropContentERC721[] memory contents = _getContentsERC721(1000); - - vm.prank(signer); - - airdrop.airdropERC721(address(erc721), contents); + for (uint256 i = 0; i < contents.length; i++) { + assertEq(erc721.ownerOf(contents[i].tokenId), contents[i].recipient); + } } /*/////////////////////////////////////////////////////////////// Benchmark: Airdrop Signature ERC721 //////////////////////////////////////////////////////////////*/ - function test_benchmark_airdropSignature_erc721_10() public { + function test_state_airdropSignature_erc721() public { erc721.mint(signer, 1000); vm.prank(signer); erc721.setApprovalForAll(address(airdrop), true); @@ -373,51 +308,17 @@ contract AirdropTest is BaseTest { vm.prank(signer); airdrop.airdropERC721WithSignature(req, signature); - } - - function test_benchmark_airdropSignature_erc721_100() public { - erc721.mint(signer, 1000); - vm.prank(signer); - erc721.setApprovalForAll(address(airdrop), true); - Airdrop.AirdropContentERC721[] memory contents = _getContentsERC721(100); - Airdrop.AirdropRequestERC721 memory req = Airdrop.AirdropRequestERC721({ - uid: bytes32(uint256(1)), - tokenAddress: address(erc721), - expirationTimestamp: 1000, - contents: contents - }); - bytes memory signature = _signReqERC721(req, privateKey); - - vm.prank(signer); - - airdrop.airdropERC721WithSignature(req, signature); - } - - function test_benchmark_airdropSignature_erc721_1000() public { - erc721.mint(signer, 1000); - vm.prank(signer); - erc721.setApprovalForAll(address(airdrop), true); - - Airdrop.AirdropContentERC721[] memory contents = _getContentsERC721(1000); - Airdrop.AirdropRequestERC721 memory req = Airdrop.AirdropRequestERC721({ - uid: bytes32(uint256(1)), - tokenAddress: address(erc721), - expirationTimestamp: 1000, - contents: contents - }); - bytes memory signature = _signReqERC721(req, privateKey); - - vm.prank(signer); - - airdrop.airdropERC721WithSignature(req, signature); + for (uint256 i = 0; i < contents.length; i++) { + assertEq(erc721.ownerOf(contents[i].tokenId), contents[i].recipient); + } } /*/////////////////////////////////////////////////////////////// Benchmark: Airdrop Claim ERC721 //////////////////////////////////////////////////////////////*/ - function test_benchmark_airdropClaim_erc721() public { + function test_state_airdropClaim_erc721() public { erc721.mint(signer, 100); vm.prank(signer); erc721.setApprovalForAll(address(airdrop), true); @@ -444,13 +345,15 @@ contract AirdropTest is BaseTest { vm.prank(receiver); airdrop.claimERC721(address(erc721), receiver, tokenId, proofs); + + assertEq(erc721.ownerOf(tokenId), receiver); } /*/////////////////////////////////////////////////////////////// Benchmark: Airdrop Push ERC1155 //////////////////////////////////////////////////////////////*/ - function test_benchmark_airdropPush_erc1155_10() public { + function test_state_airdropPush_erc1155() public { erc1155.mint(signer, 0, 100 ether); vm.prank(signer); erc1155.setApprovalForAll(address(airdrop), true); @@ -460,37 +363,17 @@ contract AirdropTest is BaseTest { vm.prank(signer); airdrop.airdropERC1155(address(erc1155), contents); - } - - function test_benchmark_airdropPush_erc1155_100() public { - erc1155.mint(signer, 0, 100 ether); - vm.prank(signer); - erc1155.setApprovalForAll(address(airdrop), true); - - Airdrop.AirdropContentERC1155[] memory contents = _getContentsERC1155(100); - - vm.prank(signer); - - airdrop.airdropERC1155(address(erc1155), contents); - } - - function test_benchmark_airdropPush_erc1155_1000() public { - erc1155.mint(signer, 0, 100 ether); - vm.prank(signer); - erc1155.setApprovalForAll(address(airdrop), true); - - Airdrop.AirdropContentERC1155[] memory contents = _getContentsERC1155(1000); - - vm.prank(signer); - airdrop.airdropERC1155(address(erc1155), contents); + for (uint256 i = 0; i < contents.length; i++) { + assertEq(erc1155.balanceOf(contents[i].recipient, contents[i].tokenId), contents[i].amount); + } } /*/////////////////////////////////////////////////////////////// Benchmark: Airdrop Signature ERC1155 //////////////////////////////////////////////////////////////*/ - function test_benchmark_airdropSignature_erc115_10() public { + function test_state_airdropSignature_erc115() public { erc1155.mint(signer, 0, 100 ether); vm.prank(signer); erc1155.setApprovalForAll(address(airdrop), true); @@ -507,51 +390,17 @@ contract AirdropTest is BaseTest { vm.prank(signer); airdrop.airdropERC1155WithSignature(req, signature); - } - - function test_benchmark_airdropSignature_erc115_100() public { - erc1155.mint(signer, 0, 100 ether); - vm.prank(signer); - erc1155.setApprovalForAll(address(airdrop), true); - - Airdrop.AirdropContentERC1155[] memory contents = _getContentsERC1155(100); - Airdrop.AirdropRequestERC1155 memory req = Airdrop.AirdropRequestERC1155({ - uid: bytes32(uint256(1)), - tokenAddress: address(erc1155), - expirationTimestamp: 1000, - contents: contents - }); - bytes memory signature = _signReqERC1155(req, privateKey); - - vm.prank(signer); - airdrop.airdropERC1155WithSignature(req, signature); - } - - function test_benchmark_airdropSignature_erc115_1000() public { - erc1155.mint(signer, 0, 100 ether); - vm.prank(signer); - erc1155.setApprovalForAll(address(airdrop), true); - - Airdrop.AirdropContentERC1155[] memory contents = _getContentsERC1155(1000); - Airdrop.AirdropRequestERC1155 memory req = Airdrop.AirdropRequestERC1155({ - uid: bytes32(uint256(1)), - tokenAddress: address(erc1155), - expirationTimestamp: 1000, - contents: contents - }); - bytes memory signature = _signReqERC1155(req, privateKey); - - vm.prank(signer); - - airdrop.airdropERC1155WithSignature(req, signature); + for (uint256 i = 0; i < contents.length; i++) { + assertEq(erc1155.balanceOf(contents[i].recipient, contents[i].tokenId), contents[i].amount); + } } /*/////////////////////////////////////////////////////////////// Benchmark: Airdrop Claim ERC1155 //////////////////////////////////////////////////////////////*/ - function test_benchmark_airdropClaim_erc1155() public { + function test_state_airdropClaim_erc1155() public { erc1155.mint(signer, 0, 100 ether); vm.prank(signer); erc1155.setApprovalForAll(address(airdrop), true); @@ -578,5 +427,8 @@ contract AirdropTest is BaseTest { vm.prank(receiver); airdrop.claimERC1155(address(erc1155), receiver, 0, quantity, proofs); + + assertEq(erc1155.balanceOf(receiver, 0), quantity); + assertEq(erc1155.balanceOf(signer, 0), 100 ether - quantity); } } From 04393094829c93ead3e0f2ee89e83e6bafbe3abc Mon Sep 17 00:00:00 2001 From: Jake Loo <2171134+jakeloo@users.noreply.github.com> Date: Fri, 22 Mar 2024 18:28:16 +0000 Subject: [PATCH 16/30] Update --- .../prebuilts/unaudited/airdrop/Airdrop.sol | 200 ++++++++++-------- 1 file changed, 114 insertions(+), 86 deletions(-) diff --git a/contracts/prebuilts/unaudited/airdrop/Airdrop.sol b/contracts/prebuilts/unaudited/airdrop/Airdrop.sol index 7fac087bb..859cea576 100644 --- a/contracts/prebuilts/unaudited/airdrop/Airdrop.sol +++ b/contracts/prebuilts/unaudited/airdrop/Airdrop.sol @@ -15,10 +15,12 @@ pragma solidity ^0.8.11; import "@solady/src/utils/MerkleProofLib.sol"; import "@solady/src/utils/ECDSA.sol"; import "@solady/src/utils/EIP712.sol"; +import "@solady/src/utils/SafeTransferLib.sol"; import { Initializable } from "../../../extension/Initializable.sol"; import { Ownable } from "../../../extension/Ownable.sol"; +import "../../../eip/interface/IERC20.sol"; import "../../../eip/interface/IERC721.sol"; import "../../../eip/interface/IERC1155.sol"; import "../../../lib/MerkleProof.sol"; @@ -32,11 +34,11 @@ contract Airdrop is EIP712, Initializable, Ownable { //////////////////////////////////////////////////////////////*/ /// @dev token contract address => conditionId - mapping(address => bytes32) public conditionIdForToken; + mapping(address => uint256) public tokenConditionId; /// @dev token contract address => merkle root - mapping(address => bytes32) public merkleRoot; + mapping(address => bytes32) public tokenMerkleRoot; /// @dev conditionId => hash(claimer address, token address, token id [1155]) => has claimed - mapping(bytes32 => mapping(bytes32 => bool)) private claimed; + mapping(uint256 => mapping(bytes32 => bool)) private claimed; /// @dev Mapping from request UID => whether the request is processed. mapping(bytes32 => bool) private processed; @@ -108,7 +110,8 @@ contract Airdrop is EIP712, Initializable, Ownable { error AirdropNoMerkleRoot(); error AirdropValueMismatch(); error AirdropRequestExpired(uint256 expirationTimestamp); - error AirdropVerificationFailed(); + error AirdropRequestAlreadyProcessed(); + error AirdropRequestInvalidSigner(); error AirdropInvalidTokenAddress(); /*/////////////////////////////////////////////////////////////// @@ -127,23 +130,15 @@ contract Airdrop is EIP712, Initializable, Ownable { Airdrop Push //////////////////////////////////////////////////////////////*/ - function airdropERC20(address _tokenAddress, AirdropContentERC20[] calldata _contents) external payable { - address _from = msg.sender; + function airdropNativeToken(AirdropContentERC20[] calldata _contents) external payable { uint256 len = _contents.length; uint256 nativeTokenAmount; - if (_tokenAddress == CurrencyTransferLib.NATIVE_TOKEN) { - for (uint256 i = 0; i < len; i++) { - nativeTokenAmount += _contents[i].amount; - - (bool success, ) = _contents[i].recipient.call{ value: _contents[i].amount }(""); - if (!success) { - revert AirdropFailed(); - } - } - } else { - for (uint256 i = 0; i < len; i++) { - CurrencyTransferLib.transferCurrency(_tokenAddress, _from, _contents[i].recipient, _contents[i].amount); + for (uint256 i = 0; i < len; i++) { + nativeTokenAmount += _contents[i].amount; + (bool success, ) = _contents[i].recipient.call{ value: _contents[i].amount }(""); + if (!success) { + revert AirdropFailed(); } } @@ -152,23 +147,29 @@ contract Airdrop is EIP712, Initializable, Ownable { } } + function airdropERC20(address _tokenAddress, AirdropContentERC20[] calldata _contents) external { + uint256 len = _contents.length; + uint256 nativeTokenAmount; + + for (uint256 i = 0; i < len; i++) { + SafeTransferLib.safeTransferFrom(_tokenAddress, msg.sender, _contents[i].recipient, _contents[i].amount); + } + } + function airdropERC721(address _tokenAddress, AirdropContentERC721[] calldata _contents) external { - address _from = msg.sender; uint256 len = _contents.length; for (uint256 i = 0; i < len; i++) { - IERC721(_tokenAddress).safeTransferFrom(_from, _contents[i].recipient, _contents[i].tokenId); + IERC721(_tokenAddress).safeTransferFrom(msg.sender, _contents[i].recipient, _contents[i].tokenId); } } function airdropERC1155(address _tokenAddress, AirdropContentERC1155[] calldata _contents) external { - address _from = msg.sender; - uint256 len = _contents.length; for (uint256 i = 0; i < len; i++) { IERC1155(_tokenAddress).safeTransferFrom( - _from, + msg.sender, _contents[i].recipient, _contents[i].tokenId, _contents[i].amount, @@ -188,16 +189,17 @@ contract Airdrop is EIP712, Initializable, Ownable { } // verify data - if (!_verifyReqERC20(req, signature)) { - revert AirdropVerificationFailed(); + if (!_verifyRequestSignerERC20(req, signature)) { + revert AirdropRequestInvalidSigner(); } - uint256 len = req.contents.length; + processed[req.uid] = true; + uint256 len = req.contents.length; address _from = owner(); for (uint256 i = 0; i < len; i++) { - CurrencyTransferLib.transferCurrency( + SafeTransferLib.safeTransferFrom( req.tokenAddress, _from, req.contents[i].recipient, @@ -213,10 +215,12 @@ contract Airdrop is EIP712, Initializable, Ownable { } // verify data - if (!_verifyReqERC721(req, signature)) { - revert AirdropVerificationFailed(); + if (!_verifyRequestSignerERC721(req, signature)) { + revert AirdropRequestInvalidSigner(); } + processed[req.uid] = true; + address _from = owner(); uint256 len = req.contents.length; @@ -231,11 +235,17 @@ contract Airdrop is EIP712, Initializable, Ownable { revert AirdropRequestExpired(req.expirationTimestamp); } + if (processed[req.uid]) { + revert AirdropRequestAlreadyProcessed(); + } + // verify data - if (!_verifyReqERC1155(req, signature)) { - revert AirdropVerificationFailed(); + if (!_verifyRequestSignerERC1155(req, signature)) { + revert AirdropRequestInvalidSigner(); } + processed[req.uid] = true; + address _from = owner(); uint256 len = req.contents.length; @@ -254,52 +264,57 @@ contract Airdrop is EIP712, Initializable, Ownable { Airdrop Claimable //////////////////////////////////////////////////////////////*/ - function claimERC20(address _token, address _receiver, uint256 _quantity, bytes32[] calldata _proofs) external { - bytes32 claimHash = _getClaimHashERC20(msg.sender, _token); - bytes32 conditionId = conditionIdForToken[_token]; + function claimERC20( + address _token, + address _receiver, + uint256 _quantity, + bytes32[] calldata _proofs + ) external { + bytes32 claimHash = _getClaimHashERC20(_receiver, _token); + uint256 conditionId = tokenConditionId[_token]; if (claimed[conditionId][claimHash]) { revert AirdropAlreadyClaimed(); } - bytes32 _merkleRoot = merkleRoot[_token]; - - if (_merkleRoot == bytes32(0)) { + bytes32 _tokenMerkleRoot = tokenMerkleRoot[_token]; + if (_tokenMerkleRoot == bytes32(0)) { revert AirdropNoMerkleRoot(); } - bool valid = MerkleProofLib.verify(_proofs, _merkleRoot, keccak256(abi.encodePacked(msg.sender, _quantity))); - + bool valid = MerkleProofLib.verify( + _proofs, + _tokenMerkleRoot, + keccak256(abi.encodePacked(_receiver, _quantity)) + ); if (!valid) { revert AirdropInvalidProof(); } claimed[conditionId][claimHash] = true; - if (_token == CurrencyTransferLib.NATIVE_TOKEN) { - (bool success, ) = _receiver.call{ value: _quantity }(""); - if (!success) revert AirdropFailed(); - } else { - CurrencyTransferLib.transferCurrency(_token, owner(), _receiver, _quantity); - } + SafeTransferLib.safeTransferFrom(_token, owner(), _receiver, _quantity); } - function claimERC721(address _token, address _receiver, uint256 _tokenId, bytes32[] calldata _proofs) external { - bytes32 claimHash = _getClaimHashERC721(msg.sender, _token); - bytes32 conditionId = conditionIdForToken[_token]; + function claimERC721( + address _token, + address _receiver, + uint256 _tokenId, + bytes32[] calldata _proofs + ) external { + bytes32 claimHash = _getClaimHashERC721(_receiver, _token); + uint256 conditionId = tokenConditionId[_token]; if (claimed[conditionId][claimHash]) { revert AirdropAlreadyClaimed(); } - bytes32 _merkleRoot = merkleRoot[_token]; - - if (_merkleRoot == bytes32(0)) { + bytes32 _tokenMerkleRoot = tokenMerkleRoot[_token]; + if (_tokenMerkleRoot == bytes32(0)) { revert AirdropNoMerkleRoot(); } - bool valid = MerkleProofLib.verify(_proofs, _merkleRoot, keccak256(abi.encodePacked(msg.sender, _tokenId))); - + bool valid = MerkleProofLib.verify(_proofs, _tokenMerkleRoot, keccak256(abi.encodePacked(_receiver, _tokenId))); if (!valid) { revert AirdropInvalidProof(); } @@ -316,21 +331,23 @@ contract Airdrop is EIP712, Initializable, Ownable { uint256 _quantity, bytes32[] calldata _proofs ) external { - bytes32 claimHash = _getClaimHashERC1155(msg.sender, _token, _tokenId); - bytes32 conditionId = conditionIdForToken[_token]; + bytes32 claimHash = _getClaimHashERC1155(_receiver, _token, _tokenId); + uint256 conditionId = tokenConditionId[_token]; if (claimed[conditionId][claimHash]) { revert AirdropAlreadyClaimed(); } - bytes32 _merkleRoot = merkleRoot[_token]; - - if (_merkleRoot == bytes32(0)) { + bytes32 _tokenMerkleRoot = tokenMerkleRoot[_token]; + if (_tokenMerkleRoot == bytes32(0)) { revert AirdropNoMerkleRoot(); } - bool valid = MerkleProofLib.verify(_proofs, _merkleRoot, keccak256(abi.encodePacked(msg.sender, _quantity))); - + bool valid = MerkleProofLib.verify( + _proofs, + _tokenMerkleRoot, + keccak256(abi.encodePacked(_receiver, _quantity)) + ); if (!valid) { revert AirdropInvalidProof(); } @@ -344,11 +361,15 @@ contract Airdrop is EIP712, Initializable, Ownable { Setter functions //////////////////////////////////////////////////////////////*/ - function setMerkleRoot(address _token, bytes32 _merkleRoot, bool _resetClaimStatus) external onlyOwner { - if (_resetClaimStatus || conditionIdForToken[_token] == bytes32(0)) { - conditionIdForToken[_token] = keccak256(abi.encodePacked(_token, block.number)); + function setMerkleRoot( + address _token, + bytes32 _tokenMerkleRoot, + bool _resetClaimStatus + ) external onlyOwner { + if (_resetClaimStatus || tokenConditionId[_token] == 0) { + tokenConditionId[_token] += 1; } - merkleRoot[_token] = _merkleRoot; + tokenMerkleRoot[_token] = _tokenMerkleRoot; } /*/////////////////////////////////////////////////////////////// @@ -372,11 +393,15 @@ contract Airdrop is EIP712, Initializable, Ownable { return keccak256(abi.encodePacked(_sender, _token)); } - function _getClaimHashERC1155(address _sender, address _token, uint256 _tokenId) private view returns (bytes32) { + function _getClaimHashERC1155( + address _sender, + address _token, + uint256 _tokenId + ) private view returns (bytes32) { return keccak256(abi.encodePacked(_sender, _token, _tokenId)); } - function _hashContentInfo20(AirdropContentERC20[] calldata contents) private pure returns (bytes32) { + function _hashContentInfoERC20(AirdropContentERC20[] calldata contents) private pure returns (bytes32) { bytes32[] memory contentHashes = new bytes32[](contents.length); for (uint256 i = 0; i < contents.length; i++) { contentHashes[i] = keccak256(abi.encode(CONTENT_TYPEHASH_ERC20, contents[i].recipient, contents[i].amount)); @@ -384,7 +409,7 @@ contract Airdrop is EIP712, Initializable, Ownable { return keccak256(abi.encodePacked(contentHashes)); } - function _hashContentInfo721(AirdropContentERC721[] calldata contents) private pure returns (bytes32) { + function _hashContentInfoERC721(AirdropContentERC721[] calldata contents) private pure returns (bytes32) { bytes32[] memory contentHashes = new bytes32[](contents.length); for (uint256 i = 0; i < contents.length; i++) { contentHashes[i] = keccak256( @@ -394,7 +419,7 @@ contract Airdrop is EIP712, Initializable, Ownable { return keccak256(abi.encodePacked(contentHashes)); } - function _hashContentInfo1155(AirdropContentERC1155[] calldata contents) private pure returns (bytes32) { + function _hashContentInfoERC1155(AirdropContentERC1155[] calldata contents) private pure returns (bytes32) { bytes32[] memory contentHashes = new bytes32[](contents.length); for (uint256 i = 0; i < contents.length; i++) { contentHashes[i] = keccak256( @@ -404,45 +429,48 @@ contract Airdrop is EIP712, Initializable, Ownable { return keccak256(abi.encodePacked(contentHashes)); } - function _verifyReqERC20(AirdropRequestERC20 calldata req, bytes calldata signature) private view returns (bool) { - bytes32 contentHash = _hashContentInfo20(req.contents); + function _verifyRequestSignerERC20(AirdropRequestERC20 calldata req, bytes calldata signature) + private + view + returns (bool) + { + bytes32 contentHash = _hashContentInfoERC20(req.contents); bytes32 structHash = keccak256( abi.encode(REQUEST_TYPEHASH_ERC20, req.uid, req.tokenAddress, req.expirationTimestamp, contentHash) ); bytes32 digest = _hashTypedData(structHash); address recovered = digest.recover(signature); - bool valid = recovered == owner() && !processed[req.uid]; - - return valid; + return recovered == owner(); } - function _verifyReqERC721(AirdropRequestERC721 calldata req, bytes calldata signature) private view returns (bool) { - bytes32 contentHash = _hashContentInfo721(req.contents); + function _verifyRequestSignerERC721(AirdropRequestERC721 calldata req, bytes calldata signature) + private + view + returns (bool) + { + bytes32 contentHash = _hashContentInfoERC721(req.contents); bytes32 structHash = keccak256( abi.encode(REQUEST_TYPEHASH_ERC721, req.uid, req.tokenAddress, req.expirationTimestamp, contentHash) ); bytes32 digest = _hashTypedData(structHash); address recovered = digest.recover(signature); - bool valid = recovered == owner() && !processed[req.uid]; - - return valid; + return recovered == owner(); } - function _verifyReqERC1155( - AirdropRequestERC1155 calldata req, - bytes calldata signature - ) private view returns (bool) { - bytes32 contentHash = _hashContentInfo1155(req.contents); + function _verifyRequestSignerERC1155(AirdropRequestERC1155 calldata req, bytes calldata signature) + private + view + returns (bool) + { + bytes32 contentHash = _hashContentInfoERC1155(req.contents); bytes32 structHash = keccak256( abi.encode(REQUEST_TYPEHASH_ERC1155, req.uid, req.tokenAddress, req.expirationTimestamp, contentHash) ); bytes32 digest = _hashTypedData(structHash); address recovered = digest.recover(signature); - bool valid = recovered == owner() && !processed[req.uid]; - - return valid; + return recovered == owner(); } } From 9f16b8aeb19515a60c7c0797b7cef5268ec05b55 Mon Sep 17 00:00:00 2001 From: Yash Date: Sat, 23 Mar 2024 14:14:19 +0530 Subject: [PATCH 17/30] receive and withdraw functions --- .../prebuilts/unaudited/airdrop/Airdrop.sol | 69 +++++++++---------- src/test/airdrop/Airdrop.t.sol | 2 +- src/test/benchmark/AirdropBenchmark.t.sol | 2 +- 3 files changed, 34 insertions(+), 39 deletions(-) diff --git a/contracts/prebuilts/unaudited/airdrop/Airdrop.sol b/contracts/prebuilts/unaudited/airdrop/Airdrop.sol index 859cea576..114def558 100644 --- a/contracts/prebuilts/unaudited/airdrop/Airdrop.sol +++ b/contracts/prebuilts/unaudited/airdrop/Airdrop.sol @@ -100,6 +100,8 @@ contract Airdrop is EIP712, Initializable, Ownable { "AirdropRequestERC1155(bytes32 uid,address tokenAddress,uint256 expirationTimestamp,AirdropContentERC1155[] contents)AirdropContentERC1155(address recipient,uint256 tokenId,uint256 amount)" ); + address private constant NATIVE_TOKEN_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE; + /*/////////////////////////////////////////////////////////////// Errors //////////////////////////////////////////////////////////////*/ @@ -126,6 +128,20 @@ contract Airdrop is EIP712, Initializable, Ownable { _setupOwner(_defaultAdmin); } + /*/////////////////////////////////////////////////////////////// + Receive and withdraw logic + //////////////////////////////////////////////////////////////*/ + + receive() external payable {} + + function withdraw(address _tokenAddress, uint256 _amount) external onlyOwner { + if (_tokenAddress == NATIVE_TOKEN_ADDRESS) { + SafeTransferLib.safeTransferETH(msg.sender, _amount); + } else { + SafeTransferLib.safeTransferFrom(_tokenAddress, address(this), msg.sender, _amount); + } + } + /*/////////////////////////////////////////////////////////////// Airdrop Push //////////////////////////////////////////////////////////////*/ @@ -264,12 +280,7 @@ contract Airdrop is EIP712, Initializable, Ownable { Airdrop Claimable //////////////////////////////////////////////////////////////*/ - function claimERC20( - address _token, - address _receiver, - uint256 _quantity, - bytes32[] calldata _proofs - ) external { + function claimERC20(address _token, address _receiver, uint256 _quantity, bytes32[] calldata _proofs) external { bytes32 claimHash = _getClaimHashERC20(_receiver, _token); uint256 conditionId = tokenConditionId[_token]; @@ -296,12 +307,7 @@ contract Airdrop is EIP712, Initializable, Ownable { SafeTransferLib.safeTransferFrom(_token, owner(), _receiver, _quantity); } - function claimERC721( - address _token, - address _receiver, - uint256 _tokenId, - bytes32[] calldata _proofs - ) external { + function claimERC721(address _token, address _receiver, uint256 _tokenId, bytes32[] calldata _proofs) external { bytes32 claimHash = _getClaimHashERC721(_receiver, _token); uint256 conditionId = tokenConditionId[_token]; @@ -361,11 +367,7 @@ contract Airdrop is EIP712, Initializable, Ownable { Setter functions //////////////////////////////////////////////////////////////*/ - function setMerkleRoot( - address _token, - bytes32 _tokenMerkleRoot, - bool _resetClaimStatus - ) external onlyOwner { + function setMerkleRoot(address _token, bytes32 _tokenMerkleRoot, bool _resetClaimStatus) external onlyOwner { if (_resetClaimStatus || tokenConditionId[_token] == 0) { tokenConditionId[_token] += 1; } @@ -393,11 +395,7 @@ contract Airdrop is EIP712, Initializable, Ownable { return keccak256(abi.encodePacked(_sender, _token)); } - function _getClaimHashERC1155( - address _sender, - address _token, - uint256 _tokenId - ) private view returns (bytes32) { + function _getClaimHashERC1155(address _sender, address _token, uint256 _tokenId) private view returns (bytes32) { return keccak256(abi.encodePacked(_sender, _token, _tokenId)); } @@ -429,11 +427,10 @@ contract Airdrop is EIP712, Initializable, Ownable { return keccak256(abi.encodePacked(contentHashes)); } - function _verifyRequestSignerERC20(AirdropRequestERC20 calldata req, bytes calldata signature) - private - view - returns (bool) - { + function _verifyRequestSignerERC20( + AirdropRequestERC20 calldata req, + bytes calldata signature + ) private view returns (bool) { bytes32 contentHash = _hashContentInfoERC20(req.contents); bytes32 structHash = keccak256( abi.encode(REQUEST_TYPEHASH_ERC20, req.uid, req.tokenAddress, req.expirationTimestamp, contentHash) @@ -444,11 +441,10 @@ contract Airdrop is EIP712, Initializable, Ownable { return recovered == owner(); } - function _verifyRequestSignerERC721(AirdropRequestERC721 calldata req, bytes calldata signature) - private - view - returns (bool) - { + function _verifyRequestSignerERC721( + AirdropRequestERC721 calldata req, + bytes calldata signature + ) private view returns (bool) { bytes32 contentHash = _hashContentInfoERC721(req.contents); bytes32 structHash = keccak256( abi.encode(REQUEST_TYPEHASH_ERC721, req.uid, req.tokenAddress, req.expirationTimestamp, contentHash) @@ -459,11 +455,10 @@ contract Airdrop is EIP712, Initializable, Ownable { return recovered == owner(); } - function _verifyRequestSignerERC1155(AirdropRequestERC1155 calldata req, bytes calldata signature) - private - view - returns (bool) - { + function _verifyRequestSignerERC1155( + AirdropRequestERC1155 calldata req, + bytes calldata signature + ) private view returns (bool) { bytes32 contentHash = _hashContentInfoERC1155(req.contents); bytes32 structHash = keccak256( abi.encode(REQUEST_TYPEHASH_ERC1155, req.uid, req.tokenAddress, req.expirationTimestamp, contentHash) diff --git a/src/test/airdrop/Airdrop.t.sol b/src/test/airdrop/Airdrop.t.sol index 423df6473..19b715929 100644 --- a/src/test/airdrop/Airdrop.t.sol +++ b/src/test/airdrop/Airdrop.t.sol @@ -43,7 +43,7 @@ contract AirdropTest is BaseTest { address impl = address(new Airdrop()); - airdrop = Airdrop(address(new TWProxy(impl, abi.encodeCall(Airdrop.initialize, (signer))))); + airdrop = Airdrop(payable(address(new TWProxy(impl, abi.encodeCall(Airdrop.initialize, (signer)))))); domainSeparator = keccak256( abi.encode(TYPE_HASH_EIP712, NAME_HASH, VERSION_HASH, block.chainid, address(airdrop)) diff --git a/src/test/benchmark/AirdropBenchmark.t.sol b/src/test/benchmark/AirdropBenchmark.t.sol index 15cde879d..142377ecd 100644 --- a/src/test/benchmark/AirdropBenchmark.t.sol +++ b/src/test/benchmark/AirdropBenchmark.t.sol @@ -43,7 +43,7 @@ contract AirdropBenchmarkTest is BaseTest { address impl = address(new Airdrop()); - airdrop = Airdrop(address(new TWProxy(impl, abi.encodeCall(Airdrop.initialize, (signer))))); + airdrop = Airdrop(payable(address(new TWProxy(impl, abi.encodeCall(Airdrop.initialize, (signer)))))); domainSeparator = keccak256( abi.encode(TYPE_HASH_EIP712, NAME_HASH, VERSION_HASH, block.chainid, address(airdrop)) From a08405cb86a0f39c96386075cbb2b73eb55956f4 Mon Sep 17 00:00:00 2001 From: Yash Date: Sat, 23 Mar 2024 14:25:29 +0530 Subject: [PATCH 18/30] cleanup --- contracts/prebuilts/unaudited/airdrop/Airdrop.sol | 3 --- 1 file changed, 3 deletions(-) diff --git a/contracts/prebuilts/unaudited/airdrop/Airdrop.sol b/contracts/prebuilts/unaudited/airdrop/Airdrop.sol index 114def558..97135e31f 100644 --- a/contracts/prebuilts/unaudited/airdrop/Airdrop.sol +++ b/contracts/prebuilts/unaudited/airdrop/Airdrop.sol @@ -23,8 +23,6 @@ import { Ownable } from "../../../extension/Ownable.sol"; import "../../../eip/interface/IERC20.sol"; import "../../../eip/interface/IERC721.sol"; import "../../../eip/interface/IERC1155.sol"; -import "../../../lib/MerkleProof.sol"; -import "../../../lib/CurrencyTransferLib.sol"; contract Airdrop is EIP712, Initializable, Ownable { using ECDSA for bytes32; @@ -165,7 +163,6 @@ contract Airdrop is EIP712, Initializable, Ownable { function airdropERC20(address _tokenAddress, AirdropContentERC20[] calldata _contents) external { uint256 len = _contents.length; - uint256 nativeTokenAmount; for (uint256 i = 0; i < len; i++) { SafeTransferLib.safeTransferFrom(_tokenAddress, msg.sender, _contents[i].recipient, _contents[i].amount); From 0a8755def413a43d584b7adf8561e21013fded23 Mon Sep 17 00:00:00 2001 From: Yash Date: Mon, 25 Mar 2024 14:29:35 +0530 Subject: [PATCH 19/30] fix uid check --- contracts/prebuilts/unaudited/airdrop/Airdrop.sol | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/contracts/prebuilts/unaudited/airdrop/Airdrop.sol b/contracts/prebuilts/unaudited/airdrop/Airdrop.sol index 97135e31f..19dfe95b7 100644 --- a/contracts/prebuilts/unaudited/airdrop/Airdrop.sol +++ b/contracts/prebuilts/unaudited/airdrop/Airdrop.sol @@ -201,6 +201,10 @@ contract Airdrop is EIP712, Initializable, Ownable { revert AirdropRequestExpired(req.expirationTimestamp); } + if (processed[req.uid]) { + revert AirdropRequestAlreadyProcessed(); + } + // verify data if (!_verifyRequestSignerERC20(req, signature)) { revert AirdropRequestInvalidSigner(); @@ -227,6 +231,10 @@ contract Airdrop is EIP712, Initializable, Ownable { revert AirdropRequestExpired(req.expirationTimestamp); } + if (processed[req.uid]) { + revert AirdropRequestAlreadyProcessed(); + } + // verify data if (!_verifyRequestSignerERC721(req, signature)) { revert AirdropRequestInvalidSigner(); From 636776271216f87d55fae6f49bb648fde4fb9157 Mon Sep 17 00:00:00 2001 From: Yash Date: Mon, 25 Mar 2024 15:04:08 +0530 Subject: [PATCH 20/30] test revert cases --- src/test/airdrop/Airdrop.t.sol | 223 +++++++++++++++++++++++++++++++++ 1 file changed, 223 insertions(+) diff --git a/src/test/airdrop/Airdrop.t.sol b/src/test/airdrop/Airdrop.t.sol index 19b715929..a79bdc421 100644 --- a/src/test/airdrop/Airdrop.t.sol +++ b/src/test/airdrop/Airdrop.t.sol @@ -201,6 +201,47 @@ contract AirdropTest is BaseTest { assertEq(erc20.balanceOf(signer), 100 ether - totalAmount); } + function test_state_airdropPush_nativeToken() public { + vm.deal(signer, 100 ether); + + Airdrop.AirdropContentERC20[] memory contents = _getContentsERC20(10); + + uint256 totalAmount; + for (uint256 i = 0; i < contents.length; i++) { + totalAmount += contents[i].amount; + assertEq(contents[i].recipient.balance, 0); + } + + vm.prank(signer); + airdrop.airdropNativeToken{ value: totalAmount }(contents); + + for (uint256 i = 0; i < contents.length; i++) { + assertEq(contents[i].recipient.balance, contents[i].amount); + } + + assertEq(signer.balance, 100 ether - totalAmount); + } + + function test_revert_airdropPush_nativeToken() public { + vm.deal(signer, 100 ether); + + Airdrop.AirdropContentERC20[] memory contents = _getContentsERC20(10); + + vm.prank(signer); + vm.expectRevert(abi.encodeWithSelector(Airdrop.AirdropFailed.selector)); + airdrop.airdropNativeToken{ value: 0 }(contents); + + // add some balance to airdrop contract, which it will try sending to recipeints when msg.value zero + vm.deal(address(airdrop), 50 ether); + // should revert + vm.prank(signer); + vm.expectRevert(abi.encodeWithSelector(Airdrop.AirdropValueMismatch.selector)); + airdrop.airdropNativeToken{ value: 0 }(contents); + + // contract balance should remain untouched + assertEq(address(airdrop).balance, 50 ether); + } + /*/////////////////////////////////////////////////////////////// Benchmark: Airdrop Signature ERC20 //////////////////////////////////////////////////////////////*/ @@ -231,6 +272,69 @@ contract AirdropTest is BaseTest { assertEq(erc20.balanceOf(signer), 100 ether - totalAmount); } + function test_revert_airdropSignature_erc20_expired() public { + erc20.mint(signer, 100 ether); + vm.prank(signer); + erc20.approve(address(airdrop), 100 ether); + + Airdrop.AirdropContentERC20[] memory contents = _getContentsERC20(10); + Airdrop.AirdropRequestERC20 memory req = Airdrop.AirdropRequestERC20({ + uid: bytes32(uint256(1)), + tokenAddress: address(erc20), + expirationTimestamp: 1000, + contents: contents + }); + bytes memory signature = _signReqERC20(req, privateKey); + + vm.warp(1001); + + vm.prank(signer); + vm.expectRevert(abi.encodeWithSelector(Airdrop.AirdropRequestExpired.selector, req.expirationTimestamp)); + airdrop.airdropERC20WithSignature(req, signature); + } + + function test_revert_airdropSignature_erc20_alreadyProcessed() public { + erc20.mint(signer, 100 ether); + vm.prank(signer); + erc20.approve(address(airdrop), 100 ether); + + Airdrop.AirdropContentERC20[] memory contents = _getContentsERC20(10); + Airdrop.AirdropRequestERC20 memory req = Airdrop.AirdropRequestERC20({ + uid: bytes32(uint256(1)), + tokenAddress: address(erc20), + expirationTimestamp: 1000, + contents: contents + }); + bytes memory signature = _signReqERC20(req, privateKey); + + vm.prank(signer); + + airdrop.airdropERC20WithSignature(req, signature); + + // try re-sending same request/signature + vm.expectRevert(abi.encodeWithSelector(Airdrop.AirdropRequestAlreadyProcessed.selector)); + airdrop.airdropERC20WithSignature(req, signature); + } + + function test_revert_airdropSignature_erc20_invalidSigner() public { + erc20.mint(signer, 100 ether); + vm.prank(signer); + erc20.approve(address(airdrop), 100 ether); + + Airdrop.AirdropContentERC20[] memory contents = _getContentsERC20(10); + Airdrop.AirdropRequestERC20 memory req = Airdrop.AirdropRequestERC20({ + uid: bytes32(uint256(1)), + tokenAddress: address(erc20), + expirationTimestamp: 1000, + contents: contents + }); + bytes memory signature = _signReqERC20(req, 123); + + vm.prank(signer); + vm.expectRevert(abi.encodeWithSelector(Airdrop.AirdropRequestInvalidSigner.selector)); + airdrop.airdropERC20WithSignature(req, signature); + } + /*/////////////////////////////////////////////////////////////// Benchmark: Airdrop Claim ERC20 //////////////////////////////////////////////////////////////*/ @@ -314,6 +418,67 @@ contract AirdropTest is BaseTest { } } + function test_revert_airdropSignature_erc721_expired() public { + erc721.mint(signer, 1000); + vm.prank(signer); + erc721.setApprovalForAll(address(airdrop), true); + + Airdrop.AirdropContentERC721[] memory contents = _getContentsERC721(10); + Airdrop.AirdropRequestERC721 memory req = Airdrop.AirdropRequestERC721({ + uid: bytes32(uint256(1)), + tokenAddress: address(erc721), + expirationTimestamp: 1000, + contents: contents + }); + bytes memory signature = _signReqERC721(req, privateKey); + + vm.warp(1001); + + vm.prank(signer); + vm.expectRevert(abi.encodeWithSelector(Airdrop.AirdropRequestExpired.selector, req.expirationTimestamp)); + airdrop.airdropERC721WithSignature(req, signature); + } + + function test_revert_airdropSignature_erc721_alreadyProcessed() public { + erc721.mint(signer, 1000); + vm.prank(signer); + erc721.setApprovalForAll(address(airdrop), true); + + Airdrop.AirdropContentERC721[] memory contents = _getContentsERC721(10); + Airdrop.AirdropRequestERC721 memory req = Airdrop.AirdropRequestERC721({ + uid: bytes32(uint256(1)), + tokenAddress: address(erc721), + expirationTimestamp: 1000, + contents: contents + }); + bytes memory signature = _signReqERC721(req, privateKey); + + vm.prank(signer); + airdrop.airdropERC721WithSignature(req, signature); + + // send it again + vm.expectRevert(abi.encodeWithSelector(Airdrop.AirdropRequestAlreadyProcessed.selector)); + airdrop.airdropERC721WithSignature(req, signature); + } + + function test_revert_airdropSignature_erc721_invalidSigner() public { + erc721.mint(signer, 1000); + vm.prank(signer); + erc721.setApprovalForAll(address(airdrop), true); + + Airdrop.AirdropContentERC721[] memory contents = _getContentsERC721(10); + Airdrop.AirdropRequestERC721 memory req = Airdrop.AirdropRequestERC721({ + uid: bytes32(uint256(1)), + tokenAddress: address(erc721), + expirationTimestamp: 1000, + contents: contents + }); + bytes memory signature = _signReqERC721(req, 123); + + vm.expectRevert(abi.encodeWithSelector(Airdrop.AirdropRequestInvalidSigner.selector)); + airdrop.airdropERC721WithSignature(req, signature); + } + /*/////////////////////////////////////////////////////////////// Benchmark: Airdrop Claim ERC721 //////////////////////////////////////////////////////////////*/ @@ -396,6 +561,64 @@ contract AirdropTest is BaseTest { } } + function test_revert_airdropSignature_erc115_expired() public { + erc1155.mint(signer, 0, 100 ether); + vm.prank(signer); + erc1155.setApprovalForAll(address(airdrop), true); + + Airdrop.AirdropContentERC1155[] memory contents = _getContentsERC1155(10); + Airdrop.AirdropRequestERC1155 memory req = Airdrop.AirdropRequestERC1155({ + uid: bytes32(uint256(1)), + tokenAddress: address(erc1155), + expirationTimestamp: 1000, + contents: contents + }); + bytes memory signature = _signReqERC1155(req, privateKey); + + vm.warp(1001); + + vm.expectRevert(abi.encodeWithSelector(Airdrop.AirdropRequestExpired.selector, req.expirationTimestamp)); + airdrop.airdropERC1155WithSignature(req, signature); + } + + function test_revert_airdropSignature_erc115_alreadyProcessed() public { + erc1155.mint(signer, 0, 100 ether); + vm.prank(signer); + erc1155.setApprovalForAll(address(airdrop), true); + + Airdrop.AirdropContentERC1155[] memory contents = _getContentsERC1155(10); + Airdrop.AirdropRequestERC1155 memory req = Airdrop.AirdropRequestERC1155({ + uid: bytes32(uint256(1)), + tokenAddress: address(erc1155), + expirationTimestamp: 1000, + contents: contents + }); + bytes memory signature = _signReqERC1155(req, privateKey); + + airdrop.airdropERC1155WithSignature(req, signature); + + // send it again + vm.expectRevert(abi.encodeWithSelector(Airdrop.AirdropRequestAlreadyProcessed.selector)); + airdrop.airdropERC1155WithSignature(req, signature); + } + + function test_revert_airdropSignature_erc115_invalidSigner() public { + erc1155.mint(signer, 0, 100 ether); + vm.prank(signer); + erc1155.setApprovalForAll(address(airdrop), true); + + Airdrop.AirdropContentERC1155[] memory contents = _getContentsERC1155(10); + Airdrop.AirdropRequestERC1155 memory req = Airdrop.AirdropRequestERC1155({ + uid: bytes32(uint256(1)), + tokenAddress: address(erc1155), + expirationTimestamp: 1000, + contents: contents + }); + bytes memory signature = _signReqERC1155(req, 123); + + vm.expectRevert(abi.encodeWithSelector(Airdrop.AirdropRequestInvalidSigner.selector)); + airdrop.airdropERC1155WithSignature(req, signature); + } /*/////////////////////////////////////////////////////////////// Benchmark: Airdrop Claim ERC1155 //////////////////////////////////////////////////////////////*/ From a43526d3adc4f9b799b6d679d75334a7f52d2fc0 Mon Sep 17 00:00:00 2001 From: Yash Date: Mon, 25 Mar 2024 16:10:03 +0530 Subject: [PATCH 21/30] update claim hash generation and merkle root checks --- .../prebuilts/unaudited/airdrop/Airdrop.sol | 16 +++++----- src/test/airdrop/Airdrop.t.sol | 9 +++--- src/test/benchmark/AirdropBenchmark.t.sol | 9 +++--- src/test/scripts/generateRootAirdrop1155.ts | 27 ++++++++++++++++ src/test/scripts/getProofAirdrop1155.ts | 31 +++++++++++++++++++ 5 files changed, 76 insertions(+), 16 deletions(-) create mode 100644 src/test/scripts/generateRootAirdrop1155.ts create mode 100644 src/test/scripts/getProofAirdrop1155.ts diff --git a/contracts/prebuilts/unaudited/airdrop/Airdrop.sol b/contracts/prebuilts/unaudited/airdrop/Airdrop.sol index 19dfe95b7..5d00d0f34 100644 --- a/contracts/prebuilts/unaudited/airdrop/Airdrop.sol +++ b/contracts/prebuilts/unaudited/airdrop/Airdrop.sol @@ -313,7 +313,7 @@ contract Airdrop is EIP712, Initializable, Ownable { } function claimERC721(address _token, address _receiver, uint256 _tokenId, bytes32[] calldata _proofs) external { - bytes32 claimHash = _getClaimHashERC721(_receiver, _token); + bytes32 claimHash = _getClaimHashERC721(_receiver, _token, _tokenId); uint256 conditionId = tokenConditionId[_token]; if (claimed[conditionId][claimHash]) { @@ -357,7 +357,7 @@ contract Airdrop is EIP712, Initializable, Ownable { bool valid = MerkleProofLib.verify( _proofs, _tokenMerkleRoot, - keccak256(abi.encodePacked(_receiver, _quantity)) + keccak256(abi.encodePacked(_receiver, _tokenId, _quantity)) ); if (!valid) { revert AirdropInvalidProof(); @@ -392,16 +392,16 @@ contract Airdrop is EIP712, Initializable, Ownable { version = "1"; } - function _getClaimHashERC20(address _sender, address _token) private view returns (bytes32) { - return keccak256(abi.encodePacked(_sender, _token)); + function _getClaimHashERC20(address _receiver, address _token) private view returns (bytes32) { + return keccak256(abi.encodePacked(_receiver, _token)); } - function _getClaimHashERC721(address _sender, address _token) private view returns (bytes32) { - return keccak256(abi.encodePacked(_sender, _token)); + function _getClaimHashERC721(address _receiver, address _token, uint256 _tokenId) private view returns (bytes32) { + return keccak256(abi.encodePacked(_receiver, _token, _tokenId)); } - function _getClaimHashERC1155(address _sender, address _token, uint256 _tokenId) private view returns (bytes32) { - return keccak256(abi.encodePacked(_sender, _token, _tokenId)); + function _getClaimHashERC1155(address _receiver, address _token, uint256 _tokenId) private view returns (bytes32) { + return keccak256(abi.encodePacked(_receiver, _token, _tokenId)); } function _hashContentInfoERC20(AirdropContentERC20[] calldata contents) private pure returns (bytes32) { diff --git a/src/test/airdrop/Airdrop.t.sol b/src/test/airdrop/Airdrop.t.sol index a79bdc421..a37859388 100644 --- a/src/test/airdrop/Airdrop.t.sol +++ b/src/test/airdrop/Airdrop.t.sol @@ -628,10 +628,11 @@ contract AirdropTest is BaseTest { vm.prank(signer); erc1155.setApprovalForAll(address(airdrop), true); - string[] memory inputs = new string[](3); + string[] memory inputs = new string[](4); inputs[0] = "node"; - inputs[1] = "src/test/scripts/generateRootAirdrop.ts"; - inputs[2] = Strings.toString(uint256(5)); + inputs[1] = "src/test/scripts/generateRootAirdrop1155.ts"; + inputs[2] = Strings.toString(uint256(0)); + inputs[3] = Strings.toString(uint256(5)); bytes memory result = vm.ffi(inputs); bytes32 root = abi.decode(result, (bytes32)); @@ -640,7 +641,7 @@ contract AirdropTest is BaseTest { airdrop.setMerkleRoot(address(erc1155), root, true); // generate proof - inputs[1] = "src/test/scripts/getProofAirdrop.ts"; + inputs[1] = "src/test/scripts/getProofAirdrop1155.ts"; result = vm.ffi(inputs); bytes32[] memory proofs = abi.decode(result, (bytes32[])); diff --git a/src/test/benchmark/AirdropBenchmark.t.sol b/src/test/benchmark/AirdropBenchmark.t.sol index 142377ecd..6686a1ba0 100644 --- a/src/test/benchmark/AirdropBenchmark.t.sol +++ b/src/test/benchmark/AirdropBenchmark.t.sol @@ -598,10 +598,11 @@ contract AirdropBenchmarkTest is BaseTest { vm.prank(signer); erc1155.setApprovalForAll(address(airdrop), true); - string[] memory inputs = new string[](3); + string[] memory inputs = new string[](4); inputs[0] = "node"; - inputs[1] = "src/test/scripts/generateRootAirdrop.ts"; - inputs[2] = Strings.toString(uint256(5)); + inputs[1] = "src/test/scripts/generateRootAirdrop1155.ts"; + inputs[2] = Strings.toString(uint256(0)); + inputs[3] = Strings.toString(uint256(5)); bytes memory result = vm.ffi(inputs); bytes32 root = abi.decode(result, (bytes32)); @@ -610,7 +611,7 @@ contract AirdropBenchmarkTest is BaseTest { airdrop.setMerkleRoot(address(erc1155), root, true); // generate proof - inputs[1] = "src/test/scripts/getProofAirdrop.ts"; + inputs[1] = "src/test/scripts/getProofAirdrop1155.ts"; result = vm.ffi(inputs); bytes32[] memory proofs = abi.decode(result, (bytes32[])); diff --git a/src/test/scripts/generateRootAirdrop1155.ts b/src/test/scripts/generateRootAirdrop1155.ts new file mode 100644 index 000000000..3eb821e6f --- /dev/null +++ b/src/test/scripts/generateRootAirdrop1155.ts @@ -0,0 +1,27 @@ +const { MerkleTree } = require("@thirdweb-dev/merkletree"); + +const keccak256 = require("keccak256"); +const { ethers } = require("ethers"); + +const process = require("process"); + +const members = [ + "0x92Bb439374a091c7507bE100183d8D1Ed2c9dAD3", + "0xDDdDddDdDdddDDddDDddDDDDdDdDDdDDdDDDDDDd", + "0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", +]; + +let tokenId = process.argv[2]; +let quantity = process.argv[3]; + +const hashedLeafs = members.map(l => + ethers.utils.solidityKeccak256(["address", "uint256", "uint256"], [l, tokenId, quantity]), +); + +const tree = new MerkleTree(hashedLeafs, keccak256, { + sort: true, + sortLeaves: true, + sortPairs: true, +}); + +process.stdout.write(ethers.utils.defaultAbiCoder.encode(["bytes32"], [tree.getHexRoot()])); diff --git a/src/test/scripts/getProofAirdrop1155.ts b/src/test/scripts/getProofAirdrop1155.ts new file mode 100644 index 000000000..4bb7916f2 --- /dev/null +++ b/src/test/scripts/getProofAirdrop1155.ts @@ -0,0 +1,31 @@ +const { MerkleTree } = require("@thirdweb-dev/merkletree"); + +const keccak256 = require("keccak256"); +const { ethers } = require("ethers"); + +const process = require("process"); + +const members = [ + "0x92Bb439374a091c7507bE100183d8D1Ed2c9dAD3", + "0xDDdDddDdDdddDDddDDddDDDDdDdDDdDDdDDDDDDd", + "0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", +]; + +let tokenId = process.argv[2]; +let quantity = process.argv[3]; + +const hashedLeafs = members.map(l => + ethers.utils.solidityKeccak256(["address", "uint256", "uint256"], [l, tokenId, quantity]), +); + +const tree = new MerkleTree(hashedLeafs, keccak256, { + sort: true, + sortLeaves: true, + sortPairs: true, +}); + +const expectedProof = tree.getHexProof( + ethers.utils.solidityKeccak256(["address", "uint256", "uint256"], [members[1], tokenId, quantity]), +); + +process.stdout.write(ethers.utils.defaultAbiCoder.encode(["bytes32[]"], [expectedProof])); From 489d5356358ee98468de05688e9f6b618d519207 Mon Sep 17 00:00:00 2001 From: Yash Date: Mon, 25 Mar 2024 16:29:23 +0530 Subject: [PATCH 22/30] tests --- src/test/airdrop/Airdrop.t.sol | 229 ++++++++++++++++++++++++++++++++- 1 file changed, 223 insertions(+), 6 deletions(-) diff --git a/src/test/airdrop/Airdrop.t.sol b/src/test/airdrop/Airdrop.t.sol index a37859388..3eef9d519 100644 --- a/src/test/airdrop/Airdrop.t.sol +++ b/src/test/airdrop/Airdrop.t.sol @@ -363,14 +363,86 @@ contract AirdropTest is BaseTest { address receiver = address(0xDDdDddDdDdddDDddDDddDDDDdDdDDdDDdDDDDDDd); uint256 quantity = 5; - vm.prank(receiver); - airdrop.claimERC20(address(erc20), receiver, quantity, proofs); assertEq(erc20.balanceOf(receiver), quantity); assertEq(erc20.balanceOf(signer), 100 ether - quantity); } + function test_revert_airdropClaim_erc20_alreadyClaimed() public { + erc20.mint(signer, 100 ether); + vm.prank(signer); + erc20.approve(address(airdrop), 100 ether); + + string[] memory inputs = new string[](3); + inputs[0] = "node"; + inputs[1] = "src/test/scripts/generateRootAirdrop.ts"; + inputs[2] = Strings.toString(uint256(5)); + bytes memory result = vm.ffi(inputs); + bytes32 root = abi.decode(result, (bytes32)); + + // set merkle root + vm.prank(signer); + airdrop.setMerkleRoot(address(erc20), root, true); + + // generate proof + inputs[1] = "src/test/scripts/getProofAirdrop.ts"; + result = vm.ffi(inputs); + bytes32[] memory proofs = abi.decode(result, (bytes32[])); + + address receiver = address(0xDDdDddDdDdddDDddDDddDDDDdDdDDdDDdDDDDDDd); + uint256 quantity = 5; + + airdrop.claimERC20(address(erc20), receiver, quantity, proofs); + + // revert when claiming again + vm.expectRevert(abi.encodeWithSelector(Airdrop.AirdropAlreadyClaimed.selector)); + airdrop.claimERC20(address(erc20), receiver, quantity, proofs); + } + + function test_revert_airdropClaim_erc20_noMerkleRoot() public { + erc20.mint(signer, 100 ether); + vm.prank(signer); + erc20.approve(address(airdrop), 100 ether); + + bytes32[] memory proofs; + + address receiver = address(0xDDdDddDdDdddDDddDDddDDDDdDdDDdDDdDDDDDDd); + uint256 quantity = 5; + + // revert when claiming again + vm.expectRevert(abi.encodeWithSelector(Airdrop.AirdropNoMerkleRoot.selector)); + airdrop.claimERC20(address(erc20), receiver, quantity, proofs); + } + + function test_revert_airdropClaim_erc20_invalidProof() public { + erc20.mint(signer, 100 ether); + vm.prank(signer); + erc20.approve(address(airdrop), 100 ether); + + string[] memory inputs = new string[](3); + inputs[0] = "node"; + inputs[1] = "src/test/scripts/generateRootAirdrop.ts"; + inputs[2] = Strings.toString(uint256(5)); + bytes memory result = vm.ffi(inputs); + bytes32 root = abi.decode(result, (bytes32)); + + // set merkle root + vm.prank(signer); + airdrop.setMerkleRoot(address(erc20), root, true); + + // generate proof + inputs[1] = "src/test/scripts/getProofAirdrop.ts"; + result = vm.ffi(inputs); + bytes32[] memory proofs = abi.decode(result, (bytes32[])); + + address receiver = address(0x12345); + uint256 quantity = 5; + + vm.expectRevert(abi.encodeWithSelector(Airdrop.AirdropInvalidProof.selector)); + airdrop.claimERC20(address(erc20), receiver, quantity, proofs); + } + /*/////////////////////////////////////////////////////////////// Benchmark: Airdrop Push ERC721 //////////////////////////////////////////////////////////////*/ @@ -507,13 +579,84 @@ contract AirdropTest is BaseTest { address receiver = address(0xDDdDddDdDdddDDddDDddDDDDdDdDDdDDdDDDDDDd); uint256 tokenId = 5; - vm.prank(receiver); - airdrop.claimERC721(address(erc721), receiver, tokenId, proofs); assertEq(erc721.ownerOf(tokenId), receiver); } + function test_revert_airdropClaim_erc721_alreadyClaimed() public { + erc721.mint(signer, 100); + vm.prank(signer); + erc721.setApprovalForAll(address(airdrop), true); + + string[] memory inputs = new string[](3); + inputs[0] = "node"; + inputs[1] = "src/test/scripts/generateRootAirdrop.ts"; + inputs[2] = Strings.toString(uint256(5)); + bytes memory result = vm.ffi(inputs); + bytes32 root = abi.decode(result, (bytes32)); + + // set merkle root + vm.prank(signer); + airdrop.setMerkleRoot(address(erc721), root, true); + + // generate proof + inputs[1] = "src/test/scripts/getProofAirdrop.ts"; + result = vm.ffi(inputs); + bytes32[] memory proofs = abi.decode(result, (bytes32[])); + + address receiver = address(0xDDdDddDdDdddDDddDDddDDDDdDdDDdDDdDDDDDDd); + uint256 tokenId = 5; + + airdrop.claimERC721(address(erc721), receiver, tokenId, proofs); + + // revert when claiming again + vm.expectRevert(abi.encodeWithSelector(Airdrop.AirdropAlreadyClaimed.selector)); + airdrop.claimERC721(address(erc721), receiver, tokenId, proofs); + } + + function test_revert_airdropClaim_erc721_noMerkleRoot() public { + erc721.mint(signer, 100); + vm.prank(signer); + erc721.setApprovalForAll(address(airdrop), true); + + bytes32[] memory proofs; + + address receiver = address(0xDDdDddDdDdddDDddDDddDDDDdDdDDdDDdDDDDDDd); + uint256 tokenId = 5; + + vm.expectRevert(abi.encodeWithSelector(Airdrop.AirdropNoMerkleRoot.selector)); + airdrop.claimERC721(address(erc721), receiver, tokenId, proofs); + } + + function test_revert_airdropClaim_erc721_invalidProof() public { + erc721.mint(signer, 100); + vm.prank(signer); + erc721.setApprovalForAll(address(airdrop), true); + + string[] memory inputs = new string[](3); + inputs[0] = "node"; + inputs[1] = "src/test/scripts/generateRootAirdrop.ts"; + inputs[2] = Strings.toString(uint256(5)); + bytes memory result = vm.ffi(inputs); + bytes32 root = abi.decode(result, (bytes32)); + + // set merkle root + vm.prank(signer); + airdrop.setMerkleRoot(address(erc721), root, true); + + // generate proof + inputs[1] = "src/test/scripts/getProofAirdrop.ts"; + result = vm.ffi(inputs); + bytes32[] memory proofs = abi.decode(result, (bytes32[])); + + address receiver = address(0x12345); + uint256 tokenId = 5; + + vm.expectRevert(abi.encodeWithSelector(Airdrop.AirdropInvalidProof.selector)); + airdrop.claimERC721(address(erc721), receiver, tokenId, proofs); + } + /*/////////////////////////////////////////////////////////////// Benchmark: Airdrop Push ERC1155 //////////////////////////////////////////////////////////////*/ @@ -648,11 +791,85 @@ contract AirdropTest is BaseTest { address receiver = address(0xDDdDddDdDdddDDddDDddDDDDdDdDDdDDdDDDDDDd); uint256 quantity = 5; - vm.prank(receiver); - airdrop.claimERC1155(address(erc1155), receiver, 0, quantity, proofs); assertEq(erc1155.balanceOf(receiver, 0), quantity); assertEq(erc1155.balanceOf(signer, 0), 100 ether - quantity); } + + function test_revert_airdropClaim_erc1155_alreadyClaimed() public { + erc1155.mint(signer, 0, 100 ether); + vm.prank(signer); + erc1155.setApprovalForAll(address(airdrop), true); + + string[] memory inputs = new string[](4); + inputs[0] = "node"; + inputs[1] = "src/test/scripts/generateRootAirdrop1155.ts"; + inputs[2] = Strings.toString(uint256(0)); + inputs[3] = Strings.toString(uint256(5)); + bytes memory result = vm.ffi(inputs); + bytes32 root = abi.decode(result, (bytes32)); + + // set merkle root + vm.prank(signer); + airdrop.setMerkleRoot(address(erc1155), root, true); + + // generate proof + inputs[1] = "src/test/scripts/getProofAirdrop1155.ts"; + result = vm.ffi(inputs); + bytes32[] memory proofs = abi.decode(result, (bytes32[])); + + address receiver = address(0xDDdDddDdDdddDDddDDddDDDDdDdDDdDDdDDDDDDd); + uint256 quantity = 5; + + airdrop.claimERC1155(address(erc1155), receiver, 0, quantity, proofs); + + // revert when claiming again + vm.expectRevert(abi.encodeWithSelector(Airdrop.AirdropAlreadyClaimed.selector)); + airdrop.claimERC1155(address(erc1155), receiver, 0, quantity, proofs); + } + + function test_revert_airdropClaim_erc1155_noMerkleRoot() public { + erc1155.mint(signer, 0, 100 ether); + vm.prank(signer); + erc1155.setApprovalForAll(address(airdrop), true); + + // generate proof + bytes32[] memory proofs; + + address receiver = address(0xDDdDddDdDdddDDddDDddDDDDdDdDDdDDdDDDDDDd); + uint256 quantity = 5; + + vm.expectRevert(abi.encodeWithSelector(Airdrop.AirdropNoMerkleRoot.selector)); + airdrop.claimERC1155(address(erc1155), receiver, 0, quantity, proofs); + } + + function test_revert_airdropClaim_erc1155_invalidProof() public { + erc1155.mint(signer, 0, 100 ether); + vm.prank(signer); + erc1155.setApprovalForAll(address(airdrop), true); + + string[] memory inputs = new string[](4); + inputs[0] = "node"; + inputs[1] = "src/test/scripts/generateRootAirdrop1155.ts"; + inputs[2] = Strings.toString(uint256(0)); + inputs[3] = Strings.toString(uint256(5)); + bytes memory result = vm.ffi(inputs); + bytes32 root = abi.decode(result, (bytes32)); + + // set merkle root + vm.prank(signer); + airdrop.setMerkleRoot(address(erc1155), root, true); + + // generate proof + inputs[1] = "src/test/scripts/getProofAirdrop1155.ts"; + result = vm.ffi(inputs); + bytes32[] memory proofs = abi.decode(result, (bytes32[])); + + address receiver = address(0x12345); + uint256 quantity = 5; + + vm.expectRevert(abi.encodeWithSelector(Airdrop.AirdropInvalidProof.selector)); + airdrop.claimERC1155(address(erc1155), receiver, 0, quantity, proofs); + } } From f5bc18312355956868b29a61d4d5d4655d342ae8 Mon Sep 17 00:00:00 2001 From: Yash Date: Mon, 25 Mar 2024 18:35:10 +0530 Subject: [PATCH 23/30] gasreport --- gasreport.txt | 200 +++++++++++++++++++++++++++++++------------------- 1 file changed, 125 insertions(+), 75 deletions(-) diff --git a/gasreport.txt b/gasreport.txt index 16642e3cb..5cd46c496 100644 --- a/gasreport.txt +++ b/gasreport.txt @@ -1,16 +1,30 @@ -No files changed, compilation skipped +Compiling 1 files with 0.8.23 +Solc 0.8.23 finished in 22.27s +Compiler run successful with warnings: +Warning (5667): Unused function parameter. Remove or comment out the variable name to silence this warning. + --> contracts/prebuilts/pack/Pack.sol:101:9: + | +101 | address[] memory _trustedForwarders, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Warning (2018): Function state mutability can be restricted to pure + --> contracts/prebuilts/unaudited/airdrop/Airdrop.sol:395:5: + | +395 | function _getClaimHashERC20(address _receiver, address _token) private view returns (bytes32) { + | ^ (Relevant source part starts here and spans across multiple lines). + +Warning (2018): Function state mutability can be restricted to pure + --> contracts/prebuilts/unaudited/airdrop/Airdrop.sol:399:5: + | +399 | function _getClaimHashERC721(address _receiver, address _token, uint256 _tokenId) private view returns (bytes32) { + | ^ (Relevant source part starts here and spans across multiple lines). + +Warning (2018): Function state mutability can be restricted to pure + --> contracts/prebuilts/unaudited/airdrop/Airdrop.sol:403:5: + | +403 | function _getClaimHashERC1155(address _receiver, address _token, uint256 _tokenId) private view returns (bytes32) { + | ^ (Relevant source part starts here and spans across multiple lines). -Ran 3 tests for src/test/benchmark/EditionStakeBenchmark.t.sol:EditionStakeBenchmarkTest -[PASS] test_benchmark_editionStake_claimRewards() (gas: 98765) -[PASS] test_benchmark_editionStake_stake() (gas: 203676) -[PASS] test_benchmark_editionStake_withdraw() (gas: 94296) -Suite result: ok. 3 passed; 0 failed; 0 skipped; finished in 652.02ms (715.83µs CPU time) - -Ran 3 tests for src/test/benchmark/PackBenchmark.t.sol:PackBenchmarkTest -[PASS] test_benchmark_pack_addPackContents() (gas: 312595) -[PASS] test_benchmark_pack_createPack() (gas: 1419379) -[PASS] test_benchmark_pack_openPack() (gas: 306658) -Suite result: ok. 3 passed; 0 failed; 0 skipped; finished in 660.31ms (3.57ms CPU time) Ran 5 tests for src/test/benchmark/SignatureDropBenchmark.t.sol:SignatureDropBenchmarkTest [PASS] test_benchmark_signatureDrop_claim_five_tokens() (gas: 185688) @@ -18,25 +32,29 @@ Ran 5 tests for src/test/benchmark/SignatureDropBenchmark.t.sol:SignatureDropBen [PASS] test_benchmark_signatureDrop_lazyMint_for_delayed_reveal() (gas: 249057) [PASS] test_benchmark_signatureDrop_reveal() (gas: 49802) [PASS] test_benchmark_signatureDrop_setClaimConditions() (gas: 100719) -Suite result: ok. 5 passed; 0 failed; 0 skipped; finished in 667.52ms (808.25µs CPU time) +Suite result: ok. 5 passed; 0 failed; 0 skipped; finished in 777.81ms (1.16ms CPU time) + +Ran 3 tests for src/test/benchmark/EditionStakeBenchmark.t.sol:EditionStakeBenchmarkTest +[PASS] test_benchmark_editionStake_claimRewards() (gas: 98765) +[PASS] test_benchmark_editionStake_stake() (gas: 203676) +[PASS] test_benchmark_editionStake_withdraw() (gas: 94296) +Suite result: ok. 3 passed; 0 failed; 0 skipped; finished in 777.55ms (1.41ms CPU time) Ran 3 tests for src/test/benchmark/NFTStakeBenchmark.t.sol:NFTStakeBenchmarkTest [PASS] test_benchmark_nftStake_claimRewards() (gas: 99831) [PASS] test_benchmark_nftStake_stake_five_tokens() (gas: 553577) [PASS] test_benchmark_nftStake_withdraw() (gas: 96144) -Suite result: ok. 3 passed; 0 failed; 0 skipped; finished in 670.59ms (846.13µs CPU time) +Suite result: ok. 3 passed; 0 failed; 0 skipped; finished in 781.23ms (899.88µs CPU time) + +Ran 3 tests for src/test/benchmark/PackBenchmark.t.sol:PackBenchmarkTest +[PASS] test_benchmark_pack_addPackContents() (gas: 312595) +[PASS] test_benchmark_pack_createPack() (gas: 1419379) +[PASS] test_benchmark_pack_openPack() (gas: 302612) +Suite result: ok. 3 passed; 0 failed; 0 skipped; finished in 783.66ms (3.44ms CPU time) Ran 1 test for src/test/smart-wallet/utils/AABenchmarkPrepare.sol:AABenchmarkPrepare [PASS] test_prepareBenchmarkFile() (gas: 2955770) -Suite result: ok. 1 passed; 0 failed; 0 skipped; finished in 672.41ms (20.88ms CPU time) - -Ran 1 test for src/test/benchmark/AirdropERC20Benchmark.t.sol:AirdropERC20BenchmarkTest -[PASS] test_benchmark_airdropERC20_airdrop() (gas: 32443785) -Suite result: ok. 1 passed; 0 failed; 0 skipped; finished in 676.87ms (15.63ms CPU time) - -Ran 1 test for src/test/benchmark/AirdropERC721Benchmark.t.sol:AirdropERC721BenchmarkTest -[PASS] test_benchmark_airdropERC721_airdrop() (gas: 42241588) -Suite result: ok. 1 passed; 0 failed; 0 skipped; finished in 685.01ms (16.22ms CPU time) +Suite result: ok. 1 passed; 0 failed; 0 skipped; finished in 797.24ms (20.05ms CPU time) Ran 14 tests for src/test/benchmark/AccountBenchmark.t.sol:AccountBenchmarkTest [PASS] test_state_accountReceivesNativeTokens() (gas: 34537) @@ -53,83 +71,109 @@ Ran 14 tests for src/test/benchmark/AccountBenchmark.t.sol:AccountBenchmarkTest [PASS] test_state_receiveERC1155NFT() (gas: 66043) [PASS] test_state_receiveERC721NFT() (gas: 100196) [PASS] test_state_transferOutsNativeTokens() (gas: 133673) -Suite result: ok. 14 passed; 0 failed; 0 skipped; finished in 738.85ms (21.33ms CPU time) +Suite result: ok. 14 passed; 0 failed; 0 skipped; finished in 798.25ms (21.10ms CPU time) -Ran 2 tests for src/test/benchmark/MultiwrapBenchmark.t.sol:MultiwrapBenchmarkTest -[PASS] test_benchmark_multiwrap_unwrap() (gas: 152040) -[PASS] test_benchmark_multiwrap_wrap() (gas: 480722) -Suite result: ok. 2 passed; 0 failed; 0 skipped; finished in 222.28ms (685.96µs CPU time) +Ran 1 test for src/test/benchmark/AirdropERC20Benchmark.t.sol:AirdropERC20BenchmarkTest +[PASS] test_benchmark_airdropERC20_airdrop() (gas: 32443785) +Suite result: ok. 1 passed; 0 failed; 0 skipped; finished in 809.63ms (27.77ms CPU time) + +Ran 1 test for src/test/benchmark/AirdropERC721Benchmark.t.sol:AirdropERC721BenchmarkTest +[PASS] test_benchmark_airdropERC721_airdrop() (gas: 42241588) +Suite result: ok. 1 passed; 0 failed; 0 skipped; finished in 818.36ms (26.52ms CPU time) Ran 3 tests for src/test/benchmark/PackVRFDirectBenchmark.t.sol:PackVRFDirectBenchmarkTest [PASS] test_benchmark_packvrf_createPack() (gas: 1392387) [PASS] test_benchmark_packvrf_openPack() (gas: 150677) [PASS] test_benchmark_packvrf_openPackAndClaimRewards() (gas: 3621) -Suite result: ok. 3 passed; 0 failed; 0 skipped; finished in 217.48ms (1.99ms CPU time) +Suite result: ok. 3 passed; 0 failed; 0 skipped; finished in 232.32ms (1.99ms CPU time) Ran 4 tests for src/test/benchmark/TokenERC1155Benchmark.t.sol:TokenERC1155BenchmarkTest [PASS] test_benchmark_tokenERC1155_burn() (gas: 30352) [PASS] test_benchmark_tokenERC1155_mintTo() (gas: 144229) [PASS] test_benchmark_tokenERC1155_mintWithSignature_pay_with_ERC20() (gas: 307291) [PASS] test_benchmark_tokenERC1155_mintWithSignature_pay_with_native_token() (gas: 318712) -Suite result: ok. 4 passed; 0 failed; 0 skipped; finished in 229.46ms (1.60ms CPU time) +Suite result: ok. 4 passed; 0 failed; 0 skipped; finished in 297.36ms (1.61ms CPU time) -Ran 3 tests for src/test/benchmark/TokenERC20Benchmark.t.sol:TokenERC20BenchmarkTest -[PASS] test_benchmark_tokenERC20_mintTo() (gas: 139513) -[PASS] test_benchmark_tokenERC20_mintWithSignature_pay_with_ERC20() (gas: 221724) -[PASS] test_benchmark_tokenERC20_mintWithSignature_pay_with_native_token() (gas: 228786) -Suite result: ok. 3 passed; 0 failed; 0 skipped; finished in 229.79ms (1.31ms CPU time) +Ran 2 tests for src/test/benchmark/MultiwrapBenchmark.t.sol:MultiwrapBenchmarkTest +[PASS] test_benchmark_multiwrap_unwrap() (gas: 152040) +[PASS] test_benchmark_multiwrap_wrap() (gas: 480722) +Suite result: ok. 2 passed; 0 failed; 0 skipped; finished in 310.37ms (726.13µs CPU time) Ran 1 test for src/test/benchmark/AirdropERC1155Benchmark.t.sol:AirdropERC1155BenchmarkTest [PASS] test_benchmark_airdropERC1155_airdrop() (gas: 38536544) -Suite result: ok. 1 passed; 0 failed; 0 skipped; finished in 262.58ms (18.95ms CPU time) +Suite result: ok. 1 passed; 0 failed; 0 skipped; finished in 273.46ms (21.60ms CPU time) -Ran 3 tests for src/test/benchmark/TokenStakeBenchmark.t.sol:TokenStakeBenchmarkTest -[PASS] test_benchmark_tokenStake_claimRewards() (gas: 101098) -[PASS] test_benchmark_tokenStake_stake() (gas: 195556) -[PASS] test_benchmark_tokenStake_withdraw() (gas: 104792) -Suite result: ok. 3 passed; 0 failed; 0 skipped; finished in 205.37ms (599.46µs CPU time) +Ran 3 tests for src/test/benchmark/TokenERC20Benchmark.t.sol:TokenERC20BenchmarkTest +[PASS] test_benchmark_tokenERC20_mintTo() (gas: 139513) +[PASS] test_benchmark_tokenERC20_mintWithSignature_pay_with_ERC20() (gas: 221724) +[PASS] test_benchmark_tokenERC20_mintWithSignature_pay_with_native_token() (gas: 228786) +Suite result: ok. 3 passed; 0 failed; 0 skipped; finished in 339.25ms (3.19ms CPU time) Ran 4 tests for src/test/benchmark/TokenERC721Benchmark.t.sol:TokenERC721BenchmarkTest [PASS] test_benchmark_tokenERC721_burn() (gas: 40392) [PASS] test_benchmark_tokenERC721_mintTo() (gas: 172834) [PASS] test_benchmark_tokenERC721_mintWithSignature_pay_with_ERC20() (gas: 301844) [PASS] test_benchmark_tokenERC721_mintWithSignature_pay_with_native_token() (gas: 308814) -Suite result: ok. 4 passed; 0 failed; 0 skipped; finished in 303.02ms (1.56ms CPU time) +Suite result: ok. 4 passed; 0 failed; 0 skipped; finished in 311.67ms (1.86ms CPU time) + +Ran 3 tests for src/test/benchmark/TokenStakeBenchmark.t.sol:TokenStakeBenchmarkTest +[PASS] test_benchmark_tokenStake_claimRewards() (gas: 101098) +[PASS] test_benchmark_tokenStake_stake() (gas: 195556) +[PASS] test_benchmark_tokenStake_withdraw() (gas: 104792) +Suite result: ok. 3 passed; 0 failed; 0 skipped; finished in 194.65ms (694.21µs CPU time) Ran 21 tests for src/test/benchmark/AirdropBenchmark.t.sol:AirdropBenchmarkTest -[PASS] test_benchmark_airdropClaim_erc1155() (gas: 103778) -[PASS] test_benchmark_airdropClaim_erc20() (gas: 109548) -[PASS] test_benchmark_airdropClaim_erc721() (gas: 107657) -[PASS] test_benchmark_airdropPush_erc1155_10() (gas: 366949) -[PASS] test_benchmark_airdropPush_erc1155_100() (gas: 3263174) -[PASS] test_benchmark_airdropPush_erc1155_1000() (gas: 32346075) -[PASS] test_benchmark_airdropPush_erc20_10() (gas: 358772) -[PASS] test_benchmark_airdropPush_erc20_100() (gas: 3137837) -[PASS] test_benchmark_airdropPush_erc20_1000() (gas: 31113395) -[PASS] test_benchmark_airdropPush_erc721_10() (gas: 423341) -[PASS] test_benchmark_airdropPush_erc721_100() (gas: 3834095) -[PASS] test_benchmark_airdropPush_erc721_1000() (gas: 38105680) -[PASS] test_benchmark_airdropSignature_erc115_10() (gas: 395103) -[PASS] test_benchmark_airdropSignature_erc115_100() (gas: 3436492) -[PASS] test_benchmark_airdropSignature_erc115_1000() (gas: 34312635) -[PASS] test_benchmark_airdropSignature_erc20_10() (gas: 384317) -[PASS] test_benchmark_airdropSignature_erc20_100() (gas: 3284223) -[PASS] test_benchmark_airdropSignature_erc20_1000() (gas: 32869617) -[PASS] test_benchmark_airdropSignature_erc721_10() (gas: 448536) -[PASS] test_benchmark_airdropSignature_erc721_100() (gas: 3987990) -[PASS] test_benchmark_airdropSignature_erc721_1000() (gas: 39670457) -Suite result: ok. 21 passed; 0 failed; 0 skipped; finished in 1.30s (1.14s CPU time) +[PASS] test_benchmark_airdropClaim_erc1155() (gas: 103870) +[PASS] test_benchmark_airdropClaim_erc20() (gas: 108214) +[PASS] test_benchmark_airdropClaim_erc721() (gas: 107404) +[PASS] test_benchmark_airdropPush_erc1155_10() (gas: 366803) +[PASS] test_benchmark_airdropPush_erc1155_100() (gas: 3262938) +[PASS] test_benchmark_airdropPush_erc1155_1000() (gas: 32344939) +[PASS] test_benchmark_airdropPush_erc20_10() (gas: 342387) +[PASS] test_benchmark_airdropPush_erc20_100() (gas: 2972974) +[PASS] test_benchmark_airdropPush_erc20_1000() (gas: 29348844) +[PASS] test_benchmark_airdropPush_erc721_10() (gas: 423239) +[PASS] test_benchmark_airdropPush_erc721_100() (gas: 3833903) +[PASS] test_benchmark_airdropPush_erc721_1000() (gas: 38104588) +[PASS] test_benchmark_airdropSignature_erc115_10() (gas: 415414) +[PASS] test_benchmark_airdropSignature_erc115_100() (gas: 3456815) +[PASS] test_benchmark_airdropSignature_erc115_1000() (gas: 34332958) +[PASS] test_benchmark_airdropSignature_erc20_10() (gas: 388010) +[PASS] test_benchmark_airdropSignature_erc20_100() (gas: 3137606) +[PASS] test_benchmark_airdropSignature_erc20_1000() (gas: 30935300) +[PASS] test_benchmark_airdropSignature_erc721_10() (gas: 468925) +[PASS] test_benchmark_airdropSignature_erc721_100() (gas: 4008367) +[PASS] test_benchmark_airdropSignature_erc721_1000() (gas: 39690834) +Suite result: ok. 21 passed; 0 failed; 0 skipped; finished in 1.63s (1.75s CPU time) + +Ran 21 tests for src/test/benchmark/AirdropBenchmarkAlt.t.sol:AirdropBenchmarkAltTest +[PASS] test_benchmark_airdropClaim_erc1155() (gas: 103870) +[PASS] test_benchmark_airdropClaim_erc20() (gas: 108214) +[PASS] test_benchmark_airdropClaim_erc721() (gas: 107404) +[PASS] test_benchmark_airdropPush_erc1155_10() (gas: 366803) +[PASS] test_benchmark_airdropPush_erc1155_100() (gas: 3262938) +[PASS] test_benchmark_airdropPush_erc1155_1000() (gas: 32344939) +[PASS] test_benchmark_airdropPush_erc20_10() (gas: 342387) +[PASS] test_benchmark_airdropPush_erc20_100() (gas: 2972974) +[PASS] test_benchmark_airdropPush_erc20_1000() (gas: 29348844) +[PASS] test_benchmark_airdropPush_erc721_10() (gas: 423239) +[PASS] test_benchmark_airdropPush_erc721_100() (gas: 3833903) +[PASS] test_benchmark_airdropPush_erc721_1000() (gas: 38104588) +[PASS] test_benchmark_airdropSignature_erc115_10() (gas: 415414) +[PASS] test_benchmark_airdropSignature_erc115_100() (gas: 3456815) +[PASS] test_benchmark_airdropSignature_erc115_1000() (gas: 34332958) +[PASS] test_benchmark_airdropSignature_erc20_10() (gas: 388010) +[PASS] test_benchmark_airdropSignature_erc20_100() (gas: 3137606) +[PASS] test_benchmark_airdropSignature_erc20_1000() (gas: 30935300) +[PASS] test_benchmark_airdropSignature_erc721_10() (gas: 468925) +[PASS] test_benchmark_airdropSignature_erc721_100() (gas: 4008367) +[PASS] test_benchmark_airdropSignature_erc721_1000() (gas: 39690834) +Suite result: ok. 21 passed; 0 failed; 0 skipped; finished in 866.76ms (1.41s CPU time) Ran 2 tests for src/test/benchmark/DropERC20Benchmark.t.sol:DropERC20BenchmarkTest [PASS] test_benchmark_dropERC20_claim() (gas: 291508) [PASS] test_benchmark_dropERC20_setClaimConditions_five_conditions() (gas: 530026) -Suite result: ok. 2 passed; 0 failed; 0 skipped; finished in 444.21ms (516.94ms CPU time) - -Ran 3 tests for src/test/benchmark/DropERC1155Benchmark.t.sol:DropERC1155BenchmarkTest -[PASS] test_benchmark_dropERC1155_claim() (gas: 245552) -[PASS] test_benchmark_dropERC1155_lazyMint() (gas: 146425) -[PASS] test_benchmark_dropERC1155_setClaimConditions_five_conditions() (gas: 525725) -Suite result: ok. 3 passed; 0 failed; 0 skipped; finished in 1.31s (677.77ms CPU time) +Suite result: ok. 2 passed; 0 failed; 0 skipped; finished in 915.15ms (767.18ms CPU time) Ran 5 tests for src/test/benchmark/DropERC721Benchmark.t.sol:DropERC721BenchmarkTest [PASS] test_benchmark_dropERC721_claim_five_tokens() (gas: 273303) @@ -137,10 +181,16 @@ Ran 5 tests for src/test/benchmark/DropERC721Benchmark.t.sol:DropERC721Benchmark [PASS] test_benchmark_dropERC721_lazyMint_for_delayed_reveal() (gas: 248985) [PASS] test_benchmark_dropERC721_reveal() (gas: 49433) [PASS] test_benchmark_dropERC721_setClaimConditions_five_conditions() (gas: 529470) -Suite result: ok. 5 passed; 0 failed; 0 skipped; finished in 429.81ms (520.49ms CPU time) +Suite result: ok. 5 passed; 0 failed; 0 skipped; finished in 462.45ms (550.25ms CPU time) + +Ran 3 tests for src/test/benchmark/DropERC1155Benchmark.t.sol:DropERC1155BenchmarkTest +[PASS] test_benchmark_dropERC1155_claim() (gas: 245552) +[PASS] test_benchmark_dropERC1155_lazyMint() (gas: 146425) +[PASS] test_benchmark_dropERC1155_setClaimConditions_five_conditions() (gas: 525725) +Suite result: ok. 3 passed; 0 failed; 0 skipped; finished in 1.79s (1.05s CPU time) -Ran 19 test suites in 1.52s (10.57s CPU time): 82 tests passed, 0 failed, 0 skipped (82 total tests) +Ran 20 test suites in 2.00s (13.97s CPU time): 103 tests passed, 0 failed, 0 skipped (103 total tests) test_benchmark_packvrf_openPackAndClaimRewards() (gas: 0 (0.000%)) test_benchmark_pack_createPack() (gas: 6511 (0.461%)) test_benchmark_airdropERC721_airdrop() (gas: 329052 (0.785%)) @@ -194,7 +244,7 @@ test_state_executeBatchTransaction() (gas: 36192 (90.766%)) test_state_executeTransaction() (gas: 33156 (92.783%)) test_state_contractMetadata() (gas: 57800 (102.288%)) test_benchmark_editionStake_withdraw() (gas: 47932 (103.382%)) -test_benchmark_pack_openPack() (gas: 164798 (116.169%)) +test_benchmark_pack_openPack() (gas: 160752 (113.317%)) test_benchmark_tokenStake_withdraw() (gas: 57396 (121.099%)) test_benchmark_nftStake_withdraw() (gas: 58068 (152.506%)) test_state_accountReceivesNativeTokens() (gas: 23500 (212.920%)) @@ -202,4 +252,4 @@ test_benchmark_dropERC721_reveal() (gas: 35701 (259.984%)) test_benchmark_tokenERC721_burn() (gas: 31438 (351.106%)) test_benchmark_signatureDrop_reveal() (gas: 39155 (367.756%)) test_benchmark_tokenERC1155_burn() (gas: 24624 (429.888%)) -Overall gas change: 3379969 (2.656%) +Overall gas change: 3375923 (2.652%) From 3db324d6c71987a82895a87572c46aa5f4468325 Mon Sep 17 00:00:00 2001 From: Jake Loo <2171134+jakeloo@users.noreply.github.com> Date: Mon, 25 Mar 2024 15:35:39 +0000 Subject: [PATCH 24/30] Add onlyOwner for airdrop functions --- .../prebuilts/unaudited/airdrop/Airdrop.sol | 99 ++++++++----------- 1 file changed, 39 insertions(+), 60 deletions(-) diff --git a/contracts/prebuilts/unaudited/airdrop/Airdrop.sol b/contracts/prebuilts/unaudited/airdrop/Airdrop.sol index 5d00d0f34..015a2514b 100644 --- a/contracts/prebuilts/unaudited/airdrop/Airdrop.sol +++ b/contracts/prebuilts/unaudited/airdrop/Airdrop.sol @@ -17,8 +17,8 @@ import "@solady/src/utils/ECDSA.sol"; import "@solady/src/utils/EIP712.sol"; import "@solady/src/utils/SafeTransferLib.sol"; -import { Initializable } from "../../../extension/Initializable.sol"; -import { Ownable } from "../../../extension/Ownable.sol"; +import {Initializable} from "../../../extension/Initializable.sol"; +import {Ownable} from "../../../extension/Ownable.sol"; import "../../../eip/interface/IERC20.sol"; import "../../../eip/interface/IERC721.sol"; @@ -77,26 +77,22 @@ contract Airdrop is EIP712, Initializable, Ownable { AirdropContentERC1155[] contents; } - bytes32 private constant CONTENT_TYPEHASH_ERC20 = - keccak256("AirdropContentERC20(address recipient,uint256 amount)"); - bytes32 private constant REQUEST_TYPEHASH_ERC20 = - keccak256( - "AirdropRequestERC20(bytes32 uid,address tokenAddress,uint256 expirationTimestamp,AirdropContentERC20[] contents)AirdropContentERC20(address recipient,uint256 amount)" - ); + bytes32 private constant CONTENT_TYPEHASH_ERC20 = keccak256("AirdropContentERC20(address recipient,uint256 amount)"); + bytes32 private constant REQUEST_TYPEHASH_ERC20 = keccak256( + "AirdropRequestERC20(bytes32 uid,address tokenAddress,uint256 expirationTimestamp,AirdropContentERC20[] contents)AirdropContentERC20(address recipient,uint256 amount)" + ); bytes32 private constant CONTENT_TYPEHASH_ERC721 = keccak256("AirdropContentERC721(address recipient,uint256 tokenId)"); - bytes32 private constant REQUEST_TYPEHASH_ERC721 = - keccak256( - "AirdropRequestERC721(bytes32 uid,address tokenAddress,uint256 expirationTimestamp,AirdropContentERC721[] contents)AirdropContentERC721(address recipient,uint256 tokenId)" - ); + bytes32 private constant REQUEST_TYPEHASH_ERC721 = keccak256( + "AirdropRequestERC721(bytes32 uid,address tokenAddress,uint256 expirationTimestamp,AirdropContentERC721[] contents)AirdropContentERC721(address recipient,uint256 tokenId)" + ); bytes32 private constant CONTENT_TYPEHASH_ERC1155 = keccak256("AirdropContentERC1155(address recipient,uint256 tokenId,uint256 amount)"); - bytes32 private constant REQUEST_TYPEHASH_ERC1155 = - keccak256( - "AirdropRequestERC1155(bytes32 uid,address tokenAddress,uint256 expirationTimestamp,AirdropContentERC1155[] contents)AirdropContentERC1155(address recipient,uint256 tokenId,uint256 amount)" - ); + bytes32 private constant REQUEST_TYPEHASH_ERC1155 = keccak256( + "AirdropRequestERC1155(bytes32 uid,address tokenAddress,uint256 expirationTimestamp,AirdropContentERC1155[] contents)AirdropContentERC1155(address recipient,uint256 tokenId,uint256 amount)" + ); address private constant NATIVE_TOKEN_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE; @@ -144,13 +140,13 @@ contract Airdrop is EIP712, Initializable, Ownable { Airdrop Push //////////////////////////////////////////////////////////////*/ - function airdropNativeToken(AirdropContentERC20[] calldata _contents) external payable { + function airdropNativeToken(AirdropContentERC20[] calldata _contents) external payable onlyOwner { uint256 len = _contents.length; uint256 nativeTokenAmount; for (uint256 i = 0; i < len; i++) { nativeTokenAmount += _contents[i].amount; - (bool success, ) = _contents[i].recipient.call{ value: _contents[i].amount }(""); + (bool success,) = _contents[i].recipient.call{value: _contents[i].amount}(""); if (!success) { revert AirdropFailed(); } @@ -161,7 +157,7 @@ contract Airdrop is EIP712, Initializable, Ownable { } } - function airdropERC20(address _tokenAddress, AirdropContentERC20[] calldata _contents) external { + function airdropERC20(address _tokenAddress, AirdropContentERC20[] calldata _contents) external onlyOwner { uint256 len = _contents.length; for (uint256 i = 0; i < len; i++) { @@ -169,7 +165,7 @@ contract Airdrop is EIP712, Initializable, Ownable { } } - function airdropERC721(address _tokenAddress, AirdropContentERC721[] calldata _contents) external { + function airdropERC721(address _tokenAddress, AirdropContentERC721[] calldata _contents) external onlyOwner { uint256 len = _contents.length; for (uint256 i = 0; i < len; i++) { @@ -177,16 +173,12 @@ contract Airdrop is EIP712, Initializable, Ownable { } } - function airdropERC1155(address _tokenAddress, AirdropContentERC1155[] calldata _contents) external { + function airdropERC1155(address _tokenAddress, AirdropContentERC1155[] calldata _contents) external onlyOwner { uint256 len = _contents.length; for (uint256 i = 0; i < len; i++) { IERC1155(_tokenAddress).safeTransferFrom( - msg.sender, - _contents[i].recipient, - _contents[i].tokenId, - _contents[i].amount, - "" + msg.sender, _contents[i].recipient, _contents[i].tokenId, _contents[i].amount, "" ); } } @@ -216,12 +208,7 @@ contract Airdrop is EIP712, Initializable, Ownable { address _from = owner(); for (uint256 i = 0; i < len; i++) { - SafeTransferLib.safeTransferFrom( - req.tokenAddress, - _from, - req.contents[i].recipient, - req.contents[i].amount - ); + SafeTransferLib.safeTransferFrom(req.tokenAddress, _from, req.contents[i].recipient, req.contents[i].amount); } } @@ -272,11 +259,7 @@ contract Airdrop is EIP712, Initializable, Ownable { for (uint256 i = 0; i < len; i++) { IERC1155(req.tokenAddress).safeTransferFrom( - _from, - req.contents[i].recipient, - req.contents[i].tokenId, - req.contents[i].amount, - "" + _from, req.contents[i].recipient, req.contents[i].tokenId, req.contents[i].amount, "" ); } } @@ -298,11 +281,7 @@ contract Airdrop is EIP712, Initializable, Ownable { revert AirdropNoMerkleRoot(); } - bool valid = MerkleProofLib.verify( - _proofs, - _tokenMerkleRoot, - keccak256(abi.encodePacked(_receiver, _quantity)) - ); + bool valid = MerkleProofLib.verify(_proofs, _tokenMerkleRoot, keccak256(abi.encodePacked(_receiver, _quantity))); if (!valid) { revert AirdropInvalidProof(); } @@ -355,9 +334,7 @@ contract Airdrop is EIP712, Initializable, Ownable { } bool valid = MerkleProofLib.verify( - _proofs, - _tokenMerkleRoot, - keccak256(abi.encodePacked(_receiver, _tokenId, _quantity)) + _proofs, _tokenMerkleRoot, keccak256(abi.encodePacked(_receiver, _tokenId, _quantity)) ); if (!valid) { revert AirdropInvalidProof(); @@ -415,9 +392,8 @@ contract Airdrop is EIP712, Initializable, Ownable { function _hashContentInfoERC721(AirdropContentERC721[] calldata contents) private pure returns (bytes32) { bytes32[] memory contentHashes = new bytes32[](contents.length); for (uint256 i = 0; i < contents.length; i++) { - contentHashes[i] = keccak256( - abi.encode(CONTENT_TYPEHASH_ERC721, contents[i].recipient, contents[i].tokenId) - ); + contentHashes[i] = + keccak256(abi.encode(CONTENT_TYPEHASH_ERC721, contents[i].recipient, contents[i].tokenId)); } return keccak256(abi.encodePacked(contentHashes)); } @@ -432,10 +408,11 @@ contract Airdrop is EIP712, Initializable, Ownable { return keccak256(abi.encodePacked(contentHashes)); } - function _verifyRequestSignerERC20( - AirdropRequestERC20 calldata req, - bytes calldata signature - ) private view returns (bool) { + function _verifyRequestSignerERC20(AirdropRequestERC20 calldata req, bytes calldata signature) + private + view + returns (bool) + { bytes32 contentHash = _hashContentInfoERC20(req.contents); bytes32 structHash = keccak256( abi.encode(REQUEST_TYPEHASH_ERC20, req.uid, req.tokenAddress, req.expirationTimestamp, contentHash) @@ -446,10 +423,11 @@ contract Airdrop is EIP712, Initializable, Ownable { return recovered == owner(); } - function _verifyRequestSignerERC721( - AirdropRequestERC721 calldata req, - bytes calldata signature - ) private view returns (bool) { + function _verifyRequestSignerERC721(AirdropRequestERC721 calldata req, bytes calldata signature) + private + view + returns (bool) + { bytes32 contentHash = _hashContentInfoERC721(req.contents); bytes32 structHash = keccak256( abi.encode(REQUEST_TYPEHASH_ERC721, req.uid, req.tokenAddress, req.expirationTimestamp, contentHash) @@ -460,10 +438,11 @@ contract Airdrop is EIP712, Initializable, Ownable { return recovered == owner(); } - function _verifyRequestSignerERC1155( - AirdropRequestERC1155 calldata req, - bytes calldata signature - ) private view returns (bool) { + function _verifyRequestSignerERC1155(AirdropRequestERC1155 calldata req, bytes calldata signature) + private + view + returns (bool) + { bytes32 contentHash = _hashContentInfoERC1155(req.contents); bytes32 structHash = keccak256( abi.encode(REQUEST_TYPEHASH_ERC1155, req.uid, req.tokenAddress, req.expirationTimestamp, contentHash) From 150fbd19fe0273014f8baae9f325551cf183d073 Mon Sep 17 00:00:00 2001 From: Yash Date: Mon, 25 Mar 2024 21:30:07 +0530 Subject: [PATCH 25/30] isClaimed view function --- .../prebuilts/unaudited/airdrop/Airdrop.sol | 108 ++++++++++++------ 1 file changed, 73 insertions(+), 35 deletions(-) diff --git a/contracts/prebuilts/unaudited/airdrop/Airdrop.sol b/contracts/prebuilts/unaudited/airdrop/Airdrop.sol index 015a2514b..034c82764 100644 --- a/contracts/prebuilts/unaudited/airdrop/Airdrop.sol +++ b/contracts/prebuilts/unaudited/airdrop/Airdrop.sol @@ -17,8 +17,8 @@ import "@solady/src/utils/ECDSA.sol"; import "@solady/src/utils/EIP712.sol"; import "@solady/src/utils/SafeTransferLib.sol"; -import {Initializable} from "../../../extension/Initializable.sol"; -import {Ownable} from "../../../extension/Ownable.sol"; +import { Initializable } from "../../../extension/Initializable.sol"; +import { Ownable } from "../../../extension/Ownable.sol"; import "../../../eip/interface/IERC20.sol"; import "../../../eip/interface/IERC721.sol"; @@ -77,22 +77,26 @@ contract Airdrop is EIP712, Initializable, Ownable { AirdropContentERC1155[] contents; } - bytes32 private constant CONTENT_TYPEHASH_ERC20 = keccak256("AirdropContentERC20(address recipient,uint256 amount)"); - bytes32 private constant REQUEST_TYPEHASH_ERC20 = keccak256( - "AirdropRequestERC20(bytes32 uid,address tokenAddress,uint256 expirationTimestamp,AirdropContentERC20[] contents)AirdropContentERC20(address recipient,uint256 amount)" - ); + bytes32 private constant CONTENT_TYPEHASH_ERC20 = + keccak256("AirdropContentERC20(address recipient,uint256 amount)"); + bytes32 private constant REQUEST_TYPEHASH_ERC20 = + keccak256( + "AirdropRequestERC20(bytes32 uid,address tokenAddress,uint256 expirationTimestamp,AirdropContentERC20[] contents)AirdropContentERC20(address recipient,uint256 amount)" + ); bytes32 private constant CONTENT_TYPEHASH_ERC721 = keccak256("AirdropContentERC721(address recipient,uint256 tokenId)"); - bytes32 private constant REQUEST_TYPEHASH_ERC721 = keccak256( - "AirdropRequestERC721(bytes32 uid,address tokenAddress,uint256 expirationTimestamp,AirdropContentERC721[] contents)AirdropContentERC721(address recipient,uint256 tokenId)" - ); + bytes32 private constant REQUEST_TYPEHASH_ERC721 = + keccak256( + "AirdropRequestERC721(bytes32 uid,address tokenAddress,uint256 expirationTimestamp,AirdropContentERC721[] contents)AirdropContentERC721(address recipient,uint256 tokenId)" + ); bytes32 private constant CONTENT_TYPEHASH_ERC1155 = keccak256("AirdropContentERC1155(address recipient,uint256 tokenId,uint256 amount)"); - bytes32 private constant REQUEST_TYPEHASH_ERC1155 = keccak256( - "AirdropRequestERC1155(bytes32 uid,address tokenAddress,uint256 expirationTimestamp,AirdropContentERC1155[] contents)AirdropContentERC1155(address recipient,uint256 tokenId,uint256 amount)" - ); + bytes32 private constant REQUEST_TYPEHASH_ERC1155 = + keccak256( + "AirdropRequestERC1155(bytes32 uid,address tokenAddress,uint256 expirationTimestamp,AirdropContentERC1155[] contents)AirdropContentERC1155(address recipient,uint256 tokenId,uint256 amount)" + ); address private constant NATIVE_TOKEN_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE; @@ -146,7 +150,7 @@ contract Airdrop is EIP712, Initializable, Ownable { for (uint256 i = 0; i < len; i++) { nativeTokenAmount += _contents[i].amount; - (bool success,) = _contents[i].recipient.call{value: _contents[i].amount}(""); + (bool success, ) = _contents[i].recipient.call{ value: _contents[i].amount }(""); if (!success) { revert AirdropFailed(); } @@ -178,7 +182,11 @@ contract Airdrop is EIP712, Initializable, Ownable { for (uint256 i = 0; i < len; i++) { IERC1155(_tokenAddress).safeTransferFrom( - msg.sender, _contents[i].recipient, _contents[i].tokenId, _contents[i].amount, "" + msg.sender, + _contents[i].recipient, + _contents[i].tokenId, + _contents[i].amount, + "" ); } } @@ -208,7 +216,12 @@ contract Airdrop is EIP712, Initializable, Ownable { address _from = owner(); for (uint256 i = 0; i < len; i++) { - SafeTransferLib.safeTransferFrom(req.tokenAddress, _from, req.contents[i].recipient, req.contents[i].amount); + SafeTransferLib.safeTransferFrom( + req.tokenAddress, + _from, + req.contents[i].recipient, + req.contents[i].amount + ); } } @@ -259,7 +272,11 @@ contract Airdrop is EIP712, Initializable, Ownable { for (uint256 i = 0; i < len; i++) { IERC1155(req.tokenAddress).safeTransferFrom( - _from, req.contents[i].recipient, req.contents[i].tokenId, req.contents[i].amount, "" + _from, + req.contents[i].recipient, + req.contents[i].tokenId, + req.contents[i].amount, + "" ); } } @@ -281,7 +298,11 @@ contract Airdrop is EIP712, Initializable, Ownable { revert AirdropNoMerkleRoot(); } - bool valid = MerkleProofLib.verify(_proofs, _tokenMerkleRoot, keccak256(abi.encodePacked(_receiver, _quantity))); + bool valid = MerkleProofLib.verify( + _proofs, + _tokenMerkleRoot, + keccak256(abi.encodePacked(_receiver, _quantity)) + ); if (!valid) { revert AirdropInvalidProof(); } @@ -334,7 +355,9 @@ contract Airdrop is EIP712, Initializable, Ownable { } bool valid = MerkleProofLib.verify( - _proofs, _tokenMerkleRoot, keccak256(abi.encodePacked(_receiver, _tokenId, _quantity)) + _proofs, + _tokenMerkleRoot, + keccak256(abi.encodePacked(_receiver, _tokenId, _quantity)) ); if (!valid) { revert AirdropInvalidProof(); @@ -360,6 +383,23 @@ contract Airdrop is EIP712, Initializable, Ownable { Miscellaneous //////////////////////////////////////////////////////////////*/ + function isClaimed( + address _receiver, + address _token, + uint256 _tokenId, + uint256 _conditionId + ) external view returns (bool) { + bytes32 claimHash = keccak256(abi.encodePacked(_receiver, _token, _tokenId)); + + if (!claimed[_conditionId][claimHash]) { + claimHash = keccak256(abi.encodePacked(_receiver, _token)); + + return claimed[_conditionId][claimHash]; + } + + return true; + } + function _canSetOwner() internal view virtual override returns (bool) { return msg.sender == owner(); } @@ -392,8 +432,9 @@ contract Airdrop is EIP712, Initializable, Ownable { function _hashContentInfoERC721(AirdropContentERC721[] calldata contents) private pure returns (bytes32) { bytes32[] memory contentHashes = new bytes32[](contents.length); for (uint256 i = 0; i < contents.length; i++) { - contentHashes[i] = - keccak256(abi.encode(CONTENT_TYPEHASH_ERC721, contents[i].recipient, contents[i].tokenId)); + contentHashes[i] = keccak256( + abi.encode(CONTENT_TYPEHASH_ERC721, contents[i].recipient, contents[i].tokenId) + ); } return keccak256(abi.encodePacked(contentHashes)); } @@ -408,11 +449,10 @@ contract Airdrop is EIP712, Initializable, Ownable { return keccak256(abi.encodePacked(contentHashes)); } - function _verifyRequestSignerERC20(AirdropRequestERC20 calldata req, bytes calldata signature) - private - view - returns (bool) - { + function _verifyRequestSignerERC20( + AirdropRequestERC20 calldata req, + bytes calldata signature + ) private view returns (bool) { bytes32 contentHash = _hashContentInfoERC20(req.contents); bytes32 structHash = keccak256( abi.encode(REQUEST_TYPEHASH_ERC20, req.uid, req.tokenAddress, req.expirationTimestamp, contentHash) @@ -423,11 +463,10 @@ contract Airdrop is EIP712, Initializable, Ownable { return recovered == owner(); } - function _verifyRequestSignerERC721(AirdropRequestERC721 calldata req, bytes calldata signature) - private - view - returns (bool) - { + function _verifyRequestSignerERC721( + AirdropRequestERC721 calldata req, + bytes calldata signature + ) private view returns (bool) { bytes32 contentHash = _hashContentInfoERC721(req.contents); bytes32 structHash = keccak256( abi.encode(REQUEST_TYPEHASH_ERC721, req.uid, req.tokenAddress, req.expirationTimestamp, contentHash) @@ -438,11 +477,10 @@ contract Airdrop is EIP712, Initializable, Ownable { return recovered == owner(); } - function _verifyRequestSignerERC1155(AirdropRequestERC1155 calldata req, bytes calldata signature) - private - view - returns (bool) - { + function _verifyRequestSignerERC1155( + AirdropRequestERC1155 calldata req, + bytes calldata signature + ) private view returns (bool) { bytes32 contentHash = _hashContentInfoERC1155(req.contents); bytes32 structHash = keccak256( abi.encode(REQUEST_TYPEHASH_ERC1155, req.uid, req.tokenAddress, req.expirationTimestamp, contentHash) From 17df1dc41a07fe838506c838e0aafa445a183c59 Mon Sep 17 00:00:00 2001 From: Yash Date: Tue, 26 Mar 2024 00:10:02 +0530 Subject: [PATCH 26/30] remove conditionId param from isClaimed --- contracts/prebuilts/unaudited/airdrop/Airdrop.sol | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/contracts/prebuilts/unaudited/airdrop/Airdrop.sol b/contracts/prebuilts/unaudited/airdrop/Airdrop.sol index 034c82764..6047aec84 100644 --- a/contracts/prebuilts/unaudited/airdrop/Airdrop.sol +++ b/contracts/prebuilts/unaudited/airdrop/Airdrop.sol @@ -383,12 +383,8 @@ contract Airdrop is EIP712, Initializable, Ownable { Miscellaneous //////////////////////////////////////////////////////////////*/ - function isClaimed( - address _receiver, - address _token, - uint256 _tokenId, - uint256 _conditionId - ) external view returns (bool) { + function isClaimed(address _receiver, address _token, uint256 _tokenId) external view returns (bool) { + uint256 _conditionId = tokenConditionId[_token]; bytes32 claimHash = keccak256(abi.encodePacked(_receiver, _token, _tokenId)); if (!claimed[_conditionId][claimHash]) { From e4f83a624db63c650a11260742528b3ffb7d29e0 Mon Sep 17 00:00:00 2001 From: Yash Date: Tue, 26 Mar 2024 00:17:36 +0530 Subject: [PATCH 27/30] events --- .../prebuilts/unaudited/airdrop/Airdrop.sol | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/contracts/prebuilts/unaudited/airdrop/Airdrop.sol b/contracts/prebuilts/unaudited/airdrop/Airdrop.sol index 6047aec84..b3f5af776 100644 --- a/contracts/prebuilts/unaudited/airdrop/Airdrop.sol +++ b/contracts/prebuilts/unaudited/airdrop/Airdrop.sol @@ -114,6 +114,13 @@ contract Airdrop is EIP712, Initializable, Ownable { error AirdropRequestInvalidSigner(); error AirdropInvalidTokenAddress(); + /*/////////////////////////////////////////////////////////////// + Events + //////////////////////////////////////////////////////////////*/ + + event Airdrop(address token); + event AirdropClaimed(address token, address receiver); + /*/////////////////////////////////////////////////////////////// Constructor //////////////////////////////////////////////////////////////*/ @@ -159,6 +166,8 @@ contract Airdrop is EIP712, Initializable, Ownable { if (nativeTokenAmount != msg.value) { revert AirdropValueMismatch(); } + + emit Airdrop(NATIVE_TOKEN_ADDRESS); } function airdropERC20(address _tokenAddress, AirdropContentERC20[] calldata _contents) external onlyOwner { @@ -167,6 +176,8 @@ contract Airdrop is EIP712, Initializable, Ownable { for (uint256 i = 0; i < len; i++) { SafeTransferLib.safeTransferFrom(_tokenAddress, msg.sender, _contents[i].recipient, _contents[i].amount); } + + emit Airdrop(_tokenAddress); } function airdropERC721(address _tokenAddress, AirdropContentERC721[] calldata _contents) external onlyOwner { @@ -175,6 +186,8 @@ contract Airdrop is EIP712, Initializable, Ownable { for (uint256 i = 0; i < len; i++) { IERC721(_tokenAddress).safeTransferFrom(msg.sender, _contents[i].recipient, _contents[i].tokenId); } + + emit Airdrop(_tokenAddress); } function airdropERC1155(address _tokenAddress, AirdropContentERC1155[] calldata _contents) external onlyOwner { @@ -189,6 +202,8 @@ contract Airdrop is EIP712, Initializable, Ownable { "" ); } + + emit Airdrop(_tokenAddress); } /*/////////////////////////////////////////////////////////////// @@ -223,6 +238,8 @@ contract Airdrop is EIP712, Initializable, Ownable { req.contents[i].amount ); } + + emit Airdrop(req.tokenAddress); } function airdropERC721WithSignature(AirdropRequestERC721 calldata req, bytes calldata signature) external { @@ -248,6 +265,8 @@ contract Airdrop is EIP712, Initializable, Ownable { for (uint256 i = 0; i < len; i++) { IERC721(req.tokenAddress).safeTransferFrom(_from, req.contents[i].recipient, req.contents[i].tokenId); } + + emit Airdrop(req.tokenAddress); } function airdropERC1155WithSignature(AirdropRequestERC1155 calldata req, bytes calldata signature) external { @@ -279,6 +298,8 @@ contract Airdrop is EIP712, Initializable, Ownable { "" ); } + + emit Airdrop(req.tokenAddress); } /*/////////////////////////////////////////////////////////////// @@ -310,6 +331,8 @@ contract Airdrop is EIP712, Initializable, Ownable { claimed[conditionId][claimHash] = true; SafeTransferLib.safeTransferFrom(_token, owner(), _receiver, _quantity); + + emit AirdropClaimed(_token, _receiver); } function claimERC721(address _token, address _receiver, uint256 _tokenId, bytes32[] calldata _proofs) external { @@ -333,6 +356,8 @@ contract Airdrop is EIP712, Initializable, Ownable { claimed[conditionId][claimHash] = true; IERC721(_token).safeTransferFrom(owner(), _receiver, _tokenId); + + emit AirdropClaimed(_token, _receiver); } function claimERC1155( @@ -366,6 +391,8 @@ contract Airdrop is EIP712, Initializable, Ownable { claimed[conditionId][claimHash] = true; IERC1155(_token).safeTransferFrom(owner(), _receiver, _tokenId, _quantity, ""); + + emit AirdropClaimed(_token, _receiver); } /*/////////////////////////////////////////////////////////////// From ea526c3d3c553bab68f48063aafafe38832683c2 Mon Sep 17 00:00:00 2001 From: Jake Loo <2171134+jakeloo@users.noreply.github.com> Date: Mon, 25 Mar 2024 18:55:03 +0000 Subject: [PATCH 28/30] update isClaimed --- contracts/prebuilts/unaudited/airdrop/Airdrop.sol | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/contracts/prebuilts/unaudited/airdrop/Airdrop.sol b/contracts/prebuilts/unaudited/airdrop/Airdrop.sol index b3f5af776..9fba1dae6 100644 --- a/contracts/prebuilts/unaudited/airdrop/Airdrop.sol +++ b/contracts/prebuilts/unaudited/airdrop/Airdrop.sol @@ -412,15 +412,18 @@ contract Airdrop is EIP712, Initializable, Ownable { function isClaimed(address _receiver, address _token, uint256 _tokenId) external view returns (bool) { uint256 _conditionId = tokenConditionId[_token]; - bytes32 claimHash = keccak256(abi.encodePacked(_receiver, _token, _tokenId)); - if (!claimed[_conditionId][claimHash]) { - claimHash = keccak256(abi.encodePacked(_receiver, _token)); + bytes32 claimHash = keccak256(abi.encodePacked(_receiver, _token, _tokenId)); + if (claimed[_conditionId][claimHash]) { + return true; + } - return claimed[_conditionId][claimHash]; + claimHash = keccak256(abi.encodePacked(_receiver, _token)); + if (claimed[_conditionId][claimHash]) { + return true; } - return true; + return false; } function _canSetOwner() internal view virtual override returns (bool) { From 770874d3f7d9fd4bfee9449a8ba9b2888adb3629 Mon Sep 17 00:00:00 2001 From: Yash Date: Tue, 26 Mar 2024 02:41:51 +0530 Subject: [PATCH 29/30] update dependencies --- package.json | 3 --- yarn.lock | 18 +++++++++--------- 2 files changed, 9 insertions(+), 12 deletions(-) diff --git a/package.json b/package.json index 09b39fcf8..5f73d961b 100644 --- a/package.json +++ b/package.json @@ -58,8 +58,5 @@ "gas": "forge snapshot --isolate --mc Benchmark --gas-report --diff .gas-snapshot > gasreport.txt", "forge:snapshot": "forge snapshot --check", "aabenchmark": "forge test --mc AABenchmarkPrepare && forge test --mc ProfileThirdwebAccount -vvv" - }, - "dependencies": { - "@thirdweb-dev/merkletree": "^0.2.1" } } diff --git a/yarn.lock b/yarn.lock index 92d7be0c9..0fa25712f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -539,10 +539,10 @@ resolved "https://registry.yarnpkg.com/@solidity-parser/parser/-/parser-0.17.0.tgz#52a2fcc97ff609f72011014e4c5b485ec52243ef" integrity sha512-Nko8R0/kUo391jsEHHxrGM07QFdnPGvlmox4rmH0kNiNAashItAilhy4Mv4pK5gQmW5f4sXAF58fwJbmlkGcVw== -"@thirdweb-dev/crypto@0.2.1": - version "0.2.1" - resolved "https://registry.yarnpkg.com/@thirdweb-dev/crypto/-/crypto-0.2.1.tgz#7643c91c9d87e4d51a77163b87f6bff547e9506c" - integrity sha512-SYEkdtdhTOAcgGklqPrKgyIftA2x0WBTtpAEyJBTLCL1z+2IKvExWZyZn3Mx2cZ8skO3iAfGzC4Si2ORWBcS2g== +"@thirdweb-dev/crypto@0.2.2": + version "0.2.2" + resolved "https://registry.yarnpkg.com/@thirdweb-dev/crypto/-/crypto-0.2.2.tgz#455c7564610a1eb4597ae1d02c0ce3d722072709" + integrity sha512-jOwHtdViJYZ5015F3xZvwmnFZLrgTx2RkE7bAiG/N83f5TduwQBM3PAPTbW3aBOECaoSrbmgj/lQEOv7543z3Q== dependencies: "@noble/hashes" "^1.3.2" js-sha3 "^0.9.2" @@ -552,12 +552,12 @@ resolved "https://registry.yarnpkg.com/@thirdweb-dev/dynamic-contracts/-/dynamic-contracts-1.2.5.tgz#f9735c0d46198e7bf2f98c277f0a9a79c54da1e8" integrity sha512-YVsz+jUWbwj+6aF2eTZGMfyw47a1HRmgNl4LQ3gW9gwYL5y5+OX/yOzv6aV5ibvoqCk/k10aIVK2eFrcpMubQA== -"@thirdweb-dev/merkletree@^0.2.1": - version "0.2.1" - resolved "https://registry.yarnpkg.com/@thirdweb-dev/merkletree/-/merkletree-0.2.1.tgz#1604e238a921fe520520e18b63312ca049376707" - integrity sha512-NQEo+KlwQFWr0z4+OlD5WJ9GZEFOrVufvjG2zcn2eylFZacJq5GvRz04Yan9eMR844M7LNx5godA5B7DAinqKg== +"@thirdweb-dev/merkletree@^0.2.2": + version "0.2.2" + resolved "https://registry.yarnpkg.com/@thirdweb-dev/merkletree/-/merkletree-0.2.2.tgz#179faa2cbfaaab0a8dfc2b4fb9601a4ec87f60f8" + integrity sha512-cOEU6ga8+Lyk3b/XsI0h40ljxcTyommQhA38eAWXxUYV1wxH/g7Mry3OOHyY1HCBC2R2MXykCdiFuaoUsQB6Pw== dependencies: - "@thirdweb-dev/crypto" "0.2.1" + "@thirdweb-dev/crypto" "0.2.2" buffer "^6.0.3" buffer-reverse "^1.0.1" treeify "^1.1.0" From 9fe8f194c418839b1e7ffbfe18ba55010965c1d3 Mon Sep 17 00:00:00 2001 From: Yash Date: Tue, 26 Mar 2024 03:11:16 +0530 Subject: [PATCH 30/30] fix --- src/test/scripts/generateRootAirdrop1155.ts | 2 +- src/test/scripts/getProofAirdrop1155.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/scripts/generateRootAirdrop1155.ts b/src/test/scripts/generateRootAirdrop1155.ts index 3eb821e6f..d76990fad 100644 --- a/src/test/scripts/generateRootAirdrop1155.ts +++ b/src/test/scripts/generateRootAirdrop1155.ts @@ -6,7 +6,7 @@ const { ethers } = require("ethers"); const process = require("process"); const members = [ - "0x92Bb439374a091c7507bE100183d8D1Ed2c9dAD3", + "0x9999999999999999999999999999999999999999", "0xDDdDddDdDdddDDddDDddDDDDdDdDDdDDdDDDDDDd", "0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", ]; diff --git a/src/test/scripts/getProofAirdrop1155.ts b/src/test/scripts/getProofAirdrop1155.ts index 4bb7916f2..6701fc479 100644 --- a/src/test/scripts/getProofAirdrop1155.ts +++ b/src/test/scripts/getProofAirdrop1155.ts @@ -6,7 +6,7 @@ const { ethers } = require("ethers"); const process = require("process"); const members = [ - "0x92Bb439374a091c7507bE100183d8D1Ed2c9dAD3", + "0x9999999999999999999999999999999999999999", "0xDDdDddDdDdddDDddDDddDDDDdDdDDdDDdDDDDDDd", "0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", ];