More Info
Private Name Tags
ContractCreator
Latest 25 from a total of 562 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Claim | 20121722 | 303 days ago | IN | 0 ETH | 0.00061245 | ||||
Claim | 20112751 | 304 days ago | IN | 0 ETH | 0.00204861 | ||||
Claim | 20106533 | 305 days ago | IN | 0 ETH | 0.00029448 | ||||
Claim | 20105036 | 305 days ago | IN | 0 ETH | 0.00044483 | ||||
Claim | 20083775 | 308 days ago | IN | 0 ETH | 0.00146785 | ||||
Claim | 20070898 | 310 days ago | IN | 0 ETH | 0.00171238 | ||||
Claim | 20021773 | 317 days ago | IN | 0 ETH | 0.00064527 | ||||
Claim | 20011623 | 318 days ago | IN | 0 ETH | 0.00126339 | ||||
Claim | 20011390 | 318 days ago | IN | 0 ETH | 0.00101607 | ||||
Claim | 20004045 | 319 days ago | IN | 0 ETH | 0.00068112 | ||||
Claim | 19954012 | 326 days ago | IN | 0 ETH | 0.0003418 | ||||
Claim | 19949531 | 327 days ago | IN | 0 ETH | 0.00036276 | ||||
Claim | 19948642 | 327 days ago | IN | 0 ETH | 0.00036801 | ||||
Claim | 19941144 | 328 days ago | IN | 0 ETH | 0.0011829 | ||||
Claim | 19911841 | 332 days ago | IN | 0 ETH | 0.00131316 | ||||
Claim | 19911182 | 332 days ago | IN | 0 ETH | 0.00050863 | ||||
Claim | 19902774 | 333 days ago | IN | 0 ETH | 0.00025354 | ||||
Claim | 19879011 | 337 days ago | IN | 0 ETH | 0.00027752 | ||||
Claim | 19877538 | 337 days ago | IN | 0 ETH | 0.00080407 | ||||
Claim | 19875173 | 337 days ago | IN | 0 ETH | 0.00050856 | ||||
Claim | 19871629 | 338 days ago | IN | 0 ETH | 0.00031235 | ||||
Claim | 19851692 | 341 days ago | IN | 0 ETH | 0.00027461 | ||||
Claim | 19838653 | 342 days ago | IN | 0 ETH | 0.00035844 | ||||
Claim | 19836589 | 343 days ago | IN | 0 ETH | 0.00034005 | ||||
Claim | 19829355 | 344 days ago | IN | 0 ETH | 0.00038978 |
Latest 1 internal transaction
Advanced mode:
Parent Transaction Hash | Method | Block |
From
|
To
|
|||
---|---|---|---|---|---|---|---|
0x6100c43d | 19328689 | 414 days ago | Contract Creation | 0 ETH |
Loading...
Loading
Minimal Proxy Contract for 0xe1bc3fba09e8141463b55ecd07c0ad40f17bc1f5
Contract Name:
Merkledrop
Compiler Version
v0.8.13+commit.abaa5c0e
Optimization Enabled:
Yes with 200 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.13; import "solbase/utils/SafeTransferLib.sol"; import "solbase/utils/MerkleProofLib.sol"; import "solbase/utils/Clone.sol"; abstract contract ERC20 { function balanceOf(address) external view virtual returns (uint256); } contract Merkledrop is Clone { receive() external payable {} /// ----------------------------------------------------------------------- /// Dependencies /// ----------------------------------------------------------------------- using SafeTransferLib for address; using MerkleProofLib for bytes32[]; /// ----------------------------------------------------------------------- /// Events /// ----------------------------------------------------------------------- event Claim(address account, uint256 amount); event Recovered(address to); /// ----------------------------------------------------------------------- /// Errors /// ----------------------------------------------------------------------- error InvalidProof(); error CallerNotCreator(); /// ----------------------------------------------------------------------- /// Mutables /// ----------------------------------------------------------------------- mapping(address => bool) public claimed; /// ----------------------------------------------------------------------- /// Immutables /// ----------------------------------------------------------------------- function creator() public pure returns (address) { return _getArgAddress(12); } function asset() public pure returns (address) { return _getArgAddress(44); } function merkleRoot() public pure returns (bytes32) { return bytes32(_getArgBytes(64, 32)); } /// ----------------------------------------------------------------------- /// Transfer Helper /// ----------------------------------------------------------------------- function universalTransfer(address token, address to, uint256 amount) internal { if (token != address(0)) { token.safeTransfer(to, amount); } else { to.safeTransferETH(amount); } } /// ----------------------------------------------------------------------- /// Actions /// ----------------------------------------------------------------------- function claim(bytes32[] calldata proof, uint256 value) external { bool valid = proof.verify( merkleRoot(), keccak256(abi.encodePacked(msg.sender, value)) ); if (valid && !claimed[msg.sender]) { claimed[msg.sender] = true; universalTransfer(asset(), msg.sender, value); } else { revert InvalidProof(); } emit Claim(msg.sender, value); } /// @notice Allows creator to refund/remove all deposited funds. function recover(address token, address to) external { if (msg.sender != creator()) revert CallerNotCreator(); uint256 balance = token != address(0) // If 'token' address is provided assume we're sending ERC20 tokens. ? ERC20(asset()).balanceOf(address(this)) // Otherwise assume we're sending ether. : address(this).balance; universalTransfer(asset(), to, balance); emit Recovered(to); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; /// @notice Class with helper read functions for clone with immutable args. /// @author SolDAO (https://github.com/Sol-DAO/solbase/blob/main/src/utils/Clone.sol) /// @author Modified from Solady (https://github.com/vectorized/solady/blob/main/src/utils/Clone.sol) abstract contract Clone { /// @dev Reads an immutable arg with type bytes. function _getArgBytes(uint256 argOffset, uint256 length) internal pure returns (bytes memory arg) { uint256 offset = _getImmutableArgsOffset(); assembly { // Grab the free memory pointer. arg := mload(0x40) // Store the array length. mstore(arg, length) // Copy the array. calldatacopy(add(arg, 0x20), add(offset, argOffset), length) // Allocate the memory, rounded up to the next 32 byte boudnary. mstore(0x40, and(add(add(arg, 0x3f), length), not(0x1f))) } } /// @dev Reads an immutable arg with type address. function _getArgAddress(uint256 argOffset) internal pure returns (address arg) { uint256 offset = _getImmutableArgsOffset(); assembly { arg := shr(0x60, calldataload(add(offset, argOffset))) } } /// @dev Reads an immutable arg with type uint256 function _getArgUint256(uint256 argOffset) internal pure returns (uint256 arg) { uint256 offset = _getImmutableArgsOffset(); assembly { arg := calldataload(add(offset, argOffset)) } } /// @dev Reads a uint256 array stored in the immutable args. function _getArgUint256Array(uint256 argOffset, uint256 length) internal pure returns (uint256[] memory arg) { uint256 offset = _getImmutableArgsOffset(); assembly { // Grab the free memory pointer. arg := mload(0x40) // Store the array length. mstore(arg, length) // Copy the array. calldatacopy(add(arg, 0x20), add(offset, argOffset), shl(5, length)) // Allocate the memory. mstore(0x40, add(add(arg, 0x20), shl(5, length))) } } /// @dev Reads an immutable arg with type uint64. function _getArgUint64(uint256 argOffset) internal pure returns (uint64 arg) { uint256 offset = _getImmutableArgsOffset(); assembly { arg := shr(0xc0, calldataload(add(offset, argOffset))) } } /// @dev Reads an immutable arg with type uint8. function _getArgUint8(uint256 argOffset) internal pure returns (uint8 arg) { uint256 offset = _getImmutableArgsOffset(); assembly { arg := shr(0xf8, calldataload(add(offset, argOffset))) } } /// @return offset The offset of the packed immutable args in calldata. function _getImmutableArgsOffset() internal pure returns (uint256 offset) { assembly { offset := sub(calldatasize(), shr(0xf0, calldataload(sub(calldatasize(), 2)))) } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; /// @notice Gas-optimized verification of proof of inclusion for a leaf in a Merkle tree. /// @author SolDAO (https://github.com/Sol-DAO/solbase/blob/main/src/utils/MerkleProofLib.sol) /// @author Modified from Solady (https://github.com/vectorized/solady/blob/main/src/utils/MerkleProofLib.sol) library MerkleProofLib { function verify(bytes32[] calldata proof, bytes32 root, bytes32 leaf) internal pure returns (bool isValid) { assembly { if proof.length { // Left shift by 5 is equivalent to multiplying by 0x20. let end := add(proof.offset, shl(5, proof.length)) // Initialize `offset` to the offset of `proof` in the calldata. let offset := proof.offset // Iterate over proof elements to compute root hash. // prettier-ignore for {} 1 {} { // Slot of `leaf` in scratch space. // If the condition is true: 0x20, otherwise: 0x00. let scratch := shl(5, gt(leaf, calldataload(offset))) // Store elements to hash contiguously in scratch space. // Scratch space is 64 bytes (0x00 - 0x3f) and both elements are 32 bytes. mstore(scratch, leaf) mstore(xor(scratch, 0x20), calldataload(offset)) // Reuse `leaf` to store the hash to reduce stack operations. leaf := keccak256(0x00, 0x40) offset := add(offset, 0x20) // prettier-ignore if iszero(lt(offset, end)) { break } } } isValid := eq(leaf, root) } } function verifyMultiProof( bytes32[] calldata proof, bytes32 root, bytes32[] calldata leafs, bool[] calldata flags ) internal pure returns (bool isValid) { // Rebuilds the root by consuming and producing values on a queue. // The queue starts with the `leafs` array, and goes into a `hashes` array. // After the process, the last element on the queue is verified // to be equal to the `root`. // // The `flags` array denotes whether the sibling // should be popped from the queue (`flag == true`), or // should be popped from the `proof` (`flag == false`). assembly { // If the number of flags is correct. // prettier-ignore for {} eq(add(leafs.length, proof.length), add(flags.length, 1)) {} { // Left shift by 5 is equivalent to multiplying by 0x20. // Compute the end calldata offset of `leafs`. let leafsEnd := add(leafs.offset, shl(5, leafs.length)) // These are the calldata offsets. let leafsOffset := leafs.offset let flagsOffset := flags.offset let proofOffset := proof.offset // We can use the free memory space for the queue. // We don't need to allocate, since the queue is temporary. let hashesFront := mload(0x40) let hashesBack := hashesFront // This is the end of the memory for the queue. let end := add(hashesBack, shl(5, flags.length)) // For the case where `proof.length + leafs.length == 1`. if iszero(flags.length) { // If `proof.length` is zero, `leafs.length` is 1. if iszero(proof.length) { isValid := eq(calldataload(leafsOffset), root) break } // If `leafs.length` is zero, `proof.length` is 1. if iszero(leafs.length) { isValid := eq(calldataload(proofOffset), root) break } } // prettier-ignore for {} 1 {} { let a := 0 // Pops a value from the queue into `a`. switch lt(leafsOffset, leafsEnd) case 0 { // Pop from `hashes` if there are no more leafs. a := mload(hashesFront) hashesFront := add(hashesFront, 0x20) } default { // Otherwise, pop from `leafs`. a := calldataload(leafsOffset) leafsOffset := add(leafsOffset, 0x20) } let b := 0 // If the flag is false, load the next proof, // else, pops from the queue. switch calldataload(flagsOffset) case 0 { // Loads the next proof. b := calldataload(proofOffset) proofOffset := add(proofOffset, 0x20) } default { // Pops a value from the queue into `a`. switch lt(leafsOffset, leafsEnd) case 0 { // Pop from `hashes` if there are no more leafs. b := mload(hashesFront) hashesFront := add(hashesFront, 0x20) } default { // Otherwise, pop from `leafs`. b := calldataload(leafsOffset) leafsOffset := add(leafsOffset, 0x20) } } // Advance to the next flag offset. flagsOffset := add(flagsOffset, 0x20) // Slot of `a` in scratch space. // If the condition is true: 0x20, otherwise: 0x00. let scratch := shl(5, gt(a, b)) // Hash the scratch space and push the result onto the queue. mstore(scratch, a) mstore(xor(scratch, 0x20), b) mstore(hashesBack, keccak256(0x00, 0x40)) hashesBack := add(hashesBack, 0x20) // prettier-ignore if iszero(lt(hashesBack, end)) { break } } // Checks if the last value in the queue is same as the root. isValid := eq(mload(sub(hashesBack, 0x20)), root) break } } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; /// @notice Safe ETH and ERC20 transfer library that gracefully handles missing return values. /// @author SolDAO (https://github.com/Sol-DAO/solbase/blob/main/src/utils/SafeTransferLib.sol) /// @author Modified from Solady (https://github.com/vectorized/solady/blob/main/src/utils/SafeTransferLib.sol) /// @dev Caution! This library won't check that a token has code, responsibility is delegated to the caller. library SafeTransferLib { /// ----------------------------------------------------------------------- /// Custom Errors /// ----------------------------------------------------------------------- error ETHTransferFailed(); error ApproveFailed(); error TransferFailed(); error TransferFromFailed(); /// ----------------------------------------------------------------------- /// ETH Operations /// ----------------------------------------------------------------------- function safeTransferETH(address to, uint256 amount) internal { /// @solidity memory-safe-assembly assembly { // Transfer the ETH and check if it succeeded or not. if iszero(call(gas(), to, amount, 0, 0, 0, 0)) { // Store the function selector of `ETHTransferFailed()`. mstore(0x00, 0xb12d13eb) // Revert with (offset, size). revert(0x1c, 0x04) } } } /// ----------------------------------------------------------------------- /// ERC20 Operations /// ----------------------------------------------------------------------- function safeApprove(address token, address to, uint256 amount) internal { /// @solidity memory-safe-assembly assembly { // We'll write our calldata to this slot below, but restore it later. let memPointer := mload(0x40) // Write the abi-encoded calldata into memory, beginning with the function selector. mstore(0x00, 0x095ea7b3) mstore(0x20, to) // Append the "to" argument. mstore(0x40, amount) // Append the "amount" argument. if iszero( and( // Set success to whether the call reverted, if not we check it either // returned exactly 1 (can't just be non-zero data), or had no return data. or(eq(mload(0x00), 1), iszero(returndatasize())), // We use 0x44 because that's the total length of our calldata (0x04 + 0x20 * 2) // Counterintuitively, this call() must be positioned after the or() in the // surrounding and() because and() evaluates its arguments from right to left. call(gas(), token, 0, 0x1c, 0x44, 0x00, 0x20) ) ) { // Store the function selector of `ApproveFailed()`. mstore(0x00, 0x3e3f8f73) // Revert with (offset, size). revert(0x1c, 0x04) } mstore(0x40, memPointer) // Restore the memPointer. } } function safeTransfer(address token, address to, uint256 amount) internal { /// @solidity memory-safe-assembly assembly { // We'll write our calldata to this slot below, but restore it later. let memPointer := mload(0x40) // Write the abi-encoded calldata into memory, beginning with the function selector. mstore(0x00, 0xa9059cbb) mstore(0x20, to) // Append the "to" argument. mstore(0x40, amount) // Append the "amount" argument. if iszero( and( // Set success to whether the call reverted, if not we check it either // returned exactly 1 (can't just be non-zero data), or had no return data. or(eq(mload(0x00), 1), iszero(returndatasize())), // We use 0x44 because that's the total length of our calldata (0x04 + 0x20 * 2) // Counterintuitively, this call() must be positioned after the or() in the // surrounding and() because and() evaluates its arguments from right to left. call(gas(), token, 0, 0x1c, 0x44, 0x00, 0x20) ) ) { // Store the function selector of `TransferFailed()`. mstore(0x00, 0x90b8ec18) // Revert with (offset, size). revert(0x1c, 0x04) } mstore(0x40, memPointer) // Restore the memPointer. } } function safeTransferFrom(address token, address from, address to, uint256 amount) internal { /// @solidity memory-safe-assembly assembly { // We'll write our calldata to this slot below, but restore it later. let memPointer := mload(0x40) // Write the abi-encoded calldata into memory, beginning with the function selector. mstore(0x00, 0x23b872dd) mstore(0x20, from) // Append the "from" argument. mstore(0x40, to) // Append the "to" argument. mstore(0x60, amount) // Append the "amount" argument. if iszero( and( // Set success to whether the call reverted, if not we check it either // returned exactly 1 (can't just be non-zero data), or had no return data. or(eq(mload(0x00), 1), iszero(returndatasize())), // We use 0x64 because that's the total length of our calldata (0x04 + 0x20 * 3) // Counterintuitively, this call() must be positioned after the or() in the // surrounding and() because and() evaluates its arguments from right to left. call(gas(), token, 0, 0x1c, 0x64, 0x00, 0x20) ) ) { // Store the function selector of `TransferFromFailed()`. mstore(0x00, 0x7939f424) // Revert with (offset, size). revert(0x1c, 0x04) } mstore(0x60, 0) // Restore the zero slot to zero. mstore(0x40, memPointer) // Restore the memPointer. } } }
{ "remappings": [ "ds-test/=lib/forge-std/lib/ds-test/src/", "forge-std/=lib/forge-std/src/", "murky/=lib/murky/src/", "openzeppelin-contracts/=lib/murky/lib/openzeppelin-contracts/", "solbase/=lib/solbase/src/" ], "optimizer": { "enabled": true, "runs": 200 }, "metadata": { "bytecodeHash": "ipfs" }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "evmVersion": "london", "libraries": {} }
Contract ABI
API[{"inputs":[],"name":"CallerNotCreator","type":"error"},{"inputs":[],"name":"InvalidProof","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Claim","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"to","type":"address"}],"name":"Recovered","type":"event"},{"inputs":[],"name":"asset","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes32[]","name":"proof","type":"bytes32[]"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"claim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"claimed","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"creator","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"merkleRoot","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"to","type":"address"}],"name":"recover","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 34 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.