Transaction Hash:
Block:
16729070 at Feb-28-2023 08:36:47 PM +UTC
Transaction Fee:
0.001784607383571984 ETH
$4.50
Gas Used:
56,634 Gas / 31.511236776 Gwei
Emitted Events:
213 |
VerseToken.Transfer( from=[Receiver] VerseClaimer, to=[Sender] 0x8930f85579225766db745fd5fb1257a5196eefc1, value=570529051306597063171452 )
|
214 |
VerseClaimer.tokensScraped( scraper=[Sender] 0x8930f85579225766db745fd5fb1257a5196eefc1, scrapedAmount=570529051306597063171452, timestamp=1677616607 )
|
Account State Difference:
Address | Before | After | State Difference | ||
---|---|---|---|---|---|
0x249cA826...765350a18 | |||||
0x690B9A9E...Db4FaC990
Miner
| (builder0x69) | 2.146728094362284181 Eth | 2.146737184119340815 Eth | 0.000009089757056634 | |
0x8930f855...5196eEFC1 |
0.009783000929583074 Eth
Nonce: 28
|
0.00799839354601109 Eth
Nonce: 29
| 0.001784607383571984 | ||
0xE5aC5142...11f60B8d5 |
Execution Trace
VerseClaimer.CALL( )
-
VerseToken.transfer( _to=0x8930f85579225766db745FD5Fb1257A5196eEFC1, _value=570529051306597063171452 ) => ( True )
File 1 of 2: VerseClaimer
File 2 of 2: VerseToken
{"MerkleProof.sol":{"content":"// SPDX-License-Identifier: --BCOM--\n\npragma solidity =0.8.17;\n\nlibrary MerkleProof {\n\n function verify(\n bytes32[] memory proof,\n bytes32 root,\n bytes32 leaf\n )\n internal\n pure\n returns (bool)\n {\n bytes32 computedHash = leaf;\n\n for (uint256 i = 0; i \u003c proof.length; i++) {\n\n bytes32 proofElement = proof[i];\n\n computedHash = computedHash \u003c= proofElement\n ? keccak256(abi.encodePacked(computedHash, proofElement))\n : keccak256(abi.encodePacked(proofElement, computedHash));\n }\n\n return computedHash == root;\n }\n}\n"},"VerseClaimer.sol":{"content":"// SPDX-License-Identifier: --BCOM--\n\npragma solidity =0.8.17;\n\nimport \"./MerkleProof.sol\";\nimport \"./VerseHelper.sol\";\n\ncontract VerseClaimer is VerseHelper {\n\n bytes32 public immutable merkleRoot;\n uint256 public immutable createTime;\n\n uint256 immutable minimumTimeFrame;\n\n struct KeeperInfo {\n uint256 keeperRate;\n uint256 keeperTill;\n uint256 keeperInstant;\n uint256 keeperPayouts;\n }\n\n mapping(address =\u003e KeeperInfo) public keeperList;\n\n constructor(\n bytes32 _merkleRoot,\n uint256 _minimumTimeFrame,\n address _verseTokenAddress\n )\n VerseHelper(_verseTokenAddress)\n {\n require(\n _minimumTimeFrame \u003e 0,\n \"VerseClaimer: INVALID_TIMEFRAME\"\n );\n\n require(\n _merkleRoot \u003e 0,\n \"VerseClaimer: INVALID_MERKLE_ROOT\"\n );\n\n createTime = getNow();\n merkleRoot = _merkleRoot;\n minimumTimeFrame = _minimumTimeFrame;\n }\n\n function enrollRecipient(\n uint256 _index,\n address _recipient,\n uint256 _tokensLocked,\n uint256 _tokensOpened,\n uint256 _timeFrame,\n bytes32[] calldata _merkleProof\n )\n external\n {\n _enrollRecipient(\n _index,\n _recipient,\n _tokensLocked,\n _tokensOpened,\n _timeFrame,\n _merkleProof\n );\n }\n\n function enrollRecipientBulk(\n uint256 _index,\n address[] calldata _recipient,\n uint256[] calldata _tokensLocked,\n uint256[] calldata _tokensOpened,\n uint256[] calldata _timeFrame,\n bytes32[][] calldata _merkleProof\n )\n external\n {\n require(\n _recipient.length \u003c 10,\n \"VerseClaimer: TOO_MANY\"\n );\n\n for (uint256 i = 0; i \u003c _recipient.length; i++) {\n _enrollRecipient(\n _index + i,\n _recipient[i],\n _tokensLocked[i],\n _tokensOpened[i],\n _timeFrame[i],\n _merkleProof[i]\n );\n }\n }\n\n function _enrollRecipient(\n uint256 _index,\n address _recipient,\n uint256 _tokensLocked,\n uint256 _tokensOpened,\n uint256 _timeFrame,\n bytes32[] memory _merkleProof\n )\n private\n {\n require(\n keeperList[_recipient].keeperTill == 0,\n \"VerseClaimer: RECIPIENT_ALREADY_ENROLLED\"\n );\n\n bytes32 node = keccak256(\n abi.encodePacked(\n _index,\n _recipient,\n _tokensLocked,\n _tokensOpened,\n _timeFrame\n )\n );\n\n require(\n MerkleProof.verify(\n _merkleProof,\n merkleRoot,\n node\n ),\n \"VerseClaimer: INVALID_PROOF\"\n );\n\n _allocateTokens(\n _recipient,\n _tokensLocked,\n _tokensOpened,\n _timeFrame\n );\n }\n\n function _allocateTokens(\n address _recipient,\n uint256 _tokensLocked,\n uint256 _tokensOpened,\n uint256 _timeFrame\n )\n private\n {\n require(\n _timeFrame \u003e= minimumTimeFrame,\n \"VerseClaimer: INVALID_TIME_FRAME\"\n );\n\n totalRequired = totalRequired\n + _tokensOpened\n + _tokensLocked;\n\n keeperList[_recipient].keeperTill = createTime\n + _timeFrame;\n\n keeperList[_recipient].keeperRate = _tokensLocked\n / _timeFrame;\n\n keeperList[_recipient].keeperInstant = _tokensLocked\n % _timeFrame\n + _tokensOpened;\n\n _checkVerseBalance(\n totalRequired\n );\n\n emit recipientEnrolled(\n _recipient,\n _timeFrame,\n _tokensLocked,\n _tokensOpened\n );\n }\n\n function enrollAndScrape(\n uint256 _index,\n uint256 _tokensLocked,\n uint256 _tokensOpened,\n uint256 _timeFrame,\n bytes32[] calldata _merkleProof\n )\n external\n {\n _enrollRecipient(\n _index,\n msg.sender,\n _tokensLocked,\n _tokensOpened,\n _timeFrame,\n _merkleProof\n );\n\n _scrapeTokens(\n msg.sender\n );\n }\n\n function scrapeMyTokens()\n external\n {\n _scrapeTokens(\n msg.sender\n );\n }\n\n function _scrapeTokens(\n address _recipient\n )\n private\n {\n uint256 scrapeAmount = availableBalance(\n _recipient\n );\n\n keeperList[_recipient].keeperPayouts += scrapeAmount;\n\n _safeVerseScrape(\n _recipient,\n scrapeAmount\n );\n\n emit tokensScraped(\n _recipient,\n scrapeAmount,\n getNow()\n );\n }\n\n function availableBalance(\n address _recipient\n )\n public\n view\n returns (uint256 balance)\n {\n uint256 timeNow = getNow();\n uint256 timeMax = keeperList[_recipient].keeperTill;\n\n if (timeMax == 0) return 0;\n\n uint256 timePassed = timeNow \u003e timeMax\n ? timeMax - createTime\n : timeNow - createTime;\n\n balance = keeperList[_recipient].keeperRate\n * timePassed\n + keeperList[_recipient].keeperInstant\n - keeperList[_recipient].keeperPayouts;\n }\n\n function lockedBalance(\n address _recipient\n )\n external\n view\n returns (uint256 balance)\n {\n uint256 timeNow = getNow();\n\n uint256 timeRemaining =\n keeperList[_recipient].keeperTill \u003e timeNow ?\n keeperList[_recipient].keeperTill - timeNow : 0;\n\n balance = keeperList[_recipient].keeperRate\n * timeRemaining;\n }\n}\n"},"VerseHelper.sol":{"content":"// SPDX-License-Identifier: --BCOM--\n\npragma solidity =0.8.17;\n\ncontract VerseHelper {\n\n uint256 public totalRequired;\n address public immutable verseToken;\n\n event recipientEnrolled(\n address indexed recipient,\n uint256 timeFrame,\n uint256 tokensLocked,\n uint256 tokensOpened\n );\n\n event tokensScraped(\n address indexed scraper,\n uint256 scrapedAmount,\n uint256 timestamp\n );\n\n constructor(\n address _verseTokenAddress\n ) {\n if (_verseTokenAddress == address(0x0)) {\n revert(\"VerseHelper: INVALID_VERSE_TOKEN\");\n }\n\n verseToken = _verseTokenAddress;\n }\n\n bytes4 private constant TRANSFER = bytes4(\n keccak256(\n bytes(\n \"transfer(address,uint256)\"\n )\n )\n );\n\n bytes4 private constant BALANCEOF = bytes4(\n keccak256(\n bytes(\n \"balanceOf(address)\"\n )\n )\n );\n\n function _safeVerseScrape(\n address _to,\n uint256 _scrapeAmount\n )\n internal\n {\n totalRequired -= _scrapeAmount;\n\n (bool success, bytes memory data) = verseToken.call(\n abi.encodeWithSelector(\n TRANSFER,\n _to,\n _scrapeAmount\n )\n );\n\n require(\n success \u0026\u0026 (\n abi.decode(\n data, (bool)\n )\n ),\n \"VerseHelper: TRANSFER_FAILED\"\n );\n }\n\n function _checkVerseBalance(\n uint256 _required\n )\n internal\n {\n (bool success, bytes memory data) = verseToken.call(\n abi.encodeWithSelector(\n BALANCEOF,\n address(this)\n )\n );\n\n require(\n success \u0026\u0026 abi.decode(\n data, (uint256)\n ) \u003e= _required,\n \"VerseHelper: BALANCE_CHECK_FAILED\"\n );\n }\n\n function getNow()\n public\n view\n returns (uint256 time)\n {\n time = block.timestamp;\n }\n}\n"}}
File 2 of 2: VerseToken
{"MerkleProof.sol":{"content":"// SPDX-License-Identifier: --BCOM--\n\npragma solidity =0.8.17;\n\nlibrary MerkleProof {\n\n function verify(\n bytes32[] memory proof,\n bytes32 root,\n bytes32 leaf\n )\n internal\n pure\n returns (bool)\n {\n bytes32 computedHash = leaf;\n\n for (uint256 i = 0; i \u003c proof.length; i++) {\n\n bytes32 proofElement = proof[i];\n\n computedHash = computedHash \u003c= proofElement\n ? keccak256(abi.encodePacked(computedHash, proofElement))\n : keccak256(abi.encodePacked(proofElement, computedHash));\n }\n\n return computedHash == root;\n }\n}\n"},"VerseClaimer.sol":{"content":"// SPDX-License-Identifier: --BCOM--\n\npragma solidity =0.8.17;\n\nimport \"./MerkleProof.sol\";\nimport \"./VerseHelper.sol\";\n\ncontract VerseClaimer is VerseHelper {\n\n bytes32 public immutable merkleRoot;\n uint256 public immutable createTime;\n\n uint256 immutable minimumTimeFrame;\n\n struct KeeperInfo {\n uint256 keeperRate;\n uint256 keeperTill;\n uint256 keeperInstant;\n uint256 keeperPayouts;\n }\n\n mapping(address =\u003e KeeperInfo) public keeperList;\n\n constructor(\n bytes32 _merkleRoot,\n uint256 _minimumTimeFrame,\n address _verseTokenAddress\n )\n VerseHelper(_verseTokenAddress)\n {\n require(\n _minimumTimeFrame \u003e 0,\n \"VerseClaimer: INVALID_TIMEFRAME\"\n );\n\n require(\n _merkleRoot \u003e 0,\n \"VerseClaimer: INVALID_MERKLE_ROOT\"\n );\n\n createTime = getNow();\n merkleRoot = _merkleRoot;\n minimumTimeFrame = _minimumTimeFrame;\n }\n\n function enrollRecipient(\n uint256 _index,\n address _recipient,\n uint256 _tokensLocked,\n uint256 _tokensOpened,\n uint256 _timeFrame,\n bytes32[] calldata _merkleProof\n )\n external\n {\n _enrollRecipient(\n _index,\n _recipient,\n _tokensLocked,\n _tokensOpened,\n _timeFrame,\n _merkleProof\n );\n }\n\n function enrollRecipientBulk(\n uint256 _index,\n address[] calldata _recipient,\n uint256[] calldata _tokensLocked,\n uint256[] calldata _tokensOpened,\n uint256[] calldata _timeFrame,\n bytes32[][] calldata _merkleProof\n )\n external\n {\n require(\n _recipient.length \u003c 10,\n \"VerseClaimer: TOO_MANY\"\n );\n\n for (uint256 i = 0; i \u003c _recipient.length; i++) {\n _enrollRecipient(\n _index + i,\n _recipient[i],\n _tokensLocked[i],\n _tokensOpened[i],\n _timeFrame[i],\n _merkleProof[i]\n );\n }\n }\n\n function _enrollRecipient(\n uint256 _index,\n address _recipient,\n uint256 _tokensLocked,\n uint256 _tokensOpened,\n uint256 _timeFrame,\n bytes32[] memory _merkleProof\n )\n private\n {\n require(\n keeperList[_recipient].keeperTill == 0,\n \"VerseClaimer: RECIPIENT_ALREADY_ENROLLED\"\n );\n\n bytes32 node = keccak256(\n abi.encodePacked(\n _index,\n _recipient,\n _tokensLocked,\n _tokensOpened,\n _timeFrame\n )\n );\n\n require(\n MerkleProof.verify(\n _merkleProof,\n merkleRoot,\n node\n ),\n \"VerseClaimer: INVALID_PROOF\"\n );\n\n _allocateTokens(\n _recipient,\n _tokensLocked,\n _tokensOpened,\n _timeFrame\n );\n }\n\n function _allocateTokens(\n address _recipient,\n uint256 _tokensLocked,\n uint256 _tokensOpened,\n uint256 _timeFrame\n )\n private\n {\n require(\n _timeFrame \u003e= minimumTimeFrame,\n \"VerseClaimer: INVALID_TIME_FRAME\"\n );\n\n totalRequired = totalRequired\n + _tokensOpened\n + _tokensLocked;\n\n keeperList[_recipient].keeperTill = createTime\n + _timeFrame;\n\n keeperList[_recipient].keeperRate = _tokensLocked\n / _timeFrame;\n\n keeperList[_recipient].keeperInstant = _tokensLocked\n % _timeFrame\n + _tokensOpened;\n\n _checkVerseBalance(\n totalRequired\n );\n\n emit recipientEnrolled(\n _recipient,\n _timeFrame,\n _tokensLocked,\n _tokensOpened\n );\n }\n\n function enrollAndScrape(\n uint256 _index,\n uint256 _tokensLocked,\n uint256 _tokensOpened,\n uint256 _timeFrame,\n bytes32[] calldata _merkleProof\n )\n external\n {\n _enrollRecipient(\n _index,\n msg.sender,\n _tokensLocked,\n _tokensOpened,\n _timeFrame,\n _merkleProof\n );\n\n _scrapeTokens(\n msg.sender\n );\n }\n\n function scrapeMyTokens()\n external\n {\n _scrapeTokens(\n msg.sender\n );\n }\n\n function _scrapeTokens(\n address _recipient\n )\n private\n {\n uint256 scrapeAmount = availableBalance(\n _recipient\n );\n\n keeperList[_recipient].keeperPayouts += scrapeAmount;\n\n _safeVerseScrape(\n _recipient,\n scrapeAmount\n );\n\n emit tokensScraped(\n _recipient,\n scrapeAmount,\n getNow()\n );\n }\n\n function availableBalance(\n address _recipient\n )\n public\n view\n returns (uint256 balance)\n {\n uint256 timeNow = getNow();\n uint256 timeMax = keeperList[_recipient].keeperTill;\n\n if (timeMax == 0) return 0;\n\n uint256 timePassed = timeNow \u003e timeMax\n ? timeMax - createTime\n : timeNow - createTime;\n\n balance = keeperList[_recipient].keeperRate\n * timePassed\n + keeperList[_recipient].keeperInstant\n - keeperList[_recipient].keeperPayouts;\n }\n\n function lockedBalance(\n address _recipient\n )\n external\n view\n returns (uint256 balance)\n {\n uint256 timeNow = getNow();\n\n uint256 timeRemaining =\n keeperList[_recipient].keeperTill \u003e timeNow ?\n keeperList[_recipient].keeperTill - timeNow : 0;\n\n balance = keeperList[_recipient].keeperRate\n * timeRemaining;\n }\n}\n"},"VerseHelper.sol":{"content":"// SPDX-License-Identifier: --BCOM--\n\npragma solidity =0.8.17;\n\ncontract VerseHelper {\n\n uint256 public totalRequired;\n address public immutable verseToken;\n\n event recipientEnrolled(\n address indexed recipient,\n uint256 timeFrame,\n uint256 tokensLocked,\n uint256 tokensOpened\n );\n\n event tokensScraped(\n address indexed scraper,\n uint256 scrapedAmount,\n uint256 timestamp\n );\n\n constructor(\n address _verseTokenAddress\n ) {\n if (_verseTokenAddress == address(0x0)) {\n revert(\"VerseHelper: INVALID_VERSE_TOKEN\");\n }\n\n verseToken = _verseTokenAddress;\n }\n\n bytes4 private constant TRANSFER = bytes4(\n keccak256(\n bytes(\n \"transfer(address,uint256)\"\n )\n )\n );\n\n bytes4 private constant BALANCEOF = bytes4(\n keccak256(\n bytes(\n \"balanceOf(address)\"\n )\n )\n );\n\n function _safeVerseScrape(\n address _to,\n uint256 _scrapeAmount\n )\n internal\n {\n totalRequired -= _scrapeAmount;\n\n (bool success, bytes memory data) = verseToken.call(\n abi.encodeWithSelector(\n TRANSFER,\n _to,\n _scrapeAmount\n )\n );\n\n require(\n success \u0026\u0026 (\n abi.decode(\n data, (bool)\n )\n ),\n \"VerseHelper: TRANSFER_FAILED\"\n );\n }\n\n function _checkVerseBalance(\n uint256 _required\n )\n internal\n {\n (bool success, bytes memory data) = verseToken.call(\n abi.encodeWithSelector(\n BALANCEOF,\n address(this)\n )\n );\n\n require(\n success \u0026\u0026 abi.decode(\n data, (uint256)\n ) \u003e= _required,\n \"VerseHelper: BALANCE_CHECK_FAILED\"\n );\n }\n\n function getNow()\n public\n view\n returns (uint256 time)\n {\n time = block.timestamp;\n }\n}\n"},"VerseToken.sol":{"content":"// SPDX-License-Identifier: --BCOM--\n\npragma solidity =0.8.17;\n\nimport \"./VerseClaimer.sol\";\n\ncontract VerseToken {\n\n string public constant name = \"Verse\";\n string public constant symbol = \"VERSE\";\n uint8 public constant decimals = 18;\n\n VerseClaimer public immutable claimer;\n\n address constant ZERO_ADDRESS = address(0);\n uint256 constant UINT256_MAX = type(uint256).max;\n\n uint256 public totalSupply;\n\n mapping(address =\u003e uint256) public balanceOf;\n mapping(address =\u003e mapping(address =\u003e uint256)) public allowance;\n mapping(address =\u003e uint256) public nonces;\n\n bytes32 public immutable DOMAIN_SEPARATOR;\n bytes32 public constant PERMIT_TYPEHASH = keccak256(\n \"Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)\"\n );\n\n event Approval(\n address indexed owner,\n address indexed spender,\n uint256 value\n );\n\n event Transfer(\n address indexed from,\n address indexed to,\n uint256 value\n );\n\n constructor(\n uint256 _initialSupply,\n uint256 _minimumTimeFrame,\n bytes32 _merkleRoot\n ) {\n DOMAIN_SEPARATOR = keccak256(\n abi.encode(\n keccak256(\"EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)\"),\n keccak256(bytes(name)),\n keccak256(bytes(\"1\")),\n block.chainid,\n address(this)\n )\n );\n\n claimer = new VerseClaimer(\n _merkleRoot,\n _minimumTimeFrame,\n address(this)\n );\n\n _mint(\n address(claimer),\n _initialSupply\n );\n }\n\n function _mint(\n address _to,\n uint256 _value\n )\n internal\n {\n totalSupply =\n totalSupply + _value;\n\n unchecked {\n balanceOf[_to] =\n balanceOf[_to] + _value;\n }\n\n emit Transfer(\n ZERO_ADDRESS,\n _to,\n _value\n );\n }\n\n function burn(\n uint256 _value\n )\n external\n {\n _burn(\n msg.sender,\n _value\n );\n }\n\n function _burn(\n address _from,\n uint256 _value\n )\n internal\n {\n unchecked {\n totalSupply =\n totalSupply - _value;\n }\n\n balanceOf[_from] =\n balanceOf[_from] - _value;\n\n emit Transfer(\n _from,\n ZERO_ADDRESS,\n _value\n );\n }\n\n function _approve(\n address _owner,\n address _spender,\n uint256 _value\n )\n private\n {\n allowance[_owner][_spender] = _value;\n\n emit Approval(\n _owner,\n _spender,\n _value\n );\n }\n\n function _transfer(\n address _from,\n address _to,\n uint256 _value\n )\n private\n {\n balanceOf[_from] =\n balanceOf[_from] - _value;\n\n unchecked {\n balanceOf[_to] =\n balanceOf[_to] + _value;\n }\n\n emit Transfer(\n _from,\n _to,\n _value\n );\n }\n\n function approve(\n address _spender,\n uint256 _value\n )\n external\n returns (bool)\n {\n _approve(\n msg.sender,\n _spender,\n _value\n );\n\n return true;\n }\n\n function increaseAllowance(\n address _spender,\n uint256 _addedValue\n )\n external\n returns (bool)\n {\n _approve(\n msg.sender,\n _spender,\n allowance[msg.sender][_spender] + _addedValue\n );\n\n return true;\n }\n\n function decreaseAllowance(\n address _spender,\n uint256 _subtractedValue\n )\n external\n returns (bool)\n {\n _approve(\n msg.sender,\n _spender,\n allowance[msg.sender][_spender] - _subtractedValue\n );\n\n return true;\n }\n\n function transfer(\n address _to,\n uint256 _value\n )\n external\n returns (bool)\n {\n _transfer(\n msg.sender,\n _to,\n _value\n );\n\n return true;\n }\n\n function transferFrom(\n address _from,\n address _to,\n uint256 _value\n )\n external\n returns (bool)\n {\n if (allowance[_from][msg.sender] != UINT256_MAX) {\n allowance[_from][msg.sender] -= _value;\n }\n\n _transfer(\n _from,\n _to,\n _value\n );\n\n return true;\n }\n\n function permit(\n address _owner,\n address _spender,\n uint256 _value,\n uint256 _deadline,\n uint8 _v,\n bytes32 _r,\n bytes32 _s\n )\n external\n {\n require(\n _deadline \u003e= block.timestamp,\n \"VerseToken: PERMIT_CALL_EXPIRED\"\n );\n\n bytes32 digest = keccak256(\n abi.encodePacked(\n \"\\x19\\x01\",\n DOMAIN_SEPARATOR,\n keccak256(\n abi.encode(\n PERMIT_TYPEHASH,\n _owner,\n _spender,\n _value,\n nonces[_owner]++,\n _deadline\n )\n )\n )\n );\n\n if (uint256(_s) \u003e 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\n revert(\"VerseToken: INVALID_SIGNATURE\");\n }\n\n address recoveredAddress = ecrecover(\n digest,\n _v,\n _r,\n _s\n );\n\n require(\n recoveredAddress != ZERO_ADDRESS \u0026\u0026\n recoveredAddress == _owner,\n \"VerseToken: INVALID_SIGNATURE\"\n );\n\n _approve(\n _owner,\n _spender,\n _value\n );\n }\n}\n"}}