ETH Price: $2,519.56 (-0.02%)
Gas: 0.36 Gwei

Transaction Decoder

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 Code
0x249cA826...765350a18
(builder0x69)
2.146728094362284181 Eth2.146737184119340815 Eth0.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
    {"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"}}