Transaction Hash:
Block:
12892877 at Jul-25-2021 02:49:34 AM +UTC
Transaction Fee:
0.0016386 ETH
$4.55
Gas Used:
40,965 Gas / 40 Gwei
Account State Difference:
Address | Before | After | State Difference | ||
---|---|---|---|---|---|
0xEA674fdD...16B898ec8
Miner
| (Ethermine) | 2,345.581453992086591693 Eth | 2,345.583092592086591693 Eth | 0.0016386 | |
0xF2948Eb2...7bffAFf65 |
0.050841974 Eth
Nonce: 9
|
0.049203374 Eth
Nonce: 10
| 0.0016386 |
Execution Trace
MerkleRedeem.claimWeeks( _liquidityProvider=0xF2948Eb21cD5F5c4E332ffC5238Be657bffAFf65, claims= )
1{"IERC20.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.6.0;\n\n/**\n * @dev Interface of the ERC20 standard as defined in theEIP.\n */\ninterface IERC20 {\n /**\n * @dev Returns the amount of tokens in existence.\n */\n function totalSupply() external viewreturns (uint256);\n\n /**\n * @dev Returns the amount of tokens owned by `account`.\n */\n function balanceOf(address account)external view returns (uint256);\n\n /**\n * @dev Moves `amount` tokens from the caller\u0027s account to `recipient`.\n *\n *Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address recipient, uint256 amount) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` willbe\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when{approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n/**\n * @dev Sets `amount` as the allowance of `spender` over the caller\u0027s tokens.\n *\n * Returns a boolean value indicatingwhether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someonemay use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n *condition is to first reduce the spender\u0027s allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 amount)external returns (bool);\n\n /**\n * @dev Moves `amount` tokens from `sender` to `recipient` using the\n * allowance mechanism. `amount`is then deducted from the caller\u0027s\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n*\n * Emits a {Transfer} event.\n */\n function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);\n\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that`value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted whenthe allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n}\n"},"MerkleProof.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragmasolidity ^0.6.0;\n\n/**\n * @dev These functions deal with verification of Merkle trees (hash trees),\n */\nlibrary MerkleProof {\n /**\n *@dev Returns true if a `leaf` can be proved to be a part of a Merkle tree\n * defined by `root`. For this, a `proof` must be provided,containing\n * sibling hashes on the branch from the leaf to the root of the tree. Each\n * pair of leaves and each pair of pre-images areassumed to be sorted.\n */\n function verify(bytes32[] memory proof, bytes32 root, bytes32 leaf) internal pure returns (bool) {\nbytes32 computedHash = leaf;\n\n for (uint256 i = 0; i \u003c proof.length; i++) {\n bytes32 proofElement = proof[i];\n\nif (computedHash \u003c= proofElement) {\n // Hash(current computed hash + current element of the proof)\ncomputedHash = keccak256(abi.encodePacked(computedHash, proofElement));\n } else {\n // Hash(current element of the proof+ current computed hash)\n computedHash = keccak256(abi.encodePacked(proofElement, computedHash));\n }\n }\n\n// Check if the computed hash (root) is equal to the provided root\n return computedHash == root;\n }\n}\n"},"MerkleRedeem.sol":{"content":"pragma solidity 0.6.8;\npragma experimental ABIEncoderV2;\n\nimport \"./MerkleProof.sol\";\nimport \"./Ownable.sol\";\nimport \"./IERC20.sol\";\n\ncontract MerkleRedeem is Ownable {\n\n IERC20 public token;\n\n event Claimed(address _claimant, uint256 _balance);\n\n// Recorded weeks\n mapping(uint =\u003e bytes32) public weekMerkleRoots;\n mapping(uint =\u003e mapping(address =\u003e bool)) publicclaimed;\n\n constructor(\n address _token\n ) public {\n token = IERC20(_token);\n }\n\n function disburse(\naddress _liquidityProvider,\n uint _balance\n )\n private\n {\n if (_balance \u003e 0) {\n emit Claimed(_liquidityProvider, _balance);\n require(token.transfer(_liquidityProvider, _balance), \"ERR_TRANSFER_FAILED\");\n }\n }\n\nfunction claimWeek(\n address _liquidityProvider,\n uint _week,\n uint _claimedBalance,\n bytes32[] memory_merkleProof\n )\n public\n {\n require(!claimed[_week][_liquidityProvider]);\n require(verifyClaim(_liquidityProvider,_week, _claimedBalance, _merkleProof), \u0027Incorrect merkle proof\u0027);\n\n claimed[_week][_liquidityProvider] = true;\n disburse(_liquidityProvider, _claimedBalance);\n }\n\n struct Claim {\n uint week;\n uint balance;\n bytes32[] merkleProof;\n}\n\n function claimWeeks(\n address _liquidityProvider,\n Claim[] memory claims\n )\n public\n {\n uinttotalBalance = 0;\n Claim memory claim ;\n for(uint i = 0; i \u003c claims.length; i++) {\n claim = claims[i];\n\nrequire(!claimed[claim.week][_liquidityProvider]);\n require(verifyClaim(_liquidityProvider, claim.week, claim.balance, claim.merkleProof), \u0027Incorrect merkle proof\u0027);\n\n totalBalance += claim.balance;\n claimed[claim.week][_liquidityProvider] = true;\n }\n disburse(_liquidityProvider, totalBalance);\n }\n\n function claimStatus(\naddress _liquidityProvider,\n uint _begin,\n uint _end\n )\n external\n view\n returns (bool[] memory)\n{\n uint size = 1 + _end - _begin;\n bool[] memory arr = new bool[](size);\n for(uint i = 0; i \u003c size; i++) {\narr[i] = claimed[_begin + i][_liquidityProvider];\n }\n return arr;\n }\n\n function merkleRoots(\n uint _begin,\nuint _end\n ) \n external\n view \n returns (bytes32[] memory)\n {\n uint size = 1 + _end - _begin;\nbytes32[] memory arr = new bytes32[](size);\n for(uint i = 0; i \u003c size; i++) {\n arr[i] = weekMerkleRoots[_begin + i];\n}\n return arr;\n }\n\n function verifyClaim(\n address _liquidityProvider,\n uint _week,\n uint_claimedBalance,\n bytes32[] memory _merkleProof\n )\n public\n view\n returns (bool valid)\n {\n bytes32leaf = keccak256(abi.encodePacked(_liquidityProvider, _claimedBalance));\n return MerkleProof.verify(_merkleProof, weekMerkleRoots[_week],leaf);\n }\n\n function seedAllocations(\n uint _week,\n bytes32 _merkleRoot,\n uint _totalAllocation\n )\nexternal\n onlyOwner\n {\n require(weekMerkleRoots[_week] == bytes32(0), \"cannot rewrite merkle root\");\nweekMerkleRoots[_week] = _merkleRoot;\n\n require(token.transferFrom(msg.sender, address(this), _totalAllocation), \"ERR_TRANSFER_FAILED\");\n }\n}\n"},"Ownable.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.6.0;\n\n/*\n * @dev Provides information about thecurrent execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with GSN meta-transactions the account sending and\n * payingfor execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate,library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address payable) {\nreturn msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes memory) {\n this; // silence state mutabilitywarning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691\n return msg.data;\n }\n}\n\n/**\n * @devContract module which provides a basic access control mechanism, where\n * there is an account (an owner) that can be granted exclusive access to\n* specific functions.\n *\n * By default, the owner account will be the one that deploys the contract. This\n * can later be changed with{transferOwnership}.\n *\n * This module is used through inheritance. It will make available the modifier\n * `onlyOwner`, which can be applied toyour functions to restrict their use to\n * the owner.\n */\ncontract Ownable is Context {\n address private _owner;\n\n eventOwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n /**\n * @dev Initializes the contract setting thedeployer as the initial owner.\n */\n constructor () internal {\n address msgSender = _msgSender();\n _owner = msgSender;\nemit OwnershipTransferred(address(0), msgSender);\n }\n\n /**\n * @dev Returns the address of the current owner.\n */\nfunction owner() public view returns (address) {\n return _owner;\n }\n\n /**\n * @dev Throws if called by any account other thanthe owner.\n */\n modifier onlyOwner() {\n require(_owner == _msgSender(), \"Ownable: caller is not the owner\");\n _;\n}\n\n /**\n * @dev Leaves the contract without owner. It will not be possible to call\n * `onlyOwner` functions anymore. Can only becalled by the current owner.\n *\n * NOTE: Renouncing ownership will leave the contract without an owner,\n * thereby removing anyfunctionality that is only available to the owner.\n */\n function renounceOwnership() public virtual onlyOwner {\n emitOwnershipTransferred(_owner, address(0));\n _owner = address(0);\n }\n\n /**\n * @dev Transfers ownership of the contract to a newaccount (`newOwner`).\n * Can only be called by the current owner.\n */\n function transferOwnership(address newOwner) public virtualonlyOwner {\n require(newOwner != address(0), \"Ownable: new owner is the zero address\");\n emit OwnershipTransferred(_owner,newOwner);\n _owner = newOwner;\n }\n}\n"}}