ETH Price: $1,862.24 (-0.57%)

Transaction Decoder

Block:
14123044 at Feb-01-2022 11:12:46 PM +UTC
Transaction Fee:
0.010205706157196 ETH $19.01
Gas Used:
56,500 Gas / 180.631967384 Gwei

Emitted Events:

3 Invoice.PaymentAccepted( hash=9152C12BB4827E9E3E5FB4367DBB05F9A78F55B1F24B9D7BD4AF0D12E7523D30, tokenContract=0x00000000...000000000, time=1643757166, value=518215000000000000 )

Account State Difference:

  Address   Before After State Difference Code
0x52dE8D3f...2B80DCf12
(BitPay: Invoice 2)
46.430001000000000006 Eth46.948216000000000006 Eth0.518215
(F2Pool Old)
6,640.104936043243434653 Eth6,640.106488337099783653 Eth0.001552293856349
0x8767614D...af2E7D353
0.540011777662916051 Eth
Nonce: 51
0.011591071505720051 Eth
Nonce: 52
0.528420706157196

Execution Trace

ETH 0.518215 Invoice.pay( value=518215000000000000, gasPrice=164210879440, expiration=1643758065, payload=1192A0D5A3A445442226F73734737ACF627396B19D1E7FCC72EB7E87A05A81AE, hash=9152C12BB4827E9E3E5FB4367DBB05F9A78F55B1F24B9D7BD4AF0D12E7523D30, v=28, r=5B6BC1F5A3FB832D7D7809DECFA5FAF7B5D8CB5B8E7737CFD584C5475CAC00CC, s=5C7E8E54B0CFF62B641C4E48637B3F6E64D728C56537686237CA4FC9D1DAB4A5, tokenContract=0x0000000000000000000000000000000000000000 )
  • Null: 0x000...001.c1bd6bcc( )
    {"IERC20.sol":{"content":"pragma solidity ^0.4.23;\n\ncontract IERC20 {\n  function totalSupply() public constant returns (uint);\n  function balanceOf(address tokenOwner) public constant returns (uint balance);\n  function allowance(address tokenOwner, address spender) public constant returns (uint remaining);\n  function transfer(address to, uint tokens) public returns (bool success);\n  function approve(address spender, uint tokens) public returns (bool success);\n  function transferFrom(address from, address to, uint tokens) public returns (bool success);\n\n  event Transfer(address indexed from, address indexed to, uint tokens);\n  event Approval(address indexed tokenOwner, address indexed spender, uint tokens);\n}\n"},"Invoice_old.sol":{"content":"pragma solidity ^0.4.23;\n\nimport \"./IERC20.sol\";\n\n\ncontract Invoice {\n  address public owner;\n  address public quoteSigner;\n  mapping(bytes32 =\u003e bool) public isPaid;\n\n  event PaymentAccepted(bytes32 indexed hash, address indexed tokenContract,  uint time, uint value);\n\n\n  constructor(address valueSigner) public {\n    owner = msg.sender;\n    quoteSigner = valueSigner;\n  }\n\n  function isValidPayment(\n    uint value,\n    uint gasPrice,\n    uint expiration,\n    bytes32 payload,\n    bytes32 hash,\n    uint8 v,\n    bytes32 r,\n    bytes32 s,\n    address tokenContract\n  ) public view returns(bool valid) {\n    bool isValid = !isPaid[payload];\n    isValid = isValid \u0026\u0026 block.timestamp \u003c= expiration;\n    isValid = isValid \u0026\u0026 tx.gasprice \u003e= gasPrice;\n    bytes memory prefix = \"\\x19Ethereum Signed Message:\\n32\";\n    bytes32 ourHash = keccak256(abi.encodePacked(value, gasPrice, expiration, payload, tokenContract));\n    bytes32 payloadHash = keccak256(abi.encodePacked(prefix, ourHash));\n    isValid = isValid \u0026\u0026 ourHash == hash;\n    isValid = isValid \u0026\u0026 (ecrecover(payloadHash, v, r, s) == quoteSigner);\n    return isValid;\n  }\n\n  function validatePayment(\n    uint value,\n    uint gasPrice,\n    uint expiration,\n    bytes32 payload,\n    bytes32 hash,\n    uint8 v,\n    bytes32 r,\n    bytes32 s,\n    address tokenContract\n  ) public view returns(bool valid) {\n    require(isPaid[payload] == false, \"Already been paid\");\n    require(block.timestamp \u003c= expiration, \"Payment is late\");\n    require(tx.gasprice \u003e= gasPrice, \"Gas price lower than required\");\n    bytes memory prefix = \"\\x19Ethereum Signed Message:\\n32\";\n    bytes32 ourHash = keccak256(abi.encodePacked(value, gasPrice, expiration, payload, tokenContract));\n    bytes32 payloadHash = keccak256(abi.encodePacked(prefix, ourHash));\n    require(ourHash == hash, \"Hash mismatch\");\n    require(ecrecover(payloadHash, v, r, s) == quoteSigner, \"Signature mismatch for quote\");\n    return true;\n  }\n\n\n  function pay(\n    uint value,\n    uint gasPrice,\n    uint expiration,\n    bytes32 payload,\n    bytes32 hash,\n    uint8 v,\n    bytes32 r,\n    bytes32 s,\n    address tokenContract\n  ) public payable {\n    if(tokenContract == 0x0) {\n      require(validatePayment(msg.value, gasPrice, expiration, payload, hash, v, r, s, tokenContract), \"Only accept valid payments\");\n    } else {\n      IERC20 token = IERC20(tokenContract);\n      require(token.allowance(msg.sender, address(this)) \u003e= value, \"Must have enough tokens to pay\");\n      require(validatePayment(value, gasPrice, expiration, payload, hash, v, r, s, tokenContract), \"Only accept valid payments\");\n      require(token.transferFrom(msg.sender, address(this), value), \"Transfer must succeed\");\n    }\n    isPaid[payload] = true;\n    emit PaymentAccepted(hash, tokenContract, block.timestamp, value);\n  }\n\n  modifier isAdmin() {\n    require(msg.sender == owner, \"Must be the contract owner\");\n    _;\n  }\n\n  function withdraw(address tokenContract) public isAdmin {\n    if(tokenContract == 0x0) {\n      owner.transfer(address(this).balance);\n    } else {\n      IERC20 token = IERC20(tokenContract);\n      uint balance = token.balanceOf(address(this));\n      require(token.transfer(owner, balance), \"Must succeed withdrawing tokens\");\n    }\n  }\n\n  function setSigner(address newQuoteSigner) public isAdmin {\n    quoteSigner = newQuoteSigner;\n  }\n  function setAdmin(address newAdmin) public isAdmin {\n    owner = newAdmin;\n  }\n}\n\n"}}