More Info
Private Name Tags
ContractCreator
Latest 20 from a total of 20 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Claim | 19154373 | 283 days ago | IN | 0 ETH | 0.0009999 | ||||
Claim | 17649147 | 494 days ago | IN | 0 ETH | 0.00160895 | ||||
Claim | 16825580 | 610 days ago | IN | 0 ETH | 0.00128986 | ||||
Claim | 16061673 | 717 days ago | IN | 0 ETH | 0.00098914 | ||||
Claim | 16018215 | 723 days ago | IN | 0 ETH | 0.00090076 | ||||
Claim | 16015751 | 724 days ago | IN | 0 ETH | 0.00082512 | ||||
Claim | 16004713 | 725 days ago | IN | 0 ETH | 0.00109965 | ||||
Claim | 15933646 | 735 days ago | IN | 0 ETH | 0.00835878 | ||||
Claim | 15837847 | 749 days ago | IN | 0 ETH | 0.00099203 | ||||
Claim | 15754320 | 760 days ago | IN | 0 ETH | 0.0015085 | ||||
Claim | 15754011 | 760 days ago | IN | 0 ETH | 0.00149174 | ||||
Claim | 15734045 | 763 days ago | IN | 0 ETH | 0.00195073 | ||||
Claim | 15733286 | 763 days ago | IN | 0 ETH | 0.00154593 | ||||
Claim | 15729838 | 764 days ago | IN | 0 ETH | 0.00167548 | ||||
Claim | 15729804 | 764 days ago | IN | 0 ETH | 0.00134613 | ||||
Claim | 15729543 | 764 days ago | IN | 0 ETH | 0.00182759 | ||||
Claim | 15727241 | 764 days ago | IN | 0 ETH | 0.00292978 | ||||
Claim | 15726882 | 764 days ago | IN | 0 ETH | 0.00277295 | ||||
Claim | 15726582 | 764 days ago | IN | 0 ETH | 0.00269291 | ||||
Claim | 15726362 | 764 days ago | IN | 0 ETH | 0.00250835 |
Latest 1 internal transaction
Advanced mode:
Parent Transaction Hash | Block | From | To | |||
---|---|---|---|---|---|---|
15726204 | 764 days ago | Contract Creation | 0 ETH |
Loading...
Loading
Minimal Proxy Contract for 0x594c62030edbf4d09564bce0efe2885b34b12e24
Contract Name:
Astrodrop
Compiler Version
v0.8.1+commit.df193b15
Contract Source Code (Solidity)
/** *Submitted for verification at Etherscan.io on 2021-03-27 */ // SPDX-License-Identifier: MIT AND GPL-v3-or-later pragma solidity 0.8.1; abstract contract Context { function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691 return msg.data; } } abstract contract Ownable is Context { address private _owner; event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Returns the address of the current owner. */ function owner() public view returns (address) { return _owner; } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { require(isOwner(), "Ownable: caller is not the owner"); _; } /** * @dev Returns true if the caller is the current owner. */ function isOwner() public view returns (bool) { return _msgSender() == _owner; } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions anymore. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby removing any functionality that is only available to the owner. */ function renounceOwnership() public onlyOwner { emit OwnershipTransferred(_owner, address(0)); _owner = address(0); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner. */ function transferOwnership(address newOwner) public onlyOwner { _transferOwnership(newOwner); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). */ function _transferOwnership(address newOwner) internal { require(newOwner != address(0), "Ownable: new owner is the zero address"); emit OwnershipTransferred(_owner, newOwner); _owner = newOwner; } } contract CloneFactory { function createClone(address target, bytes32 salt) internal returns (address result) { bytes20 targetBytes = bytes20(target); assembly { let clone := mload(0x40) mstore(clone, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000) mstore(add(clone, 0x14), targetBytes) mstore(add(clone, 0x28), 0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000) result := create2(0, clone, 0x37, salt) } } function computeCloneAddress(address target, bytes32 salt) internal view returns (address) { bytes20 targetBytes = bytes20(target); bytes32 bytecodeHash; assembly { let clone := mload(0x40) mstore(clone, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000) mstore(add(clone, 0x14), targetBytes) mstore(add(clone, 0x28), 0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000) bytecodeHash := keccak256(clone, 0x37) } bytes32 _data = keccak256( abi.encodePacked(bytes1(0xff), address(this), salt, bytecodeHash) ); return address(bytes20(_data << 96)); } function isClone(address target, address query) internal view returns (bool result) { bytes20 targetBytes = bytes20(target); assembly { let clone := mload(0x40) mstore(clone, 0x363d3d373d3d3d363d7300000000000000000000000000000000000000000000) mstore(add(clone, 0xa), targetBytes) mstore(add(clone, 0x1e), 0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000) let other := add(clone, 0x40) extcodecopy(query, other, 0, 0x2d) result := and( eq(mload(clone), mload(other)), eq(mload(add(clone, 0xd)), mload(add(other, 0xd))) ) } } } library MerkleProof { /** * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree * defined by `root`. For this, a `proof` must be provided, containing * sibling hashes on the branch from the leaf to the root of the tree. Each * pair of leaves and each pair of pre-images are assumed to be sorted. */ function verify(bytes32[] memory proof, bytes32 root, bytes32 leaf) internal pure returns (bool) { bytes32 computedHash = leaf; for (uint256 i = 0; i < proof.length; i++) { bytes32 proofElement = proof[i]; if (computedHash <= proofElement) { // Hash(current computed hash + current element of the proof) computedHash = keccak256(abi.encodePacked(computedHash, proofElement)); } else { // Hash(current element of the proof + current computed hash) computedHash = keccak256(abi.encodePacked(proofElement, computedHash)); } } // Check if the computed hash (root) is equal to the provided root return computedHash == root; } } interface IERC20 { function transfer(address recipient, uint256 amount) external returns (bool); function balanceOf(address account) external view returns (uint256); } interface IERC721 { function safeTransferFrom(address from, address to, uint256 tokenId) external; function ownerOf(uint256 tokenId) external view returns (address owner); } library Address { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize, which returns 0 for contracts in // construction, since the code is only stored at the end of the // constructor execution. uint256 size; // solhint-disable-next-line no-inline-assembly assembly { size := extcodesize(account) } return size > 0; } } library SafeERC20 { using Address for address; function safeTransfer(IERC20 token, address to, uint256 value) internal { callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)); } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). */ function callOptionalReturn(IERC20 token, bytes memory data) private { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. // A Solidity high level call has three parts: // 1. The target address is checked to verify it contains contract code // 2. The call itself is made, and success asserted // 3. The return value is decoded, which in turn checks the size of the returned data. // solhint-disable-next-line max-line-length require(address(token).isContract(), "SafeERC20: call to non-contract"); // solhint-disable-next-line avoid-low-level-calls (bool success, bytes memory returndata) = address(token).call(data); require(success, "SafeERC20: low-level call failed"); if (returndata.length > 0) { // Return data is optional // solhint-disable-next-line max-line-length require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); } } } interface IAstrodrop { // Returns the address of the token distributed by this contract. function token() external view returns (address); // Returns the merkle root of the merkle tree containing account balances available to claim. function merkleRoot() external view returns (bytes32); // Returns true if the index has been marked claimed. function isClaimed(uint256 index) external view returns (bool); // Claim the given amount of the token to the given address. Reverts if the inputs are invalid. function claim(uint256 index, address account, uint256 amount, bytes32[] calldata merkleProof) external; // This event is triggered whenever a call to #claim succeeds. event Claimed(uint256 index, address account, uint256 amount); } contract Astrodrop is IAstrodrop, Ownable { using SafeERC20 for IERC20; address public override token; bytes32 public override merkleRoot; bool public initialized; uint256 public expireTimestamp; // This is a packed array of booleans. mapping(uint256 => uint256) public claimedBitMap; function init(address owner_, address token_, bytes32 merkleRoot_, uint256 expireTimestamp_) external { require(!initialized, "Astrodrop: Initialized"); initialized = true; token = token_; merkleRoot = merkleRoot_; expireTimestamp = expireTimestamp_; _transferOwnership(owner_); } function isClaimed(uint256 index) public view override returns (bool) { uint256 claimedWordIndex = index / 256; uint256 claimedBitIndex = index % 256; uint256 claimedWord = claimedBitMap[claimedWordIndex]; uint256 mask = (1 << claimedBitIndex); return claimedWord & mask == mask; } function _setClaimed(uint256 index) private { uint256 claimedWordIndex = index / 256; uint256 claimedBitIndex = index % 256; claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex); } function claim(uint256 index, address account, uint256 amount, bytes32[] calldata merkleProof) external override { require(!isClaimed(index), 'MerkleDistributor: Drop already claimed.'); // Verify the merkle proof. bytes32 node = keccak256(abi.encodePacked(index, account, amount)); require(MerkleProof.verify(merkleProof, merkleRoot, node), 'Astrodrop: Invalid proof'); // Mark it claimed and send the token. _setClaimed(index); IERC20(token).safeTransfer(account, amount); emit Claimed(index, account, amount); } function sweep(address token_, address target) external onlyOwner { require(block.timestamp >= expireTimestamp || token_ != token, "Astrodrop: Not expired"); IERC20 tokenContract = IERC20(token_); uint256 balance = tokenContract.balanceOf(address(this)); tokenContract.safeTransfer(target, balance); } } contract AstrodropERC721 is IAstrodrop, Ownable { using SafeERC20 for IERC20; address public override token; bytes32 public override merkleRoot; bool public initialized; uint256 public expireTimestamp; // This is a packed array of booleans. mapping(uint256 => uint256) public claimedBitMap; function init(address owner_, address token_, bytes32 merkleRoot_, uint256 expireTimestamp_) external { require(!initialized, "Astrodrop: Initialized"); initialized = true; token = token_; merkleRoot = merkleRoot_; expireTimestamp = expireTimestamp_; _transferOwnership(owner_); } function isClaimed(uint256 index) public view override returns (bool) { uint256 claimedWordIndex = index / 256; uint256 claimedBitIndex = index % 256; uint256 claimedWord = claimedBitMap[claimedWordIndex]; uint256 mask = (1 << claimedBitIndex); return claimedWord & mask == mask; } function _setClaimed(uint256 index) private { uint256 claimedWordIndex = index / 256; uint256 claimedBitIndex = index % 256; claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex); } function claim(uint256 index, address account, uint256 amount, bytes32[] calldata merkleProof) external override { require(!isClaimed(index), 'MerkleDistributor: Drop already claimed.'); // Verify the merkle proof. bytes32 node = keccak256(abi.encodePacked(index, account, amount)); require(MerkleProof.verify(merkleProof, merkleRoot, node), 'Astrodrop: Invalid proof'); // Mark it claimed and send the token. _setClaimed(index); IERC721 tokenContract = IERC721(token); tokenContract.safeTransferFrom(tokenContract.ownerOf(amount), account, amount); emit Claimed(index, account, amount); } function sweep(address token_, address target) external onlyOwner { require(block.timestamp >= expireTimestamp || token_ != token, "Astrodrop: Not expired"); IERC20 tokenContract = IERC20(token_); uint256 balance = tokenContract.balanceOf(address(this)); tokenContract.safeTransfer(target, balance); } } contract AstrodropFactory is CloneFactory { event CreateAstrodrop(address astrodrop, bytes32 ipfsHash); function createAstrodrop( address template, address token, bytes32 merkleRoot, uint256 expireTimestamp, bytes32 salt, bytes32 ipfsHash ) external returns (Astrodrop drop) { drop = Astrodrop(createClone(template, salt)); drop.init(msg.sender, token, merkleRoot, expireTimestamp); emit CreateAstrodrop(address(drop), ipfsHash); } function computeAstrodropAddress( address template, bytes32 salt ) external view returns (address) { return computeCloneAddress(template, salt); } function isAstrodrop(address template, address query) external view returns (bool) { return isClone(template, query); } }
[{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"index","type":"uint256"},{"indexed":false,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Claimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"inputs":[{"internalType":"uint256","name":"index","type":"uint256"},{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bytes32[]","name":"merkleProof","type":"bytes32[]"}],"name":"claim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"claimedBitMap","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"expireTimestamp","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner_","type":"address"},{"internalType":"address","name":"token_","type":"address"},{"internalType":"bytes32","name":"merkleRoot_","type":"bytes32"},{"internalType":"uint256","name":"expireTimestamp_","type":"uint256"}],"name":"init","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"initialized","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"index","type":"uint256"}],"name":"isClaimed","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isOwner","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"merkleRoot","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token_","type":"address"},{"internalType":"address","name":"target","type":"address"}],"name":"sweep","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"token","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"}]
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
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.