From d735ed62b158d5e526a22c1e15965c111704617a Mon Sep 17 00:00:00 2001 From: Christian Lohr Date: Fri, 9 Aug 2024 13:04:31 +0200 Subject: [PATCH 1/6] feat: gas estimation changes (#419) * feat: gas estimation loops * chore: remove unused test * feat: estimate messages before sending * feat: submit_batch estimation * fix: linting * Update chain/evm/client.go Co-authored-by: Luis Carvalho * Update chain/evm/compass.go Co-authored-by: Luis Carvalho * Update chain/evm/compass.go Co-authored-by: Luis Carvalho * Update chain/evm/compass.go Co-authored-by: Luis Carvalho * Update chain/paloma/skyway.go Co-authored-by: Luis Carvalho * fix: linting --------- Co-authored-by: Luis Carvalho --- chain/evm/abi/compass/compass.abi | 1000 +++++++++++- chain/evm/abi/compass/compass.go | 1518 ++++++++++++++++-- chain/evm/abi/feemgr/feemgr.abi | 296 ++++ chain/evm/abi/feemgr/feemgr.go | 589 +++++++ chain/evm/client.go | 44 +- chain/evm/client_test.go | 33 +- chain/evm/compass.go | 262 ++- chain/evm/compass_test.go | 920 ++++++++++- chain/evm/contracts/compass-evm.json | 1218 +++++++++++--- chain/evm/factory.go | 2 + chain/evm/mock_ethClientConn_test.go | 9 +- chain/evm/mock_ethClientToFilterLogs_test.go | 6 +- chain/evm/mock_ethClienter_test.go | 9 +- chain/evm/mock_evmClienter_test.go | 130 +- chain/evm/mock_mevClient_test.go | 6 +- chain/evm/mocks/CompassBinding.go | 107 +- chain/evm/processor.go | 60 +- chain/mocks/Processor.go | 63 +- chain/paloma/client.go | 59 +- chain/paloma/client_test.go | 4 +- chain/paloma/mocks/IonClient.go | 6 +- chain/paloma/mocks/MessageSender.go | 8 +- chain/paloma/query.go | 127 +- chain/paloma/skyway.go | 76 +- chain/paloma/statusupdater.go | 2 +- chain/paloma/statusupdater_test.go | 4 +- chain/relayer.go | 17 + go.mod | 3 +- go.sum | 4 +- health/mocks/PalomaStatuser.go | 6 +- relayer/build_processors.go | 1 + relayer/build_processors_test.go | 8 +- relayer/health_check_test.go | 6 +- relayer/message_attester_test.go | 4 +- relayer/message_estimator.go | 82 + relayer/message_estimator_test.go | 155 ++ relayer/message_relayer_test.go | 4 +- relayer/message_signer_test.go | 4 +- relayer/mocks/EvmFactorier.go | 23 +- relayer/mocks/PalomaClienter.go | 113 +- relayer/relayer.go | 5 + relayer/skyway_batch_estimator.go | 83 + relayer/start.go | 10 +- relayer/update_chain_infos_test.go | 6 +- util/time/mocks/Time.go | 6 +- 45 files changed, 6407 insertions(+), 691 deletions(-) create mode 100644 chain/evm/abi/feemgr/feemgr.abi create mode 100644 chain/evm/abi/feemgr/feemgr.go create mode 100644 relayer/message_estimator.go create mode 100644 relayer/message_estimator_test.go create mode 100644 relayer/skyway_batch_estimator.go diff --git a/chain/evm/abi/compass/compass.abi b/chain/evm/abi/compass/compass.abi index 9add0244..666eeae2 100644 --- a/chain/evm/abi/compass/compass.abi +++ b/chain/evm/abi/compass/compass.abi @@ -1 +1,999 @@ -[{"anonymous":false,"inputs":[{"indexed":false,"name":"checkpoint","type":"bytes32"},{"indexed":false,"name":"valset_id","type":"uint256"}],"name":"ValsetUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"logic_contract_address","type":"address"},{"indexed":false,"name":"payload","type":"bytes"},{"indexed":false,"name":"message_id","type":"uint256"}],"name":"LogicCallEvent","type":"event"},{"inputs":[{"name":"turnstone_id","type":"bytes32"},{"components":[{"name":"validators","type":"address[]"},{"name":"powers","type":"uint256[]"},{"name":"valset_id","type":"uint256"}],"name":"valset","type":"tuple"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"turnstone_id","outputs":[{"name":"","type":"bytes32"}],"stateMutability":"pure","type":"function"},{"inputs":[{"components":[{"components":[{"name":"validators","type":"address[]"},{"name":"powers","type":"uint256[]"},{"name":"valset_id","type":"uint256"}],"name":"valset","type":"tuple"},{"components":[{"name":"v","type":"uint256"},{"name":"r","type":"uint256"},{"name":"s","type":"uint256"}],"name":"signatures","type":"tuple[]"}],"name":"consensus","type":"tuple"},{"components":[{"name":"validators","type":"address[]"},{"name":"powers","type":"uint256[]"},{"name":"valset_id","type":"uint256"}],"name":"new_valset","type":"tuple"}],"name":"update_valset","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"components":[{"name":"validators","type":"address[]"},{"name":"powers","type":"uint256[]"},{"name":"valset_id","type":"uint256"}],"name":"valset","type":"tuple"},{"components":[{"name":"v","type":"uint256"},{"name":"r","type":"uint256"},{"name":"s","type":"uint256"}],"name":"signatures","type":"tuple[]"}],"name":"consensus","type":"tuple"},{"components":[{"name":"logic_contract_address","type":"address"},{"name":"payload","type":"bytes"}],"name":"args","type":"tuple"},{"name":"message_id","type":"uint256"},{"name":"deadline","type":"uint256"}],"name":"submit_logic_call","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"last_checkpoint","outputs":[{"name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"last_valset_id","outputs":[{"name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"name":"arg0","type":"uint256"}],"name":"message_id_used","outputs":[{"name":"","type":"bool"}],"stateMutability":"view","type":"function"}]' 0x60206111126000396000516020816110f20160003960005181016101406020826110f201600039600051116110ed576020816110f2016000396000518060405260008161014081116110ed57801561008357905b60208160051b60208601016110f2016000396000518060a01c6110ed578160051b60600152600101818118610053575b505050506020602082016110f20160003960005181016101406020826110f201600039600051116110ed576020816110f2016000396000518061286052602082018160051b80826110f20161288039505050506020604082016110f2016000396000516150805250346110ed5760206110f260003960005161a200526040366150a037600060405161014081116110ed57801561018857905b8060051b606001516150e0526150a0516150c051612860518110156110ed5760051b61288001518082018281106110ed57905090506150a05263aaaaaaaa6150a0511061016857610188565b6150c051600181018181106110ed5790506150c05260010181811861011c575b505063aaaaaaaa6150a05110156101ff5760126150e0527f496e73756666696369656e7420506f7765720000000000000000000000000000615100526150e0506150e0518061510001601f826000031636823750506308c379a06150a05260206150c052601f19601f6150e05101166044016150bcfd5b63299018c261510452600460808061512452806151240160006040518083528060051b60008261014081116110ed57801561025357905b8060051b606001518160051b602088010152600101818118610236575b50508201602001915050905081019050806151445280615124016000612860518083528060051b60008261014081116110ed5780156102ac57905b8060051b61288001518160051b60208801015260010181811861028e575b50508201602001915050905081019050615080516151645260206110f26000396000516151845201615100526151008051602082012090506150e0526150e051600055615080516001557f09d40458cf931745f8d532ef13fa9c74bfb7fe0edcee88e0a677b0cbef88f0f96150e0516151005261508051615120526040615100a1610dad61033f61945339610dcd619453f36003361161000c57610a38565b60003560e01c34610d9b5763f0f40504811861003e5760043610610d9b576020610dad60003960005160405260206040f35b63eadf4af78118610518576101e43610610d9b576004356004018035810180358101610140813511610d9b5780358061cb40526000816101408111610d9b5780156100ab57905b8060051b6020850101358060a01c610d9b578160051b61cb600152600101818118610085575b5050505060208101358101610140813511610d9b5780358061f36052602082018160051b808261f3803750505050604081013562011b80525060208101358101610140813511610d9b5780358062011ba0526020820160608202808262011bc037505050505060243560040180358101610140813511610d9b57803580620193c0526000816101408111610d9b57801561016857905b8060051b6020850101358060a01c610d9b578160051b620193e00152600101818118610141575b5050505060208101358101610140813511610d9b578035806201bbe052602082018160051b80826201bc00375050505060408101356201e400525062011b80516201e40051116102215760116201e420527f496e76616c69642056616c7365742049440000000000000000000000000000006201e440526201e420506201e42051806201e44001601f826000031636823750506308c379a06201e3e05260206201e40052601f19601f6201e4205101166044016201e3fcfd5b6040366201e420376000620193c0516101408111610d9b5780156102b857905b8060051b620193e001516201e460526201e420516201e440516201bbe051811015610d9b5760051b6201bc000151808201828110610d9b57905090506201e4205263aaaaaaaa6201e4205110610296576102b8565b6201e4405160018101818110610d9b5790506201e44052600101818118610241575b505063aaaaaaaa6201e4205110156103395760126201e460527f496e73756666696369656e7420506f77657200000000000000000000000000006201e480526201e460506201e46051806201e48001601f826000031636823750506308c379a06201e4205260206201e44052601f19601f6201e4605101166044016201e43cfd5b61cb4051806040528060051b8060608261cb6060045afa50505061f3605180612860528060051b806128808261f38060045afa50505062011b8051615080526103846201e460610cb1565b6201e4605160005418156104015760146201e480527f496e636f727265637420436865636b706f696e740000000000000000000000006201e4a0526201e480506201e48051806201e4a001601f826000031636823750506308c379a06201e4405260206201e46052601f19601f6201e4805101166044016201e45cfd5b620193c051806040528060051b80606082620193e060045afa5050506201bbe05180612860528060051b80612880826201bc0060045afa5050506201e40051615080526104506201e480610cb1565b6201e480516201e4605261cb4051806101a0528060051b806101c08261cb6060045afa50505061f36051806129c0528060051b806129e08261f38060045afa50505062011b80516151e05262011ba051806152005260608102806152208262011bc060045afa5050506201e4605161ca20526104ca610ae1565b6201e460516000556201e400516001557f09d40458cf931745f8d532ef13fa9c74bfb7fe0edcee88e0a677b0cbef88f0f96201e460516201e480526201e400516201e4a05260406201e480a1005b631029ae6f81186109cb576101e43610610d9b576004356004018035810180358101610140813511610d9b5780358061cb40526000816101408111610d9b57801561058557905b8060051b6020850101358060a01c610d9b578160051b61cb60015260010181811861055f575b5050505060208101358101610140813511610d9b5780358061f36052602082018160051b808261f3803750505050604081013562011b80525060208101358101610140813511610d9b5780358062011ba0526020820160608202808262011bc037505050505060243560040180358060a01c610d9b57620193c05260208101358101615000813511610d9b57803580620193e0526020820181816201940037505050506064354211156106a15760076201e400527f54696d656f7574000000000000000000000000000000000000000000000000006201e420526201e400506201e40051806201e42001601f826000031636823750506308c379a06201e3c05260206201e3e052601f19601f6201e4005101166044016201e3dcfd5b60026044356020526000526040600020541561072657600f6201e400527f55736564204d6573736167655f494400000000000000000000000000000000006201e420526201e400506201e40051806201e42001601f826000031636823750506308c379a06201e3c05260206201e3e052601f19601f6201e4005101166044016201e3dcfd5b6001600260443560205260005260406000205561cb4051806040528060051b8060608261cb6060045afa50505061f3605180612860528060051b806128808261f38060045afa50505062011b8051615080526107846201e400610cb1565b6201e4005160005418156108015760146201e420527f496e636f727265637420436865636b706f696e740000000000000000000000006201e440526201e420506201e42051806201e44001601f826000031636823750506308c379a06201e3e05260206201e40052601f19601f6201e4205101166044016201e3fcfd5b63980721b26201e4245260046080806201e44452806201e444016040620193c0518252806020830152808201620193e051808252602082018181836201940060045afa5050508051806020830101601f82600003163682375050601f19601f825160200101169050810190509050810190506044356201e464526020610dad6000396000516201e484526064356201e4a452016201e420526201e4208051602082012090506201e4005261cb4051806101a0528060051b806101c08261cb6060045afa50505061f36051806129c0528060051b806129e08261f38060045afa50505062011b80516151e05262011ba051806152005260608102806152208262011bc060045afa5050506201e4005161ca205261091b610ae1565b620193e0600060008251602084016000620193c0515af19050610943573d600060003e3d6000fd5b7f0d2bd340033bb64fd086788e6685b480a9bf10b98d63e9b8073eb5d0bd6c6ee96060620193c0516201e42052806201e44052806201e42001620193e051808252602082018181836201940060045afa5050508051806020830101601f82600003163682375050601f19601f825160200101169050810190506044356201e460526201e420a1005b63a9a4a98381186109ea5760043610610d9b5760005460405260206040f35b634da6ecc98118610a095760043610610d9b5760015460405260206040f35b6338d6172d8118610a365760243610610d9b57600260043560205260005260406000205460405260206040f35b505b60006000fd5b6000601c610100527f19457468657265756d205369676e6564204d6573736167653a0a333200000000610120526101008051602082018361016001815181525050808301925050506060518161016001526020810190508061014052610140905080516020820120905060e05260e051610100526080516101205260a0516101405260c0516101605260206000608061010060015afa5060005160405114815250565b60403661ca40376000615200516101408111610d9b578015610c3857905b6060810261522001805161ca8052602081015161caa052604081015161cac0525061ca805115610c185761ca40516101a051811015610d9b5760051b6101c0015160405261ca205160605261ca805160805261caa05160a05261cac05160c052610b6a61cae0610a3e565b61cae051610bd857601161cb00527f496e76616c6964205369676e617475726500000000000000000000000000000061cb205261cb005061cb00518061cb2001601f826000031636823750506308c379a061cac052602061cae052601f19601f61cb0051011660440161cadcfd5b61ca605161ca40516129c051811015610d9b5760051b6129e00151808201828110610d9b579050905061ca605263aaaaaaaa61ca605110610c1857610c38565b61ca405160018101818110610d9b57905061ca4052600101818118610aff575b505063aaaaaaaa61ca60511015610caf57601261ca80527f496e73756666696369656e7420506f776572000000000000000000000000000061caa05261ca805061ca80518061caa001601f826000031636823750506308c379a061ca4052602061ca6052601f19601f61ca8051011660440161ca5cfd5b565b63299018c26150a45260046080806150c452806150c40160006040518083528060051b6000826101408111610d9b578015610d0557905b8060051b606001518160051b602088010152600101818118610ce8575b50508201602001915050905081019050806150e452806150c4016000612860518083528060051b6000826101408111610d9b578015610d5e57905b8060051b61288001518160051b602088010152600101818118610d40575b5050820160200191505090508101905061508051615104526020610dad60003960005161512452016150a0526150a0805160208201209050815250565b600080fda165767970657283000307000b005b600080fd +[ + { + "anonymous":false, + "inputs":[ + { + "indexed":false, + "name":"checkpoint", + "type":"bytes32" + }, + { + "indexed":false, + "name":"valset_id", + "type":"uint256" + }, + { + "indexed":false, + "name":"event_id", + "type":"uint256" + } + ], + "name":"ValsetUpdated", + "type":"event" + }, + { + "anonymous":false, + "inputs":[ + { + "indexed":false, + "name":"logic_contract_address", + "type":"address" + }, + { + "indexed":false, + "name":"payload", + "type":"bytes" + }, + { + "indexed":false, + "name":"message_id", + "type":"uint256" + }, + { + "indexed":false, + "name":"event_id", + "type":"uint256" + } + ], + "name":"LogicCallEvent", + "type":"event" + }, + { + "anonymous":false, + "inputs":[ + { + "indexed":false, + "name":"token", + "type":"address" + }, + { + "indexed":false, + "name":"sender", + "type":"address" + }, + { + "indexed":false, + "name":"receiver", + "type":"bytes32" + }, + { + "indexed":false, + "name":"amount", + "type":"uint256" + }, + { + "indexed":false, + "name":"nonce", + "type":"uint256" + }, + { + "indexed":false, + "name":"event_id", + "type":"uint256" + } + ], + "name":"SendToPalomaEvent", + "type":"event" + }, + { + "anonymous":false, + "inputs":[ + { + "indexed":false, + "name":"token", + "type":"address" + }, + { + "indexed":false, + "name":"batch_id", + "type":"uint256" + }, + { + "indexed":false, + "name":"nonce", + "type":"uint256" + }, + { + "indexed":false, + "name":"event_id", + "type":"uint256" + } + ], + "name":"BatchSendEvent", + "type":"event" + }, + { + "anonymous":false, + "inputs":[ + { + "indexed":false, + "name":"paloma_denom", + "type":"string" + }, + { + "indexed":false, + "name":"token_contract", + "type":"address" + }, + { + "indexed":false, + "name":"name", + "type":"string" + }, + { + "indexed":false, + "name":"symbol", + "type":"string" + }, + { + "indexed":false, + "name":"decimals", + "type":"uint8" + }, + { + "indexed":false, + "name":"event_id", + "type":"uint256" + } + ], + "name":"ERC20DeployedEvent", + "type":"event" + }, + { + "anonymous":false, + "inputs":[ + { + "indexed":false, + "name":"depositor_paloma_address", + "type":"bytes32" + }, + { + "indexed":false, + "name":"sender", + "type":"address" + }, + { + "indexed":false, + "name":"amount", + "type":"uint256" + } + ], + "name":"FundsDepositedEvent", + "type":"event" + }, + { + "anonymous":false, + "inputs":[ + { + "indexed":false, + "name":"receiver", + "type":"address" + }, + { + "indexed":false, + "name":"amount", + "type":"uint256" + } + ], + "name":"FundsWithdrawnEvent", + "type":"event" + }, + { + "anonymous":false, + "inputs":[ + { + "indexed":false, + "name":"new_compass", + "type":"address" + }, + { + "indexed":false, + "name":"event_id", + "type":"uint256" + } + ], + "name":"UpdateCompassAddressInFeeManager", + "type":"event" + }, + { + "anonymous":false, + "inputs":[ + { + "indexed":false, + "name":"contract_address", + "type":"address" + }, + { + "indexed":false, + "name":"buyer", + "type":"address" + }, + { + "indexed":false, + "name":"paloma", + "type":"bytes32" + }, + { + "indexed":false, + "name":"node_count", + "type":"uint256" + }, + { + "indexed":false, + "name":"grain_amount", + "type":"uint256" + }, + { + "indexed":false, + "name":"nonce", + "type":"uint256" + }, + { + "indexed":false, + "name":"event_id", + "type":"uint256" + } + ], + "name":"NodeSaleEvent", + "type":"event" + }, + { + "inputs":[ + { + "name":"_compass_id", + "type":"bytes32" + }, + { + "name":"_event_id", + "type":"uint256" + }, + { + "name":"_gravity_nonce", + "type":"uint256" + }, + { + "components":[ + { + "name":"validators", + "type":"address[]" + }, + { + "name":"powers", + "type":"uint256[]" + }, + { + "name":"valset_id", + "type":"uint256" + } + ], + "name":"valset", + "type":"tuple" + }, + { + "name":"fee_manager", + "type":"address" + } + ], + "stateMutability":"nonpayable", + "type":"constructor" + }, + { + "inputs":[ + { + "components":[ + { + "components":[ + { + "name":"validators", + "type":"address[]" + }, + { + "name":"powers", + "type":"uint256[]" + }, + { + "name":"valset_id", + "type":"uint256" + } + ], + "name":"valset", + "type":"tuple" + }, + { + "components":[ + { + "name":"v", + "type":"uint256" + }, + { + "name":"r", + "type":"uint256" + }, + { + "name":"s", + "type":"uint256" + } + ], + "name":"signatures", + "type":"tuple[]" + } + ], + "name":"consensus", + "type":"tuple" + }, + { + "components":[ + { + "name":"validators", + "type":"address[]" + }, + { + "name":"powers", + "type":"uint256[]" + }, + { + "name":"valset_id", + "type":"uint256" + } + ], + "name":"new_valset", + "type":"tuple" + }, + { + "name":"relayer", + "type":"address" + }, + { + "name":"gas_estimate", + "type":"uint256" + } + ], + "name":"update_valset", + "outputs":[ + + ], + "stateMutability":"nonpayable", + "type":"function" + }, + { + "inputs":[ + { + "components":[ + { + "components":[ + { + "name":"validators", + "type":"address[]" + }, + { + "name":"powers", + "type":"uint256[]" + }, + { + "name":"valset_id", + "type":"uint256" + } + ], + "name":"valset", + "type":"tuple" + }, + { + "components":[ + { + "name":"v", + "type":"uint256" + }, + { + "name":"r", + "type":"uint256" + }, + { + "name":"s", + "type":"uint256" + } + ], + "name":"signatures", + "type":"tuple[]" + } + ], + "name":"consensus", + "type":"tuple" + }, + { + "components":[ + { + "name":"logic_contract_address", + "type":"address" + }, + { + "name":"payload", + "type":"bytes" + } + ], + "name":"args", + "type":"tuple" + }, + { + "components":[ + { + "name":"relayer_fee", + "type":"uint256" + }, + { + "name":"community_fee", + "type":"uint256" + }, + { + "name":"security_fee", + "type":"uint256" + }, + { + "name":"fee_payer_paloma_address", + "type":"bytes32" + } + ], + "name":"fee_args", + "type":"tuple" + }, + { + "name":"message_id", + "type":"uint256" + }, + { + "name":"deadline", + "type":"uint256" + }, + { + "name":"relayer", + "type":"address" + } + ], + "name":"submit_logic_call", + "outputs":[ + + ], + "stateMutability":"nonpayable", + "type":"function" + }, + { + "inputs":[ + { + "name":"token", + "type":"address" + }, + { + "name":"receiver", + "type":"bytes32" + }, + { + "name":"amount", + "type":"uint256" + } + ], + "name":"send_token_to_paloma", + "outputs":[ + + ], + "stateMutability":"nonpayable", + "type":"function" + }, + { + "inputs":[ + { + "components":[ + { + "components":[ + { + "name":"validators", + "type":"address[]" + }, + { + "name":"powers", + "type":"uint256[]" + }, + { + "name":"valset_id", + "type":"uint256" + } + ], + "name":"valset", + "type":"tuple" + }, + { + "components":[ + { + "name":"v", + "type":"uint256" + }, + { + "name":"r", + "type":"uint256" + }, + { + "name":"s", + "type":"uint256" + } + ], + "name":"signatures", + "type":"tuple[]" + } + ], + "name":"consensus", + "type":"tuple" + }, + { + "name":"token", + "type":"address" + }, + { + "components":[ + { + "name":"receiver", + "type":"address[]" + }, + { + "name":"amount", + "type":"uint256[]" + } + ], + "name":"args", + "type":"tuple" + }, + { + "name":"batch_id", + "type":"uint256" + }, + { + "name":"deadline", + "type":"uint256" + }, + { + "name":"relayer", + "type":"address" + }, + { + "name":"gas_estimate", + "type":"uint256" + } + ], + "name":"submit_batch", + "outputs":[ + + ], + "stateMutability":"nonpayable", + "type":"function" + }, + { + "inputs":[ + { + "name":"buyer", + "type":"address" + }, + { + "name":"paloma", + "type":"bytes32" + }, + { + "name":"node_count", + "type":"uint256" + }, + { + "name":"grain_amount", + "type":"uint256" + } + ], + "name":"emit_nodesale_event", + "outputs":[ + + ], + "stateMutability":"nonpayable", + "type":"function" + }, + { + "inputs":[ + { + "name":"_paloma_denom", + "type":"string" + }, + { + "name":"_name", + "type":"string" + }, + { + "name":"_symbol", + "type":"string" + }, + { + "name":"_decimals", + "type":"uint8" + }, + { + "name":"_blueprint", + "type":"address" + } + ], + "name":"deploy_erc20", + "outputs":[ + + ], + "stateMutability":"nonpayable", + "type":"function" + }, + { + "inputs":[ + { + "name":"contract_address", + "type":"address" + }, + { + "name":"payload", + "type":"bytes" + } + ], + "name":"arbitrary_view", + "outputs":[ + { + "name":"", + "type":"bytes" + } + ], + "stateMutability":"view", + "type":"function" + }, + { + "inputs":[ + { + "name":"depositor_paloma_address", + "type":"bytes32" + }, + { + "name":"amount", + "type":"uint256" + } + ], + "name":"deposit", + "outputs":[ + + ], + "stateMutability":"payable", + "type":"function" + }, + { + "inputs":[ + { + "name":"amount", + "type":"uint256" + }, + { + "name":"dex", + "type":"address" + }, + { + "name":"payload", + "type":"bytes" + }, + { + "name":"min_grain", + "type":"uint256" + } + ], + "name":"withdraw", + "outputs":[ + + ], + "stateMutability":"nonpayable", + "type":"function" + }, + { + "inputs":[ + { + "name":"amount", + "type":"uint256" + } + ], + "name":"security_fee_topup", + "outputs":[ + + ], + "stateMutability":"payable", + "type":"function" + }, + { + "inputs":[ + { + "components":[ + { + "components":[ + { + "name":"validators", + "type":"address[]" + }, + { + "name":"powers", + "type":"uint256[]" + }, + { + "name":"valset_id", + "type":"uint256" + } + ], + "name":"valset", + "type":"tuple" + }, + { + "components":[ + { + "name":"v", + "type":"uint256" + }, + { + "name":"r", + "type":"uint256" + }, + { + "name":"s", + "type":"uint256" + } + ], + "name":"signatures", + "type":"tuple[]" + } + ], + "name":"consensus", + "type":"tuple" + }, + { + "name":"message_id", + "type":"uint256" + }, + { + "name":"deadline", + "type":"uint256" + }, + { + "name":"receiver", + "type":"bytes32" + }, + { + "name":"relayer", + "type":"address" + }, + { + "name":"gas_estimate", + "type":"uint256" + }, + { + "name":"amount", + "type":"uint256" + }, + { + "name":"dex", + "type":"address" + }, + { + "name":"payload", + "type":"bytes" + }, + { + "name":"min_grain", + "type":"uint256" + } + ], + "name":"bridge_community_tax_to_paloma", + "outputs":[ + + ], + "stateMutability":"nonpayable", + "type":"function" + }, + { + "inputs":[ + { + "components":[ + { + "components":[ + { + "name":"validators", + "type":"address[]" + }, + { + "name":"powers", + "type":"uint256[]" + }, + { + "name":"valset_id", + "type":"uint256" + } + ], + "name":"valset", + "type":"tuple" + }, + { + "components":[ + { + "name":"v", + "type":"uint256" + }, + { + "name":"r", + "type":"uint256" + }, + { + "name":"s", + "type":"uint256" + } + ], + "name":"signatures", + "type":"tuple[]" + } + ], + "name":"consensus", + "type":"tuple" + }, + { + "name":"deadline", + "type":"uint256" + }, + { + "name":"gas_estimate", + "type":"uint256" + }, + { + "name":"_new_compass", + "type":"address" + }, + { + "name":"relayer", + "type":"address" + } + ], + "name":"update_compass_address_in_fee_manager", + "outputs":[ + + ], + "stateMutability":"nonpayable", + "type":"function" + }, + { + "inputs":[ + + ], + "name":"compass_id", + "outputs":[ + { + "name":"", + "type":"bytes32" + } + ], + "stateMutability":"view", + "type":"function" + }, + { + "inputs":[ + + ], + "name":"last_checkpoint", + "outputs":[ + { + "name":"", + "type":"bytes32" + } + ], + "stateMutability":"view", + "type":"function" + }, + { + "inputs":[ + + ], + "name":"last_valset_id", + "outputs":[ + { + "name":"", + "type":"uint256" + } + ], + "stateMutability":"view", + "type":"function" + }, + { + "inputs":[ + + ], + "name":"last_event_id", + "outputs":[ + { + "name":"", + "type":"uint256" + } + ], + "stateMutability":"view", + "type":"function" + }, + { + "inputs":[ + + ], + "name":"last_gravity_nonce", + "outputs":[ + { + "name":"", + "type":"uint256" + } + ], + "stateMutability":"view", + "type":"function" + }, + { + "inputs":[ + { + "name":"arg0", + "type":"address" + } + ], + "name":"last_batch_id", + "outputs":[ + { + "name":"", + "type":"uint256" + } + ], + "stateMutability":"view", + "type":"function" + }, + { + "inputs":[ + { + "name":"arg0", + "type":"uint256" + } + ], + "name":"message_id_used", + "outputs":[ + { + "name":"", + "type":"bool" + } + ], + "stateMutability":"view", + "type":"function" + }, + { + "inputs":[ + + ], + "name":"slc_switch", + "outputs":[ + { + "name":"", + "type":"bool" + } + ], + "stateMutability":"view", + "type":"function" + }, + { + "inputs":[ + + ], + "name":"FEE_MANAGER", + "outputs":[ + { + "name":"", + "type":"address" + } + ], + "stateMutability":"view", + "type":"function" + } +] diff --git a/chain/evm/abi/compass/compass.go b/chain/evm/abi/compass/compass.go index d75dc642..edee1db3 100644 --- a/chain/evm/abi/compass/compass.go +++ b/chain/evm/abi/compass/compass.go @@ -41,6 +41,12 @@ type Struct3 struct { Payload []byte } +// Struct5 is an auto generated low-level Go binding around an user-defined struct. +type Struct5 struct { + Receiver []common.Address + Amount []*big.Int +} + // Struct0 is an auto generated low-level Go binding around an user-defined struct. type Struct0 struct { Validators []common.Address @@ -55,9 +61,17 @@ type Struct1 struct { S *big.Int } +// Struct4 is an auto generated low-level Go binding around an user-defined struct. +type Struct4 struct { + RelayerFee *big.Int + CommunityFee *big.Int + SecurityFee *big.Int + FeePayerPalomaAddress [32]byte +} + // CompassMetaData contains all meta data concerning the Compass contract. var CompassMetaData = &bind.MetaData{ - ABI: "[{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"name\":\"checkpoint\",\"type\":\"bytes32\"},{\"indexed\":false,\"name\":\"valset_id\",\"type\":\"uint256\"}],\"name\":\"ValsetUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"name\":\"logic_contract_address\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"payload\",\"type\":\"bytes\"},{\"indexed\":false,\"name\":\"message_id\",\"type\":\"uint256\"}],\"name\":\"LogicCallEvent\",\"type\":\"event\"},{\"inputs\":[{\"name\":\"turnstone_id\",\"type\":\"bytes32\"},{\"components\":[{\"name\":\"validators\",\"type\":\"address[]\"},{\"name\":\"powers\",\"type\":\"uint256[]\"},{\"name\":\"valset_id\",\"type\":\"uint256\"}],\"name\":\"valset\",\"type\":\"tuple\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"turnstone_id\",\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"components\":[{\"name\":\"validators\",\"type\":\"address[]\"},{\"name\":\"powers\",\"type\":\"uint256[]\"},{\"name\":\"valset_id\",\"type\":\"uint256\"}],\"name\":\"valset\",\"type\":\"tuple\"},{\"components\":[{\"name\":\"v\",\"type\":\"uint256\"},{\"name\":\"r\",\"type\":\"uint256\"},{\"name\":\"s\",\"type\":\"uint256\"}],\"name\":\"signatures\",\"type\":\"tuple[]\"}],\"name\":\"consensus\",\"type\":\"tuple\"},{\"components\":[{\"name\":\"validators\",\"type\":\"address[]\"},{\"name\":\"powers\",\"type\":\"uint256[]\"},{\"name\":\"valset_id\",\"type\":\"uint256\"}],\"name\":\"new_valset\",\"type\":\"tuple\"}],\"name\":\"update_valset\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"components\":[{\"name\":\"validators\",\"type\":\"address[]\"},{\"name\":\"powers\",\"type\":\"uint256[]\"},{\"name\":\"valset_id\",\"type\":\"uint256\"}],\"name\":\"valset\",\"type\":\"tuple\"},{\"components\":[{\"name\":\"v\",\"type\":\"uint256\"},{\"name\":\"r\",\"type\":\"uint256\"},{\"name\":\"s\",\"type\":\"uint256\"}],\"name\":\"signatures\",\"type\":\"tuple[]\"}],\"name\":\"consensus\",\"type\":\"tuple\"},{\"components\":[{\"name\":\"logic_contract_address\",\"type\":\"address\"},{\"name\":\"payload\",\"type\":\"bytes\"}],\"name\":\"args\",\"type\":\"tuple\"},{\"name\":\"message_id\",\"type\":\"uint256\"},{\"name\":\"deadline\",\"type\":\"uint256\"}],\"name\":\"submit_logic_call\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"last_checkpoint\",\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"last_valset_id\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"name\":\"arg0\",\"type\":\"uint256\"}],\"name\":\"message_id_used\",\"outputs\":[{\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]'0x60206111126000396000516020816110f20160003960005181016101406020826110f201600039600051116110ed576020816110f2016000396000518060405260008161014081116110ed57801561008357905b60208160051b60208601016110f2016000396000518060a01c6110ed578160051b60600152600101818118610053575b505050506020602082016110f20160003960005181016101406020826110f201600039600051116110ed576020816110f2016000396000518061286052602082018160051b80826110f20161288039505050506020604082016110f2016000396000516150805250346110ed5760206110f260003960005161a200526040366150a037600060405161014081116110ed57801561018857905b8060051b606001516150e0526150a0516150c051612860518110156110ed5760051b61288001518082018281106110ed57905090506150a05263aaaaaaaa6150a0511061016857610188565b6150c051600181018181106110ed5790506150c05260010181811861011c575b505063aaaaaaaa6150a05110156101ff5760126150e0527f496e73756666696369656e7420506f7765720000000000000000000000000000615100526150e0506150e0518061510001601f826000031636823750506308c379a06150a05260206150c052601f19601f6150e05101166044016150bcfd5b63299018c261510452600460808061512452806151240160006040518083528060051b60008261014081116110ed57801561025357905b8060051b606001518160051b602088010152600101818118610236575b50508201602001915050905081019050806151445280615124016000612860518083528060051b60008261014081116110ed5780156102ac57905b8060051b61288001518160051b60208801015260010181811861028e575b50508201602001915050905081019050615080516151645260206110f26000396000516151845201615100526151008051602082012090506150e0526150e051600055615080516001557f09d40458cf931745f8d532ef13fa9c74bfb7fe0edcee88e0a677b0cbef88f0f96150e0516151005261508051615120526040615100a1610dad61033f61945339610dcd619453f36003361161000c57610a38565b60003560e01c34610d9b5763f0f40504811861003e5760043610610d9b576020610dad60003960005160405260206040f35b63eadf4af78118610518576101e43610610d9b576004356004018035810180358101610140813511610d9b5780358061cb40526000816101408111610d9b5780156100ab57905b8060051b6020850101358060a01c610d9b578160051b61cb600152600101818118610085575b5050505060208101358101610140813511610d9b5780358061f36052602082018160051b808261f3803750505050604081013562011b80525060208101358101610140813511610d9b5780358062011ba0526020820160608202808262011bc037505050505060243560040180358101610140813511610d9b57803580620193c0526000816101408111610d9b57801561016857905b8060051b6020850101358060a01c610d9b578160051b620193e00152600101818118610141575b5050505060208101358101610140813511610d9b578035806201bbe052602082018160051b80826201bc00375050505060408101356201e400525062011b80516201e40051116102215760116201e420527f496e76616c69642056616c7365742049440000000000000000000000000000006201e440526201e420506201e42051806201e44001601f826000031636823750506308c379a06201e3e05260206201e40052601f19601f6201e4205101166044016201e3fcfd5b6040366201e420376000620193c0516101408111610d9b5780156102b857905b8060051b620193e001516201e460526201e420516201e440516201bbe051811015610d9b5760051b6201bc000151808201828110610d9b57905090506201e4205263aaaaaaaa6201e4205110610296576102b8565b6201e4405160018101818110610d9b5790506201e44052600101818118610241575b505063aaaaaaaa6201e4205110156103395760126201e460527f496e73756666696369656e7420506f77657200000000000000000000000000006201e480526201e460506201e46051806201e48001601f826000031636823750506308c379a06201e4205260206201e44052601f19601f6201e4605101166044016201e43cfd5b61cb4051806040528060051b8060608261cb6060045afa50505061f3605180612860528060051b806128808261f38060045afa50505062011b8051615080526103846201e460610cb1565b6201e4605160005418156104015760146201e480527f496e636f727265637420436865636b706f696e740000000000000000000000006201e4a0526201e480506201e48051806201e4a001601f826000031636823750506308c379a06201e4405260206201e46052601f19601f6201e4805101166044016201e45cfd5b620193c051806040528060051b80606082620193e060045afa5050506201bbe05180612860528060051b80612880826201bc0060045afa5050506201e40051615080526104506201e480610cb1565b6201e480516201e4605261cb4051806101a0528060051b806101c08261cb6060045afa50505061f36051806129c0528060051b806129e08261f38060045afa50505062011b80516151e05262011ba051806152005260608102806152208262011bc060045afa5050506201e4605161ca20526104ca610ae1565b6201e460516000556201e400516001557f09d40458cf931745f8d532ef13fa9c74bfb7fe0edcee88e0a677b0cbef88f0f96201e460516201e480526201e400516201e4a05260406201e480a1005b631029ae6f81186109cb576101e43610610d9b576004356004018035810180358101610140813511610d9b5780358061cb40526000816101408111610d9b57801561058557905b8060051b6020850101358060a01c610d9b578160051b61cb60015260010181811861055f575b5050505060208101358101610140813511610d9b5780358061f36052602082018160051b808261f3803750505050604081013562011b80525060208101358101610140813511610d9b5780358062011ba0526020820160608202808262011bc037505050505060243560040180358060a01c610d9b57620193c05260208101358101615000813511610d9b57803580620193e0526020820181816201940037505050506064354211156106a15760076201e400527f54696d656f7574000000000000000000000000000000000000000000000000006201e420526201e400506201e40051806201e42001601f826000031636823750506308c379a06201e3c05260206201e3e052601f19601f6201e4005101166044016201e3dcfd5b60026044356020526000526040600020541561072657600f6201e400527f55736564204d6573736167655f494400000000000000000000000000000000006201e420526201e400506201e40051806201e42001601f826000031636823750506308c379a06201e3c05260206201e3e052601f19601f6201e4005101166044016201e3dcfd5b6001600260443560205260005260406000205561cb4051806040528060051b8060608261cb6060045afa50505061f3605180612860528060051b806128808261f38060045afa50505062011b8051615080526107846201e400610cb1565b6201e4005160005418156108015760146201e420527f496e636f727265637420436865636b706f696e740000000000000000000000006201e440526201e420506201e42051806201e44001601f826000031636823750506308c379a06201e3e05260206201e40052601f19601f6201e4205101166044016201e3fcfd5b63980721b26201e4245260046080806201e44452806201e444016040620193c0518252806020830152808201620193e051808252602082018181836201940060045afa5050508051806020830101601f82600003163682375050601f19601f825160200101169050810190509050810190506044356201e464526020610dad6000396000516201e484526064356201e4a452016201e420526201e4208051602082012090506201e4005261cb4051806101a0528060051b806101c08261cb6060045afa50505061f36051806129c0528060051b806129e08261f38060045afa50505062011b80516151e05262011ba051806152005260608102806152208262011bc060045afa5050506201e4005161ca205261091b610ae1565b620193e0600060008251602084016000620193c0515af19050610943573d600060003e3d6000fd5b7f0d2bd340033bb64fd086788e6685b480a9bf10b98d63e9b8073eb5d0bd6c6ee96060620193c0516201e42052806201e44052806201e42001620193e051808252602082018181836201940060045afa5050508051806020830101601f82600003163682375050601f19601f825160200101169050810190506044356201e460526201e420a1005b63a9a4a98381186109ea5760043610610d9b5760005460405260206040f35b634da6ecc98118610a095760043610610d9b5760015460405260206040f35b6338d6172d8118610a365760243610610d9b57600260043560205260005260406000205460405260206040f35b505b60006000fd5b6000601c610100527f19457468657265756d205369676e6564204d6573736167653a0a333200000000610120526101008051602082018361016001815181525050808301925050506060518161016001526020810190508061014052610140905080516020820120905060e05260e051610100526080516101205260a0516101405260c0516101605260206000608061010060015afa5060005160405114815250565b60403661ca40376000615200516101408111610d9b578015610c3857905b6060810261522001805161ca8052602081015161caa052604081015161cac0525061ca805115610c185761ca40516101a051811015610d9b5760051b6101c0015160405261ca205160605261ca805160805261caa05160a05261cac05160c052610b6a61cae0610a3e565b61cae051610bd857601161cb00527f496e76616c6964205369676e617475726500000000000000000000000000000061cb205261cb005061cb00518061cb2001601f826000031636823750506308c379a061cac052602061cae052601f19601f61cb0051011660440161cadcfd5b61ca605161ca40516129c051811015610d9b5760051b6129e00151808201828110610d9b579050905061ca605263aaaaaaaa61ca605110610c1857610c38565b61ca405160018101818110610d9b57905061ca4052600101818118610aff575b505063aaaaaaaa61ca60511015610caf57601261ca80527f496e73756666696369656e7420506f776572000000000000000000000000000061caa05261ca805061ca80518061caa001601f826000031636823750506308c379a061ca4052602061ca6052601f19601f61ca8051011660440161ca5cfd5b565b63299018c26150a45260046080806150c452806150c40160006040518083528060051b6000826101408111610d9b578015610d0557905b8060051b606001518160051b602088010152600101818118610ce8575b50508201602001915050905081019050806150e452806150c4016000612860518083528060051b6000826101408111610d9b578015610d5e57905b8060051b61288001518160051b602088010152600101818118610d40575b5050820160200191505090508101905061508051615104526020610dad60003960005161512452016150a0526150a0805160208201209050815250565b600080fda165767970657283000307000b005b600080fd", + ABI: "[{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"name\":\"checkpoint\",\"type\":\"bytes32\"},{\"indexed\":false,\"name\":\"valset_id\",\"type\":\"uint256\"},{\"indexed\":false,\"name\":\"event_id\",\"type\":\"uint256\"}],\"name\":\"ValsetUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"name\":\"logic_contract_address\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"payload\",\"type\":\"bytes\"},{\"indexed\":false,\"name\":\"message_id\",\"type\":\"uint256\"},{\"indexed\":false,\"name\":\"event_id\",\"type\":\"uint256\"}],\"name\":\"LogicCallEvent\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"receiver\",\"type\":\"bytes32\"},{\"indexed\":false,\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"name\":\"nonce\",\"type\":\"uint256\"},{\"indexed\":false,\"name\":\"event_id\",\"type\":\"uint256\"}],\"name\":\"SendToPalomaEvent\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"batch_id\",\"type\":\"uint256\"},{\"indexed\":false,\"name\":\"nonce\",\"type\":\"uint256\"},{\"indexed\":false,\"name\":\"event_id\",\"type\":\"uint256\"}],\"name\":\"BatchSendEvent\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"name\":\"paloma_denom\",\"type\":\"string\"},{\"indexed\":false,\"name\":\"token_contract\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"name\",\"type\":\"string\"},{\"indexed\":false,\"name\":\"symbol\",\"type\":\"string\"},{\"indexed\":false,\"name\":\"decimals\",\"type\":\"uint8\"},{\"indexed\":false,\"name\":\"event_id\",\"type\":\"uint256\"}],\"name\":\"ERC20DeployedEvent\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"name\":\"depositor_paloma_address\",\"type\":\"bytes32\"},{\"indexed\":false,\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"FundsDepositedEvent\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"name\":\"receiver\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"FundsWithdrawnEvent\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"name\":\"new_compass\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"event_id\",\"type\":\"uint256\"}],\"name\":\"UpdateCompassAddressInFeeManager\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"name\":\"contract_address\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"buyer\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"paloma\",\"type\":\"bytes32\"},{\"indexed\":false,\"name\":\"node_count\",\"type\":\"uint256\"},{\"indexed\":false,\"name\":\"grain_amount\",\"type\":\"uint256\"},{\"indexed\":false,\"name\":\"nonce\",\"type\":\"uint256\"},{\"indexed\":false,\"name\":\"event_id\",\"type\":\"uint256\"}],\"name\":\"NodeSaleEvent\",\"type\":\"event\"},{\"inputs\":[{\"name\":\"_compass_id\",\"type\":\"bytes32\"},{\"name\":\"_event_id\",\"type\":\"uint256\"},{\"name\":\"_gravity_nonce\",\"type\":\"uint256\"},{\"components\":[{\"name\":\"validators\",\"type\":\"address[]\"},{\"name\":\"powers\",\"type\":\"uint256[]\"},{\"name\":\"valset_id\",\"type\":\"uint256\"}],\"name\":\"valset\",\"type\":\"tuple\"},{\"name\":\"fee_manager\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[{\"components\":[{\"components\":[{\"name\":\"validators\",\"type\":\"address[]\"},{\"name\":\"powers\",\"type\":\"uint256[]\"},{\"name\":\"valset_id\",\"type\":\"uint256\"}],\"name\":\"valset\",\"type\":\"tuple\"},{\"components\":[{\"name\":\"v\",\"type\":\"uint256\"},{\"name\":\"r\",\"type\":\"uint256\"},{\"name\":\"s\",\"type\":\"uint256\"}],\"name\":\"signatures\",\"type\":\"tuple[]\"}],\"name\":\"consensus\",\"type\":\"tuple\"},{\"components\":[{\"name\":\"validators\",\"type\":\"address[]\"},{\"name\":\"powers\",\"type\":\"uint256[]\"},{\"name\":\"valset_id\",\"type\":\"uint256\"}],\"name\":\"new_valset\",\"type\":\"tuple\"},{\"name\":\"relayer\",\"type\":\"address\"},{\"name\":\"gas_estimate\",\"type\":\"uint256\"}],\"name\":\"update_valset\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"components\":[{\"name\":\"validators\",\"type\":\"address[]\"},{\"name\":\"powers\",\"type\":\"uint256[]\"},{\"name\":\"valset_id\",\"type\":\"uint256\"}],\"name\":\"valset\",\"type\":\"tuple\"},{\"components\":[{\"name\":\"v\",\"type\":\"uint256\"},{\"name\":\"r\",\"type\":\"uint256\"},{\"name\":\"s\",\"type\":\"uint256\"}],\"name\":\"signatures\",\"type\":\"tuple[]\"}],\"name\":\"consensus\",\"type\":\"tuple\"},{\"components\":[{\"name\":\"logic_contract_address\",\"type\":\"address\"},{\"name\":\"payload\",\"type\":\"bytes\"}],\"name\":\"args\",\"type\":\"tuple\"},{\"components\":[{\"name\":\"relayer_fee\",\"type\":\"uint256\"},{\"name\":\"community_fee\",\"type\":\"uint256\"},{\"name\":\"security_fee\",\"type\":\"uint256\"},{\"name\":\"fee_payer_paloma_address\",\"type\":\"bytes32\"}],\"name\":\"fee_args\",\"type\":\"tuple\"},{\"name\":\"message_id\",\"type\":\"uint256\"},{\"name\":\"deadline\",\"type\":\"uint256\"},{\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"submit_logic_call\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"name\":\"token\",\"type\":\"address\"},{\"name\":\"receiver\",\"type\":\"bytes32\"},{\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"send_token_to_paloma\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"components\":[{\"name\":\"validators\",\"type\":\"address[]\"},{\"name\":\"powers\",\"type\":\"uint256[]\"},{\"name\":\"valset_id\",\"type\":\"uint256\"}],\"name\":\"valset\",\"type\":\"tuple\"},{\"components\":[{\"name\":\"v\",\"type\":\"uint256\"},{\"name\":\"r\",\"type\":\"uint256\"},{\"name\":\"s\",\"type\":\"uint256\"}],\"name\":\"signatures\",\"type\":\"tuple[]\"}],\"name\":\"consensus\",\"type\":\"tuple\"},{\"name\":\"token\",\"type\":\"address\"},{\"components\":[{\"name\":\"receiver\",\"type\":\"address[]\"},{\"name\":\"amount\",\"type\":\"uint256[]\"}],\"name\":\"args\",\"type\":\"tuple\"},{\"name\":\"batch_id\",\"type\":\"uint256\"},{\"name\":\"deadline\",\"type\":\"uint256\"},{\"name\":\"relayer\",\"type\":\"address\"},{\"name\":\"gas_estimate\",\"type\":\"uint256\"}],\"name\":\"submit_batch\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"name\":\"buyer\",\"type\":\"address\"},{\"name\":\"paloma\",\"type\":\"bytes32\"},{\"name\":\"node_count\",\"type\":\"uint256\"},{\"name\":\"grain_amount\",\"type\":\"uint256\"}],\"name\":\"emit_nodesale_event\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"name\":\"_paloma_denom\",\"type\":\"string\"},{\"name\":\"_name\",\"type\":\"string\"},{\"name\":\"_symbol\",\"type\":\"string\"},{\"name\":\"_decimals\",\"type\":\"uint8\"},{\"name\":\"_blueprint\",\"type\":\"address\"}],\"name\":\"deploy_erc20\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"name\":\"contract_address\",\"type\":\"address\"},{\"name\":\"payload\",\"type\":\"bytes\"}],\"name\":\"arbitrary_view\",\"outputs\":[{\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"name\":\"depositor_paloma_address\",\"type\":\"bytes32\"},{\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"deposit\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"name\":\"amount\",\"type\":\"uint256\"},{\"name\":\"dex\",\"type\":\"address\"},{\"name\":\"payload\",\"type\":\"bytes\"},{\"name\":\"min_grain\",\"type\":\"uint256\"}],\"name\":\"withdraw\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"security_fee_topup\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"components\":[{\"name\":\"validators\",\"type\":\"address[]\"},{\"name\":\"powers\",\"type\":\"uint256[]\"},{\"name\":\"valset_id\",\"type\":\"uint256\"}],\"name\":\"valset\",\"type\":\"tuple\"},{\"components\":[{\"name\":\"v\",\"type\":\"uint256\"},{\"name\":\"r\",\"type\":\"uint256\"},{\"name\":\"s\",\"type\":\"uint256\"}],\"name\":\"signatures\",\"type\":\"tuple[]\"}],\"name\":\"consensus\",\"type\":\"tuple\"},{\"name\":\"message_id\",\"type\":\"uint256\"},{\"name\":\"deadline\",\"type\":\"uint256\"},{\"name\":\"receiver\",\"type\":\"bytes32\"},{\"name\":\"relayer\",\"type\":\"address\"},{\"name\":\"gas_estimate\",\"type\":\"uint256\"},{\"name\":\"amount\",\"type\":\"uint256\"},{\"name\":\"dex\",\"type\":\"address\"},{\"name\":\"payload\",\"type\":\"bytes\"},{\"name\":\"min_grain\",\"type\":\"uint256\"}],\"name\":\"bridge_community_tax_to_paloma\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"components\":[{\"name\":\"validators\",\"type\":\"address[]\"},{\"name\":\"powers\",\"type\":\"uint256[]\"},{\"name\":\"valset_id\",\"type\":\"uint256\"}],\"name\":\"valset\",\"type\":\"tuple\"},{\"components\":[{\"name\":\"v\",\"type\":\"uint256\"},{\"name\":\"r\",\"type\":\"uint256\"},{\"name\":\"s\",\"type\":\"uint256\"}],\"name\":\"signatures\",\"type\":\"tuple[]\"}],\"name\":\"consensus\",\"type\":\"tuple\"},{\"name\":\"deadline\",\"type\":\"uint256\"},{\"name\":\"gas_estimate\",\"type\":\"uint256\"},{\"name\":\"_new_compass\",\"type\":\"address\"},{\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"update_compass_address_in_fee_manager\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"compass_id\",\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"last_checkpoint\",\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"last_valset_id\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"last_event_id\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"last_gravity_nonce\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"name\":\"arg0\",\"type\":\"address\"}],\"name\":\"last_batch_id\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"name\":\"arg0\",\"type\":\"uint256\"}],\"name\":\"message_id_used\",\"outputs\":[{\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"slc_switch\",\"outputs\":[{\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"FEE_MANAGER\",\"outputs\":[{\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]", } // CompassABI is the input ABI used to generate the binding from. @@ -206,13 +220,128 @@ func (_Compass *CompassTransactorRaw) Transact(opts *bind.TransactOpts, method s return _Compass.Contract.contract.Transact(opts, method, params...) } +// FEEMANAGER is a free data retrieval call binding the contract method 0xea26266c. +// +// Solidity: function FEE_MANAGER() view returns(address) +func (_Compass *CompassCaller) FEEMANAGER(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _Compass.contract.Call(opts, &out, "FEE_MANAGER") + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err +} + +// FEEMANAGER is a free data retrieval call binding the contract method 0xea26266c. +// +// Solidity: function FEE_MANAGER() view returns(address) +func (_Compass *CompassSession) FEEMANAGER() (common.Address, error) { + return _Compass.Contract.FEEMANAGER(&_Compass.CallOpts) +} + +// FEEMANAGER is a free data retrieval call binding the contract method 0xea26266c. +// +// Solidity: function FEE_MANAGER() view returns(address) +func (_Compass *CompassCallerSession) FEEMANAGER() (common.Address, error) { + return _Compass.Contract.FEEMANAGER(&_Compass.CallOpts) +} + +// ArbitraryView is a free data retrieval call binding the contract method 0x0b14c545. +// +// Solidity: function arbitrary_view(address contract_address, bytes payload) view returns(bytes) +func (_Compass *CompassCaller) ArbitraryView(opts *bind.CallOpts, contract_address common.Address, payload []byte) ([]byte, error) { + var out []interface{} + err := _Compass.contract.Call(opts, &out, "arbitrary_view", contract_address, payload) + if err != nil { + return *new([]byte), err + } + + out0 := *abi.ConvertType(out[0], new([]byte)).(*[]byte) + + return out0, err +} + +// ArbitraryView is a free data retrieval call binding the contract method 0x0b14c545. +// +// Solidity: function arbitrary_view(address contract_address, bytes payload) view returns(bytes) +func (_Compass *CompassSession) ArbitraryView(contract_address common.Address, payload []byte) ([]byte, error) { + return _Compass.Contract.ArbitraryView(&_Compass.CallOpts, contract_address, payload) +} + +// ArbitraryView is a free data retrieval call binding the contract method 0x0b14c545. +// +// Solidity: function arbitrary_view(address contract_address, bytes payload) view returns(bytes) +func (_Compass *CompassCallerSession) ArbitraryView(contract_address common.Address, payload []byte) ([]byte, error) { + return _Compass.Contract.ArbitraryView(&_Compass.CallOpts, contract_address, payload) +} + +// CompassId is a free data retrieval call binding the contract method 0x84d38f2c. +// +// Solidity: function compass_id() view returns(bytes32) +func (_Compass *CompassCaller) CompassId(opts *bind.CallOpts) ([32]byte, error) { + var out []interface{} + err := _Compass.contract.Call(opts, &out, "compass_id") + if err != nil { + return *new([32]byte), err + } + + out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte) + + return out0, err +} + +// CompassId is a free data retrieval call binding the contract method 0x84d38f2c. +// +// Solidity: function compass_id() view returns(bytes32) +func (_Compass *CompassSession) CompassId() ([32]byte, error) { + return _Compass.Contract.CompassId(&_Compass.CallOpts) +} + +// CompassId is a free data retrieval call binding the contract method 0x84d38f2c. +// +// Solidity: function compass_id() view returns(bytes32) +func (_Compass *CompassCallerSession) CompassId() ([32]byte, error) { + return _Compass.Contract.CompassId(&_Compass.CallOpts) +} + +// LastBatchId is a free data retrieval call binding the contract method 0xfa822567. +// +// Solidity: function last_batch_id(address arg0) view returns(uint256) +func (_Compass *CompassCaller) LastBatchId(opts *bind.CallOpts, arg0 common.Address) (*big.Int, error) { + var out []interface{} + err := _Compass.contract.Call(opts, &out, "last_batch_id", arg0) + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err +} + +// LastBatchId is a free data retrieval call binding the contract method 0xfa822567. +// +// Solidity: function last_batch_id(address arg0) view returns(uint256) +func (_Compass *CompassSession) LastBatchId(arg0 common.Address) (*big.Int, error) { + return _Compass.Contract.LastBatchId(&_Compass.CallOpts, arg0) +} + +// LastBatchId is a free data retrieval call binding the contract method 0xfa822567. +// +// Solidity: function last_batch_id(address arg0) view returns(uint256) +func (_Compass *CompassCallerSession) LastBatchId(arg0 common.Address) (*big.Int, error) { + return _Compass.Contract.LastBatchId(&_Compass.CallOpts, arg0) +} + // LastCheckpoint is a free data retrieval call binding the contract method 0xa9a4a983. // // Solidity: function last_checkpoint() view returns(bytes32) func (_Compass *CompassCaller) LastCheckpoint(opts *bind.CallOpts) ([32]byte, error) { var out []interface{} err := _Compass.contract.Call(opts, &out, "last_checkpoint") - if err != nil { return *new([32]byte), err } @@ -220,7 +349,6 @@ func (_Compass *CompassCaller) LastCheckpoint(opts *bind.CallOpts) ([32]byte, er out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte) return out0, err - } // LastCheckpoint is a free data retrieval call binding the contract method 0xa9a4a983. @@ -237,13 +365,70 @@ func (_Compass *CompassCallerSession) LastCheckpoint() ([32]byte, error) { return _Compass.Contract.LastCheckpoint(&_Compass.CallOpts) } +// LastEventId is a free data retrieval call binding the contract method 0x19429b8d. +// +// Solidity: function last_event_id() view returns(uint256) +func (_Compass *CompassCaller) LastEventId(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _Compass.contract.Call(opts, &out, "last_event_id") + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err +} + +// LastEventId is a free data retrieval call binding the contract method 0x19429b8d. +// +// Solidity: function last_event_id() view returns(uint256) +func (_Compass *CompassSession) LastEventId() (*big.Int, error) { + return _Compass.Contract.LastEventId(&_Compass.CallOpts) +} + +// LastEventId is a free data retrieval call binding the contract method 0x19429b8d. +// +// Solidity: function last_event_id() view returns(uint256) +func (_Compass *CompassCallerSession) LastEventId() (*big.Int, error) { + return _Compass.Contract.LastEventId(&_Compass.CallOpts) +} + +// LastGravityNonce is a free data retrieval call binding the contract method 0x0cb39e96. +// +// Solidity: function last_gravity_nonce() view returns(uint256) +func (_Compass *CompassCaller) LastGravityNonce(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _Compass.contract.Call(opts, &out, "last_gravity_nonce") + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err +} + +// LastGravityNonce is a free data retrieval call binding the contract method 0x0cb39e96. +// +// Solidity: function last_gravity_nonce() view returns(uint256) +func (_Compass *CompassSession) LastGravityNonce() (*big.Int, error) { + return _Compass.Contract.LastGravityNonce(&_Compass.CallOpts) +} + +// LastGravityNonce is a free data retrieval call binding the contract method 0x0cb39e96. +// +// Solidity: function last_gravity_nonce() view returns(uint256) +func (_Compass *CompassCallerSession) LastGravityNonce() (*big.Int, error) { + return _Compass.Contract.LastGravityNonce(&_Compass.CallOpts) +} + // LastValsetId is a free data retrieval call binding the contract method 0x4da6ecc9. // // Solidity: function last_valset_id() view returns(uint256) func (_Compass *CompassCaller) LastValsetId(opts *bind.CallOpts) (*big.Int, error) { var out []interface{} err := _Compass.contract.Call(opts, &out, "last_valset_id") - if err != nil { return *new(*big.Int), err } @@ -251,7 +436,6 @@ func (_Compass *CompassCaller) LastValsetId(opts *bind.CallOpts) (*big.Int, erro out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) return out0, err - } // LastValsetId is a free data retrieval call binding the contract method 0x4da6ecc9. @@ -274,7 +458,6 @@ func (_Compass *CompassCallerSession) LastValsetId() (*big.Int, error) { func (_Compass *CompassCaller) MessageIdUsed(opts *bind.CallOpts, arg0 *big.Int) (bool, error) { var out []interface{} err := _Compass.contract.Call(opts, &out, "message_id_used", arg0) - if err != nil { return *new(bool), err } @@ -282,7 +465,6 @@ func (_Compass *CompassCaller) MessageIdUsed(opts *bind.CallOpts, arg0 *big.Int) out0 := *abi.ConvertType(out[0], new(bool)).(*bool) return out0, err - } // MessageIdUsed is a free data retrieval call binding the contract method 0x38d6172d. @@ -299,82 +481,269 @@ func (_Compass *CompassCallerSession) MessageIdUsed(arg0 *big.Int) (bool, error) return _Compass.Contract.MessageIdUsed(&_Compass.CallOpts, arg0) } -// TurnstoneId is a free data retrieval call binding the contract method 0xf0f40504. +// SlcSwitch is a free data retrieval call binding the contract method 0x844105e1. // -// Solidity: function turnstone_id() pure returns(bytes32) -func (_Compass *CompassCaller) TurnstoneId(opts *bind.CallOpts) ([32]byte, error) { +// Solidity: function slc_switch() view returns(bool) +func (_Compass *CompassCaller) SlcSwitch(opts *bind.CallOpts) (bool, error) { var out []interface{} - err := _Compass.contract.Call(opts, &out, "turnstone_id") - + err := _Compass.contract.Call(opts, &out, "slc_switch") if err != nil { - return *new([32]byte), err + return *new(bool), err } - out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte) + out0 := *abi.ConvertType(out[0], new(bool)).(*bool) return out0, err +} +// SlcSwitch is a free data retrieval call binding the contract method 0x844105e1. +// +// Solidity: function slc_switch() view returns(bool) +func (_Compass *CompassSession) SlcSwitch() (bool, error) { + return _Compass.Contract.SlcSwitch(&_Compass.CallOpts) } -// TurnstoneId is a free data retrieval call binding the contract method 0xf0f40504. +// SlcSwitch is a free data retrieval call binding the contract method 0x844105e1. // -// Solidity: function turnstone_id() pure returns(bytes32) -func (_Compass *CompassSession) TurnstoneId() ([32]byte, error) { - return _Compass.Contract.TurnstoneId(&_Compass.CallOpts) +// Solidity: function slc_switch() view returns(bool) +func (_Compass *CompassCallerSession) SlcSwitch() (bool, error) { + return _Compass.Contract.SlcSwitch(&_Compass.CallOpts) } -// TurnstoneId is a free data retrieval call binding the contract method 0xf0f40504. +// BridgeCommunityTaxToPaloma is a paid mutator transaction binding the contract method 0xa0dd2e49. // -// Solidity: function turnstone_id() pure returns(bytes32) -func (_Compass *CompassCallerSession) TurnstoneId() ([32]byte, error) { - return _Compass.Contract.TurnstoneId(&_Compass.CallOpts) +// Solidity: function bridge_community_tax_to_paloma(((address[],uint256[],uint256),(uint256,uint256,uint256)[]) consensus, uint256 message_id, uint256 deadline, bytes32 receiver, address relayer, uint256 gas_estimate, uint256 amount, address dex, bytes payload, uint256 min_grain) returns() +func (_Compass *CompassTransactor) BridgeCommunityTaxToPaloma(opts *bind.TransactOpts, consensus Struct2, message_id *big.Int, deadline *big.Int, receiver [32]byte, relayer common.Address, gas_estimate *big.Int, amount *big.Int, dex common.Address, payload []byte, min_grain *big.Int) (*types.Transaction, error) { + return _Compass.contract.Transact(opts, "bridge_community_tax_to_paloma", consensus, message_id, deadline, receiver, relayer, gas_estimate, amount, dex, payload, min_grain) } -// SubmitLogicCall is a paid mutator transaction binding the contract method 0x1029ae6f. +// BridgeCommunityTaxToPaloma is a paid mutator transaction binding the contract method 0xa0dd2e49. // -// Solidity: function submit_logic_call(((address[],uint256[],uint256),(uint256,uint256,uint256)[]) consensus, (address,bytes) args, uint256 message_id, uint256 deadline) returns() -func (_Compass *CompassTransactor) SubmitLogicCall(opts *bind.TransactOpts, consensus Struct2, args Struct3, message_id *big.Int, deadline *big.Int) (*types.Transaction, error) { - return _Compass.contract.Transact(opts, "submit_logic_call", consensus, args, message_id, deadline) +// Solidity: function bridge_community_tax_to_paloma(((address[],uint256[],uint256),(uint256,uint256,uint256)[]) consensus, uint256 message_id, uint256 deadline, bytes32 receiver, address relayer, uint256 gas_estimate, uint256 amount, address dex, bytes payload, uint256 min_grain) returns() +func (_Compass *CompassSession) BridgeCommunityTaxToPaloma(consensus Struct2, message_id *big.Int, deadline *big.Int, receiver [32]byte, relayer common.Address, gas_estimate *big.Int, amount *big.Int, dex common.Address, payload []byte, min_grain *big.Int) (*types.Transaction, error) { + return _Compass.Contract.BridgeCommunityTaxToPaloma(&_Compass.TransactOpts, consensus, message_id, deadline, receiver, relayer, gas_estimate, amount, dex, payload, min_grain) } -// SubmitLogicCall is a paid mutator transaction binding the contract method 0x1029ae6f. +// BridgeCommunityTaxToPaloma is a paid mutator transaction binding the contract method 0xa0dd2e49. // -// Solidity: function submit_logic_call(((address[],uint256[],uint256),(uint256,uint256,uint256)[]) consensus, (address,bytes) args, uint256 message_id, uint256 deadline) returns() -func (_Compass *CompassSession) SubmitLogicCall(consensus Struct2, args Struct3, message_id *big.Int, deadline *big.Int) (*types.Transaction, error) { - return _Compass.Contract.SubmitLogicCall(&_Compass.TransactOpts, consensus, args, message_id, deadline) +// Solidity: function bridge_community_tax_to_paloma(((address[],uint256[],uint256),(uint256,uint256,uint256)[]) consensus, uint256 message_id, uint256 deadline, bytes32 receiver, address relayer, uint256 gas_estimate, uint256 amount, address dex, bytes payload, uint256 min_grain) returns() +func (_Compass *CompassTransactorSession) BridgeCommunityTaxToPaloma(consensus Struct2, message_id *big.Int, deadline *big.Int, receiver [32]byte, relayer common.Address, gas_estimate *big.Int, amount *big.Int, dex common.Address, payload []byte, min_grain *big.Int) (*types.Transaction, error) { + return _Compass.Contract.BridgeCommunityTaxToPaloma(&_Compass.TransactOpts, consensus, message_id, deadline, receiver, relayer, gas_estimate, amount, dex, payload, min_grain) } -// SubmitLogicCall is a paid mutator transaction binding the contract method 0x1029ae6f. +// DeployErc20 is a paid mutator transaction binding the contract method 0x08a92ad7. // -// Solidity: function submit_logic_call(((address[],uint256[],uint256),(uint256,uint256,uint256)[]) consensus, (address,bytes) args, uint256 message_id, uint256 deadline) returns() -func (_Compass *CompassTransactorSession) SubmitLogicCall(consensus Struct2, args Struct3, message_id *big.Int, deadline *big.Int) (*types.Transaction, error) { - return _Compass.Contract.SubmitLogicCall(&_Compass.TransactOpts, consensus, args, message_id, deadline) +// Solidity: function deploy_erc20(string _paloma_denom, string _name, string _symbol, uint8 _decimals, address _blueprint) returns() +func (_Compass *CompassTransactor) DeployErc20(opts *bind.TransactOpts, _paloma_denom string, _name string, _symbol string, _decimals uint8, _blueprint common.Address) (*types.Transaction, error) { + return _Compass.contract.Transact(opts, "deploy_erc20", _paloma_denom, _name, _symbol, _decimals, _blueprint) } -// UpdateValset is a paid mutator transaction binding the contract method 0xeadf4af7. +// DeployErc20 is a paid mutator transaction binding the contract method 0x08a92ad7. // -// Solidity: function update_valset(((address[],uint256[],uint256),(uint256,uint256,uint256)[]) consensus, (address[],uint256[],uint256) new_valset) returns() -func (_Compass *CompassTransactor) UpdateValset(opts *bind.TransactOpts, consensus Struct2, new_valset Struct0) (*types.Transaction, error) { - return _Compass.contract.Transact(opts, "update_valset", consensus, new_valset) +// Solidity: function deploy_erc20(string _paloma_denom, string _name, string _symbol, uint8 _decimals, address _blueprint) returns() +func (_Compass *CompassSession) DeployErc20(_paloma_denom string, _name string, _symbol string, _decimals uint8, _blueprint common.Address) (*types.Transaction, error) { + return _Compass.Contract.DeployErc20(&_Compass.TransactOpts, _paloma_denom, _name, _symbol, _decimals, _blueprint) } -// UpdateValset is a paid mutator transaction binding the contract method 0xeadf4af7. +// DeployErc20 is a paid mutator transaction binding the contract method 0x08a92ad7. // -// Solidity: function update_valset(((address[],uint256[],uint256),(uint256,uint256,uint256)[]) consensus, (address[],uint256[],uint256) new_valset) returns() -func (_Compass *CompassSession) UpdateValset(consensus Struct2, new_valset Struct0) (*types.Transaction, error) { - return _Compass.Contract.UpdateValset(&_Compass.TransactOpts, consensus, new_valset) +// Solidity: function deploy_erc20(string _paloma_denom, string _name, string _symbol, uint8 _decimals, address _blueprint) returns() +func (_Compass *CompassTransactorSession) DeployErc20(_paloma_denom string, _name string, _symbol string, _decimals uint8, _blueprint common.Address) (*types.Transaction, error) { + return _Compass.Contract.DeployErc20(&_Compass.TransactOpts, _paloma_denom, _name, _symbol, _decimals, _blueprint) } -// UpdateValset is a paid mutator transaction binding the contract method 0xeadf4af7. +// Deposit is a paid mutator transaction binding the contract method 0x1de26e16. // -// Solidity: function update_valset(((address[],uint256[],uint256),(uint256,uint256,uint256)[]) consensus, (address[],uint256[],uint256) new_valset) returns() -func (_Compass *CompassTransactorSession) UpdateValset(consensus Struct2, new_valset Struct0) (*types.Transaction, error) { - return _Compass.Contract.UpdateValset(&_Compass.TransactOpts, consensus, new_valset) +// Solidity: function deposit(bytes32 depositor_paloma_address, uint256 amount) payable returns() +func (_Compass *CompassTransactor) Deposit(opts *bind.TransactOpts, depositor_paloma_address [32]byte, amount *big.Int) (*types.Transaction, error) { + return _Compass.contract.Transact(opts, "deposit", depositor_paloma_address, amount) } -// CompassLogicCallEventIterator is returned from FilterLogicCallEvent and is used to iterate over the raw logs and unpacked data for LogicCallEvent events raised by the Compass contract. -type CompassLogicCallEventIterator struct { - Event *CompassLogicCallEvent // Event containing the contract specifics and raw log +// Deposit is a paid mutator transaction binding the contract method 0x1de26e16. +// +// Solidity: function deposit(bytes32 depositor_paloma_address, uint256 amount) payable returns() +func (_Compass *CompassSession) Deposit(depositor_paloma_address [32]byte, amount *big.Int) (*types.Transaction, error) { + return _Compass.Contract.Deposit(&_Compass.TransactOpts, depositor_paloma_address, amount) +} + +// Deposit is a paid mutator transaction binding the contract method 0x1de26e16. +// +// Solidity: function deposit(bytes32 depositor_paloma_address, uint256 amount) payable returns() +func (_Compass *CompassTransactorSession) Deposit(depositor_paloma_address [32]byte, amount *big.Int) (*types.Transaction, error) { + return _Compass.Contract.Deposit(&_Compass.TransactOpts, depositor_paloma_address, amount) +} + +// EmitNodesaleEvent is a paid mutator transaction binding the contract method 0xa3299771. +// +// Solidity: function emit_nodesale_event(address buyer, bytes32 paloma, uint256 node_count, uint256 grain_amount) returns() +func (_Compass *CompassTransactor) EmitNodesaleEvent(opts *bind.TransactOpts, buyer common.Address, paloma [32]byte, node_count *big.Int, grain_amount *big.Int) (*types.Transaction, error) { + return _Compass.contract.Transact(opts, "emit_nodesale_event", buyer, paloma, node_count, grain_amount) +} + +// EmitNodesaleEvent is a paid mutator transaction binding the contract method 0xa3299771. +// +// Solidity: function emit_nodesale_event(address buyer, bytes32 paloma, uint256 node_count, uint256 grain_amount) returns() +func (_Compass *CompassSession) EmitNodesaleEvent(buyer common.Address, paloma [32]byte, node_count *big.Int, grain_amount *big.Int) (*types.Transaction, error) { + return _Compass.Contract.EmitNodesaleEvent(&_Compass.TransactOpts, buyer, paloma, node_count, grain_amount) +} + +// EmitNodesaleEvent is a paid mutator transaction binding the contract method 0xa3299771. +// +// Solidity: function emit_nodesale_event(address buyer, bytes32 paloma, uint256 node_count, uint256 grain_amount) returns() +func (_Compass *CompassTransactorSession) EmitNodesaleEvent(buyer common.Address, paloma [32]byte, node_count *big.Int, grain_amount *big.Int) (*types.Transaction, error) { + return _Compass.Contract.EmitNodesaleEvent(&_Compass.TransactOpts, buyer, paloma, node_count, grain_amount) +} + +// SecurityFeeTopup is a paid mutator transaction binding the contract method 0xda29a8c6. +// +// Solidity: function security_fee_topup(uint256 amount) payable returns() +func (_Compass *CompassTransactor) SecurityFeeTopup(opts *bind.TransactOpts, amount *big.Int) (*types.Transaction, error) { + return _Compass.contract.Transact(opts, "security_fee_topup", amount) +} + +// SecurityFeeTopup is a paid mutator transaction binding the contract method 0xda29a8c6. +// +// Solidity: function security_fee_topup(uint256 amount) payable returns() +func (_Compass *CompassSession) SecurityFeeTopup(amount *big.Int) (*types.Transaction, error) { + return _Compass.Contract.SecurityFeeTopup(&_Compass.TransactOpts, amount) +} + +// SecurityFeeTopup is a paid mutator transaction binding the contract method 0xda29a8c6. +// +// Solidity: function security_fee_topup(uint256 amount) payable returns() +func (_Compass *CompassTransactorSession) SecurityFeeTopup(amount *big.Int) (*types.Transaction, error) { + return _Compass.Contract.SecurityFeeTopup(&_Compass.TransactOpts, amount) +} + +// SendTokenToPaloma is a paid mutator transaction binding the contract method 0xf650f6e9. +// +// Solidity: function send_token_to_paloma(address token, bytes32 receiver, uint256 amount) returns() +func (_Compass *CompassTransactor) SendTokenToPaloma(opts *bind.TransactOpts, token common.Address, receiver [32]byte, amount *big.Int) (*types.Transaction, error) { + return _Compass.contract.Transact(opts, "send_token_to_paloma", token, receiver, amount) +} + +// SendTokenToPaloma is a paid mutator transaction binding the contract method 0xf650f6e9. +// +// Solidity: function send_token_to_paloma(address token, bytes32 receiver, uint256 amount) returns() +func (_Compass *CompassSession) SendTokenToPaloma(token common.Address, receiver [32]byte, amount *big.Int) (*types.Transaction, error) { + return _Compass.Contract.SendTokenToPaloma(&_Compass.TransactOpts, token, receiver, amount) +} + +// SendTokenToPaloma is a paid mutator transaction binding the contract method 0xf650f6e9. +// +// Solidity: function send_token_to_paloma(address token, bytes32 receiver, uint256 amount) returns() +func (_Compass *CompassTransactorSession) SendTokenToPaloma(token common.Address, receiver [32]byte, amount *big.Int) (*types.Transaction, error) { + return _Compass.Contract.SendTokenToPaloma(&_Compass.TransactOpts, token, receiver, amount) +} + +// SubmitBatch is a paid mutator transaction binding the contract method 0x14fe978f. +// +// Solidity: function submit_batch(((address[],uint256[],uint256),(uint256,uint256,uint256)[]) consensus, address token, (address[],uint256[]) args, uint256 batch_id, uint256 deadline, address relayer, uint256 gas_estimate) returns() +func (_Compass *CompassTransactor) SubmitBatch(opts *bind.TransactOpts, consensus Struct2, token common.Address, args Struct5, batch_id *big.Int, deadline *big.Int, relayer common.Address, gas_estimate *big.Int) (*types.Transaction, error) { + return _Compass.contract.Transact(opts, "submit_batch", consensus, token, args, batch_id, deadline, relayer, gas_estimate) +} + +// SubmitBatch is a paid mutator transaction binding the contract method 0x14fe978f. +// +// Solidity: function submit_batch(((address[],uint256[],uint256),(uint256,uint256,uint256)[]) consensus, address token, (address[],uint256[]) args, uint256 batch_id, uint256 deadline, address relayer, uint256 gas_estimate) returns() +func (_Compass *CompassSession) SubmitBatch(consensus Struct2, token common.Address, args Struct5, batch_id *big.Int, deadline *big.Int, relayer common.Address, gas_estimate *big.Int) (*types.Transaction, error) { + return _Compass.Contract.SubmitBatch(&_Compass.TransactOpts, consensus, token, args, batch_id, deadline, relayer, gas_estimate) +} + +// SubmitBatch is a paid mutator transaction binding the contract method 0x14fe978f. +// +// Solidity: function submit_batch(((address[],uint256[],uint256),(uint256,uint256,uint256)[]) consensus, address token, (address[],uint256[]) args, uint256 batch_id, uint256 deadline, address relayer, uint256 gas_estimate) returns() +func (_Compass *CompassTransactorSession) SubmitBatch(consensus Struct2, token common.Address, args Struct5, batch_id *big.Int, deadline *big.Int, relayer common.Address, gas_estimate *big.Int) (*types.Transaction, error) { + return _Compass.Contract.SubmitBatch(&_Compass.TransactOpts, consensus, token, args, batch_id, deadline, relayer, gas_estimate) +} + +// SubmitLogicCall is a paid mutator transaction binding the contract method 0xa930e8dc. +// +// Solidity: function submit_logic_call(((address[],uint256[],uint256),(uint256,uint256,uint256)[]) consensus, (address,bytes) args, (uint256,uint256,uint256,bytes32) fee_args, uint256 message_id, uint256 deadline, address relayer) returns() +func (_Compass *CompassTransactor) SubmitLogicCall(opts *bind.TransactOpts, consensus Struct2, args Struct3, fee_args Struct4, message_id *big.Int, deadline *big.Int, relayer common.Address) (*types.Transaction, error) { + return _Compass.contract.Transact(opts, "submit_logic_call", consensus, args, fee_args, message_id, deadline, relayer) +} + +// SubmitLogicCall is a paid mutator transaction binding the contract method 0xa930e8dc. +// +// Solidity: function submit_logic_call(((address[],uint256[],uint256),(uint256,uint256,uint256)[]) consensus, (address,bytes) args, (uint256,uint256,uint256,bytes32) fee_args, uint256 message_id, uint256 deadline, address relayer) returns() +func (_Compass *CompassSession) SubmitLogicCall(consensus Struct2, args Struct3, fee_args Struct4, message_id *big.Int, deadline *big.Int, relayer common.Address) (*types.Transaction, error) { + return _Compass.Contract.SubmitLogicCall(&_Compass.TransactOpts, consensus, args, fee_args, message_id, deadline, relayer) +} + +// SubmitLogicCall is a paid mutator transaction binding the contract method 0xa930e8dc. +// +// Solidity: function submit_logic_call(((address[],uint256[],uint256),(uint256,uint256,uint256)[]) consensus, (address,bytes) args, (uint256,uint256,uint256,bytes32) fee_args, uint256 message_id, uint256 deadline, address relayer) returns() +func (_Compass *CompassTransactorSession) SubmitLogicCall(consensus Struct2, args Struct3, fee_args Struct4, message_id *big.Int, deadline *big.Int, relayer common.Address) (*types.Transaction, error) { + return _Compass.Contract.SubmitLogicCall(&_Compass.TransactOpts, consensus, args, fee_args, message_id, deadline, relayer) +} + +// UpdateCompassAddressInFeeManager is a paid mutator transaction binding the contract method 0x120e8ddd. +// +// Solidity: function update_compass_address_in_fee_manager(((address[],uint256[],uint256),(uint256,uint256,uint256)[]) consensus, uint256 deadline, uint256 gas_estimate, address _new_compass, address relayer) returns() +func (_Compass *CompassTransactor) UpdateCompassAddressInFeeManager(opts *bind.TransactOpts, consensus Struct2, deadline *big.Int, gas_estimate *big.Int, _new_compass common.Address, relayer common.Address) (*types.Transaction, error) { + return _Compass.contract.Transact(opts, "update_compass_address_in_fee_manager", consensus, deadline, gas_estimate, _new_compass, relayer) +} + +// UpdateCompassAddressInFeeManager is a paid mutator transaction binding the contract method 0x120e8ddd. +// +// Solidity: function update_compass_address_in_fee_manager(((address[],uint256[],uint256),(uint256,uint256,uint256)[]) consensus, uint256 deadline, uint256 gas_estimate, address _new_compass, address relayer) returns() +func (_Compass *CompassSession) UpdateCompassAddressInFeeManager(consensus Struct2, deadline *big.Int, gas_estimate *big.Int, _new_compass common.Address, relayer common.Address) (*types.Transaction, error) { + return _Compass.Contract.UpdateCompassAddressInFeeManager(&_Compass.TransactOpts, consensus, deadline, gas_estimate, _new_compass, relayer) +} + +// UpdateCompassAddressInFeeManager is a paid mutator transaction binding the contract method 0x120e8ddd. +// +// Solidity: function update_compass_address_in_fee_manager(((address[],uint256[],uint256),(uint256,uint256,uint256)[]) consensus, uint256 deadline, uint256 gas_estimate, address _new_compass, address relayer) returns() +func (_Compass *CompassTransactorSession) UpdateCompassAddressInFeeManager(consensus Struct2, deadline *big.Int, gas_estimate *big.Int, _new_compass common.Address, relayer common.Address) (*types.Transaction, error) { + return _Compass.Contract.UpdateCompassAddressInFeeManager(&_Compass.TransactOpts, consensus, deadline, gas_estimate, _new_compass, relayer) +} + +// UpdateValset is a paid mutator transaction binding the contract method 0xf064acb2. +// +// Solidity: function update_valset(((address[],uint256[],uint256),(uint256,uint256,uint256)[]) consensus, (address[],uint256[],uint256) new_valset, address relayer, uint256 gas_estimate) returns() +func (_Compass *CompassTransactor) UpdateValset(opts *bind.TransactOpts, consensus Struct2, new_valset Struct0, relayer common.Address, gas_estimate *big.Int) (*types.Transaction, error) { + return _Compass.contract.Transact(opts, "update_valset", consensus, new_valset, relayer, gas_estimate) +} + +// UpdateValset is a paid mutator transaction binding the contract method 0xf064acb2. +// +// Solidity: function update_valset(((address[],uint256[],uint256),(uint256,uint256,uint256)[]) consensus, (address[],uint256[],uint256) new_valset, address relayer, uint256 gas_estimate) returns() +func (_Compass *CompassSession) UpdateValset(consensus Struct2, new_valset Struct0, relayer common.Address, gas_estimate *big.Int) (*types.Transaction, error) { + return _Compass.Contract.UpdateValset(&_Compass.TransactOpts, consensus, new_valset, relayer, gas_estimate) +} + +// UpdateValset is a paid mutator transaction binding the contract method 0xf064acb2. +// +// Solidity: function update_valset(((address[],uint256[],uint256),(uint256,uint256,uint256)[]) consensus, (address[],uint256[],uint256) new_valset, address relayer, uint256 gas_estimate) returns() +func (_Compass *CompassTransactorSession) UpdateValset(consensus Struct2, new_valset Struct0, relayer common.Address, gas_estimate *big.Int) (*types.Transaction, error) { + return _Compass.Contract.UpdateValset(&_Compass.TransactOpts, consensus, new_valset, relayer, gas_estimate) +} + +// Withdraw is a paid mutator transaction binding the contract method 0x048a245d. +// +// Solidity: function withdraw(uint256 amount, address dex, bytes payload, uint256 min_grain) returns() +func (_Compass *CompassTransactor) Withdraw(opts *bind.TransactOpts, amount *big.Int, dex common.Address, payload []byte, min_grain *big.Int) (*types.Transaction, error) { + return _Compass.contract.Transact(opts, "withdraw", amount, dex, payload, min_grain) +} + +// Withdraw is a paid mutator transaction binding the contract method 0x048a245d. +// +// Solidity: function withdraw(uint256 amount, address dex, bytes payload, uint256 min_grain) returns() +func (_Compass *CompassSession) Withdraw(amount *big.Int, dex common.Address, payload []byte, min_grain *big.Int) (*types.Transaction, error) { + return _Compass.Contract.Withdraw(&_Compass.TransactOpts, amount, dex, payload, min_grain) +} + +// Withdraw is a paid mutator transaction binding the contract method 0x048a245d. +// +// Solidity: function withdraw(uint256 amount, address dex, bytes payload, uint256 min_grain) returns() +func (_Compass *CompassTransactorSession) Withdraw(amount *big.Int, dex common.Address, payload []byte, min_grain *big.Int) (*types.Transaction, error) { + return _Compass.Contract.Withdraw(&_Compass.TransactOpts, amount, dex, payload, min_grain) +} + +// CompassBatchSendEventIterator is returned from FilterBatchSendEvent and is used to iterate over the raw logs and unpacked data for BatchSendEvent events raised by the Compass contract. +type CompassBatchSendEventIterator struct { + Event *CompassBatchSendEvent // Event containing the contract specifics and raw log contract *bind.BoundContract // Generic contract to use for unpacking event data event string // Event name to use for unpacking event data @@ -388,7 +757,7 @@ type CompassLogicCallEventIterator struct { // Next advances the iterator to the subsequent event, returning whether there // are any more events found. In case of a retrieval or parsing error, false is // returned and Error() can be queried for the exact failure. -func (it *CompassLogicCallEventIterator) Next() bool { +func (it *CompassBatchSendEventIterator) Next() bool { // If the iterator failed, stop iterating if it.fail != nil { return false @@ -397,7 +766,7 @@ func (it *CompassLogicCallEventIterator) Next() bool { if it.done { select { case log := <-it.logs: - it.Event = new(CompassLogicCallEvent) + it.Event = new(CompassBatchSendEvent) if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { it.fail = err return false @@ -412,7 +781,7 @@ func (it *CompassLogicCallEventIterator) Next() bool { // Iterator still in progress, wait for either a data or an error event select { case log := <-it.logs: - it.Event = new(CompassLogicCallEvent) + it.Event = new(CompassBatchSendEvent) if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { it.fail = err return false @@ -428,43 +797,42 @@ func (it *CompassLogicCallEventIterator) Next() bool { } // Error returns any retrieval or parsing error occurred during filtering. -func (it *CompassLogicCallEventIterator) Error() error { +func (it *CompassBatchSendEventIterator) Error() error { return it.fail } // Close terminates the iteration process, releasing any pending underlying // resources. -func (it *CompassLogicCallEventIterator) Close() error { +func (it *CompassBatchSendEventIterator) Close() error { it.sub.Unsubscribe() return nil } -// CompassLogicCallEvent represents a LogicCallEvent event raised by the Compass contract. -type CompassLogicCallEvent struct { - LogicContractAddress common.Address - Payload []byte - MessageId *big.Int - Raw types.Log // Blockchain specific contextual infos +// CompassBatchSendEvent represents a BatchSendEvent event raised by the Compass contract. +type CompassBatchSendEvent struct { + Token common.Address + BatchId *big.Int + Nonce *big.Int + EventId *big.Int + Raw types.Log // Blockchain specific contextual infos } -// FilterLogicCallEvent is a free log retrieval operation binding the contract event 0x0d2bd340033bb64fd086788e6685b480a9bf10b98d63e9b8073eb5d0bd6c6ee9. +// FilterBatchSendEvent is a free log retrieval operation binding the contract event 0x0ba40544a53f11e70bd7e03a4cfeec841fc3566e81dfbef26f669358a705ad2c. // -// Solidity: event LogicCallEvent(address logic_contract_address, bytes payload, uint256 message_id) -func (_Compass *CompassFilterer) FilterLogicCallEvent(opts *bind.FilterOpts) (*CompassLogicCallEventIterator, error) { - - logs, sub, err := _Compass.contract.FilterLogs(opts, "LogicCallEvent") +// Solidity: event BatchSendEvent(address token, uint256 batch_id, uint256 nonce, uint256 event_id) +func (_Compass *CompassFilterer) FilterBatchSendEvent(opts *bind.FilterOpts) (*CompassBatchSendEventIterator, error) { + logs, sub, err := _Compass.contract.FilterLogs(opts, "BatchSendEvent") if err != nil { return nil, err } - return &CompassLogicCallEventIterator{contract: _Compass.contract, event: "LogicCallEvent", logs: logs, sub: sub}, nil + return &CompassBatchSendEventIterator{contract: _Compass.contract, event: "BatchSendEvent", logs: logs, sub: sub}, nil } -// WatchLogicCallEvent is a free log subscription operation binding the contract event 0x0d2bd340033bb64fd086788e6685b480a9bf10b98d63e9b8073eb5d0bd6c6ee9. +// WatchBatchSendEvent is a free log subscription operation binding the contract event 0x0ba40544a53f11e70bd7e03a4cfeec841fc3566e81dfbef26f669358a705ad2c. // -// Solidity: event LogicCallEvent(address logic_contract_address, bytes payload, uint256 message_id) -func (_Compass *CompassFilterer) WatchLogicCallEvent(opts *bind.WatchOpts, sink chan<- *CompassLogicCallEvent) (event.Subscription, error) { - - logs, sub, err := _Compass.contract.WatchLogs(opts, "LogicCallEvent") +// Solidity: event BatchSendEvent(address token, uint256 batch_id, uint256 nonce, uint256 event_id) +func (_Compass *CompassFilterer) WatchBatchSendEvent(opts *bind.WatchOpts, sink chan<- *CompassBatchSendEvent) (event.Subscription, error) { + logs, sub, err := _Compass.contract.WatchLogs(opts, "BatchSendEvent") if err != nil { return nil, err } @@ -474,8 +842,8 @@ func (_Compass *CompassFilterer) WatchLogicCallEvent(opts *bind.WatchOpts, sink select { case log := <-logs: // New log arrived, parse the event and forward to the user - event := new(CompassLogicCallEvent) - if err := _Compass.contract.UnpackLog(event, "LogicCallEvent", log); err != nil { + event := new(CompassBatchSendEvent) + if err := _Compass.contract.UnpackLog(event, "BatchSendEvent", log); err != nil { return err } event.Raw = log @@ -496,21 +864,21 @@ func (_Compass *CompassFilterer) WatchLogicCallEvent(opts *bind.WatchOpts, sink }), nil } -// ParseLogicCallEvent is a log parse operation binding the contract event 0x0d2bd340033bb64fd086788e6685b480a9bf10b98d63e9b8073eb5d0bd6c6ee9. +// ParseBatchSendEvent is a log parse operation binding the contract event 0x0ba40544a53f11e70bd7e03a4cfeec841fc3566e81dfbef26f669358a705ad2c. // -// Solidity: event LogicCallEvent(address logic_contract_address, bytes payload, uint256 message_id) -func (_Compass *CompassFilterer) ParseLogicCallEvent(log types.Log) (*CompassLogicCallEvent, error) { - event := new(CompassLogicCallEvent) - if err := _Compass.contract.UnpackLog(event, "LogicCallEvent", log); err != nil { +// Solidity: event BatchSendEvent(address token, uint256 batch_id, uint256 nonce, uint256 event_id) +func (_Compass *CompassFilterer) ParseBatchSendEvent(log types.Log) (*CompassBatchSendEvent, error) { + event := new(CompassBatchSendEvent) + if err := _Compass.contract.UnpackLog(event, "BatchSendEvent", log); err != nil { return nil, err } event.Raw = log return event, nil } -// CompassValsetUpdatedIterator is returned from FilterValsetUpdated and is used to iterate over the raw logs and unpacked data for ValsetUpdated events raised by the Compass contract. -type CompassValsetUpdatedIterator struct { - Event *CompassValsetUpdated // Event containing the contract specifics and raw log +// CompassERC20DeployedEventIterator is returned from FilterERC20DeployedEvent and is used to iterate over the raw logs and unpacked data for ERC20DeployedEvent events raised by the Compass contract. +type CompassERC20DeployedEventIterator struct { + Event *CompassERC20DeployedEvent // Event containing the contract specifics and raw log contract *bind.BoundContract // Generic contract to use for unpacking event data event string // Event name to use for unpacking event data @@ -524,7 +892,7 @@ type CompassValsetUpdatedIterator struct { // Next advances the iterator to the subsequent event, returning whether there // are any more events found. In case of a retrieval or parsing error, false is // returned and Error() can be queried for the exact failure. -func (it *CompassValsetUpdatedIterator) Next() bool { +func (it *CompassERC20DeployedEventIterator) Next() bool { // If the iterator failed, stop iterating if it.fail != nil { return false @@ -533,7 +901,7 @@ func (it *CompassValsetUpdatedIterator) Next() bool { if it.done { select { case log := <-it.logs: - it.Event = new(CompassValsetUpdated) + it.Event = new(CompassERC20DeployedEvent) if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { it.fail = err return false @@ -548,7 +916,7 @@ func (it *CompassValsetUpdatedIterator) Next() bool { // Iterator still in progress, wait for either a data or an error event select { case log := <-it.logs: - it.Event = new(CompassValsetUpdated) + it.Event = new(CompassERC20DeployedEvent) if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { it.fail = err return false @@ -564,41 +932,987 @@ func (it *CompassValsetUpdatedIterator) Next() bool { } // Error returns any retrieval or parsing error occurred during filtering. -func (it *CompassValsetUpdatedIterator) Error() error { +func (it *CompassERC20DeployedEventIterator) Error() error { return it.fail } // Close terminates the iteration process, releasing any pending underlying // resources. -func (it *CompassValsetUpdatedIterator) Close() error { +func (it *CompassERC20DeployedEventIterator) Close() error { it.sub.Unsubscribe() return nil } -// CompassValsetUpdated represents a ValsetUpdated event raised by the Compass contract. -type CompassValsetUpdated struct { - Checkpoint [32]byte - ValsetId *big.Int - Raw types.Log // Blockchain specific contextual infos +// CompassERC20DeployedEvent represents a ERC20DeployedEvent event raised by the Compass contract. +type CompassERC20DeployedEvent struct { + PalomaDenom string + TokenContract common.Address + Name string + Symbol string + Decimals uint8 + EventId *big.Int + Raw types.Log // Blockchain specific contextual infos } -// FilterValsetUpdated is a free log retrieval operation binding the contract event 0x09d40458cf931745f8d532ef13fa9c74bfb7fe0edcee88e0a677b0cbef88f0f9. +// FilterERC20DeployedEvent is a free log retrieval operation binding the contract event 0x82fe3a4fa49c6382d0c085746698ddbbafe6c2bf61285b19410644b5b26287c7. // -// Solidity: event ValsetUpdated(bytes32 checkpoint, uint256 valset_id) -func (_Compass *CompassFilterer) FilterValsetUpdated(opts *bind.FilterOpts) (*CompassValsetUpdatedIterator, error) { - - logs, sub, err := _Compass.contract.FilterLogs(opts, "ValsetUpdated") +// Solidity: event ERC20DeployedEvent(string paloma_denom, address token_contract, string name, string symbol, uint8 decimals, uint256 event_id) +func (_Compass *CompassFilterer) FilterERC20DeployedEvent(opts *bind.FilterOpts) (*CompassERC20DeployedEventIterator, error) { + logs, sub, err := _Compass.contract.FilterLogs(opts, "ERC20DeployedEvent") if err != nil { return nil, err } - return &CompassValsetUpdatedIterator{contract: _Compass.contract, event: "ValsetUpdated", logs: logs, sub: sub}, nil + return &CompassERC20DeployedEventIterator{contract: _Compass.contract, event: "ERC20DeployedEvent", logs: logs, sub: sub}, nil } -// WatchValsetUpdated is a free log subscription operation binding the contract event 0x09d40458cf931745f8d532ef13fa9c74bfb7fe0edcee88e0a677b0cbef88f0f9. +// WatchERC20DeployedEvent is a free log subscription operation binding the contract event 0x82fe3a4fa49c6382d0c085746698ddbbafe6c2bf61285b19410644b5b26287c7. // -// Solidity: event ValsetUpdated(bytes32 checkpoint, uint256 valset_id) -func (_Compass *CompassFilterer) WatchValsetUpdated(opts *bind.WatchOpts, sink chan<- *CompassValsetUpdated) (event.Subscription, error) { +// Solidity: event ERC20DeployedEvent(string paloma_denom, address token_contract, string name, string symbol, uint8 decimals, uint256 event_id) +func (_Compass *CompassFilterer) WatchERC20DeployedEvent(opts *bind.WatchOpts, sink chan<- *CompassERC20DeployedEvent) (event.Subscription, error) { + logs, sub, err := _Compass.contract.WatchLogs(opts, "ERC20DeployedEvent") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(CompassERC20DeployedEvent) + if err := _Compass.contract.UnpackLog(event, "ERC20DeployedEvent", log); err != nil { + return err + } + event.Raw = log + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseERC20DeployedEvent is a log parse operation binding the contract event 0x82fe3a4fa49c6382d0c085746698ddbbafe6c2bf61285b19410644b5b26287c7. +// +// Solidity: event ERC20DeployedEvent(string paloma_denom, address token_contract, string name, string symbol, uint8 decimals, uint256 event_id) +func (_Compass *CompassFilterer) ParseERC20DeployedEvent(log types.Log) (*CompassERC20DeployedEvent, error) { + event := new(CompassERC20DeployedEvent) + if err := _Compass.contract.UnpackLog(event, "ERC20DeployedEvent", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// CompassFundsDepositedEventIterator is returned from FilterFundsDepositedEvent and is used to iterate over the raw logs and unpacked data for FundsDepositedEvent events raised by the Compass contract. +type CompassFundsDepositedEventIterator struct { + Event *CompassFundsDepositedEvent // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *CompassFundsDepositedEventIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(CompassFundsDepositedEvent) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(CompassFundsDepositedEvent) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *CompassFundsDepositedEventIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *CompassFundsDepositedEventIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// CompassFundsDepositedEvent represents a FundsDepositedEvent event raised by the Compass contract. +type CompassFundsDepositedEvent struct { + DepositorPalomaAddress [32]byte + Sender common.Address + Amount *big.Int + Raw types.Log // Blockchain specific contextual infos +} + +// FilterFundsDepositedEvent is a free log retrieval operation binding the contract event 0x4f78bbd9a86543dc57c484da46f56d43190ac1148b43565fa8d522b1d4fe5298. +// +// Solidity: event FundsDepositedEvent(bytes32 depositor_paloma_address, address sender, uint256 amount) +func (_Compass *CompassFilterer) FilterFundsDepositedEvent(opts *bind.FilterOpts) (*CompassFundsDepositedEventIterator, error) { + logs, sub, err := _Compass.contract.FilterLogs(opts, "FundsDepositedEvent") + if err != nil { + return nil, err + } + return &CompassFundsDepositedEventIterator{contract: _Compass.contract, event: "FundsDepositedEvent", logs: logs, sub: sub}, nil +} + +// WatchFundsDepositedEvent is a free log subscription operation binding the contract event 0x4f78bbd9a86543dc57c484da46f56d43190ac1148b43565fa8d522b1d4fe5298. +// +// Solidity: event FundsDepositedEvent(bytes32 depositor_paloma_address, address sender, uint256 amount) +func (_Compass *CompassFilterer) WatchFundsDepositedEvent(opts *bind.WatchOpts, sink chan<- *CompassFundsDepositedEvent) (event.Subscription, error) { + logs, sub, err := _Compass.contract.WatchLogs(opts, "FundsDepositedEvent") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(CompassFundsDepositedEvent) + if err := _Compass.contract.UnpackLog(event, "FundsDepositedEvent", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseFundsDepositedEvent is a log parse operation binding the contract event 0x4f78bbd9a86543dc57c484da46f56d43190ac1148b43565fa8d522b1d4fe5298. +// +// Solidity: event FundsDepositedEvent(bytes32 depositor_paloma_address, address sender, uint256 amount) +func (_Compass *CompassFilterer) ParseFundsDepositedEvent(log types.Log) (*CompassFundsDepositedEvent, error) { + event := new(CompassFundsDepositedEvent) + if err := _Compass.contract.UnpackLog(event, "FundsDepositedEvent", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// CompassFundsWithdrawnEventIterator is returned from FilterFundsWithdrawnEvent and is used to iterate over the raw logs and unpacked data for FundsWithdrawnEvent events raised by the Compass contract. +type CompassFundsWithdrawnEventIterator struct { + Event *CompassFundsWithdrawnEvent // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *CompassFundsWithdrawnEventIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(CompassFundsWithdrawnEvent) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(CompassFundsWithdrawnEvent) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *CompassFundsWithdrawnEventIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *CompassFundsWithdrawnEventIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// CompassFundsWithdrawnEvent represents a FundsWithdrawnEvent event raised by the Compass contract. +type CompassFundsWithdrawnEvent struct { + Receiver common.Address + Amount *big.Int + Raw types.Log // Blockchain specific contextual infos +} + +// FilterFundsWithdrawnEvent is a free log retrieval operation binding the contract event 0xbcd7c5f94d828115734ea3d51400c2e1ad93894d1a5099a1808794a924f71f24. +// +// Solidity: event FundsWithdrawnEvent(address receiver, uint256 amount) +func (_Compass *CompassFilterer) FilterFundsWithdrawnEvent(opts *bind.FilterOpts) (*CompassFundsWithdrawnEventIterator, error) { + logs, sub, err := _Compass.contract.FilterLogs(opts, "FundsWithdrawnEvent") + if err != nil { + return nil, err + } + return &CompassFundsWithdrawnEventIterator{contract: _Compass.contract, event: "FundsWithdrawnEvent", logs: logs, sub: sub}, nil +} + +// WatchFundsWithdrawnEvent is a free log subscription operation binding the contract event 0xbcd7c5f94d828115734ea3d51400c2e1ad93894d1a5099a1808794a924f71f24. +// +// Solidity: event FundsWithdrawnEvent(address receiver, uint256 amount) +func (_Compass *CompassFilterer) WatchFundsWithdrawnEvent(opts *bind.WatchOpts, sink chan<- *CompassFundsWithdrawnEvent) (event.Subscription, error) { + logs, sub, err := _Compass.contract.WatchLogs(opts, "FundsWithdrawnEvent") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(CompassFundsWithdrawnEvent) + if err := _Compass.contract.UnpackLog(event, "FundsWithdrawnEvent", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseFundsWithdrawnEvent is a log parse operation binding the contract event 0xbcd7c5f94d828115734ea3d51400c2e1ad93894d1a5099a1808794a924f71f24. +// +// Solidity: event FundsWithdrawnEvent(address receiver, uint256 amount) +func (_Compass *CompassFilterer) ParseFundsWithdrawnEvent(log types.Log) (*CompassFundsWithdrawnEvent, error) { + event := new(CompassFundsWithdrawnEvent) + if err := _Compass.contract.UnpackLog(event, "FundsWithdrawnEvent", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// CompassLogicCallEventIterator is returned from FilterLogicCallEvent and is used to iterate over the raw logs and unpacked data for LogicCallEvent events raised by the Compass contract. +type CompassLogicCallEventIterator struct { + Event *CompassLogicCallEvent // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *CompassLogicCallEventIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(CompassLogicCallEvent) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(CompassLogicCallEvent) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *CompassLogicCallEventIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *CompassLogicCallEventIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// CompassLogicCallEvent represents a LogicCallEvent event raised by the Compass contract. +type CompassLogicCallEvent struct { + LogicContractAddress common.Address + Payload []byte + MessageId *big.Int + EventId *big.Int + Raw types.Log // Blockchain specific contextual infos +} + +// FilterLogicCallEvent is a free log retrieval operation binding the contract event 0x0594b174e11e17c2cb4d0d303c2125060bea4f4da113a4e79edce87465592d00. +// +// Solidity: event LogicCallEvent(address logic_contract_address, bytes payload, uint256 message_id, uint256 event_id) +func (_Compass *CompassFilterer) FilterLogicCallEvent(opts *bind.FilterOpts) (*CompassLogicCallEventIterator, error) { + logs, sub, err := _Compass.contract.FilterLogs(opts, "LogicCallEvent") + if err != nil { + return nil, err + } + return &CompassLogicCallEventIterator{contract: _Compass.contract, event: "LogicCallEvent", logs: logs, sub: sub}, nil +} + +// WatchLogicCallEvent is a free log subscription operation binding the contract event 0x0594b174e11e17c2cb4d0d303c2125060bea4f4da113a4e79edce87465592d00. +// +// Solidity: event LogicCallEvent(address logic_contract_address, bytes payload, uint256 message_id, uint256 event_id) +func (_Compass *CompassFilterer) WatchLogicCallEvent(opts *bind.WatchOpts, sink chan<- *CompassLogicCallEvent) (event.Subscription, error) { + logs, sub, err := _Compass.contract.WatchLogs(opts, "LogicCallEvent") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(CompassLogicCallEvent) + if err := _Compass.contract.UnpackLog(event, "LogicCallEvent", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseLogicCallEvent is a log parse operation binding the contract event 0x0594b174e11e17c2cb4d0d303c2125060bea4f4da113a4e79edce87465592d00. +// +// Solidity: event LogicCallEvent(address logic_contract_address, bytes payload, uint256 message_id, uint256 event_id) +func (_Compass *CompassFilterer) ParseLogicCallEvent(log types.Log) (*CompassLogicCallEvent, error) { + event := new(CompassLogicCallEvent) + if err := _Compass.contract.UnpackLog(event, "LogicCallEvent", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// CompassNodeSaleEventIterator is returned from FilterNodeSaleEvent and is used to iterate over the raw logs and unpacked data for NodeSaleEvent events raised by the Compass contract. +type CompassNodeSaleEventIterator struct { + Event *CompassNodeSaleEvent // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *CompassNodeSaleEventIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(CompassNodeSaleEvent) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(CompassNodeSaleEvent) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *CompassNodeSaleEventIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *CompassNodeSaleEventIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// CompassNodeSaleEvent represents a NodeSaleEvent event raised by the Compass contract. +type CompassNodeSaleEvent struct { + ContractAddress common.Address + Buyer common.Address + Paloma [32]byte + NodeCount *big.Int + GrainAmount *big.Int + Nonce *big.Int + EventId *big.Int + Raw types.Log // Blockchain specific contextual infos +} + +// FilterNodeSaleEvent is a free log retrieval operation binding the contract event 0xc72b917679ae2dea3062a0a355d542c92296f3e5c39cfcb0db7c30e28c816349. +// +// Solidity: event NodeSaleEvent(address contract_address, address buyer, bytes32 paloma, uint256 node_count, uint256 grain_amount, uint256 nonce, uint256 event_id) +func (_Compass *CompassFilterer) FilterNodeSaleEvent(opts *bind.FilterOpts) (*CompassNodeSaleEventIterator, error) { + logs, sub, err := _Compass.contract.FilterLogs(opts, "NodeSaleEvent") + if err != nil { + return nil, err + } + return &CompassNodeSaleEventIterator{contract: _Compass.contract, event: "NodeSaleEvent", logs: logs, sub: sub}, nil +} + +// WatchNodeSaleEvent is a free log subscription operation binding the contract event 0xc72b917679ae2dea3062a0a355d542c92296f3e5c39cfcb0db7c30e28c816349. +// +// Solidity: event NodeSaleEvent(address contract_address, address buyer, bytes32 paloma, uint256 node_count, uint256 grain_amount, uint256 nonce, uint256 event_id) +func (_Compass *CompassFilterer) WatchNodeSaleEvent(opts *bind.WatchOpts, sink chan<- *CompassNodeSaleEvent) (event.Subscription, error) { + logs, sub, err := _Compass.contract.WatchLogs(opts, "NodeSaleEvent") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(CompassNodeSaleEvent) + if err := _Compass.contract.UnpackLog(event, "NodeSaleEvent", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseNodeSaleEvent is a log parse operation binding the contract event 0xc72b917679ae2dea3062a0a355d542c92296f3e5c39cfcb0db7c30e28c816349. +// +// Solidity: event NodeSaleEvent(address contract_address, address buyer, bytes32 paloma, uint256 node_count, uint256 grain_amount, uint256 nonce, uint256 event_id) +func (_Compass *CompassFilterer) ParseNodeSaleEvent(log types.Log) (*CompassNodeSaleEvent, error) { + event := new(CompassNodeSaleEvent) + if err := _Compass.contract.UnpackLog(event, "NodeSaleEvent", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// CompassSendToPalomaEventIterator is returned from FilterSendToPalomaEvent and is used to iterate over the raw logs and unpacked data for SendToPalomaEvent events raised by the Compass contract. +type CompassSendToPalomaEventIterator struct { + Event *CompassSendToPalomaEvent // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *CompassSendToPalomaEventIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(CompassSendToPalomaEvent) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(CompassSendToPalomaEvent) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *CompassSendToPalomaEventIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *CompassSendToPalomaEventIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// CompassSendToPalomaEvent represents a SendToPalomaEvent event raised by the Compass contract. +type CompassSendToPalomaEvent struct { + Token common.Address + Sender common.Address + Receiver [32]byte + Amount *big.Int + Nonce *big.Int + EventId *big.Int + Raw types.Log // Blockchain specific contextual infos +} + +// FilterSendToPalomaEvent is a free log retrieval operation binding the contract event 0xc5bdbcfcfae5c5b84c56bbf0860c4286d627aefaf28ce4011ba4fcb9b5aadf08. +// +// Solidity: event SendToPalomaEvent(address token, address sender, bytes32 receiver, uint256 amount, uint256 nonce, uint256 event_id) +func (_Compass *CompassFilterer) FilterSendToPalomaEvent(opts *bind.FilterOpts) (*CompassSendToPalomaEventIterator, error) { + logs, sub, err := _Compass.contract.FilterLogs(opts, "SendToPalomaEvent") + if err != nil { + return nil, err + } + return &CompassSendToPalomaEventIterator{contract: _Compass.contract, event: "SendToPalomaEvent", logs: logs, sub: sub}, nil +} + +// WatchSendToPalomaEvent is a free log subscription operation binding the contract event 0xc5bdbcfcfae5c5b84c56bbf0860c4286d627aefaf28ce4011ba4fcb9b5aadf08. +// +// Solidity: event SendToPalomaEvent(address token, address sender, bytes32 receiver, uint256 amount, uint256 nonce, uint256 event_id) +func (_Compass *CompassFilterer) WatchSendToPalomaEvent(opts *bind.WatchOpts, sink chan<- *CompassSendToPalomaEvent) (event.Subscription, error) { + logs, sub, err := _Compass.contract.WatchLogs(opts, "SendToPalomaEvent") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(CompassSendToPalomaEvent) + if err := _Compass.contract.UnpackLog(event, "SendToPalomaEvent", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseSendToPalomaEvent is a log parse operation binding the contract event 0xc5bdbcfcfae5c5b84c56bbf0860c4286d627aefaf28ce4011ba4fcb9b5aadf08. +// +// Solidity: event SendToPalomaEvent(address token, address sender, bytes32 receiver, uint256 amount, uint256 nonce, uint256 event_id) +func (_Compass *CompassFilterer) ParseSendToPalomaEvent(log types.Log) (*CompassSendToPalomaEvent, error) { + event := new(CompassSendToPalomaEvent) + if err := _Compass.contract.UnpackLog(event, "SendToPalomaEvent", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// CompassUpdateCompassAddressInFeeManagerIterator is returned from FilterUpdateCompassAddressInFeeManager and is used to iterate over the raw logs and unpacked data for UpdateCompassAddressInFeeManager events raised by the Compass contract. +type CompassUpdateCompassAddressInFeeManagerIterator struct { + Event *CompassUpdateCompassAddressInFeeManager // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *CompassUpdateCompassAddressInFeeManagerIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(CompassUpdateCompassAddressInFeeManager) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(CompassUpdateCompassAddressInFeeManager) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *CompassUpdateCompassAddressInFeeManagerIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *CompassUpdateCompassAddressInFeeManagerIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// CompassUpdateCompassAddressInFeeManager represents a UpdateCompassAddressInFeeManager event raised by the Compass contract. +type CompassUpdateCompassAddressInFeeManager struct { + NewCompass common.Address + EventId *big.Int + Raw types.Log // Blockchain specific contextual infos +} + +// FilterUpdateCompassAddressInFeeManager is a free log retrieval operation binding the contract event 0x0662fa994447aee93c78fd46a6801f664461ecbba2af6c5a0a6aecbc955835fc. +// +// Solidity: event UpdateCompassAddressInFeeManager(address new_compass, uint256 event_id) +func (_Compass *CompassFilterer) FilterUpdateCompassAddressInFeeManager(opts *bind.FilterOpts) (*CompassUpdateCompassAddressInFeeManagerIterator, error) { + logs, sub, err := _Compass.contract.FilterLogs(opts, "UpdateCompassAddressInFeeManager") + if err != nil { + return nil, err + } + return &CompassUpdateCompassAddressInFeeManagerIterator{contract: _Compass.contract, event: "UpdateCompassAddressInFeeManager", logs: logs, sub: sub}, nil +} + +// WatchUpdateCompassAddressInFeeManager is a free log subscription operation binding the contract event 0x0662fa994447aee93c78fd46a6801f664461ecbba2af6c5a0a6aecbc955835fc. +// +// Solidity: event UpdateCompassAddressInFeeManager(address new_compass, uint256 event_id) +func (_Compass *CompassFilterer) WatchUpdateCompassAddressInFeeManager(opts *bind.WatchOpts, sink chan<- *CompassUpdateCompassAddressInFeeManager) (event.Subscription, error) { + logs, sub, err := _Compass.contract.WatchLogs(opts, "UpdateCompassAddressInFeeManager") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(CompassUpdateCompassAddressInFeeManager) + if err := _Compass.contract.UnpackLog(event, "UpdateCompassAddressInFeeManager", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseUpdateCompassAddressInFeeManager is a log parse operation binding the contract event 0x0662fa994447aee93c78fd46a6801f664461ecbba2af6c5a0a6aecbc955835fc. +// +// Solidity: event UpdateCompassAddressInFeeManager(address new_compass, uint256 event_id) +func (_Compass *CompassFilterer) ParseUpdateCompassAddressInFeeManager(log types.Log) (*CompassUpdateCompassAddressInFeeManager, error) { + event := new(CompassUpdateCompassAddressInFeeManager) + if err := _Compass.contract.UnpackLog(event, "UpdateCompassAddressInFeeManager", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// CompassValsetUpdatedIterator is returned from FilterValsetUpdated and is used to iterate over the raw logs and unpacked data for ValsetUpdated events raised by the Compass contract. +type CompassValsetUpdatedIterator struct { + Event *CompassValsetUpdated // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *CompassValsetUpdatedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(CompassValsetUpdated) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(CompassValsetUpdated) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *CompassValsetUpdatedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *CompassValsetUpdatedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// CompassValsetUpdated represents a ValsetUpdated event raised by the Compass contract. +type CompassValsetUpdated struct { + Checkpoint [32]byte + ValsetId *big.Int + EventId *big.Int + Raw types.Log // Blockchain specific contextual infos +} + +// FilterValsetUpdated is a free log retrieval operation binding the contract event 0xb7ca5e46e360950244488bf096bf742a1f63183cf1ee5b3b0c53045b6247bf5b. +// +// Solidity: event ValsetUpdated(bytes32 checkpoint, uint256 valset_id, uint256 event_id) +func (_Compass *CompassFilterer) FilterValsetUpdated(opts *bind.FilterOpts) (*CompassValsetUpdatedIterator, error) { + logs, sub, err := _Compass.contract.FilterLogs(opts, "ValsetUpdated") + if err != nil { + return nil, err + } + return &CompassValsetUpdatedIterator{contract: _Compass.contract, event: "ValsetUpdated", logs: logs, sub: sub}, nil +} + +// WatchValsetUpdated is a free log subscription operation binding the contract event 0xb7ca5e46e360950244488bf096bf742a1f63183cf1ee5b3b0c53045b6247bf5b. +// +// Solidity: event ValsetUpdated(bytes32 checkpoint, uint256 valset_id, uint256 event_id) +func (_Compass *CompassFilterer) WatchValsetUpdated(opts *bind.WatchOpts, sink chan<- *CompassValsetUpdated) (event.Subscription, error) { logs, sub, err := _Compass.contract.WatchLogs(opts, "ValsetUpdated") if err != nil { return nil, err @@ -631,9 +1945,9 @@ func (_Compass *CompassFilterer) WatchValsetUpdated(opts *bind.WatchOpts, sink c }), nil } -// ParseValsetUpdated is a log parse operation binding the contract event 0x09d40458cf931745f8d532ef13fa9c74bfb7fe0edcee88e0a677b0cbef88f0f9. +// ParseValsetUpdated is a log parse operation binding the contract event 0xb7ca5e46e360950244488bf096bf742a1f63183cf1ee5b3b0c53045b6247bf5b. // -// Solidity: event ValsetUpdated(bytes32 checkpoint, uint256 valset_id) +// Solidity: event ValsetUpdated(bytes32 checkpoint, uint256 valset_id, uint256 event_id) func (_Compass *CompassFilterer) ParseValsetUpdated(log types.Log) (*CompassValsetUpdated, error) { event := new(CompassValsetUpdated) if err := _Compass.contract.UnpackLog(event, "ValsetUpdated", log); err != nil { diff --git a/chain/evm/abi/feemgr/feemgr.abi b/chain/evm/abi/feemgr/feemgr.abi new file mode 100644 index 00000000..391669a7 --- /dev/null +++ b/chain/evm/abi/feemgr/feemgr.abi @@ -0,0 +1,296 @@ +[ + { + "inputs":[ + { + "name":"grain", + "type":"address" + } + ], + "stateMutability":"nonpayable", + "type":"constructor" + }, + { + "inputs":[ + { + "name":"depositor_paloma_address", + "type":"bytes32" + } + ], + "name":"deposit", + "outputs":[ + + ], + "stateMutability":"payable", + "type":"function" + }, + { + "inputs":[ + { + "name":"receiver", + "type":"address" + }, + { + "name":"amount", + "type":"uint256" + }, + { + "name":"dex", + "type":"address" + }, + { + "name":"payload", + "type":"bytes" + }, + { + "name":"min_grain", + "type":"uint256" + } + ], + "name":"withdraw", + "outputs":[ + + ], + "stateMutability":"nonpayable", + "type":"function" + }, + { + "inputs":[ + + ], + "name":"security_fee_topup", + "outputs":[ + + ], + "stateMutability":"payable", + "type":"function" + }, + { + "inputs":[ + { + "components":[ + { + "name":"relayer_fee", + "type":"uint256" + }, + { + "name":"community_fee", + "type":"uint256" + }, + { + "name":"security_fee", + "type":"uint256" + }, + { + "name":"fee_payer_paloma_address", + "type":"bytes32" + } + ], + "name":"fee_args", + "type":"tuple" + }, + { + "name":"relayer", + "type":"address" + } + ], + "name":"transfer_fees", + "outputs":[ + + ], + "stateMutability":"nonpayable", + "type":"function" + }, + { + "inputs":[ + { + "name":"sender", + "type":"address" + }, + { + "name":"gas_fee_amount", + "type":"uint256" + } + ], + "name":"reserve_security_fee", + "outputs":[ + + ], + "stateMutability":"nonpayable", + "type":"function" + }, + { + "inputs":[ + { + "name":"amount", + "type":"uint256" + }, + { + "name":"dex", + "type":"address" + }, + { + "name":"payload", + "type":"bytes" + }, + { + "name":"min_grain", + "type":"uint256" + } + ], + "name":"bridge_community_fee_to_paloma", + "outputs":[ + { + "name":"", + "type":"uint256" + } + ], + "stateMutability":"nonpayable", + "type":"function" + }, + { + "inputs":[ + { + "name":"_new_compass", + "type":"address" + } + ], + "name":"update_compass", + "outputs":[ + + ], + "stateMutability":"nonpayable", + "type":"function" + }, + { + "inputs":[ + { + "name":"_compass", + "type":"address" + } + ], + "name":"initialize", + "outputs":[ + + ], + "stateMutability":"nonpayable", + "type":"function" + }, + { + "inputs":[ + + ], + "name":"compass", + "outputs":[ + { + "name":"", + "type":"address" + } + ], + "stateMutability":"view", + "type":"function" + }, + { + "inputs":[ + + ], + "name":"grain", + "outputs":[ + { + "name":"", + "type":"address" + } + ], + "stateMutability":"view", + "type":"function" + }, + { + "inputs":[ + + ], + "name":"rewards_community_balance", + "outputs":[ + { + "name":"", + "type":"uint256" + } + ], + "stateMutability":"view", + "type":"function" + }, + { + "inputs":[ + + ], + "name":"rewards_security_balance", + "outputs":[ + { + "name":"", + "type":"uint256" + } + ], + "stateMutability":"view", + "type":"function" + }, + { + "inputs":[ + { + "name":"arg0", + "type":"bytes32" + } + ], + "name":"funds", + "outputs":[ + { + "name":"", + "type":"uint256" + } + ], + "stateMutability":"view", + "type":"function" + }, + { + "inputs":[ + { + "name":"arg0", + "type":"address" + } + ], + "name":"claimable_rewards", + "outputs":[ + { + "name":"", + "type":"uint256" + } + ], + "stateMutability":"view", + "type":"function" + }, + { + "inputs":[ + + ], + "name":"total_funds", + "outputs":[ + { + "name":"", + "type":"uint256" + } + ], + "stateMutability":"view", + "type":"function" + }, + { + "inputs":[ + + ], + "name":"total_claims", + "outputs":[ + { + "name":"", + "type":"uint256" + } + ], + "stateMutability":"view", + "type":"function" + } +] diff --git a/chain/evm/abi/feemgr/feemgr.go b/chain/evm/abi/feemgr/feemgr.go new file mode 100644 index 00000000..42c95966 --- /dev/null +++ b/chain/evm/abi/feemgr/feemgr.go @@ -0,0 +1,589 @@ +// Code generated - DO NOT EDIT. +// This file is a generated binding and any manual changes will be lost. + +package feemgr + +import ( + "errors" + "math/big" + "strings" + + ethereum "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/event" +) + +// Reference imports to suppress errors if they are not otherwise used. +var ( + _ = errors.New + _ = big.NewInt + _ = strings.NewReader + _ = ethereum.NotFound + _ = bind.Bind + _ = common.Big1 + _ = types.BloomLookup + _ = event.NewSubscription + _ = abi.ConvertType +) + +// Struct0 is an auto generated low-level Go binding around an user-defined struct. +type Struct0 struct { + RelayerFee *big.Int + CommunityFee *big.Int + SecurityFee *big.Int + FeePayerPalomaAddress [32]byte +} + +// FeemgrMetaData contains all meta data concerning the Feemgr contract. +var FeemgrMetaData = &bind.MetaData{ + ABI: "[{\"inputs\":[{\"name\":\"grain\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[{\"name\":\"depositor_paloma_address\",\"type\":\"bytes32\"}],\"name\":\"deposit\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"name\":\"receiver\",\"type\":\"address\"},{\"name\":\"amount\",\"type\":\"uint256\"},{\"name\":\"dex\",\"type\":\"address\"},{\"name\":\"payload\",\"type\":\"bytes\"},{\"name\":\"min_grain\",\"type\":\"uint256\"}],\"name\":\"withdraw\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"security_fee_topup\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"name\":\"relayer_fee\",\"type\":\"uint256\"},{\"name\":\"community_fee\",\"type\":\"uint256\"},{\"name\":\"security_fee\",\"type\":\"uint256\"},{\"name\":\"fee_payer_paloma_address\",\"type\":\"bytes32\"}],\"name\":\"fee_args\",\"type\":\"tuple\"},{\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"transfer_fees\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"name\":\"sender\",\"type\":\"address\"},{\"name\":\"gas_fee_amount\",\"type\":\"uint256\"}],\"name\":\"reserve_security_fee\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"name\":\"amount\",\"type\":\"uint256\"},{\"name\":\"dex\",\"type\":\"address\"},{\"name\":\"payload\",\"type\":\"bytes\"},{\"name\":\"min_grain\",\"type\":\"uint256\"}],\"name\":\"bridge_community_fee_to_paloma\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"name\":\"_new_compass\",\"type\":\"address\"}],\"name\":\"update_compass\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"name\":\"_compass\",\"type\":\"address\"}],\"name\":\"initialize\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"compass\",\"outputs\":[{\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"grain\",\"outputs\":[{\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"rewards_community_balance\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"rewards_security_balance\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"name\":\"arg0\",\"type\":\"bytes32\"}],\"name\":\"funds\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"name\":\"arg0\",\"type\":\"address\"}],\"name\":\"claimable_rewards\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"total_funds\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"total_claims\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]", +} + +// FeemgrABI is the input ABI used to generate the binding from. +// Deprecated: Use FeemgrMetaData.ABI instead. +var FeemgrABI = FeemgrMetaData.ABI + +// Feemgr is an auto generated Go binding around an Ethereum contract. +type Feemgr struct { + FeemgrCaller // Read-only binding to the contract + FeemgrTransactor // Write-only binding to the contract + FeemgrFilterer // Log filterer for contract events +} + +// FeemgrCaller is an auto generated read-only Go binding around an Ethereum contract. +type FeemgrCaller struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// FeemgrTransactor is an auto generated write-only Go binding around an Ethereum contract. +type FeemgrTransactor struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// FeemgrFilterer is an auto generated log filtering Go binding around an Ethereum contract events. +type FeemgrFilterer struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// FeemgrSession is an auto generated Go binding around an Ethereum contract, +// with pre-set call and transact options. +type FeemgrSession struct { + Contract *Feemgr // Generic contract binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// FeemgrCallerSession is an auto generated read-only Go binding around an Ethereum contract, +// with pre-set call options. +type FeemgrCallerSession struct { + Contract *FeemgrCaller // Generic contract caller binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session +} + +// FeemgrTransactorSession is an auto generated write-only Go binding around an Ethereum contract, +// with pre-set transact options. +type FeemgrTransactorSession struct { + Contract *FeemgrTransactor // Generic contract transactor binding to set the session for + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// FeemgrRaw is an auto generated low-level Go binding around an Ethereum contract. +type FeemgrRaw struct { + Contract *Feemgr // Generic contract binding to access the raw methods on +} + +// FeemgrCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. +type FeemgrCallerRaw struct { + Contract *FeemgrCaller // Generic read-only contract binding to access the raw methods on +} + +// FeemgrTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. +type FeemgrTransactorRaw struct { + Contract *FeemgrTransactor // Generic write-only contract binding to access the raw methods on +} + +// NewFeemgr creates a new instance of Feemgr, bound to a specific deployed contract. +func NewFeemgr(address common.Address, backend bind.ContractBackend) (*Feemgr, error) { + contract, err := bindFeemgr(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &Feemgr{FeemgrCaller: FeemgrCaller{contract: contract}, FeemgrTransactor: FeemgrTransactor{contract: contract}, FeemgrFilterer: FeemgrFilterer{contract: contract}}, nil +} + +// NewFeemgrCaller creates a new read-only instance of Feemgr, bound to a specific deployed contract. +func NewFeemgrCaller(address common.Address, caller bind.ContractCaller) (*FeemgrCaller, error) { + contract, err := bindFeemgr(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &FeemgrCaller{contract: contract}, nil +} + +// NewFeemgrTransactor creates a new write-only instance of Feemgr, bound to a specific deployed contract. +func NewFeemgrTransactor(address common.Address, transactor bind.ContractTransactor) (*FeemgrTransactor, error) { + contract, err := bindFeemgr(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &FeemgrTransactor{contract: contract}, nil +} + +// NewFeemgrFilterer creates a new log filterer instance of Feemgr, bound to a specific deployed contract. +func NewFeemgrFilterer(address common.Address, filterer bind.ContractFilterer) (*FeemgrFilterer, error) { + contract, err := bindFeemgr(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &FeemgrFilterer{contract: contract}, nil +} + +// bindFeemgr binds a generic wrapper to an already deployed contract. +func bindFeemgr(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := FeemgrMetaData.GetAbi() + if err != nil { + return nil, err + } + return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_Feemgr *FeemgrRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _Feemgr.Contract.FeemgrCaller.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_Feemgr *FeemgrRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _Feemgr.Contract.FeemgrTransactor.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_Feemgr *FeemgrRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _Feemgr.Contract.FeemgrTransactor.contract.Transact(opts, method, params...) +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_Feemgr *FeemgrCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _Feemgr.Contract.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_Feemgr *FeemgrTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _Feemgr.Contract.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_Feemgr *FeemgrTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _Feemgr.Contract.contract.Transact(opts, method, params...) +} + +// ClaimableRewards is a free data retrieval call binding the contract method 0x6d84534a. +// +// Solidity: function claimable_rewards(address arg0) view returns(uint256) +func (_Feemgr *FeemgrCaller) ClaimableRewards(opts *bind.CallOpts, arg0 common.Address) (*big.Int, error) { + var out []interface{} + err := _Feemgr.contract.Call(opts, &out, "claimable_rewards", arg0) + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err +} + +// ClaimableRewards is a free data retrieval call binding the contract method 0x6d84534a. +// +// Solidity: function claimable_rewards(address arg0) view returns(uint256) +func (_Feemgr *FeemgrSession) ClaimableRewards(arg0 common.Address) (*big.Int, error) { + return _Feemgr.Contract.ClaimableRewards(&_Feemgr.CallOpts, arg0) +} + +// ClaimableRewards is a free data retrieval call binding the contract method 0x6d84534a. +// +// Solidity: function claimable_rewards(address arg0) view returns(uint256) +func (_Feemgr *FeemgrCallerSession) ClaimableRewards(arg0 common.Address) (*big.Int, error) { + return _Feemgr.Contract.ClaimableRewards(&_Feemgr.CallOpts, arg0) +} + +// Compass is a free data retrieval call binding the contract method 0xeb8acce6. +// +// Solidity: function compass() view returns(address) +func (_Feemgr *FeemgrCaller) Compass(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _Feemgr.contract.Call(opts, &out, "compass") + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err +} + +// Compass is a free data retrieval call binding the contract method 0xeb8acce6. +// +// Solidity: function compass() view returns(address) +func (_Feemgr *FeemgrSession) Compass() (common.Address, error) { + return _Feemgr.Contract.Compass(&_Feemgr.CallOpts) +} + +// Compass is a free data retrieval call binding the contract method 0xeb8acce6. +// +// Solidity: function compass() view returns(address) +func (_Feemgr *FeemgrCallerSession) Compass() (common.Address, error) { + return _Feemgr.Contract.Compass(&_Feemgr.CallOpts) +} + +// Funds is a free data retrieval call binding the contract method 0x6a29a620. +// +// Solidity: function funds(bytes32 arg0) view returns(uint256) +func (_Feemgr *FeemgrCaller) Funds(opts *bind.CallOpts, arg0 [32]byte) (*big.Int, error) { + var out []interface{} + err := _Feemgr.contract.Call(opts, &out, "funds", arg0) + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err +} + +// Funds is a free data retrieval call binding the contract method 0x6a29a620. +// +// Solidity: function funds(bytes32 arg0) view returns(uint256) +func (_Feemgr *FeemgrSession) Funds(arg0 [32]byte) (*big.Int, error) { + return _Feemgr.Contract.Funds(&_Feemgr.CallOpts, arg0) +} + +// Funds is a free data retrieval call binding the contract method 0x6a29a620. +// +// Solidity: function funds(bytes32 arg0) view returns(uint256) +func (_Feemgr *FeemgrCallerSession) Funds(arg0 [32]byte) (*big.Int, error) { + return _Feemgr.Contract.Funds(&_Feemgr.CallOpts, arg0) +} + +// Grain is a free data retrieval call binding the contract method 0x7f67b0ff. +// +// Solidity: function grain() view returns(address) +func (_Feemgr *FeemgrCaller) Grain(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _Feemgr.contract.Call(opts, &out, "grain") + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err +} + +// Grain is a free data retrieval call binding the contract method 0x7f67b0ff. +// +// Solidity: function grain() view returns(address) +func (_Feemgr *FeemgrSession) Grain() (common.Address, error) { + return _Feemgr.Contract.Grain(&_Feemgr.CallOpts) +} + +// Grain is a free data retrieval call binding the contract method 0x7f67b0ff. +// +// Solidity: function grain() view returns(address) +func (_Feemgr *FeemgrCallerSession) Grain() (common.Address, error) { + return _Feemgr.Contract.Grain(&_Feemgr.CallOpts) +} + +// RewardsCommunityBalance is a free data retrieval call binding the contract method 0x1bf23890. +// +// Solidity: function rewards_community_balance() view returns(uint256) +func (_Feemgr *FeemgrCaller) RewardsCommunityBalance(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _Feemgr.contract.Call(opts, &out, "rewards_community_balance") + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err +} + +// RewardsCommunityBalance is a free data retrieval call binding the contract method 0x1bf23890. +// +// Solidity: function rewards_community_balance() view returns(uint256) +func (_Feemgr *FeemgrSession) RewardsCommunityBalance() (*big.Int, error) { + return _Feemgr.Contract.RewardsCommunityBalance(&_Feemgr.CallOpts) +} + +// RewardsCommunityBalance is a free data retrieval call binding the contract method 0x1bf23890. +// +// Solidity: function rewards_community_balance() view returns(uint256) +func (_Feemgr *FeemgrCallerSession) RewardsCommunityBalance() (*big.Int, error) { + return _Feemgr.Contract.RewardsCommunityBalance(&_Feemgr.CallOpts) +} + +// RewardsSecurityBalance is a free data retrieval call binding the contract method 0x346c573e. +// +// Solidity: function rewards_security_balance() view returns(uint256) +func (_Feemgr *FeemgrCaller) RewardsSecurityBalance(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _Feemgr.contract.Call(opts, &out, "rewards_security_balance") + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err +} + +// RewardsSecurityBalance is a free data retrieval call binding the contract method 0x346c573e. +// +// Solidity: function rewards_security_balance() view returns(uint256) +func (_Feemgr *FeemgrSession) RewardsSecurityBalance() (*big.Int, error) { + return _Feemgr.Contract.RewardsSecurityBalance(&_Feemgr.CallOpts) +} + +// RewardsSecurityBalance is a free data retrieval call binding the contract method 0x346c573e. +// +// Solidity: function rewards_security_balance() view returns(uint256) +func (_Feemgr *FeemgrCallerSession) RewardsSecurityBalance() (*big.Int, error) { + return _Feemgr.Contract.RewardsSecurityBalance(&_Feemgr.CallOpts) +} + +// TotalClaims is a free data retrieval call binding the contract method 0xc22416b0. +// +// Solidity: function total_claims() view returns(uint256) +func (_Feemgr *FeemgrCaller) TotalClaims(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _Feemgr.contract.Call(opts, &out, "total_claims") + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err +} + +// TotalClaims is a free data retrieval call binding the contract method 0xc22416b0. +// +// Solidity: function total_claims() view returns(uint256) +func (_Feemgr *FeemgrSession) TotalClaims() (*big.Int, error) { + return _Feemgr.Contract.TotalClaims(&_Feemgr.CallOpts) +} + +// TotalClaims is a free data retrieval call binding the contract method 0xc22416b0. +// +// Solidity: function total_claims() view returns(uint256) +func (_Feemgr *FeemgrCallerSession) TotalClaims() (*big.Int, error) { + return _Feemgr.Contract.TotalClaims(&_Feemgr.CallOpts) +} + +// TotalFunds is a free data retrieval call binding the contract method 0x34138814. +// +// Solidity: function total_funds() view returns(uint256) +func (_Feemgr *FeemgrCaller) TotalFunds(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _Feemgr.contract.Call(opts, &out, "total_funds") + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err +} + +// TotalFunds is a free data retrieval call binding the contract method 0x34138814. +// +// Solidity: function total_funds() view returns(uint256) +func (_Feemgr *FeemgrSession) TotalFunds() (*big.Int, error) { + return _Feemgr.Contract.TotalFunds(&_Feemgr.CallOpts) +} + +// TotalFunds is a free data retrieval call binding the contract method 0x34138814. +// +// Solidity: function total_funds() view returns(uint256) +func (_Feemgr *FeemgrCallerSession) TotalFunds() (*big.Int, error) { + return _Feemgr.Contract.TotalFunds(&_Feemgr.CallOpts) +} + +// BridgeCommunityFeeToPaloma is a paid mutator transaction binding the contract method 0x06c9624d. +// +// Solidity: function bridge_community_fee_to_paloma(uint256 amount, address dex, bytes payload, uint256 min_grain) returns(uint256) +func (_Feemgr *FeemgrTransactor) BridgeCommunityFeeToPaloma(opts *bind.TransactOpts, amount *big.Int, dex common.Address, payload []byte, min_grain *big.Int) (*types.Transaction, error) { + return _Feemgr.contract.Transact(opts, "bridge_community_fee_to_paloma", amount, dex, payload, min_grain) +} + +// BridgeCommunityFeeToPaloma is a paid mutator transaction binding the contract method 0x06c9624d. +// +// Solidity: function bridge_community_fee_to_paloma(uint256 amount, address dex, bytes payload, uint256 min_grain) returns(uint256) +func (_Feemgr *FeemgrSession) BridgeCommunityFeeToPaloma(amount *big.Int, dex common.Address, payload []byte, min_grain *big.Int) (*types.Transaction, error) { + return _Feemgr.Contract.BridgeCommunityFeeToPaloma(&_Feemgr.TransactOpts, amount, dex, payload, min_grain) +} + +// BridgeCommunityFeeToPaloma is a paid mutator transaction binding the contract method 0x06c9624d. +// +// Solidity: function bridge_community_fee_to_paloma(uint256 amount, address dex, bytes payload, uint256 min_grain) returns(uint256) +func (_Feemgr *FeemgrTransactorSession) BridgeCommunityFeeToPaloma(amount *big.Int, dex common.Address, payload []byte, min_grain *big.Int) (*types.Transaction, error) { + return _Feemgr.Contract.BridgeCommunityFeeToPaloma(&_Feemgr.TransactOpts, amount, dex, payload, min_grain) +} + +// Deposit is a paid mutator transaction binding the contract method 0xb214faa5. +// +// Solidity: function deposit(bytes32 depositor_paloma_address) payable returns() +func (_Feemgr *FeemgrTransactor) Deposit(opts *bind.TransactOpts, depositor_paloma_address [32]byte) (*types.Transaction, error) { + return _Feemgr.contract.Transact(opts, "deposit", depositor_paloma_address) +} + +// Deposit is a paid mutator transaction binding the contract method 0xb214faa5. +// +// Solidity: function deposit(bytes32 depositor_paloma_address) payable returns() +func (_Feemgr *FeemgrSession) Deposit(depositor_paloma_address [32]byte) (*types.Transaction, error) { + return _Feemgr.Contract.Deposit(&_Feemgr.TransactOpts, depositor_paloma_address) +} + +// Deposit is a paid mutator transaction binding the contract method 0xb214faa5. +// +// Solidity: function deposit(bytes32 depositor_paloma_address) payable returns() +func (_Feemgr *FeemgrTransactorSession) Deposit(depositor_paloma_address [32]byte) (*types.Transaction, error) { + return _Feemgr.Contract.Deposit(&_Feemgr.TransactOpts, depositor_paloma_address) +} + +// Initialize is a paid mutator transaction binding the contract method 0xc4d66de8. +// +// Solidity: function initialize(address _compass) returns() +func (_Feemgr *FeemgrTransactor) Initialize(opts *bind.TransactOpts, _compass common.Address) (*types.Transaction, error) { + return _Feemgr.contract.Transact(opts, "initialize", _compass) +} + +// Initialize is a paid mutator transaction binding the contract method 0xc4d66de8. +// +// Solidity: function initialize(address _compass) returns() +func (_Feemgr *FeemgrSession) Initialize(_compass common.Address) (*types.Transaction, error) { + return _Feemgr.Contract.Initialize(&_Feemgr.TransactOpts, _compass) +} + +// Initialize is a paid mutator transaction binding the contract method 0xc4d66de8. +// +// Solidity: function initialize(address _compass) returns() +func (_Feemgr *FeemgrTransactorSession) Initialize(_compass common.Address) (*types.Transaction, error) { + return _Feemgr.Contract.Initialize(&_Feemgr.TransactOpts, _compass) +} + +// ReserveSecurityFee is a paid mutator transaction binding the contract method 0xd4bbab4f. +// +// Solidity: function reserve_security_fee(address sender, uint256 gas_fee_amount) returns() +func (_Feemgr *FeemgrTransactor) ReserveSecurityFee(opts *bind.TransactOpts, sender common.Address, gas_fee_amount *big.Int) (*types.Transaction, error) { + return _Feemgr.contract.Transact(opts, "reserve_security_fee", sender, gas_fee_amount) +} + +// ReserveSecurityFee is a paid mutator transaction binding the contract method 0xd4bbab4f. +// +// Solidity: function reserve_security_fee(address sender, uint256 gas_fee_amount) returns() +func (_Feemgr *FeemgrSession) ReserveSecurityFee(sender common.Address, gas_fee_amount *big.Int) (*types.Transaction, error) { + return _Feemgr.Contract.ReserveSecurityFee(&_Feemgr.TransactOpts, sender, gas_fee_amount) +} + +// ReserveSecurityFee is a paid mutator transaction binding the contract method 0xd4bbab4f. +// +// Solidity: function reserve_security_fee(address sender, uint256 gas_fee_amount) returns() +func (_Feemgr *FeemgrTransactorSession) ReserveSecurityFee(sender common.Address, gas_fee_amount *big.Int) (*types.Transaction, error) { + return _Feemgr.Contract.ReserveSecurityFee(&_Feemgr.TransactOpts, sender, gas_fee_amount) +} + +// SecurityFeeTopup is a paid mutator transaction binding the contract method 0x1d046325. +// +// Solidity: function security_fee_topup() payable returns() +func (_Feemgr *FeemgrTransactor) SecurityFeeTopup(opts *bind.TransactOpts) (*types.Transaction, error) { + return _Feemgr.contract.Transact(opts, "security_fee_topup") +} + +// SecurityFeeTopup is a paid mutator transaction binding the contract method 0x1d046325. +// +// Solidity: function security_fee_topup() payable returns() +func (_Feemgr *FeemgrSession) SecurityFeeTopup() (*types.Transaction, error) { + return _Feemgr.Contract.SecurityFeeTopup(&_Feemgr.TransactOpts) +} + +// SecurityFeeTopup is a paid mutator transaction binding the contract method 0x1d046325. +// +// Solidity: function security_fee_topup() payable returns() +func (_Feemgr *FeemgrTransactorSession) SecurityFeeTopup() (*types.Transaction, error) { + return _Feemgr.Contract.SecurityFeeTopup(&_Feemgr.TransactOpts) +} + +// TransferFees is a paid mutator transaction binding the contract method 0xffd8d4aa. +// +// Solidity: function transfer_fees((uint256,uint256,uint256,bytes32) fee_args, address relayer) returns() +func (_Feemgr *FeemgrTransactor) TransferFees(opts *bind.TransactOpts, fee_args Struct0, relayer common.Address) (*types.Transaction, error) { + return _Feemgr.contract.Transact(opts, "transfer_fees", fee_args, relayer) +} + +// TransferFees is a paid mutator transaction binding the contract method 0xffd8d4aa. +// +// Solidity: function transfer_fees((uint256,uint256,uint256,bytes32) fee_args, address relayer) returns() +func (_Feemgr *FeemgrSession) TransferFees(fee_args Struct0, relayer common.Address) (*types.Transaction, error) { + return _Feemgr.Contract.TransferFees(&_Feemgr.TransactOpts, fee_args, relayer) +} + +// TransferFees is a paid mutator transaction binding the contract method 0xffd8d4aa. +// +// Solidity: function transfer_fees((uint256,uint256,uint256,bytes32) fee_args, address relayer) returns() +func (_Feemgr *FeemgrTransactorSession) TransferFees(fee_args Struct0, relayer common.Address) (*types.Transaction, error) { + return _Feemgr.Contract.TransferFees(&_Feemgr.TransactOpts, fee_args, relayer) +} + +// UpdateCompass is a paid mutator transaction binding the contract method 0x6974af69. +// +// Solidity: function update_compass(address _new_compass) returns() +func (_Feemgr *FeemgrTransactor) UpdateCompass(opts *bind.TransactOpts, _new_compass common.Address) (*types.Transaction, error) { + return _Feemgr.contract.Transact(opts, "update_compass", _new_compass) +} + +// UpdateCompass is a paid mutator transaction binding the contract method 0x6974af69. +// +// Solidity: function update_compass(address _new_compass) returns() +func (_Feemgr *FeemgrSession) UpdateCompass(_new_compass common.Address) (*types.Transaction, error) { + return _Feemgr.Contract.UpdateCompass(&_Feemgr.TransactOpts, _new_compass) +} + +// UpdateCompass is a paid mutator transaction binding the contract method 0x6974af69. +// +// Solidity: function update_compass(address _new_compass) returns() +func (_Feemgr *FeemgrTransactorSession) UpdateCompass(_new_compass common.Address) (*types.Transaction, error) { + return _Feemgr.Contract.UpdateCompass(&_Feemgr.TransactOpts, _new_compass) +} + +// Withdraw is a paid mutator transaction binding the contract method 0xd07e9fa0. +// +// Solidity: function withdraw(address receiver, uint256 amount, address dex, bytes payload, uint256 min_grain) returns() +func (_Feemgr *FeemgrTransactor) Withdraw(opts *bind.TransactOpts, receiver common.Address, amount *big.Int, dex common.Address, payload []byte, min_grain *big.Int) (*types.Transaction, error) { + return _Feemgr.contract.Transact(opts, "withdraw", receiver, amount, dex, payload, min_grain) +} + +// Withdraw is a paid mutator transaction binding the contract method 0xd07e9fa0. +// +// Solidity: function withdraw(address receiver, uint256 amount, address dex, bytes payload, uint256 min_grain) returns() +func (_Feemgr *FeemgrSession) Withdraw(receiver common.Address, amount *big.Int, dex common.Address, payload []byte, min_grain *big.Int) (*types.Transaction, error) { + return _Feemgr.Contract.Withdraw(&_Feemgr.TransactOpts, receiver, amount, dex, payload, min_grain) +} + +// Withdraw is a paid mutator transaction binding the contract method 0xd07e9fa0. +// +// Solidity: function withdraw(address receiver, uint256 amount, address dex, bytes payload, uint256 min_grain) returns() +func (_Feemgr *FeemgrTransactorSession) Withdraw(receiver common.Address, amount *big.Int, dex common.Address, payload []byte, min_grain *big.Int) (*types.Transaction, error) { + return _Feemgr.Contract.Withdraw(&_Feemgr.TransactOpts, receiver, amount, dex, payload, min_grain) +} diff --git a/chain/evm/client.go b/chain/evm/client.go index 58d0871a..fc0b25cb 100644 --- a/chain/evm/client.go +++ b/chain/evm/client.go @@ -32,6 +32,7 @@ import ( skywaytypes "github.com/palomachain/paloma/x/skyway/types" valset "github.com/palomachain/paloma/x/valset/types" compassABI "github.com/palomachain/pigeon/chain/evm/abi/compass" + feemgrABI "github.com/palomachain/pigeon/chain/evm/abi/feemgr" "github.com/palomachain/pigeon/chain/paloma" "github.com/palomachain/pigeon/config" "github.com/palomachain/pigeon/errors" @@ -155,12 +156,12 @@ type CompassBindingCaller interface { LastCheckpoint(opts *bind.CallOpts) ([32]byte, error) LastValsetId(opts *bind.CallOpts) (*big.Int, error) MessageIdUsed(opts *bind.CallOpts, arg0 *big.Int) (bool, error) - TurnstoneId(opts *bind.CallOpts) ([32]byte, error) + CompassId(opts *bind.CallOpts) ([32]byte, error) } type CompassBindingTransactor interface { - SubmitLogicCall(opts *bind.TransactOpts, consensus compassABI.Struct2, args compassABI.Struct3, messageId *big.Int, deadline *big.Int) (*ethtypes.Transaction, error) - UpdateValset(opts *bind.TransactOpts, consensus compassABI.Struct2, newValset compassABI.Struct0) (*ethtypes.Transaction, error) + SubmitLogicCall(opts *bind.TransactOpts, consensus compassABI.Struct2, args compassABI.Struct3, fee_args compassABI.Struct4, messageId *big.Int, deadline *big.Int, relayer common.Address) (*ethtypes.Transaction, error) + UpdateValset(opts *bind.TransactOpts, consensus compassABI.Struct2, newValset compassABI.Struct0, relayer common.Address, gas_estimate *big.Int) (*ethtypes.Transaction, error) } type CompassBindingFilterer interface { @@ -240,6 +241,7 @@ type executeSmartContractIn struct { method string arguments []any + opts callOptions } func callSmartContract( @@ -376,8 +378,16 @@ func callSmartContract( }).Debug("executing legacy tx") } + // In case we only want to estimate, now is the time to return. + if args.opts.estimateOnly { + return ethtypes.NewTx( + ðtypes.LegacyTx{ + Gas: txOpts.GasLimit, + }) + } + // In case we want to relay, don't actually send the constructed TX - if args.mevClient != nil { + if args.opts.useMevRelay && args.mevClient != nil { logger.Info("MEV Client set - setting TX to not execute") txOpts.NoSend = true } @@ -644,12 +654,12 @@ func (c *Client) ExecuteSmartContract( chainID *big.Int, contractAbi abi.ABI, addr common.Address, - useMevRelay bool, + opts callOptions, method string, arguments []any, ) (*etherumtypes.Transaction, error) { var mevClient mevClient = nil - if useMevRelay { + if opts.useMevRelay { mevClient = c.mevClient logrus.WithContext(ctx).WithField("mevClient", mevClient).WithField("c.mevClient", c.mevClient).Info("Using MEV relay") } @@ -666,6 +676,7 @@ func (c *Client) ExecuteSmartContract( contract: addr, signingAddr: c.addr, keystore: c.keystore, + opts: opts, method: method, arguments: arguments, @@ -754,3 +765,24 @@ func (c *Client) LastValsetID(ctx context.Context, addr common.Address) (*big.In } return cmps.LastValsetId(callOpts) } + +func (c *Client) QueryUserFunds(ctx context.Context, feemgraddr common.Address, palomaAddress [32]byte) (*big.Int, error) { + logger := liblog.WithContext(ctx).WithField("address", feemgraddr.String()) + logger.Debug("called QueryUserFunds in EVM client") + + fm, err := feemgrABI.NewFeemgr(feemgraddr, c.conn) + if err != nil { + logger.WithError(err).Error("QueryUserFunds: error instantiating feemgr") + return nil, fmt.Errorf("error instantiating feemgr binding: %w", err) + } + + callOpts := &bind.CallOpts{ + Pending: false, + Context: ctx, + } + return fm.Funds(callOpts, palomaAddress) +} + +func (c *Client) SuggestGasPrice(ctx context.Context) (*big.Int, error) { + return c.conn.SuggestGasPrice(ctx) +} diff --git a/chain/evm/client_test.go b/chain/evm/client_test.go index e27b946f..cf8db2ae 100644 --- a/chain/evm/client_test.go +++ b/chain/evm/client_test.go @@ -50,9 +50,10 @@ func TestExecutingSmartContract(t *testing.T) { require.NoError(t, err) fakeErr := whoops.String("oh no") for _, tt := range []struct { - name string - setup func(t *testing.T, args *executeSmartContractIn) - expectedErr error + name string + setup func(t *testing.T, args *executeSmartContractIn) + expectedErr error + expectedEstimated *uint64 }{ { name: "happy path", @@ -139,8 +140,29 @@ func TestExecutingSmartContract(t *testing.T) { args.ethClient = ethMock args.mevClient = mevMock + args.opts.useMevRelay = true }, }, + { + name: "Message gas estimation only, should not send transaction", + setup: func(t *testing.T, args *executeSmartContractIn) { + ethMock := newMockEthClienter(t) + + ethMock.On("PendingNonceAt", mock.Anything, mock.Anything).Return(uint64(333), nil) + + ethMock.On("SuggestGasPrice", mock.Anything).Return(big.NewInt(444), nil) + + ethMock.On("SuggestGasTipCap", mock.Anything).Return(big.NewInt(4), nil) + + ethMock.On("PendingCodeAt", mock.Anything, args.contract).Return([]byte("a"), nil) + + ethMock.On("EstimateGas", mock.Anything, mock.Anything).Return(uint64(222), nil) + + args.ethClient = ethMock + args.opts.estimateOnly = true + }, + expectedEstimated: &([]uint64{333})[0], // afford for 1.5 multiplier + }, } { t.Run(tt.name, func(t *testing.T) { ks := keystore.NewKeyStore(t.TempDir(), keystore.StandardScryptN, keystore.StandardScryptP) @@ -163,12 +185,15 @@ func TestExecutingSmartContract(t *testing.T) { tt.setup(t, &args) - _, err = callSmartContract( + tx, err := callSmartContract( context.Background(), args, ) require.ErrorIs(t, err, tt.expectedErr) + if tt.expectedEstimated != nil { + require.Equal(t, *tt.expectedEstimated, tx.Gas()) + } }) } } diff --git a/chain/evm/compass.go b/chain/evm/compass.go index 0c67fee7..cd332b65 100644 --- a/chain/evm/compass.go +++ b/chain/evm/compass.go @@ -1,9 +1,11 @@ package evm import ( + "bytes" "context" "errors" "fmt" + gomath "math" "math/big" "time" @@ -19,6 +21,7 @@ import ( evmtypes "github.com/palomachain/paloma/x/evm/types" skywaytypes "github.com/palomachain/paloma/x/skyway/types" "github.com/palomachain/pigeon/chain" + cabi "github.com/palomachain/pigeon/chain/evm/abi/compass" "github.com/palomachain/pigeon/internal/ethfilter" "github.com/palomachain/pigeon/internal/liblog" "github.com/palomachain/pigeon/util/slice" @@ -50,7 +53,7 @@ var errValsetIDMismatch = errors.New("valset id mismatch") //go:generate mockery --name=evmClienter --inpackage --testonly type evmClienter interface { FilterLogs(ctx context.Context, fq ethereum.FilterQuery, currBlockHeight *big.Int, fn func(logs []ethtypes.Log) bool) (bool, error) - ExecuteSmartContract(ctx context.Context, chainID *big.Int, contractAbi abi.ABI, addr common.Address, mevRelay bool, method string, arguments []any) (*ethtypes.Transaction, error) + ExecuteSmartContract(ctx context.Context, chainID *big.Int, contractAbi abi.ABI, addr common.Address, opts callOptions, method string, arguments []any) (*ethtypes.Transaction, error) DeployContract(ctx context.Context, chainID *big.Int, rawABI string, bytecode, constructorInput []byte) (contractAddr common.Address, tx *ethtypes.Transaction, err error) TransactionByHash(ctx context.Context, txHash common.Hash) (*ethtypes.Transaction, bool, error) @@ -58,6 +61,8 @@ type evmClienter interface { FindBlockNearestToTime(ctx context.Context, startingHeight uint64, when time.Time) (uint64, error) FindCurrentBlockNumber(ctx context.Context) (*big.Int, error) LastValsetID(ctx context.Context, addr common.Address) (*big.Int, error) + QueryUserFunds(ctx context.Context, feemgraddr common.Address, palomaAddress [32]byte) (*big.Int, error) + SuggestGasPrice(ctx context.Context) (*big.Int, error) GetEthClient() ethClientConn } @@ -71,10 +76,12 @@ type compass struct { lastObservedBlockHeight int64 startingBlockHeight int64 smartContractAddr common.Address + feeMgrContractAddr common.Address } func newCompassClient( smartContractAddrStr, + feeMgrContractAddrStr, compassID, chainReferenceID string, chainID *big.Int, @@ -86,13 +93,14 @@ func newCompassClient( // whoops.Assert(errors.Unrecoverable(ErrInvalidAddress.Format(smartContractAddrStr))) // } return compass{ - CompassID: compassID, - ChainReferenceID: chainReferenceID, - smartContractAddr: common.HexToAddress(smartContractAddrStr), - chainID: chainID, - compassAbi: compassAbi, - paloma: paloma, - evm: evm, + CompassID: compassID, + ChainReferenceID: chainReferenceID, + smartContractAddr: common.HexToAddress(smartContractAddrStr), + feeMgrContractAddr: common.HexToAddress(feeMgrContractAddrStr), + chainID: chainID, + compassAbi: compassAbi, + paloma: paloma, + evm: evm, } } @@ -118,6 +126,8 @@ type CompassLogicCallArgs struct { LogicContractAddress common.Address } +type FeeArgs cabi.Struct4 + type CompassTokenSendArgs struct { Receiver []common.Address Amount []*big.Int @@ -132,6 +142,9 @@ func (t compass) updateValset( queueTypeName string, newValset *evmtypes.Valset, origMessage chain.MessageWithSignatures, + ethSender common.Address, + estimate *big.Int, + opts callOptions, ) (*ethtypes.Transaction, uint64, error) { currentValsetID, err := t.findLastValsetMessageID(ctx) if err != nil { @@ -157,19 +170,31 @@ func (t compass) updateValset( return nil, 0, ErrNoConsensus } - tx, err := t.callCompass(ctx, false, "update_valset", []any{ + if opts.estimateOnly { + // Simulate maximum gas estimate to ensure the transaction is not rejected + estimate = big.NewInt(gomath.MaxInt64) + } + + // TODO: Use generated contract code directly + // compass 2.0.0 + // def update_valset(consensus: Consensus, new_valset: Valset, relayer: address, gas_estimate: uint256) + tx, err := t.callCompass(ctx, opts, "update_valset", []any{ BuildCompassConsensus(currentValset, origMessage.Signatures), TransformValsetToCompassValset(newValset), + ethSender, + estimate, }) if err != nil { logger.WithError(err).Error("call_compass error") - isSmartContractError, setErr := t.SetErrorData(ctx, queueTypeName, origMessage.ID, err) - if setErr != nil { - return nil, 0, setErr - } - if isSmartContractError { - logger.Debug("smart contract error. recovering...") - return nil, 0, nil + if opts.estimateOnly == false { + isSmartContractError, setErr := t.SetErrorData(ctx, queueTypeName, origMessage.ID, err) + if setErr != nil { + return nil, 0, setErr + } + if isSmartContractError { + logger.Debug("smart contract error. recovering...") + return nil, 0, nil + } } whoops.Assert(err) } @@ -182,6 +207,8 @@ func (t compass) submitLogicCall( queueTypeName string, msg *evmtypes.SubmitLogicCall, origMessage chain.MessageWithSignatures, + ethSender common.Address, + opts callOptions, ) (*ethtypes.Transaction, uint64, error) { logger := liblog.WithContext(ctx).WithFields(log.Fields{ "chain-id": t.ChainReferenceID, @@ -189,12 +216,15 @@ func (t compass) submitLogicCall( }) logger.Info("submit logic call") - executed, err := t.isArbitraryCallAlreadyExecuted(ctx, origMessage.ID) - if err != nil { - return nil, 0, err - } - if executed { - return nil, 0, ErrCallAlreadyExecuted + // Skip already executed check in case of estimate only + if !opts.estimateOnly { + executed, err := t.isArbitraryCallAlreadyExecuted(ctx, origMessage.ID) + if err != nil { + return nil, 0, err + } + if executed { + return nil, 0, ErrCallAlreadyExecuted + } } valsetID, err := t.performValsetIDCrosscheck(ctx, t.ChainReferenceID) @@ -224,24 +254,81 @@ func (t compass) submitLogicCall( Payload: msg.GetPayload(), } + padding := bytes.Repeat([]byte{0}, 32-len(msg.SenderAddress)) + paddedSenderAddress := [32]byte(append(padding, msg.SenderAddress...)) + // We use dummy fee data during estimation. This is not enough + // to process the transaction, but the user needs to have enough + // funds to cover the fees, even in the estimation. + feeArgs := FeeArgs{ + RelayerFee: big.NewInt(100_000), + CommunityFee: big.NewInt(100_000), + SecurityFee: big.NewInt(100_000), + FeePayerPalomaAddress: paddedSenderAddress, + } + + if !opts.estimateOnly { + if msg.Fees == nil { + return nil, 0, errors.New("fees not provided") + } + + feeArgs.RelayerFee = big.NewInt(0).SetUint64(msg.Fees.RelayerFee) + feeArgs.CommunityFee = big.NewInt(0).SetUint64(msg.Fees.CommunityFee) + feeArgs.SecurityFee = big.NewInt(0).SetUint64(msg.Fees.SecurityFee) + + userFunds, err := t.evm.QueryUserFunds(ctx, t.feeMgrContractAddr, paddedSenderAddress) + if err != nil { + return nil, 0, fmt.Errorf("failed to query user funds: %w", err) + } + + gasPrice, err := t.evm.SuggestGasPrice(ctx) + if err != nil { + return nil, 0, fmt.Errorf("failed to suggest gas price: %w", err) + } + + // (relayerFee*gasPrice + communityFee*gasPrice + security*gasPrice) + totalFundsNeeded := big.NewInt(0).Add( + big.NewInt(0).Mul(feeArgs.RelayerFee, gasPrice), + big.NewInt(0).Add( + big.NewInt(0).Mul(feeArgs.CommunityFee, gasPrice), + big.NewInt(0).Mul(feeArgs.SecurityFee, gasPrice))) + + if userFunds.Cmp(totalFundsNeeded) < 0 { + err := fmt.Errorf("insufficient funds for fees: %s < %s", userFunds, totalFundsNeeded) + if _, sendErr := t.SetErrorData(ctx, queueTypeName, origMessage.ID, err); sendErr != nil { + err = fmt.Errorf("failed to set error data: %w", sendErr) + } + return nil, 0, err + } + } + + // TODO: Use generated contract code directly + // compass 2.0.0 + // def submit_logic_call(consensus: Consensus, args: LogicCallArgs, fee_args: FeeArgs, message_id: uint256, deadline: uint256, relayer: address) args := []any{ con, compassArgs, + feeArgs, new(big.Int).SetInt64(int64(origMessage.ID)), new(big.Int).SetInt64(msg.GetDeadline()), + common.BytesToAddress(msg.ContractAddress), } + if msg.ExecutionRequirements.EnforceMEVRelay { + opts.useMevRelay = true + } logger.WithField("consensus", con).WithField("args", args).Debug("submitting logic call") - tx, err := t.callCompass(ctx, msg.ExecutionRequirements.EnforceMEVRelay, "submit_logic_call", args) + tx, err := t.callCompass(ctx, opts, "submit_logic_call", args) if err != nil { logger.WithError(err).Error("submitLogicCall: error calling DeployContract") - isSmartContractError, setErr := t.SetErrorData(ctx, queueTypeName, origMessage.ID, err) - if setErr != nil { - return nil, 0, setErr - } - if isSmartContractError { - logger.Debug("smart contract error. recovering...") - return nil, 0, nil + if opts.estimateOnly == false { + isSmartContractError, setErr := t.SetErrorData(ctx, queueTypeName, origMessage.ID, err) + if setErr != nil { + return nil, 0, setErr + } + if isSmartContractError { + logger.Debug("smart contract error. recovering...") + return nil, 0, nil + } } return nil, 0, err @@ -464,9 +551,10 @@ func BuildCompassConsensus( return con } -func (t compass) processMessages(ctx context.Context, queueTypeName string, msgs []chain.MessageWithSignatures) error { +func (t compass) processMessages(ctx context.Context, queueTypeName string, msgs []chain.MessageWithSignatures, opts callOptions) ([]ethtypes.Transaction, error) { var gErr whoops.Group logger := liblog.WithContext(ctx).WithField("queue-type-name", queueTypeName) + res := make([]ethtypes.Transaction, 0, len(msgs)) for i, rawMsg := range msgs { logger = logger.WithField("message-id", rawMsg.ID) @@ -487,6 +575,11 @@ func (t compass) processMessages(ctx context.Context, queueTypeName string, msgs }) logger.Debug("processing") + ethSender, err := t.findAssigneeEthAddress(ctx, msg.Assignee) + if err != nil { + return res, fmt.Errorf("failed to find assignee eth address: %w", err) + } + switch action := msg.GetAction().(type) { case *evmtypes.Message_SubmitLogicCall: tx, valsetID, processingErr = t.submitLogicCall( @@ -494,6 +587,8 @@ func (t compass) processMessages(ctx context.Context, queueTypeName string, msgs queueTypeName, action.SubmitLogicCall, rawMsg, + ethSender, + opts, ) case *evmtypes.Message_UpdateValset: logger := logger.WithFields(log.Fields{ @@ -512,6 +607,9 @@ func (t compass) processMessages(ctx context.Context, queueTypeName string, msgs queueTypeName, action.UpdateValset.Valset, rawMsg, + ethSender, + rawMsg.Estimate, + opts, ) case *evmtypes.Message_UploadSmartContract: logger := logger.WithFields(log.Fields{ @@ -532,7 +630,7 @@ func (t compass) processMessages(ctx context.Context, queueTypeName string, msgs rawMsg, ) default: - return ErrUnsupportedMessageType.Format(action) + return res, ErrUnsupportedMessageType.Format(action) } processingErr = whoops.Enrich( @@ -541,15 +639,19 @@ func (t compass) processMessages(ctx context.Context, queueTypeName string, msgs FieldMessageType.Val(msg.GetAction()), ) + if tx != nil { + res = append(res, *tx) + } + switch { case processingErr == nil: - if tx != nil { + if tx != nil && opts.estimateOnly == false { logger.Debug("setting public access data") err := t.paloma.SetPublicAccessData(ctx, queueTypeName, rawMsg.ID, valsetID, tx.Hash().Bytes()) if err != nil { gErr.Add(err) - return gErr + return res, gErr } } case errors.Is(processingErr, ErrNoConsensus): @@ -577,7 +679,7 @@ func (t compass) processMessages(ctx context.Context, queueTypeName string, msgs } } - return gErr.Return() + return res, gErr.Return() } func (t compass) provideEvidenceForValidatorBalance(ctx context.Context, queueTypeName string, msgs []chain.MessageWithSignatures) error { @@ -1073,16 +1175,21 @@ func isConsensusReached(ctx context.Context, val *evmtypes.Valset, msg chain.Sig return s >= powerThreshold } +type callOptions struct { + useMevRelay bool + estimateOnly bool +} + func (c compass) callCompass( ctx context.Context, - useMevRelay bool, + opts callOptions, method string, arguments []any, ) (*ethtypes.Transaction, error) { if c.compassAbi == nil { return nil, ErrABINotInitialized } - return c.evm.ExecuteSmartContract(ctx, c.chainID, *c.compassAbi, c.smartContractAddr, useMevRelay, method, arguments) + return c.evm.ExecuteSmartContract(ctx, c.chainID, *c.compassAbi, c.smartContractAddr, opts, method, arguments) } func (t compass) skywayRelayBatches(ctx context.Context, batches []chain.SkywayBatchWithSignatures) error { @@ -1102,8 +1209,7 @@ func (t compass) skywayRelayBatches(ctx context.Context, batches []chain.SkywayB }) logger.Debug("relaying") - _, processingErr = t.skywayRelayBatch(ctx, batch) - + _, processingErr = t.skywayRelayBatch(ctx, batch, callOptions{}) processingErr = whoops.Enrich( processingErr, FieldMessageID.Val(batch.BatchNonce), @@ -1123,9 +1229,39 @@ func (t compass) skywayRelayBatches(ctx context.Context, batches []chain.SkywayB return gErr.Return() } +func (t compass) skywayEstimateBatches(ctx context.Context, batches []chain.SkywayBatchWithSignatures) ([]uint64, error) { + estimates := make([]uint64, 0, len(batches)) + logger := liblog.WithContext(ctx).WithField("chainReferenceID", t.ChainReferenceID) + for _, batch := range batches { + logger = logger.WithField("batch-nonce", batch.BatchNonce) + + if ctx.Err() != nil { + logger.Debug("exiting processing batch context") + break + } + + logger := logger.WithFields(log.Fields{ + "batch-nonce": batch.BatchNonce, + }) + logger.Debug("estimating") + + tx, err := t.skywayRelayBatch(ctx, batch, callOptions{estimateOnly: true}) + if err != nil { + logger.WithError(err).Error("failed to estimate batch") + return nil, fmt.Errorf("failed to estimate batch: %w", err) + } + + logger.WithField("estimate", tx.Gas()).Debug("Estimated gas for batch") + estimates = append(estimates, tx.Gas()) + } + + return estimates, nil +} + func (t compass) skywayRelayBatch( ctx context.Context, batch chain.SkywayBatchWithSignatures, + opts callOptions, ) (*ethtypes.Transaction, error) { return whoops.TryVal(func() *ethtypes.Transaction { logger := liblog.WithContext(ctx). @@ -1172,16 +1308,38 @@ func (t compass) skywayRelayBatch( Amount: amounts, } + // get relayer + // get gas estimate + ethSender, err := t.findAssigneeEthAddress(ctx, batch.Assignee) + if err != nil { + logger.WithError(err).Error("failed to retrieve assignee eth address") + whoops.Assert(fmt.Errorf("failed to retrieve assignee eth address: %w", err)) + } + + var estimate *big.Int = big.NewInt(0).SetUint64(gomath.MaxUint64) + if !opts.estimateOnly { + if batch.GasEstimate < 1 { + logger.WithField("gas-estimate", batch.GasEstimate).Error("invalid gas estimate") + whoops.Assert(fmt.Errorf("invalid gas estimate: %d", batch.GasEstimate)) + } + estimate.SetUint64(batch.GasEstimate) + } + + // TODO: Use compiled contract instead + // compass 2.0 + // def submit_batch(consensus: Consensus, token: address, args: TokenSendArgs, batch_id: uint256, deadline: uint256, relayer: address, gas_estimate: uint256) tx, err := t.callCompass( ctx, - false, + opts, "submit_batch", []any{ con, common.HexToAddress(batch.TokenContract), compassArgs, new(big.Int).SetInt64(int64(batch.BatchNonce)), - new(big.Int).SetInt64(int64(batch.GetBatchTimeout())), // TODO : Deadline + new(big.Int).SetInt64(int64(batch.GetBatchTimeout())), + ethSender, + estimate, }, ) if err != nil { @@ -1221,3 +1379,25 @@ func (t compass) performValsetIDCrosscheck(ctx context.Context, chainReferenceID return valsetID, nil } + +func (t compass) findAssigneeEthAddress(ctx context.Context, + palomaAddress string, +) (common.Address, error) { + valset, err := t.paloma.QueryGetLatestPublishedSnapshot(ctx, t.ChainReferenceID) + if err != nil { + return common.Address{}, err + } + + for _, v := range valset.Validators { + if v.Address.String() == palomaAddress { + for _, ci := range v.ExternalChainInfos { + if ci.ChainReferenceID == t.ChainReferenceID { + return common.HexToAddress(ci.Address), nil + } + } + break + } + } + + return common.Address{}, errors.New("assignee's eth address not found") +} diff --git a/chain/evm/compass_test.go b/chain/evm/compass_test.go index bd019099..8fdd2f57 100644 --- a/chain/evm/compass_test.go +++ b/chain/evm/compass_test.go @@ -1,17 +1,19 @@ package evm import ( + "bufio" "context" "crypto/ecdsa" "errors" + "fmt" "math/big" "os" - "strings" "sync/atomic" "testing" "time" "github.com/VolumeFi/whoops" + sdk "github.com/cosmos/cosmos-sdk/types" "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/common" etherumtypes "github.com/ethereum/go-ethereum/core/types" @@ -54,6 +56,7 @@ func (s *StatusUpdater) Debug(ctx context.Context) error var ( smartContractAddr = common.HexToAddress("0xDEF") + feeMgrContractAddr = common.HexToAddress("0xDEADBEEF") ethCompatibleBytesToSign = crypto.Keccak256([]byte("sign me")) bobPK, _ = crypto.GenerateKey() @@ -92,8 +95,11 @@ func powerFromPercentage(p float64) uint64 { } func getCompassABI(t *testing.T) *abi.ABI { - compassABI, err := abi.JSON(strings.NewReader(`[{"name": "ValsetUpdated", "inputs": [{"name": "checkpoint", "type": "bytes32", "indexed": false}, {"name": "valset_id", "type": "uint256", "indexed": false}, {"name": "event_id", "type": "uint256", "indexed": false}], "anonymous": false, "type": "event"}, {"name": "LogicCallEvent", "inputs": [{"name": "logic_contract_address", "type": "address", "indexed": false}, {"name": "payload", "type": "bytes", "indexed": false}, {"name": "message_id", "type": "uint256", "indexed": false}, {"name": "event_id", "type": "uint256", "indexed": false}], "anonymous": false, "type": "event"}, {"name": "SendToPalomaEvent", "inputs": [{"name": "token", "type": "address", "indexed": false}, {"name": "sender", "type": "address", "indexed": false}, {"name": "receiver", "type": "string", "indexed": false}, {"name": "amount", "type": "uint256", "indexed": false}, {"name": "event_id", "type": "uint256", "indexed": false}], "anonymous": false, "type": "event"}, {"name": "BatchSendEvent", "inputs": [{"name": "token", "type": "address", "indexed": false}, {"name": "batch_id", "type": "uint256", "indexed": false}, {"name": "event_id", "type": "uint256", "indexed": false}], "anonymous": false, "type": "event"}, {"name": "ERC20DeployedEvent", "inputs": [{"name": "paloma_denom", "type": "string", "indexed": false}, {"name": "token_contract", "type": "address", "indexed": false}, {"name": "name", "type": "string", "indexed": false}, {"name": "symbol", "type": "string", "indexed": false}, {"name": "decimals", "type": "uint8", "indexed": false}, {"name": "event_id", "type": "uint256", "indexed": false}], "anonymous": false, "type": "event"}, {"stateMutability": "nonpayable", "type": "constructor", "inputs": [{"name": "_compass_id", "type": "bytes32"}, {"name": "valset", "type": "tuple", "components": [{"name": "validators", "type": "address[]"}, {"name": "powers", "type": "uint256[]"}, {"name": "valset_id", "type": "uint256"}]}], "outputs": []}, {"stateMutability": "nonpayable", "type": "function", "name": "update_valset", "inputs": [{"name": "consensus", "type": "tuple", "components": [{"name": "valset", "type": "tuple", "components": [{"name": "validators", "type": "address[]"}, {"name": "powers", "type": "uint256[]"}, {"name": "valset_id", "type": "uint256"}]}, {"name": "signatures", "type": "tuple[]", "components": [{"name": "v", "type": "uint256"}, {"name": "r", "type": "uint256"}, {"name": "s", "type": "uint256"}]}]}, {"name": "new_valset", "type": "tuple", "components": [{"name": "validators", "type": "address[]"}, {"name": "powers", "type": "uint256[]"}, {"name": "valset_id", "type": "uint256"}]}], "outputs": []}, {"stateMutability": "nonpayable", "type": "function", "name": "submit_logic_call", "inputs": [{"name": "consensus", "type": "tuple", "components": [{"name": "valset", "type": "tuple", "components": [{"name": "validators", "type": "address[]"}, {"name": "powers", "type": "uint256[]"}, {"name": "valset_id", "type": "uint256"}]}, {"name": "signatures", "type": "tuple[]", "components": [{"name": "v", "type": "uint256"}, {"name": "r", "type": "uint256"}, {"name": "s", "type": "uint256"}]}]}, {"name": "args", "type": "tuple", "components": [{"name": "logic_contract_address", "type": "address"}, {"name": "payload", "type": "bytes"}]}, {"name": "message_id", "type": "uint256"}, {"name": "deadline", "type": "uint256"}], "outputs": []}, {"stateMutability": "nonpayable", "type": "function", "name": "send_token_to_paloma", "inputs": [{"name": "token", "type": "address"}, {"name": "receiver", "type": "string"}, {"name": "amount", "type": "uint256"}], "outputs": []}, {"stateMutability": "nonpayable", "type": "function", "name": "submit_batch", "inputs": [{"name": "consensus", "type": "tuple", "components": [{"name": "valset", "type": "tuple", "components": [{"name": "validators", "type": "address[]"}, {"name": "powers", "type": "uint256[]"}, {"name": "valset_id", "type": "uint256"}]}, {"name": "signatures", "type": "tuple[]", "components": [{"name": "v", "type": "uint256"}, {"name": "r", "type": "uint256"}, {"name": "s", "type": "uint256"}]}]}, {"name": "token", "type": "address"}, {"name": "args", "type": "tuple", "components": [{"name": "receiver", "type": "address[]"}, {"name": "amount", "type": "uint256[]"}]}, {"name": "batch_id", "type": "uint256"}, {"name": "deadline", "type": "uint256"}], "outputs": []}, {"stateMutability": "nonpayable", "type": "function", "name": "deploy_erc20", "inputs": [{"name": "_paloma_denom", "type": "string"}, {"name": "_name", "type": "string"}, {"name": "_symbol", "type": "string"}, {"name": "_decimals", "type": "uint8"}, {"name": "_blueprint", "type": "address"}], "outputs": []}, {"stateMutability": "view", "type": "function", "name": "compass_id", "inputs": [], "outputs": [{"name": "", "type": "bytes32"}]}, {"stateMutability": "view", "type": "function", "name": "last_checkpoint", "inputs": [], "outputs": [{"name": "", "type": "bytes32"}]}, {"stateMutability": "view", "type": "function", "name": "last_valset_id", "inputs": [], "outputs": [{"name": "", "type": "uint256"}]}, {"stateMutability": "view", "type": "function", "name": "last_event_id", "inputs": [], "outputs": [{"name": "", "type": "uint256"}]}, {"stateMutability": "view", "type": "function", "name": "last_batch_id", "inputs": [{"name": "arg0", "type": "address"}], "outputs": [{"name": "", "type": "uint256"}]}, {"stateMutability": "view", "type": "function", "name": "message_id_used", "inputs": [{"name": "arg0", "type": "uint256"}], "outputs": [{"name": "", "type": "bool"}]}]`)) + file, err := os.Open("abi/compass/compass.abi") require.NoError(t, err) + compassABI, err := abi.JSON(bufio.NewReader(file)) + require.NoError(t, err) + return &compassABI } @@ -238,6 +244,7 @@ func TestIsArbitraryCallAlreadyExecuted(t *testing.T) { evmClienter, palomaClienter := tt.setup(t) comp := newCompassClient( smartContractAddr.Hex(), + feeMgrContractAddr.Hex(), "id-123", "internal-chain-id", big.NewInt(1), @@ -272,10 +279,11 @@ func TestMessageProcessing(t *testing.T) { ) for _, tt := range []struct { - name string - msgs []chain.MessageWithSignatures - setup func(t *testing.T) (*mockEvmClienter, *evmmocks.PalomaClienter) - expErr error + name string + estimateOnly bool + msgs []chain.MessageWithSignatures + setup func(t *testing.T) (*mockEvmClienter, *evmmocks.PalomaClienter) + expErr error }{ { name: "submit_logic_call/message is already executed then it returns an error", @@ -284,6 +292,7 @@ func TestMessageProcessing(t *testing.T) { QueuedMessage: chain.QueuedMessage{ ID: 666, Msg: &types.Message{ + Assignee: sdk.ValAddress("validator-1").String(), Action: &types.Message_SubmitLogicCall{ SubmitLogicCall: &types.SubmitLogicCall{}, }, @@ -311,6 +320,24 @@ func TestMessageProcessing(t *testing.T) { nil, ) + paloma.On("QueryGetLatestPublishedSnapshot", mock.Anything, "internal-chain-id").Return( + &valsettypes.Snapshot{ + Id: 55, + Validators: []valsettypes.Validator{ + { + ExternalChainInfos: []*valsettypes.ExternalChainInfo{ + { + ChainReferenceID: "internal-chain-id", + Address: "0xDEADBEEF0ba39494ce839613fffba74279579268", + }, + }, + Address: sdk.ValAddress("validator-1").Bytes(), + }, + }, + }, + nil, + ) + return evm, paloma }, expErr: ErrCallAlreadyExecuted, @@ -323,12 +350,19 @@ func TestMessageProcessing(t *testing.T) { ID: 555, BytesToSign: ethCompatibleBytesToSign, Msg: &types.Message{ + Assignee: sdk.ValAddress("validator-1").String(), Action: &types.Message_SubmitLogicCall{ SubmitLogicCall: &types.SubmitLogicCall{ HexContractAddress: "0xABC", Abi: []byte("abi"), Payload: []byte("payload"), Deadline: 123, + Fees: &types.SubmitLogicCall_Fees{ + RelayerFee: 50_000, + CommunityFee: 3_000, + SecurityFee: 1_000, + }, + SenderAddress: sdk.AccAddress("message-sender").Bytes(), }, }, }, @@ -353,7 +387,15 @@ func TestMessageProcessing(t *testing.T) { nil, ) - paloma.On("QueryGetLatestPublishedSnapshot", mock.Anything, mock.Anything).Return(&valsettypes.Snapshot{Id: uint64(55)}, nil) + evm.On("QueryUserFunds", mock.Anything, mock.Anything, mock.Anything).Return( + big.NewInt(10_000_000), + nil, + ) + evm.On("SuggestGasPrice", mock.Anything).Return( + big.NewInt(10), + nil, + ) + paloma.On("QueryGetEVMValsetByID", mock.Anything, uint64(currentValsetID), "internal-chain-id").Return( &types.Valset{ Validators: []string{crypto.PubkeyToAddress(bobPK.PublicKey).Hex()}, @@ -362,8 +404,25 @@ func TestMessageProcessing(t *testing.T) { }, nil, ) + paloma.On("QueryGetLatestPublishedSnapshot", mock.Anything, "internal-chain-id").Return( + &valsettypes.Snapshot{ + Id: 55, + Validators: []valsettypes.Validator{ + { + ExternalChainInfos: []*valsettypes.ExternalChainInfo{ + { + ChainReferenceID: "internal-chain-id", + Address: "0xDEADBEEF0ba39494ce839613fffba74279579268", + }, + }, + Address: sdk.ValAddress("validator-1").Bytes(), + }, + }, + }, + nil, + ) - evm.On("ExecuteSmartContract", mock.Anything, chainID, mock.Anything, smartContractAddr, false, "submit_logic_call", mock.Anything).Return( + evm.On("ExecuteSmartContract", mock.Anything, chainID, mock.Anything, smartContractAddr, callOptions{}, "submit_logic_call", mock.Anything).Return( tx, nil, ) @@ -377,6 +436,81 @@ func TestMessageProcessing(t *testing.T) { return evm, paloma }, }, + { + name: "estimate/submit_logic_call/happy path", + estimateOnly: true, + msgs: []chain.MessageWithSignatures{ + { + QueuedMessage: chain.QueuedMessage{ + ID: 555, + BytesToSign: ethCompatibleBytesToSign, + Msg: &types.Message{ + Assignee: sdk.ValAddress("validator-1").String(), + Action: &types.Message_SubmitLogicCall{ + SubmitLogicCall: &types.SubmitLogicCall{ + HexContractAddress: "0xABC", + Abi: []byte("abi"), + Payload: []byte("payload"), + Deadline: 123, + Fees: &types.SubmitLogicCall_Fees{ + RelayerFee: 50_000, + CommunityFee: 3_000, + SecurityFee: 1_000, + }, + SenderAddress: sdk.AccAddress("message-sender").Bytes(), + }, + }, + }, + }, + Signatures: []chain.ValidatorSignature{ + addValidSignature(bobPK), + }, + }, + }, + setup: func(t *testing.T) (*mockEvmClienter, *evmmocks.PalomaClienter) { + evm, paloma := newMockEvmClienter(t), evmmocks.NewPalomaClienter(t) + + currentValsetID := int64(55) + + evm.On("LastValsetID", mock.Anything, mock.Anything).Return( + big.NewInt(55), + nil, + ) + + paloma.On("QueryGetEVMValsetByID", mock.Anything, uint64(currentValsetID), "internal-chain-id").Return( + &types.Valset{ + Validators: []string{crypto.PubkeyToAddress(bobPK.PublicKey).Hex()}, + Powers: []uint64{testPowerThreshold + 1}, + ValsetID: uint64(currentValsetID), + }, + nil, + ) + paloma.On("QueryGetLatestPublishedSnapshot", mock.Anything, "internal-chain-id").Return( + &valsettypes.Snapshot{ + Id: 55, + Validators: []valsettypes.Validator{ + { + ExternalChainInfos: []*valsettypes.ExternalChainInfo{ + { + ChainReferenceID: "internal-chain-id", + Address: "0xDEADBEEF0ba39494ce839613fffba74279579268", + }, + }, + Address: sdk.ValAddress("validator-1").Bytes(), + }, + }, + }, + nil, + ) + + evm.On("ExecuteSmartContract", mock.Anything, chainID, mock.Anything, smartContractAddr, callOptions{estimateOnly: true}, "submit_logic_call", mock.Anything).Return( + tx, + nil, + ) + + return evm, paloma + }, + }, { name: "submit_logic_call/with target chain valset id not matching expected valset id, it should NOT return an error, but report log to Paloma", msgs: []chain.MessageWithSignatures{ @@ -385,6 +519,7 @@ func TestMessageProcessing(t *testing.T) { ID: 555, BytesToSign: ethCompatibleBytesToSign, Msg: &types.Message{ + Assignee: sdk.ValAddress("validator-1").String(), Action: &types.Message_SubmitLogicCall{ SubmitLogicCall: &types.SubmitLogicCall{ HexContractAddress: "0xABC", @@ -417,7 +552,83 @@ func TestMessageProcessing(t *testing.T) { nil, ) - paloma.On("QueryGetLatestPublishedSnapshot", mock.Anything, mock.Anything).Return(&valsettypes.Snapshot{Id: uint64(56)}, nil) + paloma.On("QueryGetLatestPublishedSnapshot", mock.Anything, "internal-chain-id").Return( + &valsettypes.Snapshot{ + Id: 56, + Validators: []valsettypes.Validator{ + { + ExternalChainInfos: []*valsettypes.ExternalChainInfo{ + { + ChainReferenceID: "internal-chain-id", + Address: "0xDEADBEEF0ba39494ce839613fffba74279579268", + }, + }, + Address: sdk.ValAddress("validator-1").Bytes(), + }, + }, + }, + nil, + ) + paloma.On("NewStatus").Return(&StatusUpdater{}) + return evm, paloma + }, + }, + { + name: "estimate/submit_logic_call/with target chain valset id not matching expected valset id, it should NOT return an error, but report log to Paloma", + estimateOnly: true, + msgs: []chain.MessageWithSignatures{ + { + QueuedMessage: chain.QueuedMessage{ + ID: 555, + BytesToSign: ethCompatibleBytesToSign, + Msg: &types.Message{ + Assignee: sdk.ValAddress("validator-1").String(), + Action: &types.Message_SubmitLogicCall{ + SubmitLogicCall: &types.SubmitLogicCall{ + HexContractAddress: "0xABC", + Abi: []byte("abi"), + Payload: []byte("payload"), + Deadline: 123, + Fees: &types.SubmitLogicCall_Fees{ + RelayerFee: 50_000, + CommunityFee: 3_000, + SecurityFee: 1_000, + }, + SenderAddress: sdk.AccAddress("message-sender").Bytes(), + }, + }, + }, + }, + Signatures: []chain.ValidatorSignature{ + addValidSignature(bobPK), + }, + }, + }, + setup: func(t *testing.T) (*mockEvmClienter, *evmmocks.PalomaClienter) { + evm, paloma := newMockEvmClienter(t), evmmocks.NewPalomaClienter(t) + + evm.On("LastValsetID", mock.Anything, mock.Anything).Return( + big.NewInt(55), + nil, + ) + + paloma.On("QueryGetLatestPublishedSnapshot", mock.Anything, "internal-chain-id").Return( + &valsettypes.Snapshot{ + Id: 56, + Validators: []valsettypes.Validator{ + { + ExternalChainInfos: []*valsettypes.ExternalChainInfo{ + { + ChainReferenceID: "internal-chain-id", + Address: "0xDEADBEEF0ba39494ce839613fffba74279579268", + }, + }, + Address: sdk.ValAddress("validator-1").Bytes(), + }, + }, + }, + nil, + ) paloma.On("NewStatus").Return(&StatusUpdater{}) return evm, paloma }, @@ -430,12 +641,19 @@ func TestMessageProcessing(t *testing.T) { ID: 555, BytesToSign: ethCompatibleBytesToSign, Msg: &types.Message{ + Assignee: sdk.ValAddress("validator-1").String(), Action: &types.Message_SubmitLogicCall{ SubmitLogicCall: &types.SubmitLogicCall{ HexContractAddress: "0xABC", Abi: []byte("abi"), Payload: []byte("payload"), Deadline: 123, + Fees: &types.SubmitLogicCall_Fees{ + RelayerFee: 50_000, + CommunityFee: 3_000, + SecurityFee: 1_000, + }, + SenderAddress: sdk.AccAddress("message-sender").Bytes(), ExecutionRequirements: types.SubmitLogicCall_ExecutionRequirements{ EnforceMEVRelay: true, }, @@ -463,7 +681,15 @@ func TestMessageProcessing(t *testing.T) { nil, ) - paloma.On("QueryGetLatestPublishedSnapshot", mock.Anything, mock.Anything).Return(&valsettypes.Snapshot{Id: uint64(55)}, nil) + evm.On("QueryUserFunds", mock.Anything, mock.Anything, mock.Anything).Return( + big.NewInt(10_000_000), + nil, + ) + evm.On("SuggestGasPrice", mock.Anything).Return( + big.NewInt(10), + nil, + ) + paloma.On("QueryGetEVMValsetByID", mock.Anything, uint64(currentValsetID), "internal-chain-id").Return( &types.Valset{ Validators: []string{crypto.PubkeyToAddress(bobPK.PublicKey).Hex()}, @@ -472,8 +698,25 @@ func TestMessageProcessing(t *testing.T) { }, nil, ) + paloma.On("QueryGetLatestPublishedSnapshot", mock.Anything, "internal-chain-id").Return( + &valsettypes.Snapshot{ + Id: 55, + Validators: []valsettypes.Validator{ + { + ExternalChainInfos: []*valsettypes.ExternalChainInfo{ + { + ChainReferenceID: "internal-chain-id", + Address: "0xDEADBEEF0ba39494ce839613fffba74279579268", + }, + }, + Address: sdk.ValAddress("validator-1").Bytes(), + }, + }, + }, + nil, + ) - evm.On("ExecuteSmartContract", mock.Anything, chainID, mock.Anything, smartContractAddr, true, "submit_logic_call", mock.Anything).Return( + evm.On("ExecuteSmartContract", mock.Anything, chainID, mock.Anything, smartContractAddr, callOptions{useMevRelay: true}, "submit_logic_call", mock.Anything).Return( tx, nil, ) @@ -488,19 +731,26 @@ func TestMessageProcessing(t *testing.T) { }, }, { - name: "submit_logic_call/without a consensus it returns", + name: "submit_logic_call/insufficient funds", msgs: []chain.MessageWithSignatures{ { QueuedMessage: chain.QueuedMessage{ ID: 555, BytesToSign: ethCompatibleBytesToSign, Msg: &types.Message{ + Assignee: sdk.ValAddress("validator-1").String(), Action: &types.Message_SubmitLogicCall{ SubmitLogicCall: &types.SubmitLogicCall{ HexContractAddress: "0xABC", Abi: []byte("abi"), Payload: []byte("payload"), Deadline: 123, + Fees: &types.SubmitLogicCall_Fees{ + RelayerFee: 50_000, + CommunityFee: 3_000, + SecurityFee: 1_000, + }, + SenderAddress: sdk.AccAddress("message-sender").Bytes(), }, }, }, @@ -510,6 +760,7 @@ func TestMessageProcessing(t *testing.T) { }, }, }, + expErr: fmt.Errorf("insufficient funds for fees: 500000 < 54000"), setup: func(t *testing.T) (*mockEvmClienter, *evmmocks.PalomaClienter) { evm, paloma := newMockEvmClienter(t), evmmocks.NewPalomaClienter(t) @@ -525,54 +776,74 @@ func TestMessageProcessing(t *testing.T) { nil, ) - evm.On("FindCurrentBlockNumber", mock.Anything).Return( - big.NewInt(0), + evm.On("QueryUserFunds", mock.Anything, mock.Anything, mock.Anything).Return( + big.NewInt(500_000), + nil, + ) + evm.On("SuggestGasPrice", mock.Anything).Return( + big.NewInt(10), nil, ) - - paloma.On("QueryGetLatestPublishedSnapshot", mock.Anything, mock.Anything).Return(&valsettypes.Snapshot{Id: uint64(55)}, nil) - paloma.On("NewStatus").Return(&StatusUpdater{}) paloma.On("QueryGetEVMValsetByID", mock.Anything, uint64(currentValsetID), "internal-chain-id").Return( &types.Valset{ - Validators: []string{ - crypto.PubkeyToAddress(bobPK.PublicKey).Hex(), - crypto.PubkeyToAddress(alicePK.PublicKey).Hex(), - }, - Powers: []uint64{ - powerFromPercentage(0.65), - powerFromPercentage(0.35), + Validators: []string{crypto.PubkeyToAddress(bobPK.PublicKey).Hex()}, + Powers: []uint64{testPowerThreshold + 1}, + ValsetID: uint64(currentValsetID), + }, + nil, + ) + paloma.On("QueryGetLatestPublishedSnapshot", mock.Anything, "internal-chain-id").Return( + &valsettypes.Snapshot{ + Id: 55, + Validators: []valsettypes.Validator{ + { + ExternalChainInfos: []*valsettypes.ExternalChainInfo{ + { + ChainReferenceID: "internal-chain-id", + Address: "0xDEADBEEF0ba39494ce839613fffba74279579268", + }, + }, + Address: sdk.ValAddress("validator-1").Bytes(), + }, }, - ValsetID: uint64(currentValsetID), }, nil, ) + evm.On("FindCurrentBlockNumber", mock.Anything).Return( + big.NewInt(0), + nil, + ) + paloma.On("NewStatus").Return(&StatusUpdater{}) + paloma.On("SetErrorData", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil) return evm, paloma }, }, { - name: "update_valset/happy path", + name: "estimate/submit_logic_call/happy path with mev relaying", + estimateOnly: true, msgs: []chain.MessageWithSignatures{ { QueuedMessage: chain.QueuedMessage{ ID: 555, BytesToSign: ethCompatibleBytesToSign, Msg: &types.Message{ - Action: &types.Message_UpdateValset{ - UpdateValset: &types.UpdateValset{ - Valset: &types.Valset{ - Validators: []string{ - crypto.PubkeyToAddress(bobPK.PublicKey).Hex(), - crypto.PubkeyToAddress(alicePK.PublicKey).Hex(), - crypto.PubkeyToAddress(frankPK.PublicKey).Hex(), - }, - Powers: []uint64{ - powerFromPercentage(0.4), - powerFromPercentage(0.2), - powerFromPercentage(0.1), - }, - ValsetID: 123, + Assignee: sdk.ValAddress("validator-1").String(), + Action: &types.Message_SubmitLogicCall{ + SubmitLogicCall: &types.SubmitLogicCall{ + HexContractAddress: "0xABC", + Abi: []byte("abi"), + Payload: []byte("payload"), + Deadline: 123, + Fees: &types.SubmitLogicCall_Fees{ + RelayerFee: 50_000, + CommunityFee: 3_000, + SecurityFee: 1_000, + }, + SenderAddress: sdk.AccAddress("message-sender").Bytes(), + ExecutionRequirements: types.SubmitLogicCall_ExecutionRequirements{ + EnforceMEVRelay: true, }, }, }, @@ -580,10 +851,6 @@ func TestMessageProcessing(t *testing.T) { }, Signatures: []chain.ValidatorSignature{ addValidSignature(bobPK), - addValidSignature(alicePK), - // frank's signature is getting ignored but putting it - // here just in case if there is a bug in the code - addValidSignature(frankPK), }, }, }, @@ -599,61 +866,70 @@ func TestMessageProcessing(t *testing.T) { paloma.On("QueryGetEVMValsetByID", mock.Anything, uint64(currentValsetID), "internal-chain-id").Return( &types.Valset{ - Validators: []string{ - crypto.PubkeyToAddress(bobPK.PublicKey).Hex(), - crypto.PubkeyToAddress(alicePK.PublicKey).Hex(), - }, - Powers: []uint64{ - powerFromPercentage(0.5), - powerFromPercentage(0.3), + Validators: []string{crypto.PubkeyToAddress(bobPK.PublicKey).Hex()}, + Powers: []uint64{testPowerThreshold + 1}, + ValsetID: uint64(currentValsetID), + }, + nil, + ) + paloma.On("QueryGetLatestPublishedSnapshot", mock.Anything, "internal-chain-id").Return( + &valsettypes.Snapshot{ + Id: 55, + Validators: []valsettypes.Validator{ + { + ExternalChainInfos: []*valsettypes.ExternalChainInfo{ + { + ChainReferenceID: "internal-chain-id", + Address: "0xDEADBEEF0ba39494ce839613fffba74279579268", + }, + }, + Address: sdk.ValAddress("validator-1").Bytes(), + }, }, - ValsetID: uint64(currentValsetID), }, nil, ) - evm.On("ExecuteSmartContract", mock.Anything, chainID, mock.Anything, smartContractAddr, false, "update_valset", mock.Anything).Return(tx, nil) + evm.On("ExecuteSmartContract", mock.Anything, chainID, mock.Anything, smartContractAddr, callOptions{useMevRelay: true, estimateOnly: true}, "submit_logic_call", mock.Anything).Return( + tx, + nil, + ) - paloma.On("SetPublicAccessData", mock.Anything, "queue-name", uint64(555), uint64(55), tx.Hash().Bytes()).Return(nil) return evm, paloma }, }, { - name: "update_valset/without a consensus it returns", + name: "submit_logic_call/without a consensus it returns", msgs: []chain.MessageWithSignatures{ { QueuedMessage: chain.QueuedMessage{ ID: 555, BytesToSign: ethCompatibleBytesToSign, Msg: &types.Message{ - Action: &types.Message_UpdateValset{ - UpdateValset: &types.UpdateValset{ - Valset: &types.Valset{ - Validators: []string{ - crypto.PubkeyToAddress(bobPK.PublicKey).Hex(), - crypto.PubkeyToAddress(alicePK.PublicKey).Hex(), - crypto.PubkeyToAddress(frankPK.PublicKey).Hex(), - }, - Powers: []uint64{ - powerFromPercentage(0.4), - powerFromPercentage(0.2), - powerFromPercentage(0.1), - }, - ValsetID: 123, - }, + Assignee: sdk.ValAddress("validator-1").String(), + Action: &types.Message_SubmitLogicCall{ + SubmitLogicCall: &types.SubmitLogicCall{ + HexContractAddress: "0xABC", + Abi: []byte("abi"), + Payload: []byte("payload"), + Deadline: 123, }, }, }, }, Signatures: []chain.ValidatorSignature{ addValidSignature(bobPK), - addValidSignature(alicePK), }, }, }, setup: func(t *testing.T) (*mockEvmClienter, *evmmocks.PalomaClienter) { evm, paloma := newMockEvmClienter(t), evmmocks.NewPalomaClienter(t) + evm.On("FilterLogs", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Times(1).Return(false, nil).Run(func(args mock.Arguments) { + fn := args.Get(3).(func([]etherumtypes.Log) bool) + fn([]etherumtypes.Log{}) + }) + currentValsetID := int64(55) evm.On("LastValsetID", mock.Anything, mock.Anything).Return( @@ -661,8 +937,333 @@ func TestMessageProcessing(t *testing.T) { nil, ) - paloma.On("NewStatus").Return(&StatusUpdater{}) - paloma.On("QueryGetEVMValsetByID", mock.Anything, uint64(currentValsetID), "internal-chain-id").Return( + evm.On("FindCurrentBlockNumber", mock.Anything).Return( + big.NewInt(0), + nil, + ) + + paloma.On("NewStatus").Return(&StatusUpdater{}) + + paloma.On("QueryGetEVMValsetByID", mock.Anything, uint64(currentValsetID), "internal-chain-id").Return( + &types.Valset{ + Validators: []string{ + crypto.PubkeyToAddress(bobPK.PublicKey).Hex(), + crypto.PubkeyToAddress(alicePK.PublicKey).Hex(), + }, + Powers: []uint64{ + powerFromPercentage(0.65), + powerFromPercentage(0.35), + }, + ValsetID: uint64(currentValsetID), + }, + nil, + ) + paloma.On("QueryGetLatestPublishedSnapshot", mock.Anything, "internal-chain-id").Return( + &valsettypes.Snapshot{ + Id: 55, + Validators: []valsettypes.Validator{ + { + ExternalChainInfos: []*valsettypes.ExternalChainInfo{ + { + ChainReferenceID: "internal-chain-id", + Address: "0xDEADBEEF0ba39494ce839613fffba74279579268", + }, + }, + Address: sdk.ValAddress("validator-1").Bytes(), + }, + }, + }, + nil, + ) + + return evm, paloma + }, + }, + { + name: "estimate/submit_logic_call/without a consensus it returns", + estimateOnly: true, + msgs: []chain.MessageWithSignatures{ + { + QueuedMessage: chain.QueuedMessage{ + ID: 555, + BytesToSign: ethCompatibleBytesToSign, + Msg: &types.Message{ + Assignee: sdk.ValAddress("validator-1").String(), + Action: &types.Message_SubmitLogicCall{ + SubmitLogicCall: &types.SubmitLogicCall{ + HexContractAddress: "0xABC", + Abi: []byte("abi"), + Payload: []byte("payload"), + Deadline: 123, + }, + }, + }, + }, + Signatures: []chain.ValidatorSignature{ + addValidSignature(bobPK), + }, + }, + }, + setup: func(t *testing.T) (*mockEvmClienter, *evmmocks.PalomaClienter) { + evm, paloma := newMockEvmClienter(t), evmmocks.NewPalomaClienter(t) + + currentValsetID := int64(55) + + evm.On("LastValsetID", mock.Anything, mock.Anything).Return( + big.NewInt(55), + nil, + ) + + paloma.On("NewStatus").Return(&StatusUpdater{}) + + paloma.On("QueryGetEVMValsetByID", mock.Anything, uint64(currentValsetID), "internal-chain-id").Return( + &types.Valset{ + Validators: []string{ + crypto.PubkeyToAddress(bobPK.PublicKey).Hex(), + crypto.PubkeyToAddress(alicePK.PublicKey).Hex(), + }, + Powers: []uint64{ + powerFromPercentage(0.65), + powerFromPercentage(0.35), + }, + ValsetID: uint64(currentValsetID), + }, + nil, + ) + paloma.On("QueryGetLatestPublishedSnapshot", mock.Anything, "internal-chain-id").Return( + &valsettypes.Snapshot{ + Id: 55, + Validators: []valsettypes.Validator{ + { + ExternalChainInfos: []*valsettypes.ExternalChainInfo{ + { + ChainReferenceID: "internal-chain-id", + Address: "0xDEADBEEF0ba39494ce839613fffba74279579268", + }, + }, + Address: sdk.ValAddress("validator-1").Bytes(), + }, + }, + }, + nil, + ) + + return evm, paloma + }, + }, + { + name: "update_valset/happy path", + msgs: []chain.MessageWithSignatures{ + { + QueuedMessage: chain.QueuedMessage{ + ID: 555, + BytesToSign: ethCompatibleBytesToSign, + Msg: &types.Message{ + Assignee: sdk.ValAddress("validator-1").String(), + Action: &types.Message_UpdateValset{ + UpdateValset: &types.UpdateValset{ + Valset: &types.Valset{ + Validators: []string{ + crypto.PubkeyToAddress(bobPK.PublicKey).Hex(), + crypto.PubkeyToAddress(alicePK.PublicKey).Hex(), + crypto.PubkeyToAddress(frankPK.PublicKey).Hex(), + }, + Powers: []uint64{ + powerFromPercentage(0.4), + powerFromPercentage(0.2), + powerFromPercentage(0.1), + }, + ValsetID: 123, + }, + }, + }, + }, + }, + Signatures: []chain.ValidatorSignature{ + addValidSignature(bobPK), + addValidSignature(alicePK), + // frank's signature is getting ignored but putting it + // here just in case if there is a bug in the code + addValidSignature(frankPK), + }, + }, + }, + setup: func(t *testing.T) (*mockEvmClienter, *evmmocks.PalomaClienter) { + evm, paloma := newMockEvmClienter(t), evmmocks.NewPalomaClienter(t) + + currentValsetID := int64(55) + + evm.On("LastValsetID", mock.Anything, mock.Anything).Return( + big.NewInt(55), + nil, + ) + + paloma.On("QueryGetEVMValsetByID", mock.Anything, uint64(currentValsetID), "internal-chain-id").Return( + &types.Valset{ + Validators: []string{ + crypto.PubkeyToAddress(bobPK.PublicKey).Hex(), + crypto.PubkeyToAddress(alicePK.PublicKey).Hex(), + }, + Powers: []uint64{ + powerFromPercentage(0.5), + powerFromPercentage(0.3), + }, + ValsetID: uint64(currentValsetID), + }, + nil, + ) + paloma.On("QueryGetLatestPublishedSnapshot", mock.Anything, "internal-chain-id").Return( + &valsettypes.Snapshot{ + Validators: []valsettypes.Validator{ + { + ExternalChainInfos: []*valsettypes.ExternalChainInfo{ + { + ChainReferenceID: "internal-chain-id", + Address: "0xDEADBEEF0ba39494ce839613fffba74279579268", + }, + }, + Address: sdk.ValAddress("validator-1").Bytes(), + }, + }, + }, + nil, + ) + + evm.On("ExecuteSmartContract", mock.Anything, chainID, mock.Anything, smartContractAddr, callOptions{}, "update_valset", mock.Anything).Return(tx, nil) + + paloma.On("SetPublicAccessData", mock.Anything, "queue-name", uint64(555), uint64(55), tx.Hash().Bytes()).Return(nil) + return evm, paloma + }, + }, + { + name: "estimate/update_valset/happy path", + estimateOnly: true, + msgs: []chain.MessageWithSignatures{ + { + QueuedMessage: chain.QueuedMessage{ + ID: 555, + BytesToSign: ethCompatibleBytesToSign, + Msg: &types.Message{ + Assignee: sdk.ValAddress("validator-1").String(), + Action: &types.Message_UpdateValset{ + UpdateValset: &types.UpdateValset{ + Valset: &types.Valset{ + Validators: []string{ + crypto.PubkeyToAddress(bobPK.PublicKey).Hex(), + crypto.PubkeyToAddress(alicePK.PublicKey).Hex(), + crypto.PubkeyToAddress(frankPK.PublicKey).Hex(), + }, + Powers: []uint64{ + powerFromPercentage(0.4), + powerFromPercentage(0.2), + powerFromPercentage(0.1), + }, + ValsetID: 123, + }, + }, + }, + }, + }, + Signatures: []chain.ValidatorSignature{ + addValidSignature(bobPK), + addValidSignature(alicePK), + // frank's signature is getting ignored but putting it + // here just in case if there is a bug in the code + addValidSignature(frankPK), + }, + }, + }, + setup: func(t *testing.T) (*mockEvmClienter, *evmmocks.PalomaClienter) { + evm, paloma := newMockEvmClienter(t), evmmocks.NewPalomaClienter(t) + + currentValsetID := int64(55) + + evm.On("LastValsetID", mock.Anything, mock.Anything).Return( + big.NewInt(55), + nil, + ) + + paloma.On("QueryGetEVMValsetByID", mock.Anything, uint64(currentValsetID), "internal-chain-id").Return( + &types.Valset{ + Validators: []string{ + crypto.PubkeyToAddress(bobPK.PublicKey).Hex(), + crypto.PubkeyToAddress(alicePK.PublicKey).Hex(), + }, + Powers: []uint64{ + powerFromPercentage(0.5), + powerFromPercentage(0.3), + }, + ValsetID: uint64(currentValsetID), + }, + nil, + ) + paloma.On("QueryGetLatestPublishedSnapshot", mock.Anything, "internal-chain-id").Return( + &valsettypes.Snapshot{ + Validators: []valsettypes.Validator{ + { + ExternalChainInfos: []*valsettypes.ExternalChainInfo{ + { + ChainReferenceID: "internal-chain-id", + Address: "0xDEADBEEF0ba39494ce839613fffba74279579268", + }, + }, + Address: sdk.ValAddress("validator-1").Bytes(), + }, + }, + }, + nil, + ) + + evm.On("ExecuteSmartContract", mock.Anything, chainID, mock.Anything, smartContractAddr, callOptions{estimateOnly: true}, "update_valset", mock.Anything).Return(tx, nil) + return evm, paloma + }, + }, + { + name: "update_valset/without a consensus it returns", + msgs: []chain.MessageWithSignatures{ + { + QueuedMessage: chain.QueuedMessage{ + ID: 555, + BytesToSign: ethCompatibleBytesToSign, + Msg: &types.Message{ + Assignee: sdk.ValAddress("validator-1").String(), + Action: &types.Message_UpdateValset{ + UpdateValset: &types.UpdateValset{ + Valset: &types.Valset{ + Validators: []string{ + crypto.PubkeyToAddress(bobPK.PublicKey).Hex(), + crypto.PubkeyToAddress(alicePK.PublicKey).Hex(), + crypto.PubkeyToAddress(frankPK.PublicKey).Hex(), + }, + Powers: []uint64{ + powerFromPercentage(0.4), + powerFromPercentage(0.2), + powerFromPercentage(0.1), + }, + ValsetID: 123, + }, + }, + }, + }, + }, + Signatures: []chain.ValidatorSignature{ + addValidSignature(bobPK), + addValidSignature(alicePK), + }, + }, + }, + setup: func(t *testing.T) (*mockEvmClienter, *evmmocks.PalomaClienter) { + evm, paloma := newMockEvmClienter(t), evmmocks.NewPalomaClienter(t) + + currentValsetID := int64(55) + + evm.On("LastValsetID", mock.Anything, mock.Anything).Return( + big.NewInt(55), + nil, + ) + + paloma.On("NewStatus").Return(&StatusUpdater{}) + paloma.On("QueryGetEVMValsetByID", mock.Anything, uint64(currentValsetID), "internal-chain-id").Return( &types.Valset{ Validators: []string{ crypto.PubkeyToAddress(bobPK.PublicKey).Hex(), @@ -678,10 +1279,107 @@ func TestMessageProcessing(t *testing.T) { }, nil, ) + paloma.On("QueryGetLatestPublishedSnapshot", mock.Anything, "internal-chain-id").Return( + &valsettypes.Snapshot{ + Validators: []valsettypes.Validator{ + { + ExternalChainInfos: []*valsettypes.ExternalChainInfo{ + { + ChainReferenceID: "internal-chain-id", + Address: "0xDEADBEEF0ba39494ce839613fffba74279579268", + }, + }, + Address: sdk.ValAddress("validator-1").Bytes(), + }, + }, + }, + nil, + ) return evm, paloma }, }, + { + name: "estimate/update_valset/without a consensus it returns", + estimateOnly: true, + msgs: []chain.MessageWithSignatures{ + { + QueuedMessage: chain.QueuedMessage{ + ID: 555, + BytesToSign: ethCompatibleBytesToSign, + Msg: &types.Message{ + Assignee: sdk.ValAddress("validator-1").String(), + Action: &types.Message_UpdateValset{ + UpdateValset: &types.UpdateValset{ + Valset: &types.Valset{ + Validators: []string{ + crypto.PubkeyToAddress(bobPK.PublicKey).Hex(), + crypto.PubkeyToAddress(alicePK.PublicKey).Hex(), + crypto.PubkeyToAddress(frankPK.PublicKey).Hex(), + }, + Powers: []uint64{ + powerFromPercentage(0.4), + powerFromPercentage(0.2), + powerFromPercentage(0.1), + }, + ValsetID: 123, + }, + }, + }, + }, + }, + Signatures: []chain.ValidatorSignature{ + addValidSignature(bobPK), + addValidSignature(alicePK), + }, + }, + }, + setup: func(t *testing.T) (*mockEvmClienter, *evmmocks.PalomaClienter) { + evm, paloma := newMockEvmClienter(t), evmmocks.NewPalomaClienter(t) + + currentValsetID := int64(55) + + evm.On("LastValsetID", mock.Anything, mock.Anything).Return( + big.NewInt(55), + nil, + ) + + paloma.On("NewStatus").Return(&StatusUpdater{}) + paloma.On("QueryGetEVMValsetByID", mock.Anything, uint64(currentValsetID), "internal-chain-id").Return( + &types.Valset{ + Validators: []string{ + crypto.PubkeyToAddress(bobPK.PublicKey).Hex(), + crypto.PubkeyToAddress(alicePK.PublicKey).Hex(), + crypto.PubkeyToAddress(frankPK.PublicKey).Hex(), + }, + Powers: []uint64{ + powerFromPercentage(0.3), + powerFromPercentage(0.3), + powerFromPercentage(0.4), + }, + ValsetID: uint64(currentValsetID), + }, + nil, + ) + paloma.On("QueryGetLatestPublishedSnapshot", mock.Anything, "internal-chain-id").Return( + &valsettypes.Snapshot{ + Validators: []valsettypes.Validator{ + { + ExternalChainInfos: []*valsettypes.ExternalChainInfo{ + { + ChainReferenceID: "internal-chain-id", + Address: "0xDEADBEEF0ba39494ce839613fffba74279579268", + }, + }, + Address: sdk.ValAddress("validator-1").Bytes(), + }, + }, + }, + nil, + ) + return evm, paloma + }, + }, { name: "upload_smart_contract/happy path", msgs: []chain.MessageWithSignatures{ @@ -690,6 +1388,7 @@ func TestMessageProcessing(t *testing.T) { ID: 555, BytesToSign: ethCompatibleBytesToSign, Msg: &types.Message{ + Assignee: sdk.ValAddress("validator-1").String(), Action: &types.Message_UploadSmartContract{ UploadSmartContract: &types.UploadSmartContract{ Bytecode: []byte("bytecode"), @@ -717,6 +1416,22 @@ func TestMessageProcessing(t *testing.T) { }, nil, ) + paloma.On("QueryGetLatestPublishedSnapshot", mock.Anything, "internal-chain-id").Return( + &valsettypes.Snapshot{ + Validators: []valsettypes.Validator{ + { + ExternalChainInfos: []*valsettypes.ExternalChainInfo{ + { + ChainReferenceID: "internal-chain-id", + Address: "0xDEADBEEF0ba39494ce839613fffba74279579268", + }, + }, + Address: sdk.ValAddress("validator-1").Bytes(), + }, + }, + }, + nil, + ) evm.On("DeployContract", mock.Anything, chainID, string(StoredContracts()["simple"].Source), []byte("bytecode"), []byte("constructor input")).Return(nil, tx, nil) @@ -732,6 +1447,7 @@ func TestMessageProcessing(t *testing.T) { ID: 555, BytesToSign: ethCompatibleBytesToSign, Msg: &types.Message{ + Assignee: sdk.ValAddress("validator-1").String(), Action: &types.Message_UploadSmartContract{ UploadSmartContract: &types.UploadSmartContract{ Bytecode: []byte("bytecode"), @@ -769,6 +1485,22 @@ func TestMessageProcessing(t *testing.T) { }, nil, ) + paloma.On("QueryGetLatestPublishedSnapshot", mock.Anything, "internal-chain-id").Return( + &valsettypes.Snapshot{ + Validators: []valsettypes.Validator{ + { + ExternalChainInfos: []*valsettypes.ExternalChainInfo{ + { + ChainReferenceID: "internal-chain-id", + Address: "0xDEADBEEF0ba39494ce839613fffba74279579268", + }, + }, + Address: sdk.ValAddress("validator-1").Bytes(), + }, + }, + }, + nil, + ) return evm, paloma }, }, @@ -780,6 +1512,7 @@ func TestMessageProcessing(t *testing.T) { ID: 555, BytesToSign: ethCompatibleBytesToSign, Msg: &types.Message{ + Assignee: sdk.ValAddress("validator-1").String(), Action: &types.Message_UploadSmartContract{ UploadSmartContract: &types.UploadSmartContract{ Bytecode: []byte("bytecode"), @@ -806,6 +1539,22 @@ func TestMessageProcessing(t *testing.T) { }, nil, ) + paloma.On("QueryGetLatestPublishedSnapshot", mock.Anything, "internal-chain-id").Return( + &valsettypes.Snapshot{ + Validators: []valsettypes.Validator{ + { + ExternalChainInfos: []*valsettypes.ExternalChainInfo{ + { + ChainReferenceID: "internal-chain-id", + Address: "0xDEADBEEF0ba39494ce839613fffba74279579268", + }, + }, + Address: sdk.ValAddress("validator-1").Bytes(), + }, + }, + }, + nil, + ) evm.On("DeployContract", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil, nil, fakeErr) paloma.On("SetErrorData", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil) return evm, paloma @@ -820,6 +1569,7 @@ func TestMessageProcessing(t *testing.T) { ID: 555, BytesToSign: ethCompatibleBytesToSign, Msg: &types.Message{ + Assignee: sdk.ValAddress("validator-1").String(), Action: &types.Message_UploadSmartContract{ UploadSmartContract: &types.UploadSmartContract{ Bytecode: []byte("bytecode"), @@ -847,6 +1597,22 @@ func TestMessageProcessing(t *testing.T) { }, nil, ) + paloma.On("QueryGetLatestPublishedSnapshot", mock.Anything, "internal-chain-id").Return( + &valsettypes.Snapshot{ + Validators: []valsettypes.Validator{ + { + ExternalChainInfos: []*valsettypes.ExternalChainInfo{ + { + ChainReferenceID: "internal-chain-id", + Address: "0xDEADBEEF0ba39494ce839613fffba74279579268", + }, + }, + Address: sdk.ValAddress("validator-1").Bytes(), + }, + }, + }, + nil, + ) evm.On("DeployContract", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil, nil, fakeErr) paloma.On("SetErrorData", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(dummyErr) return evm, paloma @@ -860,6 +1626,7 @@ func TestMessageProcessing(t *testing.T) { ethClienter, palomaClienter := tt.setup(t) comp := newCompassClient( smartContractAddr.Hex(), + feeMgrContractAddr.Hex(), "id-123", "internal-chain-id", chainID, @@ -868,7 +1635,7 @@ func TestMessageProcessing(t *testing.T) { ethClienter, ) - err := comp.processMessages(ctx, "queue-name", tt.msgs) + _, err := comp.processMessages(ctx, "queue-name", tt.msgs, callOptions{estimateOnly: tt.estimateOnly}) if tt.expErr != nil { require.ErrorContains(t, err, tt.expErr.Error()) } else { @@ -883,6 +1650,7 @@ func TestProcessingvalidatorBalancesRequest(t *testing.T) { evm, paloma := newMockEvmClienter(t), evmmocks.NewPalomaClienter(t) comp := newCompassClient( smartContractAddr.Hex(), + feeMgrContractAddr.Hex(), "id-123", "internal-chain-id", big.NewInt(5), @@ -921,6 +1689,7 @@ func TestProcessingvalidatorBalancesRequestWithError(t *testing.T) { evm, paloma := newMockEvmClienter(t), evmmocks.NewPalomaClienter(t) comp := newCompassClient( smartContractAddr.Hex(), + feeMgrContractAddr.Hex(), "id-123", "internal-chain-id", big.NewInt(5), @@ -961,6 +1730,7 @@ func TestProcessingvalidatorBalancesRequestWithAllErrors(t *testing.T) { evm, paloma := newMockEvmClienter(t), evmmocks.NewPalomaClienter(t) comp := newCompassClient( smartContractAddr.Hex(), + feeMgrContractAddr.Hex(), "id-123", "internal-chain-id", big.NewInt(5), @@ -996,6 +1766,7 @@ func TestProcessingReferenceBlockRequest(t *testing.T) { evm, paloma := newMockEvmClienter(t), evmmocks.NewPalomaClienter(t) comp := newCompassClient( smartContractAddr.Hex(), + feeMgrContractAddr.Hex(), "id-123", "internal-chain-id", big.NewInt(5), @@ -1103,6 +1874,7 @@ func TestProvidingEvidenceForAMessage(t *testing.T) { ethClienter, palomaClienter := tt.setup(t) comp := newCompassClient( smartContractAddr.Hex(), + feeMgrContractAddr.Hex(), "id-123", "internal-chain-id", chainID, diff --git a/chain/evm/contracts/compass-evm.json b/chain/evm/contracts/compass-evm.json index 01c5c1e8..666eeae2 100644 --- a/chain/evm/contracts/compass-evm.json +++ b/chain/evm/contracts/compass-evm.json @@ -1,223 +1,999 @@ [ - { - "name": "ValsetUpdated", - "inputs": [ - { - "name": "checkpoint", - "type": "bytes32", - "indexed": false - }, - { - "name": "valset_id", - "type": "uint256", - "indexed": false - } - ], - "anonymous": false, - "type": "event" - }, - { - "name": "LogicCallEvent", - "inputs": [ - { - "name": "logic_contract_address", - "type": "address", - "indexed": false - }, - { - "name": "payload", - "type": "bytes", - "indexed": false - }, - { - "name": "message_id", - "type": "uint256", - "indexed": false - } - ], - "anonymous": false, - "type": "event" - }, - { - "stateMutability": "nonpayable", - "type": "constructor", - "inputs": [ - { - "name": "turnstone_id", - "type": "bytes32" - }, - { - "name": "valset", - "type": "tuple", - "components": [ - { - "name": "validators", - "type": "address[]" - }, - { - "name": "powers", - "type": "uint256[]" - }, - { - "name": "valset_id", - "type": "uint256" - } - ] - } - ], - "outputs": [] - }, - { - "stateMutability": "pure", - "type": "function", - "name": "turnstone_id", - "inputs": [], - "outputs": [ - { - "name": "", - "type": "bytes32" - } - ] - }, - { - "stateMutability": "nonpayable", - "type": "function", - "name": "update_valset", - "inputs": [ - { - "name": "consensus", - "type": "tuple", - "components": [ - { - "name": "valset", - "type": "tuple", - "components": [ - { - "name": "validators", - "type": "address[]" - }, - { - "name": "powers", - "type": "uint256[]" - }, - { - "name": "valset_id", - "type": "uint256" - } - ] - }, - { - "name": "signatures", - "type": "(uint256,uint256,uint256)[]" - } - ] - }, - { - "name": "new_valset", - "type": "tuple", - "components": [ - { - "name": "validators", - "type": "address[]" - }, - { - "name": "powers", - "type": "uint256[]" - }, - { - "name": "valset_id", - "type": "uint256" - } - ] - } - ], - "outputs": [] - }, - { - "stateMutability": "nonpayable", - "type": "function", - "name": "submit_logic_call", - "inputs": [ - { - "name": "consensus", - "type": "tuple", - "components": [ - { - "name": "valset", - "type": "tuple", - "components": [ - { - "name": "validators", - "type": "address[]" - }, - { - "name": "powers", - "type": "uint256[]" - }, - { - "name": "valset_id", - "type": "uint256" - } - ] - }, - { - "name": "signatures", - "type": "(uint256,uint256,uint256)[]" - } - ] - }, - { - "name": "args", - "type": "tuple", - "components": [ - { - "name": "logic_contract_address", - "type": "address" - }, - { - "name": "payload", - "type": "bytes" - } - ] - }, - { - "name": "message_id", - "type": "uint256" - }, - { - "name": "deadline", - "type": "uint256" - } - ], - "outputs": [] - }, - { - "stateMutability": "view", - "type": "function", - "name": "last_checkpoint", - "inputs": [], - "outputs": [ - { - "name": "", - "type": "bytes32" - } - ] - }, - { - "stateMutability": "view", - "type": "function", - "name": "message_id_used", - "inputs": [ - { - "name": "arg0", - "type": "uint256" - } - ], - "outputs": [ - { - "name": "", - "type": "bool" - } - ] - } + { + "anonymous":false, + "inputs":[ + { + "indexed":false, + "name":"checkpoint", + "type":"bytes32" + }, + { + "indexed":false, + "name":"valset_id", + "type":"uint256" + }, + { + "indexed":false, + "name":"event_id", + "type":"uint256" + } + ], + "name":"ValsetUpdated", + "type":"event" + }, + { + "anonymous":false, + "inputs":[ + { + "indexed":false, + "name":"logic_contract_address", + "type":"address" + }, + { + "indexed":false, + "name":"payload", + "type":"bytes" + }, + { + "indexed":false, + "name":"message_id", + "type":"uint256" + }, + { + "indexed":false, + "name":"event_id", + "type":"uint256" + } + ], + "name":"LogicCallEvent", + "type":"event" + }, + { + "anonymous":false, + "inputs":[ + { + "indexed":false, + "name":"token", + "type":"address" + }, + { + "indexed":false, + "name":"sender", + "type":"address" + }, + { + "indexed":false, + "name":"receiver", + "type":"bytes32" + }, + { + "indexed":false, + "name":"amount", + "type":"uint256" + }, + { + "indexed":false, + "name":"nonce", + "type":"uint256" + }, + { + "indexed":false, + "name":"event_id", + "type":"uint256" + } + ], + "name":"SendToPalomaEvent", + "type":"event" + }, + { + "anonymous":false, + "inputs":[ + { + "indexed":false, + "name":"token", + "type":"address" + }, + { + "indexed":false, + "name":"batch_id", + "type":"uint256" + }, + { + "indexed":false, + "name":"nonce", + "type":"uint256" + }, + { + "indexed":false, + "name":"event_id", + "type":"uint256" + } + ], + "name":"BatchSendEvent", + "type":"event" + }, + { + "anonymous":false, + "inputs":[ + { + "indexed":false, + "name":"paloma_denom", + "type":"string" + }, + { + "indexed":false, + "name":"token_contract", + "type":"address" + }, + { + "indexed":false, + "name":"name", + "type":"string" + }, + { + "indexed":false, + "name":"symbol", + "type":"string" + }, + { + "indexed":false, + "name":"decimals", + "type":"uint8" + }, + { + "indexed":false, + "name":"event_id", + "type":"uint256" + } + ], + "name":"ERC20DeployedEvent", + "type":"event" + }, + { + "anonymous":false, + "inputs":[ + { + "indexed":false, + "name":"depositor_paloma_address", + "type":"bytes32" + }, + { + "indexed":false, + "name":"sender", + "type":"address" + }, + { + "indexed":false, + "name":"amount", + "type":"uint256" + } + ], + "name":"FundsDepositedEvent", + "type":"event" + }, + { + "anonymous":false, + "inputs":[ + { + "indexed":false, + "name":"receiver", + "type":"address" + }, + { + "indexed":false, + "name":"amount", + "type":"uint256" + } + ], + "name":"FundsWithdrawnEvent", + "type":"event" + }, + { + "anonymous":false, + "inputs":[ + { + "indexed":false, + "name":"new_compass", + "type":"address" + }, + { + "indexed":false, + "name":"event_id", + "type":"uint256" + } + ], + "name":"UpdateCompassAddressInFeeManager", + "type":"event" + }, + { + "anonymous":false, + "inputs":[ + { + "indexed":false, + "name":"contract_address", + "type":"address" + }, + { + "indexed":false, + "name":"buyer", + "type":"address" + }, + { + "indexed":false, + "name":"paloma", + "type":"bytes32" + }, + { + "indexed":false, + "name":"node_count", + "type":"uint256" + }, + { + "indexed":false, + "name":"grain_amount", + "type":"uint256" + }, + { + "indexed":false, + "name":"nonce", + "type":"uint256" + }, + { + "indexed":false, + "name":"event_id", + "type":"uint256" + } + ], + "name":"NodeSaleEvent", + "type":"event" + }, + { + "inputs":[ + { + "name":"_compass_id", + "type":"bytes32" + }, + { + "name":"_event_id", + "type":"uint256" + }, + { + "name":"_gravity_nonce", + "type":"uint256" + }, + { + "components":[ + { + "name":"validators", + "type":"address[]" + }, + { + "name":"powers", + "type":"uint256[]" + }, + { + "name":"valset_id", + "type":"uint256" + } + ], + "name":"valset", + "type":"tuple" + }, + { + "name":"fee_manager", + "type":"address" + } + ], + "stateMutability":"nonpayable", + "type":"constructor" + }, + { + "inputs":[ + { + "components":[ + { + "components":[ + { + "name":"validators", + "type":"address[]" + }, + { + "name":"powers", + "type":"uint256[]" + }, + { + "name":"valset_id", + "type":"uint256" + } + ], + "name":"valset", + "type":"tuple" + }, + { + "components":[ + { + "name":"v", + "type":"uint256" + }, + { + "name":"r", + "type":"uint256" + }, + { + "name":"s", + "type":"uint256" + } + ], + "name":"signatures", + "type":"tuple[]" + } + ], + "name":"consensus", + "type":"tuple" + }, + { + "components":[ + { + "name":"validators", + "type":"address[]" + }, + { + "name":"powers", + "type":"uint256[]" + }, + { + "name":"valset_id", + "type":"uint256" + } + ], + "name":"new_valset", + "type":"tuple" + }, + { + "name":"relayer", + "type":"address" + }, + { + "name":"gas_estimate", + "type":"uint256" + } + ], + "name":"update_valset", + "outputs":[ + + ], + "stateMutability":"nonpayable", + "type":"function" + }, + { + "inputs":[ + { + "components":[ + { + "components":[ + { + "name":"validators", + "type":"address[]" + }, + { + "name":"powers", + "type":"uint256[]" + }, + { + "name":"valset_id", + "type":"uint256" + } + ], + "name":"valset", + "type":"tuple" + }, + { + "components":[ + { + "name":"v", + "type":"uint256" + }, + { + "name":"r", + "type":"uint256" + }, + { + "name":"s", + "type":"uint256" + } + ], + "name":"signatures", + "type":"tuple[]" + } + ], + "name":"consensus", + "type":"tuple" + }, + { + "components":[ + { + "name":"logic_contract_address", + "type":"address" + }, + { + "name":"payload", + "type":"bytes" + } + ], + "name":"args", + "type":"tuple" + }, + { + "components":[ + { + "name":"relayer_fee", + "type":"uint256" + }, + { + "name":"community_fee", + "type":"uint256" + }, + { + "name":"security_fee", + "type":"uint256" + }, + { + "name":"fee_payer_paloma_address", + "type":"bytes32" + } + ], + "name":"fee_args", + "type":"tuple" + }, + { + "name":"message_id", + "type":"uint256" + }, + { + "name":"deadline", + "type":"uint256" + }, + { + "name":"relayer", + "type":"address" + } + ], + "name":"submit_logic_call", + "outputs":[ + + ], + "stateMutability":"nonpayable", + "type":"function" + }, + { + "inputs":[ + { + "name":"token", + "type":"address" + }, + { + "name":"receiver", + "type":"bytes32" + }, + { + "name":"amount", + "type":"uint256" + } + ], + "name":"send_token_to_paloma", + "outputs":[ + + ], + "stateMutability":"nonpayable", + "type":"function" + }, + { + "inputs":[ + { + "components":[ + { + "components":[ + { + "name":"validators", + "type":"address[]" + }, + { + "name":"powers", + "type":"uint256[]" + }, + { + "name":"valset_id", + "type":"uint256" + } + ], + "name":"valset", + "type":"tuple" + }, + { + "components":[ + { + "name":"v", + "type":"uint256" + }, + { + "name":"r", + "type":"uint256" + }, + { + "name":"s", + "type":"uint256" + } + ], + "name":"signatures", + "type":"tuple[]" + } + ], + "name":"consensus", + "type":"tuple" + }, + { + "name":"token", + "type":"address" + }, + { + "components":[ + { + "name":"receiver", + "type":"address[]" + }, + { + "name":"amount", + "type":"uint256[]" + } + ], + "name":"args", + "type":"tuple" + }, + { + "name":"batch_id", + "type":"uint256" + }, + { + "name":"deadline", + "type":"uint256" + }, + { + "name":"relayer", + "type":"address" + }, + { + "name":"gas_estimate", + "type":"uint256" + } + ], + "name":"submit_batch", + "outputs":[ + + ], + "stateMutability":"nonpayable", + "type":"function" + }, + { + "inputs":[ + { + "name":"buyer", + "type":"address" + }, + { + "name":"paloma", + "type":"bytes32" + }, + { + "name":"node_count", + "type":"uint256" + }, + { + "name":"grain_amount", + "type":"uint256" + } + ], + "name":"emit_nodesale_event", + "outputs":[ + + ], + "stateMutability":"nonpayable", + "type":"function" + }, + { + "inputs":[ + { + "name":"_paloma_denom", + "type":"string" + }, + { + "name":"_name", + "type":"string" + }, + { + "name":"_symbol", + "type":"string" + }, + { + "name":"_decimals", + "type":"uint8" + }, + { + "name":"_blueprint", + "type":"address" + } + ], + "name":"deploy_erc20", + "outputs":[ + + ], + "stateMutability":"nonpayable", + "type":"function" + }, + { + "inputs":[ + { + "name":"contract_address", + "type":"address" + }, + { + "name":"payload", + "type":"bytes" + } + ], + "name":"arbitrary_view", + "outputs":[ + { + "name":"", + "type":"bytes" + } + ], + "stateMutability":"view", + "type":"function" + }, + { + "inputs":[ + { + "name":"depositor_paloma_address", + "type":"bytes32" + }, + { + "name":"amount", + "type":"uint256" + } + ], + "name":"deposit", + "outputs":[ + + ], + "stateMutability":"payable", + "type":"function" + }, + { + "inputs":[ + { + "name":"amount", + "type":"uint256" + }, + { + "name":"dex", + "type":"address" + }, + { + "name":"payload", + "type":"bytes" + }, + { + "name":"min_grain", + "type":"uint256" + } + ], + "name":"withdraw", + "outputs":[ + + ], + "stateMutability":"nonpayable", + "type":"function" + }, + { + "inputs":[ + { + "name":"amount", + "type":"uint256" + } + ], + "name":"security_fee_topup", + "outputs":[ + + ], + "stateMutability":"payable", + "type":"function" + }, + { + "inputs":[ + { + "components":[ + { + "components":[ + { + "name":"validators", + "type":"address[]" + }, + { + "name":"powers", + "type":"uint256[]" + }, + { + "name":"valset_id", + "type":"uint256" + } + ], + "name":"valset", + "type":"tuple" + }, + { + "components":[ + { + "name":"v", + "type":"uint256" + }, + { + "name":"r", + "type":"uint256" + }, + { + "name":"s", + "type":"uint256" + } + ], + "name":"signatures", + "type":"tuple[]" + } + ], + "name":"consensus", + "type":"tuple" + }, + { + "name":"message_id", + "type":"uint256" + }, + { + "name":"deadline", + "type":"uint256" + }, + { + "name":"receiver", + "type":"bytes32" + }, + { + "name":"relayer", + "type":"address" + }, + { + "name":"gas_estimate", + "type":"uint256" + }, + { + "name":"amount", + "type":"uint256" + }, + { + "name":"dex", + "type":"address" + }, + { + "name":"payload", + "type":"bytes" + }, + { + "name":"min_grain", + "type":"uint256" + } + ], + "name":"bridge_community_tax_to_paloma", + "outputs":[ + + ], + "stateMutability":"nonpayable", + "type":"function" + }, + { + "inputs":[ + { + "components":[ + { + "components":[ + { + "name":"validators", + "type":"address[]" + }, + { + "name":"powers", + "type":"uint256[]" + }, + { + "name":"valset_id", + "type":"uint256" + } + ], + "name":"valset", + "type":"tuple" + }, + { + "components":[ + { + "name":"v", + "type":"uint256" + }, + { + "name":"r", + "type":"uint256" + }, + { + "name":"s", + "type":"uint256" + } + ], + "name":"signatures", + "type":"tuple[]" + } + ], + "name":"consensus", + "type":"tuple" + }, + { + "name":"deadline", + "type":"uint256" + }, + { + "name":"gas_estimate", + "type":"uint256" + }, + { + "name":"_new_compass", + "type":"address" + }, + { + "name":"relayer", + "type":"address" + } + ], + "name":"update_compass_address_in_fee_manager", + "outputs":[ + + ], + "stateMutability":"nonpayable", + "type":"function" + }, + { + "inputs":[ + + ], + "name":"compass_id", + "outputs":[ + { + "name":"", + "type":"bytes32" + } + ], + "stateMutability":"view", + "type":"function" + }, + { + "inputs":[ + + ], + "name":"last_checkpoint", + "outputs":[ + { + "name":"", + "type":"bytes32" + } + ], + "stateMutability":"view", + "type":"function" + }, + { + "inputs":[ + + ], + "name":"last_valset_id", + "outputs":[ + { + "name":"", + "type":"uint256" + } + ], + "stateMutability":"view", + "type":"function" + }, + { + "inputs":[ + + ], + "name":"last_event_id", + "outputs":[ + { + "name":"", + "type":"uint256" + } + ], + "stateMutability":"view", + "type":"function" + }, + { + "inputs":[ + + ], + "name":"last_gravity_nonce", + "outputs":[ + { + "name":"", + "type":"uint256" + } + ], + "stateMutability":"view", + "type":"function" + }, + { + "inputs":[ + { + "name":"arg0", + "type":"address" + } + ], + "name":"last_batch_id", + "outputs":[ + { + "name":"", + "type":"uint256" + } + ], + "stateMutability":"view", + "type":"function" + }, + { + "inputs":[ + { + "name":"arg0", + "type":"uint256" + } + ], + "name":"message_id_used", + "outputs":[ + { + "name":"", + "type":"bool" + } + ], + "stateMutability":"view", + "type":"function" + }, + { + "inputs":[ + + ], + "name":"slc_switch", + "outputs":[ + { + "name":"", + "type":"bool" + } + ], + "stateMutability":"view", + "type":"function" + }, + { + "inputs":[ + + ], + "name":"FEE_MANAGER", + "outputs":[ + { + "name":"", + "type":"address" + } + ], + "stateMutability":"view", + "type":"function" + } ] diff --git a/chain/evm/factory.go b/chain/evm/factory.go index c40e8a94..4021ef97 100644 --- a/chain/evm/factory.go +++ b/chain/evm/factory.go @@ -29,6 +29,7 @@ func (f *Factory) Build( smartContractID, smartContractABIJson, smartContractAddress string, + feeMgrContractAddress string, chainID *big.Int, blockHeight int64, blockHeightHash common.Hash, @@ -65,6 +66,7 @@ func (f *Factory) Build( CompassID: smartContractID, ChainReferenceID: chainReferenceID, smartContractAddr: common.HexToAddress(smartContractAddress), + feeMgrContractAddr: common.HexToAddress(feeMgrContractAddress), chainID: chainID, compassAbi: smartContractABI, paloma: f.palomaClienter, diff --git a/chain/evm/mock_ethClientConn_test.go b/chain/evm/mock_ethClientConn_test.go index 46e51531..6151e339 100644 --- a/chain/evm/mock_ethClientConn_test.go +++ b/chain/evm/mock_ethClientConn_test.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.43.1. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package evm @@ -6,10 +6,13 @@ import ( context "context" big "math/big" - ethereum "github.com/ethereum/go-ethereum" common "github.com/ethereum/go-ethereum/common" - types "github.com/ethereum/go-ethereum/core/types" + + ethereum "github.com/ethereum/go-ethereum" + mock "github.com/stretchr/testify/mock" + + types "github.com/ethereum/go-ethereum/core/types" ) // mockEthClientConn is an autogenerated mock type for the ethClientConn type diff --git a/chain/evm/mock_ethClientToFilterLogs_test.go b/chain/evm/mock_ethClientToFilterLogs_test.go index 205e1e11..249277c5 100644 --- a/chain/evm/mock_ethClientToFilterLogs_test.go +++ b/chain/evm/mock_ethClientToFilterLogs_test.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.43.1. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package evm @@ -7,8 +7,10 @@ import ( big "math/big" ethereum "github.com/ethereum/go-ethereum" - types "github.com/ethereum/go-ethereum/core/types" + mock "github.com/stretchr/testify/mock" + + types "github.com/ethereum/go-ethereum/core/types" ) // mockEthClientToFilterLogs is an autogenerated mock type for the ethClientToFilterLogs type diff --git a/chain/evm/mock_ethClienter_test.go b/chain/evm/mock_ethClienter_test.go index 8339ceb8..ae0a31e7 100644 --- a/chain/evm/mock_ethClienter_test.go +++ b/chain/evm/mock_ethClienter_test.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.43.1. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package evm @@ -6,10 +6,13 @@ import ( context "context" big "math/big" - ethereum "github.com/ethereum/go-ethereum" common "github.com/ethereum/go-ethereum/common" - types "github.com/ethereum/go-ethereum/core/types" + + ethereum "github.com/ethereum/go-ethereum" + mock "github.com/stretchr/testify/mock" + + types "github.com/ethereum/go-ethereum/core/types" ) // mockEthClienter is an autogenerated mock type for the ethClienter type diff --git a/chain/evm/mock_evmClienter_test.go b/chain/evm/mock_evmClienter_test.go index 1e24f918..6618e0ab 100644 --- a/chain/evm/mock_evmClienter_test.go +++ b/chain/evm/mock_evmClienter_test.go @@ -1,17 +1,23 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package evm import ( - context "context" big "math/big" - time "time" - ethereum "github.com/ethereum/go-ethereum" abi "github.com/ethereum/go-ethereum/accounts/abi" + common "github.com/ethereum/go-ethereum/common" - types "github.com/ethereum/go-ethereum/core/types" + + context "context" + + ethereum "github.com/ethereum/go-ethereum" + mock "github.com/stretchr/testify/mock" + + time "time" + + types "github.com/ethereum/go-ethereum/core/types" ) // mockEvmClienter is an autogenerated mock type for the evmClienter type @@ -23,6 +29,10 @@ type mockEvmClienter struct { func (_m *mockEvmClienter) BalanceAt(ctx context.Context, address common.Address, blockHeight uint64) (*big.Int, error) { ret := _m.Called(ctx, address, blockHeight) + if len(ret) == 0 { + panic("no return value specified for BalanceAt") + } + var r0 *big.Int var r1 error if rf, ok := ret.Get(0).(func(context.Context, common.Address, uint64) (*big.Int, error)); ok { @@ -49,6 +59,10 @@ func (_m *mockEvmClienter) BalanceAt(ctx context.Context, address common.Address func (_m *mockEvmClienter) DeployContract(ctx context.Context, chainID *big.Int, rawABI string, bytecode []byte, constructorInput []byte) (common.Address, *types.Transaction, error) { ret := _m.Called(ctx, chainID, rawABI, bytecode, constructorInput) + if len(ret) == 0 { + panic("no return value specified for DeployContract") + } + var r0 common.Address var r1 *types.Transaction var r2 error @@ -80,25 +94,29 @@ func (_m *mockEvmClienter) DeployContract(ctx context.Context, chainID *big.Int, return r0, r1, r2 } -// ExecuteSmartContract provides a mock function with given fields: ctx, chainID, contractAbi, addr, mevRelay, method, arguments -func (_m *mockEvmClienter) ExecuteSmartContract(ctx context.Context, chainID *big.Int, contractAbi abi.ABI, addr common.Address, mevRelay bool, method string, arguments []interface{}) (*types.Transaction, error) { - ret := _m.Called(ctx, chainID, contractAbi, addr, mevRelay, method, arguments) +// ExecuteSmartContract provides a mock function with given fields: ctx, chainID, contractAbi, addr, opts, method, arguments +func (_m *mockEvmClienter) ExecuteSmartContract(ctx context.Context, chainID *big.Int, contractAbi abi.ABI, addr common.Address, opts callOptions, method string, arguments []interface{}) (*types.Transaction, error) { + ret := _m.Called(ctx, chainID, contractAbi, addr, opts, method, arguments) + + if len(ret) == 0 { + panic("no return value specified for ExecuteSmartContract") + } var r0 *types.Transaction var r1 error - if rf, ok := ret.Get(0).(func(context.Context, *big.Int, abi.ABI, common.Address, bool, string, []interface{}) (*types.Transaction, error)); ok { - return rf(ctx, chainID, contractAbi, addr, mevRelay, method, arguments) + if rf, ok := ret.Get(0).(func(context.Context, *big.Int, abi.ABI, common.Address, callOptions, string, []interface{}) (*types.Transaction, error)); ok { + return rf(ctx, chainID, contractAbi, addr, opts, method, arguments) } - if rf, ok := ret.Get(0).(func(context.Context, *big.Int, abi.ABI, common.Address, bool, string, []interface{}) *types.Transaction); ok { - r0 = rf(ctx, chainID, contractAbi, addr, mevRelay, method, arguments) + if rf, ok := ret.Get(0).(func(context.Context, *big.Int, abi.ABI, common.Address, callOptions, string, []interface{}) *types.Transaction); ok { + r0 = rf(ctx, chainID, contractAbi, addr, opts, method, arguments) } else { if ret.Get(0) != nil { r0 = ret.Get(0).(*types.Transaction) } } - if rf, ok := ret.Get(1).(func(context.Context, *big.Int, abi.ABI, common.Address, bool, string, []interface{}) error); ok { - r1 = rf(ctx, chainID, contractAbi, addr, mevRelay, method, arguments) + if rf, ok := ret.Get(1).(func(context.Context, *big.Int, abi.ABI, common.Address, callOptions, string, []interface{}) error); ok { + r1 = rf(ctx, chainID, contractAbi, addr, opts, method, arguments) } else { r1 = ret.Error(1) } @@ -110,6 +128,10 @@ func (_m *mockEvmClienter) ExecuteSmartContract(ctx context.Context, chainID *bi func (_m *mockEvmClienter) FilterLogs(ctx context.Context, fq ethereum.FilterQuery, currBlockHeight *big.Int, fn func([]types.Log) bool) (bool, error) { ret := _m.Called(ctx, fq, currBlockHeight, fn) + if len(ret) == 0 { + panic("no return value specified for FilterLogs") + } + var r0 bool var r1 error if rf, ok := ret.Get(0).(func(context.Context, ethereum.FilterQuery, *big.Int, func([]types.Log) bool) (bool, error)); ok { @@ -134,6 +156,10 @@ func (_m *mockEvmClienter) FilterLogs(ctx context.Context, fq ethereum.FilterQue func (_m *mockEvmClienter) FindBlockNearestToTime(ctx context.Context, startingHeight uint64, when time.Time) (uint64, error) { ret := _m.Called(ctx, startingHeight, when) + if len(ret) == 0 { + panic("no return value specified for FindBlockNearestToTime") + } + var r0 uint64 var r1 error if rf, ok := ret.Get(0).(func(context.Context, uint64, time.Time) (uint64, error)); ok { @@ -158,6 +184,10 @@ func (_m *mockEvmClienter) FindBlockNearestToTime(ctx context.Context, startingH func (_m *mockEvmClienter) FindCurrentBlockNumber(ctx context.Context) (*big.Int, error) { ret := _m.Called(ctx) + if len(ret) == 0 { + panic("no return value specified for FindCurrentBlockNumber") + } + var r0 *big.Int var r1 error if rf, ok := ret.Get(0).(func(context.Context) (*big.Int, error)); ok { @@ -184,6 +214,10 @@ func (_m *mockEvmClienter) FindCurrentBlockNumber(ctx context.Context) (*big.Int func (_m *mockEvmClienter) GetEthClient() ethClientConn { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for GetEthClient") + } + var r0 ethClientConn if rf, ok := ret.Get(0).(func() ethClientConn); ok { r0 = rf() @@ -200,6 +234,10 @@ func (_m *mockEvmClienter) GetEthClient() ethClientConn { func (_m *mockEvmClienter) LastValsetID(ctx context.Context, addr common.Address) (*big.Int, error) { ret := _m.Called(ctx, addr) + if len(ret) == 0 { + panic("no return value specified for LastValsetID") + } + var r0 *big.Int var r1 error if rf, ok := ret.Get(0).(func(context.Context, common.Address) (*big.Int, error)); ok { @@ -222,10 +260,74 @@ func (_m *mockEvmClienter) LastValsetID(ctx context.Context, addr common.Address return r0, r1 } +// QueryUserFunds provides a mock function with given fields: ctx, feemgraddr, palomaAddress +func (_m *mockEvmClienter) QueryUserFunds(ctx context.Context, feemgraddr common.Address, palomaAddress [32]byte) (*big.Int, error) { + ret := _m.Called(ctx, feemgraddr, palomaAddress) + + if len(ret) == 0 { + panic("no return value specified for QueryUserFunds") + } + + var r0 *big.Int + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, common.Address, [32]byte) (*big.Int, error)); ok { + return rf(ctx, feemgraddr, palomaAddress) + } + if rf, ok := ret.Get(0).(func(context.Context, common.Address, [32]byte) *big.Int); ok { + r0 = rf(ctx, feemgraddr, palomaAddress) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*big.Int) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, common.Address, [32]byte) error); ok { + r1 = rf(ctx, feemgraddr, palomaAddress) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// SuggestGasPrice provides a mock function with given fields: ctx +func (_m *mockEvmClienter) SuggestGasPrice(ctx context.Context) (*big.Int, error) { + ret := _m.Called(ctx) + + if len(ret) == 0 { + panic("no return value specified for SuggestGasPrice") + } + + var r0 *big.Int + var r1 error + if rf, ok := ret.Get(0).(func(context.Context) (*big.Int, error)); ok { + return rf(ctx) + } + if rf, ok := ret.Get(0).(func(context.Context) *big.Int); ok { + r0 = rf(ctx) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*big.Int) + } + } + + if rf, ok := ret.Get(1).(func(context.Context) error); ok { + r1 = rf(ctx) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + // TransactionByHash provides a mock function with given fields: ctx, txHash func (_m *mockEvmClienter) TransactionByHash(ctx context.Context, txHash common.Hash) (*types.Transaction, bool, error) { ret := _m.Called(ctx, txHash) + if len(ret) == 0 { + panic("no return value specified for TransactionByHash") + } + var r0 *types.Transaction var r1 bool var r2 error diff --git a/chain/evm/mock_mevClient_test.go b/chain/evm/mock_mevClient_test.go index 8f0cc6aa..c79597a4 100644 --- a/chain/evm/mock_mevClient_test.go +++ b/chain/evm/mock_mevClient_test.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.43.1. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package evm @@ -7,8 +7,10 @@ import ( big "math/big" common "github.com/ethereum/go-ethereum/common" - types "github.com/ethereum/go-ethereum/core/types" + mock "github.com/stretchr/testify/mock" + + types "github.com/ethereum/go-ethereum/core/types" ) // mockMevClient is an autogenerated mock type for the mevClient type diff --git a/chain/evm/mocks/CompassBinding.go b/chain/evm/mocks/CompassBinding.go index c4ef08ae..8d2ef181 100644 --- a/chain/evm/mocks/CompassBinding.go +++ b/chain/evm/mocks/CompassBinding.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.43.1. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package mocks @@ -6,10 +6,15 @@ import ( big "math/big" bind "github.com/ethereum/go-ethereum/accounts/abi/bind" - types "github.com/ethereum/go-ethereum/core/types" - event "github.com/ethereum/go-ethereum/event" + common "github.com/ethereum/go-ethereum/common" + compass "github.com/palomachain/pigeon/chain/evm/abi/compass" + + event "github.com/ethereum/go-ethereum/event" + mock "github.com/stretchr/testify/mock" + + types "github.com/ethereum/go-ethereum/core/types" ) // CompassBinding is an autogenerated mock type for the CompassBinding type @@ -17,6 +22,36 @@ type CompassBinding struct { mock.Mock } +// CompassId provides a mock function with given fields: opts +func (_m *CompassBinding) CompassId(opts *bind.CallOpts) ([32]byte, error) { + ret := _m.Called(opts) + + if len(ret) == 0 { + panic("no return value specified for CompassId") + } + + var r0 [32]byte + var r1 error + if rf, ok := ret.Get(0).(func(*bind.CallOpts) ([32]byte, error)); ok { + return rf(opts) + } + if rf, ok := ret.Get(0).(func(*bind.CallOpts) [32]byte); ok { + r0 = rf(opts) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([32]byte) + } + } + + if rf, ok := ret.Get(1).(func(*bind.CallOpts) error); ok { + r1 = rf(opts) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + // FilterLogicCallEvent provides a mock function with given fields: opts func (_m *CompassBinding) FilterLogicCallEvent(opts *bind.FilterOpts) (*compass.CompassLogicCallEventIterator, error) { ret := _m.Called(opts) @@ -225,9 +260,9 @@ func (_m *CompassBinding) ParseValsetUpdated(log types.Log) (*compass.CompassVal return r0, r1 } -// SubmitLogicCall provides a mock function with given fields: opts, consensus, args, messageId, deadline -func (_m *CompassBinding) SubmitLogicCall(opts *bind.TransactOpts, consensus compass.Struct2, args compass.Struct3, messageId *big.Int, deadline *big.Int) (*types.Transaction, error) { - ret := _m.Called(opts, consensus, args, messageId, deadline) +// SubmitLogicCall provides a mock function with given fields: opts, consensus, args, fee_args, messageId, deadline, relayer +func (_m *CompassBinding) SubmitLogicCall(opts *bind.TransactOpts, consensus compass.Struct2, args compass.Struct3, fee_args compass.Struct4, messageId *big.Int, deadline *big.Int, relayer common.Address) (*types.Transaction, error) { + ret := _m.Called(opts, consensus, args, fee_args, messageId, deadline, relayer) if len(ret) == 0 { panic("no return value specified for SubmitLogicCall") @@ -235,49 +270,19 @@ func (_m *CompassBinding) SubmitLogicCall(opts *bind.TransactOpts, consensus com var r0 *types.Transaction var r1 error - if rf, ok := ret.Get(0).(func(*bind.TransactOpts, compass.Struct2, compass.Struct3, *big.Int, *big.Int) (*types.Transaction, error)); ok { - return rf(opts, consensus, args, messageId, deadline) + if rf, ok := ret.Get(0).(func(*bind.TransactOpts, compass.Struct2, compass.Struct3, compass.Struct4, *big.Int, *big.Int, common.Address) (*types.Transaction, error)); ok { + return rf(opts, consensus, args, fee_args, messageId, deadline, relayer) } - if rf, ok := ret.Get(0).(func(*bind.TransactOpts, compass.Struct2, compass.Struct3, *big.Int, *big.Int) *types.Transaction); ok { - r0 = rf(opts, consensus, args, messageId, deadline) + if rf, ok := ret.Get(0).(func(*bind.TransactOpts, compass.Struct2, compass.Struct3, compass.Struct4, *big.Int, *big.Int, common.Address) *types.Transaction); ok { + r0 = rf(opts, consensus, args, fee_args, messageId, deadline, relayer) } else { if ret.Get(0) != nil { r0 = ret.Get(0).(*types.Transaction) } } - if rf, ok := ret.Get(1).(func(*bind.TransactOpts, compass.Struct2, compass.Struct3, *big.Int, *big.Int) error); ok { - r1 = rf(opts, consensus, args, messageId, deadline) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// TurnstoneId provides a mock function with given fields: opts -func (_m *CompassBinding) TurnstoneId(opts *bind.CallOpts) ([32]byte, error) { - ret := _m.Called(opts) - - if len(ret) == 0 { - panic("no return value specified for TurnstoneId") - } - - var r0 [32]byte - var r1 error - if rf, ok := ret.Get(0).(func(*bind.CallOpts) ([32]byte, error)); ok { - return rf(opts) - } - if rf, ok := ret.Get(0).(func(*bind.CallOpts) [32]byte); ok { - r0 = rf(opts) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).([32]byte) - } - } - - if rf, ok := ret.Get(1).(func(*bind.CallOpts) error); ok { - r1 = rf(opts) + if rf, ok := ret.Get(1).(func(*bind.TransactOpts, compass.Struct2, compass.Struct3, compass.Struct4, *big.Int, *big.Int, common.Address) error); ok { + r1 = rf(opts, consensus, args, fee_args, messageId, deadline, relayer) } else { r1 = ret.Error(1) } @@ -285,9 +290,9 @@ func (_m *CompassBinding) TurnstoneId(opts *bind.CallOpts) ([32]byte, error) { return r0, r1 } -// UpdateValset provides a mock function with given fields: opts, consensus, newValset -func (_m *CompassBinding) UpdateValset(opts *bind.TransactOpts, consensus compass.Struct2, newValset compass.Struct0) (*types.Transaction, error) { - ret := _m.Called(opts, consensus, newValset) +// UpdateValset provides a mock function with given fields: opts, consensus, newValset, relayer, gas_estimate +func (_m *CompassBinding) UpdateValset(opts *bind.TransactOpts, consensus compass.Struct2, newValset compass.Struct0, relayer common.Address, gas_estimate *big.Int) (*types.Transaction, error) { + ret := _m.Called(opts, consensus, newValset, relayer, gas_estimate) if len(ret) == 0 { panic("no return value specified for UpdateValset") @@ -295,19 +300,19 @@ func (_m *CompassBinding) UpdateValset(opts *bind.TransactOpts, consensus compas var r0 *types.Transaction var r1 error - if rf, ok := ret.Get(0).(func(*bind.TransactOpts, compass.Struct2, compass.Struct0) (*types.Transaction, error)); ok { - return rf(opts, consensus, newValset) + if rf, ok := ret.Get(0).(func(*bind.TransactOpts, compass.Struct2, compass.Struct0, common.Address, *big.Int) (*types.Transaction, error)); ok { + return rf(opts, consensus, newValset, relayer, gas_estimate) } - if rf, ok := ret.Get(0).(func(*bind.TransactOpts, compass.Struct2, compass.Struct0) *types.Transaction); ok { - r0 = rf(opts, consensus, newValset) + if rf, ok := ret.Get(0).(func(*bind.TransactOpts, compass.Struct2, compass.Struct0, common.Address, *big.Int) *types.Transaction); ok { + r0 = rf(opts, consensus, newValset, relayer, gas_estimate) } else { if ret.Get(0) != nil { r0 = ret.Get(0).(*types.Transaction) } } - if rf, ok := ret.Get(1).(func(*bind.TransactOpts, compass.Struct2, compass.Struct0) error); ok { - r1 = rf(opts, consensus, newValset) + if rf, ok := ret.Get(1).(func(*bind.TransactOpts, compass.Struct2, compass.Struct0, common.Address, *big.Int) error); ok { + r1 = rf(opts, consensus, newValset, relayer, gas_estimate) } else { r1 = ret.Error(1) } diff --git a/chain/evm/processor.go b/chain/evm/processor.go index 89688779..4e2c2ff2 100644 --- a/chain/evm/processor.go +++ b/chain/evm/processor.go @@ -114,11 +114,44 @@ func (p Processor) ProcessMessages(ctx context.Context, queueTypeName queue.Type return chain.ErrProcessorDoesNotSupportThisQueue.Format(queueTypeName) } - return p.compass.processMessages( + _, err := p.compass.processMessages( ctx, queueTypeName.String(), msgs, + callOptions{}, ) + return err +} + +func (p Processor) EstimateMessages(ctx context.Context, queueTypeName queue.TypeName, msgs []chain.MessageWithSignatures) ([]chain.MessageWithEstimate, error) { + if !queueTypeName.IsTurnstoneQueue() { + return nil, chain.ErrProcessorDoesNotSupportThisQueue.Format(queueTypeName) + } + + txs, err := p.compass.processMessages( + ctx, + queueTypeName.String(), + msgs, + callOptions{}, + ) + if err != nil { + return nil, fmt.Errorf("processor::EstimateMessages: %w", err) + } + + if len(txs) != len(msgs) { + return nil, fmt.Errorf("processor::EstimateMessages: estimated %d messages, but got %d", len(msgs), len(txs)) + } + + res := make([]chain.MessageWithEstimate, 0, len(txs)) + for i, tx := range txs { + res = append(res, chain.MessageWithEstimate{ + MessageWithSignatures: msgs[i], + Estimate: tx.Gas(), + EstimatedByAddress: p.evmClient.addr.Hex(), + }) + } + + return res, nil } func (p Processor) SkywayRelayBatches(ctx context.Context, batches []chain.SkywayBatchWithSignatures) error { @@ -128,6 +161,31 @@ func (p Processor) SkywayRelayBatches(ctx context.Context, batches []chain.Skywa ) } +func (p Processor) SkywayEstimateBatches(ctx context.Context, batches []chain.SkywayBatchWithSignatures) ([]chain.EstimatedSkywayBatch, error) { + res := make([]chain.EstimatedSkywayBatch, 0, len(batches)) + estimates, err := p.compass.skywayEstimateBatches( + ctx, + batches, + ) + if err != nil { + return nil, fmt.Errorf("processor::SkywayEstimateBatches: %w", err) + } + + if len(estimates) != len(batches) { + return nil, fmt.Errorf("processor::SkywayEstimateBatches: estimated %d batches, but got %d", len(batches), len(estimates)) + } + + for i, estimate := range estimates { + res = append(res, chain.EstimatedSkywayBatch{ + OutgoingTxBatch: batches[i].OutgoingTxBatch, + EstimatedByAddress: p.evmClient.addr.Hex(), + Value: estimate, + }) + } + + return res, nil +} + func (p Processor) ProvideEvidence(ctx context.Context, queueTypeName queue.TypeName, msgs []chain.MessageWithSignatures) error { if queueTypeName.IsValidatorsValancesQueue() { return p.compass.provideEvidenceForValidatorBalance( diff --git a/chain/mocks/Processor.go b/chain/mocks/Processor.go index 9ccd169f..86ff0855 100644 --- a/chain/mocks/Processor.go +++ b/chain/mocks/Processor.go @@ -19,6 +19,36 @@ type Processor struct { mock.Mock } +// EstimateMessages provides a mock function with given fields: _a0, _a1, _a2 +func (_m *Processor) EstimateMessages(_a0 context.Context, _a1 queue.TypeName, _a2 []chain.MessageWithSignatures) ([]chain.MessageWithEstimate, error) { + ret := _m.Called(_a0, _a1, _a2) + + if len(ret) == 0 { + panic("no return value specified for EstimateMessages") + } + + var r0 []chain.MessageWithEstimate + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, queue.TypeName, []chain.MessageWithSignatures) ([]chain.MessageWithEstimate, error)); ok { + return rf(_a0, _a1, _a2) + } + if rf, ok := ret.Get(0).(func(context.Context, queue.TypeName, []chain.MessageWithSignatures) []chain.MessageWithEstimate); ok { + r0 = rf(_a0, _a1, _a2) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]chain.MessageWithEstimate) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, queue.TypeName, []chain.MessageWithSignatures) error); ok { + r1 = rf(_a0, _a1, _a2) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + // ExternalAccount provides a mock function with given fields: func (_m *Processor) ExternalAccount() chain.ExternalAccount { ret := _m.Called() @@ -194,6 +224,36 @@ func (_m *Processor) SignMessages(ctx context.Context, messages ...chain.QueuedM return r0, r1 } +// SkywayEstimateBatches provides a mock function with given fields: _a0, _a1 +func (_m *Processor) SkywayEstimateBatches(_a0 context.Context, _a1 []chain.SkywayBatchWithSignatures) ([]chain.EstimatedSkywayBatch, error) { + ret := _m.Called(_a0, _a1) + + if len(ret) == 0 { + panic("no return value specified for SkywayEstimateBatches") + } + + var r0 []chain.EstimatedSkywayBatch + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, []chain.SkywayBatchWithSignatures) ([]chain.EstimatedSkywayBatch, error)); ok { + return rf(_a0, _a1) + } + if rf, ok := ret.Get(0).(func(context.Context, []chain.SkywayBatchWithSignatures) []chain.EstimatedSkywayBatch); ok { + r0 = rf(_a0, _a1) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]chain.EstimatedSkywayBatch) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, []chain.SkywayBatchWithSignatures) error); ok { + r1 = rf(_a0, _a1) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + // SkywayRelayBatches provides a mock function with given fields: _a0, _a1 func (_m *Processor) SkywayRelayBatches(_a0 context.Context, _a1 []chain.SkywayBatchWithSignatures) error { ret := _m.Called(_a0, _a1) @@ -292,7 +352,8 @@ func (_m *Processor) SupportedQueues() []string { func NewProcessor(t interface { mock.TestingT Cleanup(func()) -}) *Processor { +}, +) *Processor { mock := &Processor{} mock.Mock.Test(t) diff --git a/chain/paloma/client.go b/chain/paloma/client.go index aa0e3882..1ffd7bc5 100644 --- a/chain/paloma/client.go +++ b/chain/paloma/client.go @@ -13,6 +13,7 @@ import ( "github.com/cosmos/gogoproto/proto" consensus "github.com/palomachain/paloma/x/consensus/types" valset "github.com/palomachain/paloma/x/valset/types" + "github.com/palomachain/pigeon/chain" "github.com/palomachain/pigeon/config" "github.com/palomachain/pigeon/util/ion" "github.com/palomachain/pigeon/util/slice" @@ -41,10 +42,9 @@ type Client struct { PalomaConfig config.Paloma // This is only needed ONCE ! Can we remove it? GRPCClient grpc.ClientConn - // TODO: Can this shit not be made private??? - Ion IonClient - Unpacker Unpacker - MessageSender MessageSender + ic IonClient + unpacker Unpacker + messageSender MessageSender sendingOpts []ion.SendMsgOption creator string @@ -56,9 +56,9 @@ func NewClient(cfg config.Paloma, grpcWrapper grpc.ClientConn, ion IonClient, se return (&Client{ PalomaConfig: cfg, GRPCClient: grpcWrapper, - Ion: ion, - Unpacker: unpacker, - MessageSender: sender, + ic: ion, + unpacker: unpacker, + messageSender: sender, }).init() } @@ -80,11 +80,11 @@ type BroadcastMessageSignatureIn struct { // BroadcastMessageSignatures takes a list of signatures that need to be sent over to the chain. // It build the message and sends it over. func (c *Client) BroadcastMessageSignatures(ctx context.Context, signatures ...BroadcastMessageSignatureIn) error { - return broadcastMessageSignatures(ctx, c.MessageSender, c.creator, c.sendingOpts, signatures...) + return broadcastMessageSignatures(ctx, c.messageSender, c.creator, c.sendingOpts, signatures...) } func (c *Client) BlockHeight(ctx context.Context) (int64, error) { - res, err := c.Ion.Status(ctx) + res, err := c.ic.Status(ctx) if err != nil { return 0, err } @@ -130,7 +130,7 @@ func (c *Client) AddExternalChainInfo(ctx context.Context, chainInfos ...ChainIn }, ) - _, err := c.MessageSender.SendMsg(ctx, msg, "", c.sendingOpts...) + _, err := c.messageSender.SendMsg(ctx, msg, "", c.sendingOpts...) return err } @@ -148,7 +148,28 @@ func (c *Client) AddMessageEvidence(ctx context.Context, queueTypeName string, m }, } - _, err = c.MessageSender.SendMsg(ctx, msg, "", c.sendingOpts...) + _, err = c.messageSender.SendMsg(ctx, msg, "", c.sendingOpts...) + return err +} + +func (c *Client) AddMessagesGasEstimate(ctx context.Context, queueTypeName string, msgs ...chain.MessageWithEstimate) error { + estimates := make([]*consensus.MsgAddMessageGasEstimates_GasEstimate, len(msgs)) + for i, msg := range msgs { + estimates[i] = &consensus.MsgAddMessageGasEstimates_GasEstimate{ + MsgId: msg.ID, + QueueTypeName: queueTypeName, + Value: msg.Estimate, + EstimatedByAddress: msg.EstimatedByAddress, + } + } + msg := &consensus.MsgAddMessageGasEstimates{ + Estimates: estimates, + Metadata: valset.MsgMetadata{ + Creator: c.creator, + }, + } + + _, err := c.messageSender.SendMsg(ctx, msg, "", c.sendingOpts...) return err } @@ -163,7 +184,7 @@ func (c *Client) SetPublicAccessData(ctx context.Context, queueTypeName string, }, } - _, err := c.MessageSender.SendMsg(ctx, msg, "", c.sendingOpts...) + _, err := c.messageSender.SendMsg(ctx, msg, "", c.sendingOpts...) return err } @@ -177,7 +198,7 @@ func (c *Client) SetErrorData(ctx context.Context, queueTypeName string, message }, } - _, err := c.MessageSender.SendMsg(ctx, msg, "", c.sendingOpts...) + _, err := c.messageSender.SendMsg(ctx, msg, "", c.sendingOpts...) return err } @@ -189,12 +210,12 @@ func (c *Client) KeepValidatorAlive(ctx context.Context, appVersion string) erro }, } - _, err := c.MessageSender.SendMsg(ctx, msg, "", c.sendingOpts...) + _, err := c.messageSender.SendMsg(ctx, msg, "", c.sendingOpts...) return err } func (c *Client) Status(ctx context.Context) (*ResultStatus, error) { - res, err := c.Ion.Status(ctx) + res, err := c.ic.Status(ctx) if err != nil { return nil, err } @@ -218,7 +239,7 @@ func (c *Client) PalomaStatus(ctx context.Context) error { func (c *Client) GetValidator(ctx context.Context) (*stakingtypes.Validator, error) { address := c.GetValidatorAddress().String() - _, err := c.Ion.DecodeBech32ValAddr(address) + _, err := c.ic.DecodeBech32ValAddr(address) if err != nil { return nil, err } @@ -263,7 +284,7 @@ func broadcastMessageSignatures( } func (c *Client) Keyring() keyring.Keyring { - return c.Ion.GetKeybase() + return c.ic.GetKeybase() } func (c *Client) GetValidatorAddress() sdk.ValAddress { @@ -275,7 +296,7 @@ func (c *Client) GetCreator() string { } func (c *Client) GetSigner() string { - addr, err := c.Ion.GetKeyAddress() + addr, err := c.ic.GetKeyAddress() if err != nil { panic(err) } @@ -313,6 +334,6 @@ func getCreatorAsValoper(c *Client) string { } func (c Client) addressString(val sdk.Address) string { - defer (c.Ion.SetSDKContext())() + defer (c.ic.SetSDKContext())() return val.String() } diff --git a/chain/paloma/client_test.go b/chain/paloma/client_test.go index e0661742..58416ba3 100644 --- a/chain/paloma/client_test.go +++ b/chain/paloma/client_test.go @@ -310,7 +310,7 @@ func TestAddingExternalChainInfo(t *testing.T) { mocksrv := tt.mcksrv(t) client := Client{ - MessageSender: mocksrv, + messageSender: mocksrv, } err := client.AddExternalChainInfo( ctx, @@ -368,7 +368,7 @@ func TestKeepValidatorAlive(t *testing.T) { client := Client{ creator: creator, - MessageSender: sender, + messageSender: sender, } err := client.KeepValidatorAlive(ctx, tt.appVersion) diff --git a/chain/paloma/mocks/IonClient.go b/chain/paloma/mocks/IonClient.go index a381f135..f9a35a5b 100644 --- a/chain/paloma/mocks/IonClient.go +++ b/chain/paloma/mocks/IonClient.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.43.1. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package mocks @@ -7,8 +7,10 @@ import ( coretypes "github.com/cometbft/cometbft/rpc/core/types" keyring "github.com/cosmos/cosmos-sdk/crypto/keyring" - types "github.com/cosmos/cosmos-sdk/types" + mock "github.com/stretchr/testify/mock" + + types "github.com/cosmos/cosmos-sdk/types" ) // IonClient is an autogenerated mock type for the IonClient type diff --git a/chain/paloma/mocks/MessageSender.go b/chain/paloma/mocks/MessageSender.go index 721c567d..c9323a43 100644 --- a/chain/paloma/mocks/MessageSender.go +++ b/chain/paloma/mocks/MessageSender.go @@ -1,14 +1,16 @@ -// Code generated by mockery v2.43.1. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package mocks import ( context "context" - types "github.com/cosmos/cosmos-sdk/types" - proto "github.com/cosmos/gogoproto/proto" ion "github.com/palomachain/pigeon/util/ion" mock "github.com/stretchr/testify/mock" + + proto "github.com/cosmos/gogoproto/proto" + + types "github.com/cosmos/cosmos-sdk/types" ) // MessageSender is an autogenerated mock type for the MessageSender type diff --git a/chain/paloma/query.go b/chain/paloma/query.go index a37b9e53..3694d268 100644 --- a/chain/paloma/query.go +++ b/chain/paloma/query.go @@ -2,6 +2,7 @@ package paloma import ( "context" + "math/big" "strings" "github.com/VolumeFi/whoops" @@ -26,7 +27,7 @@ func (c *Client) QueryMessagesForSigning( return queryMessagesForSigning( ctx, c.GRPCClient, - c.Unpacker, + c.unpacker, c.valAddr, queueTypeName, ) @@ -34,24 +35,44 @@ func (c *Client) QueryMessagesForSigning( // QueryMessagesForAttesting returns all messages that are currently in the queue except those already attested for. func (c *Client) QueryMessagesForAttesting(ctx context.Context, queueTypeName string) ([]chain.MessageWithSignatures, error) { - return queryMessagesForAttesting( - ctx, - queueTypeName, - c.valAddr, - c.GRPCClient, - c.Unpacker, - ) + qc := consensus.NewQueryClient(c.GRPCClient) + msgs, err := qc.QueuedMessagesForAttesting(ctx, &consensus.QueryQueuedMessagesForAttestingRequest{ + QueueTypeName: queueTypeName, + ValAddress: c.valAddr, + }) + if err != nil { + return nil, err + } + + return toMessagesWithSignature(msgs.Messages, c.unpacker) +} + +// QueryMessagesForEstimating returns all messages which have not yet been estimated. +func (c *Client) QueryMessagesForEstimating(ctx context.Context, queueTypeName string) ([]chain.MessageWithSignatures, error) { + qc := consensus.NewQueryClient(c.GRPCClient) + msgs, err := qc.QueuedMessagesForGasEstimation(ctx, &consensus.QueryQueuedMessagesForGasEstimationRequest{ + QueueTypeName: queueTypeName, + ValAddress: c.valAddr, + }) + if err != nil { + return nil, err + } + + return toMessagesWithSignature(msgs.MessagesToEstimate, c.unpacker) } // QueryMessagesForRelaying returns all messages that are currently in the queue. func (c *Client) QueryMessagesForRelaying(ctx context.Context, queueTypeName string) ([]chain.MessageWithSignatures, error) { - return queryMessagesForRelaying( - ctx, - queueTypeName, - c.valAddr, - c.GRPCClient, - c.Unpacker, - ) + qc := consensus.NewQueryClient(c.GRPCClient) + msgs, err := qc.QueuedMessagesForRelaying(ctx, &consensus.QueryQueuedMessagesForRelayingRequest{ + QueueTypeName: queueTypeName, + ValAddress: c.valAddr, + }) + if err != nil { + return nil, err + } + + return toMessagesWithSignature(msgs.Messages, c.unpacker) } // QueryValidatorInfo returns info about the validator. @@ -210,25 +231,10 @@ func queryMessagesForSigning( return res, nil } -func queryMessagesForRelaying( - ctx context.Context, - queueTypeName string, - valAddress sdk.ValAddress, - c grpc.ClientConn, - anyunpacker codectypes.AnyUnpacker, -) ([]chain.MessageWithSignatures, error) { - qc := consensus.NewQueryClient(c) - msgs, err := qc.QueuedMessagesForRelaying(ctx, &consensus.QueryQueuedMessagesForRelayingRequest{ - QueueTypeName: queueTypeName, - ValAddress: valAddress, - }) - if err != nil { - return nil, err - } - - msgsWithSig := make([]chain.MessageWithSignatures, len(msgs.Messages)) +func toMessagesWithSignature(msgs []consensus.MessageWithSignatures, unpacker codectypes.AnyUnpacker) ([]chain.MessageWithSignatures, error) { + msgsWithSig := make([]chain.MessageWithSignatures, len(msgs)) - for i, msg := range msgs.Messages { + for i, msg := range msgs { valSigs := make([]chain.ValidatorSignature, len(msg.SignData)) for j, vs := range msg.SignData { valSigs[j] = chain.ValidatorSignature{ @@ -237,56 +243,13 @@ func queryMessagesForRelaying( } } var ptr consensus.ConsensusMsg - err := anyunpacker.UnpackAny(msg.GetMsg(), &ptr) + err := unpacker.UnpackAny(msg.GetMsg(), &ptr) if err != nil { return nil, err } - msgsWithSig[i] = chain.MessageWithSignatures{ - QueuedMessage: chain.QueuedMessage{ - ID: msg.Id, - Nonce: msg.Nonce, - Msg: ptr, - BytesToSign: msg.GetBytesToSign(), - PublicAccessData: msg.GetPublicAccessData(), - ErrorData: msg.GetErrorData(), - }, - Signatures: valSigs, - } - } - return msgsWithSig, err -} - -func queryMessagesForAttesting( - ctx context.Context, - queueTypeName string, - valAddress sdk.ValAddress, - c grpc.ClientConn, - anyunpacker codectypes.AnyUnpacker, -) ([]chain.MessageWithSignatures, error) { - qc := consensus.NewQueryClient(c) - msgs, err := qc.QueuedMessagesForAttesting(ctx, &consensus.QueryQueuedMessagesForAttestingRequest{ - QueueTypeName: queueTypeName, - ValAddress: valAddress, - }) - if err != nil { - return nil, err - } - - msgsWithSig := make([]chain.MessageWithSignatures, len(msgs.Messages)) - for i, msg := range msgs.Messages { - valSigs := make([]chain.ValidatorSignature, len(msg.SignData)) - for j, vs := range msg.SignData { - valSigs[j] = chain.ValidatorSignature{ - // ValAddress: vs.GetValAddress(), - Signature: vs.GetSignature(), - SignedByAddress: vs.GetExternalAccountAddress(), - // PublicKey: vs.GetPublicKey(), - } - } - var ptr consensus.ConsensusMsg - err := anyunpacker.UnpackAny(msg.GetMsg(), &ptr) - if err != nil { - return nil, err + var estimate *big.Int = nil + if msg.GasEstimate > 0 { + estimate = big.NewInt(0).SetUint64(msg.GasEstimate) } msgsWithSig[i] = chain.MessageWithSignatures{ QueuedMessage: chain.QueuedMessage{ @@ -296,9 +259,11 @@ func queryMessagesForAttesting( BytesToSign: msg.GetBytesToSign(), PublicAccessData: msg.GetPublicAccessData(), ErrorData: msg.GetErrorData(), + Estimate: estimate, }, Signatures: valSigs, } } - return msgsWithSig, err + + return msgsWithSig, nil } diff --git a/chain/paloma/skyway.go b/chain/paloma/skyway.go index cab1d1f6..8d293664 100644 --- a/chain/paloma/skyway.go +++ b/chain/paloma/skyway.go @@ -40,7 +40,7 @@ func (c *Client) SkywayConfirmBatches(ctx context.Context, signatures ...chain.S Orchestrator: c.creator, Signature: hex.EncodeToString(signedBatch.Signature), } - _, err := c.MessageSender.SendMsg(ctx, msg, "", c.sendingOpts...) + _, err := c.messageSender.SendMsg(ctx, msg, "", c.sendingOpts...) return err } @@ -61,8 +61,61 @@ func (c *Client) SkywayQueryBatchesForRelaying(ctx context.Context, chainReferen return nil, err } - batchesWithSignatures := make([]chain.SkywayBatchWithSignatures, len(batches.Batches)) - for i, batch := range batches.Batches { + return skywayLoadConfirms(ctx, qc, batches.Batches) +} + +func (c *Client) SkywayQueryLastPendingBatchForGasEstimation(ctx context.Context, chainReferenceID string) ([]chain.SkywayBatchWithSignatures, error) { + qc := skyway.NewQueryClient(c.GRPCClient) + res, err := qc.LastPendingBatchForGasEstimation(ctx, &skyway.QueryLastPendingBatchForGasEstimationRequest{ + Address: c.valAddr, + ChainReferenceId: chainReferenceID, + }) + if err != nil { + return nil, err + } + + return skywayLoadConfirms(ctx, qc, res.Batch) +} + +func (c *Client) SkywayEstimateBatchGas(ctx context.Context, estimates ...chain.EstimatedSkywayBatch) error { + if len(estimates) == 0 { + return nil + } + for _, v := range estimates { + msg := &skyway.MsgEstimateBatchGas{ + Nonce: v.BatchNonce, + TokenContract: v.TokenContract, + EthSigner: v.EstimatedByAddress, + Estimate: v.Value, + } + _, err := c.messageSender.SendMsg(ctx, msg, "", c.sendingOpts...) + if err != nil { + return err + } + + } + return nil +} + +// TODO: Combine with below method +func (c *Client) SendBatchSendToEVMClaim(ctx context.Context, claim skyway.MsgBatchSendToRemoteClaim) error { + _, err := c.messageSender.SendMsg(ctx, &claim, "", c.sendingOpts...) + return err +} + +func (c *Client) SendSendToPalomaClaim(ctx context.Context, claim skyway.MsgSendToPalomaClaim) error { + _, err := c.messageSender.SendMsg(ctx, &claim, "", c.sendingOpts...) + return err +} + +func (c *Client) SendLightNodeSaleClaim(ctx context.Context, claim skyway.MsgLightNodeSaleClaim) error { + _, err := c.messageSender.SendMsg(ctx, &claim, "", c.sendingOpts...) + return err +} + +func skywayLoadConfirms(ctx context.Context, qc skyway.QueryClient, in []skyway.OutgoingTxBatch) ([]chain.SkywayBatchWithSignatures, error) { + batchesWithSignatures := make([]chain.SkywayBatchWithSignatures, len(in)) + for i, batch := range in { confirms, err := qc.BatchConfirms(ctx, &skyway.QueryBatchConfirmsRequest{ Nonce: batch.BatchNonce, ContractAddress: batch.TokenContract, @@ -88,22 +141,5 @@ func (c *Client) SkywayQueryBatchesForRelaying(ctx context.Context, chainReferen } } - return batchesWithSignatures, nil } - -// TODO: Combine with below method -func (c *Client) SendBatchSendToEVMClaim(ctx context.Context, claim skyway.MsgBatchSendToRemoteClaim) error { - _, err := c.MessageSender.SendMsg(ctx, &claim, "", c.sendingOpts...) - return err -} - -func (c *Client) SendSendToPalomaClaim(ctx context.Context, claim skyway.MsgSendToPalomaClaim) error { - _, err := c.MessageSender.SendMsg(ctx, &claim, "", c.sendingOpts...) - return err -} - -func (c *Client) SendLightNodeSaleClaim(ctx context.Context, claim skyway.MsgLightNodeSaleClaim) error { - _, err := c.MessageSender.SendMsg(ctx, &claim, "", c.sendingOpts...) - return err -} diff --git a/chain/paloma/statusupdater.go b/chain/paloma/statusupdater.go index d7ad7d46..2ebd4dc8 100644 --- a/chain/paloma/statusupdater.go +++ b/chain/paloma/statusupdater.go @@ -111,6 +111,6 @@ func (s *statusUpdater) update(ctx context.Context) error { Args: args, } - _, err := s.c.MessageSender.SendMsg(ctx, msg, "", s.c.sendingOpts...) + _, err := s.c.messageSender.SendMsg(ctx, msg, "", s.c.sendingOpts...) return err } diff --git a/chain/paloma/statusupdater_test.go b/chain/paloma/statusupdater_test.go index 83aa88d3..d28bd4e2 100644 --- a/chain/paloma/statusupdater_test.go +++ b/chain/paloma/statusupdater_test.go @@ -38,7 +38,7 @@ func TestStatusUpdater(t *testing.T) { } t.Run("with error during sending", func(t *testing.T) { m := mocks.NewMessageSender(t) - client := Client{MessageSender: m} + client := Client{messageSender: m} m.On("SendMsg", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil, fmt.Errorf("fail")) err := client.NewStatus().Debug(context.Background()) require.Error(t, err) @@ -201,7 +201,7 @@ func TestStatusUpdater(t *testing.T) { msg := tt.setup() msg.Level = cfg.level ms.On("SendMsg", mock.Anything, mock.MatchedBy(matchArgs(msg)), mock.Anything).Return(nil, nil) - client := Client{MessageSender: ms} + client := Client{messageSender: ms} cfg.exec(tt.exec(&client)) }) } diff --git a/chain/relayer.go b/chain/relayer.go index 4f412b1f..8bcf7230 100644 --- a/chain/relayer.go +++ b/chain/relayer.go @@ -2,6 +2,7 @@ package chain import ( "context" + "math/big" sdk "github.com/cosmos/cosmos-sdk/types" skyway "github.com/palomachain/paloma/x/skyway/types" @@ -16,6 +17,7 @@ type QueuedMessage struct { PublicAccessData []byte ErrorData []byte Msg any + Estimate *big.Int } type SignedQueuedMessage struct { @@ -52,6 +54,12 @@ type MessageWithSignatures struct { Signatures []ValidatorSignature } +type MessageWithEstimate struct { + MessageWithSignatures + Estimate uint64 + EstimatedByAddress string +} + func (msg MessageWithSignatures) GetSignatures() []ValidatorSignature { return msg.Signatures } @@ -65,6 +73,12 @@ type SkywayBatchWithSignatures struct { Signatures []ValidatorSignature } +type EstimatedSkywayBatch struct { + skyway.OutgoingTxBatch + EstimatedByAddress string + Value uint64 +} + func (gb SkywayBatchWithSignatures) GetSignatures() []ValidatorSignature { return gb.Signatures } @@ -146,6 +160,8 @@ type Processor interface { // to ensure that there are enough signatures for consensus. ProcessMessages(context.Context, queue.TypeName, []MessageWithSignatures) error + EstimateMessages(context.Context, queue.TypeName, []MessageWithSignatures) ([]MessageWithEstimate, error) + // ProvideEvidence takes a queue name and a list of messages that have already been executed. This // takes the "public evidence" from the message and gets the information back to the Paloma. ProvideEvidence(context.Context, queue.TypeName, []MessageWithSignatures) error @@ -156,6 +172,7 @@ type Processor interface { IsRightChain(ctx context.Context) error SkywaySignBatches(context.Context, ...skyway.OutgoingTxBatch) ([]SignedSkywayOutgoingTxBatch, error) + SkywayEstimateBatches(context.Context, []SkywayBatchWithSignatures) ([]EstimatedSkywayBatch, error) SkywayRelayBatches(context.Context, []SkywayBatchWithSignatures) error GetSkywayEvents(context.Context, string) ([]SkywayEventer, error) diff --git a/go.mod b/go.mod index 7efe0bb2..e1a09f12 100644 --- a/go.mod +++ b/go.mod @@ -22,7 +22,7 @@ require ( github.com/jarcoal/httpmock v1.3.1 github.com/onsi/ginkgo/v2 v2.19.0 github.com/onsi/gomega v1.33.1 - github.com/palomachain/paloma v1.15.6 + github.com/palomachain/paloma v1.15.5 github.com/roodeag/arbitrum v0.0.0-20230627104516-b95e4c8ebec0 github.com/rs/xid v1.5.0 github.com/sirupsen/logrus v1.9.3 @@ -229,6 +229,7 @@ require ( replace ( // Link to op-geth, which is built on top of go-ethereum github.com/ethereum/go-ethereum => github.com/ethereum-optimism/op-geth v1.101311.0 + github.com/palomachain/paloma => github.com/palomachain/paloma v1.3.1-next.0.20240808095442-ad824cc65492 github.com/roodeag/arbitrum => github.com/palomachain/arb-geth v0.0.0-20230824112942-8e77a580a936 ) diff --git a/go.sum b/go.sum index bd740f56..3097ed63 100644 --- a/go.sum +++ b/go.sum @@ -949,8 +949,8 @@ github.com/ory/dockertest v3.3.5+incompatible/go.mod h1:1vX4m9wsvi00u5bseYwXaSnh github.com/pact-foundation/pact-go v1.0.4/go.mod h1:uExwJY4kCzNPcHRj+hCR/HBbOOIwwtUjcrb0b5/5kLM= github.com/palomachain/arb-geth v0.0.0-20230824112942-8e77a580a936 h1:fmQAgxcdYBxCZYczws/uxTVOYHZd4fNrOaoHp35HZMM= github.com/palomachain/arb-geth v0.0.0-20230824112942-8e77a580a936/go.mod h1:B2H2+2I4UiMR4hvAIaGLyYszNfSTYC8fWIw+kgfuFSQ= -github.com/palomachain/paloma v1.15.6 h1:V9Mx460obbaOfwgf13KpUaZp9DHZRKMwHdZM5etGktw= -github.com/palomachain/paloma v1.15.6/go.mod h1:91O0VRxBof+IXTZxSsSbk/lV2DSaWQIdUaoCBv6HXDo= +github.com/palomachain/paloma v1.3.1-next.0.20240808095442-ad824cc65492 h1:BBqlRicqEoJTURM0z127RSc2ZXLZ8IGgSC83narQOg8= +github.com/palomachain/paloma v1.3.1-next.0.20240808095442-ad824cc65492/go.mod h1:91O0VRxBof+IXTZxSsSbk/lV2DSaWQIdUaoCBv6HXDo= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= diff --git a/health/mocks/PalomaStatuser.go b/health/mocks/PalomaStatuser.go index 14a49aff..464fa629 100644 --- a/health/mocks/PalomaStatuser.go +++ b/health/mocks/PalomaStatuser.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package mocks @@ -17,6 +17,10 @@ type PalomaStatuser struct { func (_m *PalomaStatuser) PalomaStatus(ctx context.Context) error { ret := _m.Called(ctx) + if len(ret) == 0 { + panic("no return value specified for PalomaStatus") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context) error); ok { r0 = rf(ctx) diff --git a/relayer/build_processors.go b/relayer/build_processors.go index efbfee16..a6a56d10 100644 --- a/relayer/build_processors.go +++ b/relayer/build_processors.go @@ -87,6 +87,7 @@ func (r *Relayer) processorFactory(chainInfo *evmtypes.ChainInfo) (chain.Process string(chainInfo.GetSmartContractUniqueID()), chainInfo.GetAbi(), chainInfo.GetSmartContractAddr(), + chainInfo.GetFeeManagerAddr(), chainID, int64(chainInfo.GetReferenceBlockHeight()), common.HexToHash(chainInfo.GetReferenceBlockHash()), diff --git a/relayer/build_processors_test.go b/relayer/build_processors_test.go index 8ba29156..c99d9be1 100644 --- a/relayer/build_processors_test.go +++ b/relayer/build_processors_test.go @@ -45,7 +45,7 @@ func TestBuildProcessors(t *testing.T) { processorMock.On("IsRightChain", mock.Anything).Return(nil) evmFactoryMock := mocks.NewEvmFactorier(t) - evmFactoryMock.On("Build", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(processorMock, nil) + evmFactoryMock.On("Build", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(processorMock, nil) r := New( &config.Config{ @@ -95,7 +95,7 @@ func TestBuildProcessors(t *testing.T) { processorMock.On("IsRightChain", mock.Anything).Return(nil) evmFactoryMock := mocks.NewEvmFactorier(t) - evmFactoryMock.On("Build", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(processorMock, nil) + evmFactoryMock.On("Build", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(processorMock, nil) r := New( &config.Config{ @@ -151,7 +151,7 @@ func TestBuildProcessors(t *testing.T) { processorMock.On("IsRightChain", mock.Anything).Return(nil) evmFactoryMock := mocks.NewEvmFactorier(t) - evmFactoryMock.On("Build", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(processorMock, nil) + evmFactoryMock.On("Build", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(processorMock, nil) r := New( &config.Config{ @@ -212,7 +212,7 @@ func TestBuildProcessors(t *testing.T) { processorMock.On("IsRightChain", mock.Anything).Return(nil) evmFactoryMock := mocks.NewEvmFactorier(t) - evmFactoryMock.On("Build", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(processorMock, nil) + evmFactoryMock.On("Build", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(processorMock, nil) r := New( &config.Config{ diff --git a/relayer/health_check_test.go b/relayer/health_check_test.go index 51761af5..4f4f1bf4 100644 --- a/relayer/health_check_test.go +++ b/relayer/health_check_test.go @@ -95,7 +95,7 @@ var _ = Describe("health check", func() { MinOnChainBalance: "100000", }, }, nil) - fm.On("Build", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(pm, nil) + fm.On("Build", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(pm, nil) m.On("GetValidator", mock.Anything).Return(val, nil) pm.On("HealthCheck", mock.Anything).Return(retErr) @@ -122,7 +122,7 @@ var _ = Describe("health check", func() { MinOnChainBalance: "100000", }, }, nil) - fm.On("Build", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(pm, nil) + fm.On("Build", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(pm, nil) m.On("GetValidator", mock.Anything).Return(val, nil) pm.On("HealthCheck", mock.Anything).Return(retErr) @@ -153,7 +153,7 @@ var _ = Describe("health check", func() { MinOnChainBalance: "100000", }, }, nil) - fm.On("Build", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(pm, nil) + fm.On("Build", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(pm, nil) m.On("GetValidator", mock.Anything).Return(val, nil) pm.On("HealthCheck", mock.Anything).Return(retErr) diff --git a/relayer/message_attester_test.go b/relayer/message_attester_test.go index 68925b92..3dc28e75 100644 --- a/relayer/message_attester_test.go +++ b/relayer/message_attester_test.go @@ -92,7 +92,7 @@ func TestAttestMessages(t *testing.T) { factory := mocks.NewEvmFactorier(t) - factory.On("Build", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(p, nil) + factory.On("Build", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(p, nil) return New( &config.Config{ @@ -141,7 +141,7 @@ func TestAttestMessages(t *testing.T) { factory := mocks.NewEvmFactorier(t) - factory.On("Build", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(p, nil) + factory.On("Build", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(p, nil) return New( &config.Config{ diff --git a/relayer/message_estimator.go b/relayer/message_estimator.go new file mode 100644 index 00000000..f8264cb4 --- /dev/null +++ b/relayer/message_estimator.go @@ -0,0 +1,82 @@ +package relayer + +import ( + "context" + "sync" + + "github.com/palomachain/pigeon/chain" + "github.com/palomachain/pigeon/internal/queue" + "github.com/palomachain/pigeon/util/slice" + log "github.com/sirupsen/logrus" +) + +func (r *Relayer) EstimateMessages(ctx context.Context, _ sync.Locker) error { + log.Info("estimator loop") + if ctx.Err() != nil { + log.Info("exiting estimator loop as context has ended") + return ctx.Err() + } + + err := r.buildProcessors(ctx, nil) + if err != nil { + return err + } + + err = r.estimateMessages(ctx, r.processors) + if err != nil { + return handleProcessError(ctx, err) + } + + return handleProcessError(ctx, err) +} + +func (r *Relayer) estimateMessages(ctx context.Context, processors []chain.Processor) error { + if len(processors) == 0 { + return nil + } + + for _, p := range processors { + for _, queueName := range p.SupportedQueues() { + logger := log.WithFields(log.Fields{ + "queue-name": queueName, + "action": "estimate", + }) + + messagesInQueue, err := r.palomaClient.QueryMessagesForEstimating(ctx, queueName) + + logger = logger.WithFields(log.Fields{ + "message-ids": slice.Map(messagesInQueue, func(msg chain.MessageWithSignatures) uint64 { + return msg.ID + }), + }) + + logger.Debug("got ", len(messagesInQueue), " messages from ", queueName) + if err != nil { + logger.WithError(err).Error("couldn't get messages to estimate") + return err + } + + if len(messagesInQueue) > 0 { + logger := logger.WithFields(log.Fields{ + "messages-to-estimate": slice.Map(messagesInQueue, func(msg chain.MessageWithSignatures) uint64 { + return msg.ID + }), + }) + logger.Info("estimating ", len(messagesInQueue), " messages") + estimates, err := p.EstimateMessages(ctx, queue.FromString(queueName), messagesInQueue) + if err != nil { + logger.WithError(err).Error("error estimating messages") + return err + } + + err = r.palomaClient.AddMessagesGasEstimate(ctx, queueName, estimates...) + if err != nil { + logger.WithError(err).Error("failed to send estimates to Paloma") + return err + } + } + + } + } + return nil +} diff --git a/relayer/message_estimator_test.go b/relayer/message_estimator_test.go new file mode 100644 index 00000000..24028209 --- /dev/null +++ b/relayer/message_estimator_test.go @@ -0,0 +1,155 @@ +package relayer + +import ( + "context" + "os" + "testing" + + "github.com/ethereum/go-ethereum/common" + evmtypes "github.com/palomachain/paloma/x/evm/types" + "github.com/palomachain/pigeon/chain" + "github.com/palomachain/pigeon/chain/evm" + evmmocks "github.com/palomachain/pigeon/chain/evm/mocks" + chainmocks "github.com/palomachain/pigeon/chain/mocks" + "github.com/palomachain/pigeon/config" + "github.com/palomachain/pigeon/internal/queue" + "github.com/palomachain/pigeon/relayer/mocks" + "github.com/palomachain/pigeon/testutil" + timemocks "github.com/palomachain/pigeon/util/time/mocks" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/require" +) + +func TestEstimateMessages(t *testing.T) { + ctx := context.Background() + testcases := []struct { + name string + setup func(t *testing.T) *Relayer + expErr error + }{ + { + name: "without any processor it does nothing", + setup: func(t *testing.T) *Relayer { + pc := mocks.NewPalomaClienter(t) + pc.On("QueryGetEVMChainInfos", mock.Anything, mock.Anything).Return(nil, nil) + r := New( + &config.Config{}, + pc, + evm.NewFactory(evmmocks.NewPalomaClienter(t)), + timemocks.NewTime(t), + Config{}, + ) + return r + }, + }, + { + name: "it estimates messages", + setup: func(t *testing.T) *Relayer { + keyringPass := "abcd" + + dir := t.TempDir() + keyring := evm.OpenKeystore(dir) + acc, err := keyring.NewAccount(keyringPass) + require.NoError(t, err) + estimates := []chain.MessageWithEstimate{ + { + MessageWithSignatures: chain.MessageWithSignatures{ + QueuedMessage: chain.QueuedMessage{ID: 1}, + }, + Estimate: 21_000, + EstimatedByAddress: "validator", + }, + { + MessageWithSignatures: chain.MessageWithSignatures{ + QueuedMessage: chain.QueuedMessage{ID: 2}, + }, + Estimate: 22_000, + EstimatedByAddress: "validator", + }, + { + MessageWithSignatures: chain.MessageWithSignatures{ + QueuedMessage: chain.QueuedMessage{ID: 3}, + }, + Estimate: 23_000, + EstimatedByAddress: "validator", + }, + } + + p := chainmocks.NewProcessor(t) + p.On("IsRightChain", mock.Anything).Return(nil) + p.On("SupportedQueues").Return([]string{"a"}) + p.On( + "EstimateMessages", + mock.Anything, + queue.FromString("a"), + []chain.MessageWithSignatures{ + {QueuedMessage: chain.QueuedMessage{ID: 1}}, + {QueuedMessage: chain.QueuedMessage{ID: 2}}, + {QueuedMessage: chain.QueuedMessage{ID: 3}}, + }, + ).Return(estimates, nil) + + pal := mocks.NewPalomaClienter(t) + pal.On("QueryGetEVMChainInfos", mock.Anything, mock.Anything).Return([]*evmtypes.ChainInfo{ + { + ChainReferenceID: "main", + ChainID: 5, + SmartContractUniqueID: []byte("5"), + SmartContractAddr: common.BytesToAddress([]byte("abcd")).Hex(), + ReferenceBlockHeight: 5, + ReferenceBlockHash: "0x12", + MinOnChainBalance: "10000", + }, + }, nil) + pal.On("QueryMessagesForEstimating", mock.Anything, mock.Anything).Return( + []chain.MessageWithSignatures{ + {QueuedMessage: chain.QueuedMessage{ID: 1}}, + {QueuedMessage: chain.QueuedMessage{ID: 2}}, + {QueuedMessage: chain.QueuedMessage{ID: 3}}, + }, + nil, + ) + pal.On("AddMessagesGasEstimate", mock.Anything, mock.Anything, estimates[0], estimates[1], estimates[2]).Return(nil) + + os.Setenv("TEST_PASS", keyringPass) + t.Cleanup(func() { + os.Unsetenv("TEST_PASS") + }) + + factory := mocks.NewEvmFactorier(t) + + factory.On("Build", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(p, nil) + + return New( + &config.Config{ + EVM: map[string]config.EVM{ + "main": { + ChainClientConfig: config.ChainClientConfig{ + KeyringPassEnvName: "TEST_PASS", + SigningKey: acc.Address.Hex(), + KeyringDirectory: config.Filepath(dir), + }, + }, + }, + }, + pal, + factory, + timemocks.NewTime(t), + Config{}, + ) + }, + }, + } + + for _, tt := range testcases { + asserter := assert.New(t) + t.Run(tt.name, func(t *testing.T) { + relayer := tt.setup(t) + + var locker testutil.FakeMutex + actualErr := relayer.EstimateMessages(ctx, &locker) + asserter.Equal(tt.expErr, actualErr) + }) + } +} diff --git a/relayer/message_relayer_test.go b/relayer/message_relayer_test.go index 294ac38e..96c33fe3 100644 --- a/relayer/message_relayer_test.go +++ b/relayer/message_relayer_test.go @@ -95,7 +95,7 @@ func TestRelayMessages(t *testing.T) { factory := mocks.NewEvmFactorier(t) - factory.On("Build", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(p, nil) + factory.On("Build", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(p, nil) return New( &config.Config{ @@ -144,7 +144,7 @@ func TestRelayMessages(t *testing.T) { factory := mocks.NewEvmFactorier(t) - factory.On("Build", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(p, nil) + factory.On("Build", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(p, nil) return New( &config.Config{ diff --git a/relayer/message_signer_test.go b/relayer/message_signer_test.go index a7ada50a..9d51b6c6 100644 --- a/relayer/message_signer_test.go +++ b/relayer/message_signer_test.go @@ -86,7 +86,7 @@ func TestSignMessages(t *testing.T) { factory := mocks.NewEvmFactorier(t) - factory.On("Build", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(p, nil) + factory.On("Build", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(p, nil) return New( &config.Config{ @@ -135,7 +135,7 @@ func TestSignMessages(t *testing.T) { factory := mocks.NewEvmFactorier(t) - factory.On("Build", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(p, nil) + factory.On("Build", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(p, nil) return New( &config.Config{ diff --git a/relayer/mocks/EvmFactorier.go b/relayer/mocks/EvmFactorier.go index ff13e61e..108626bd 100644 --- a/relayer/mocks/EvmFactorier.go +++ b/relayer/mocks/EvmFactorier.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.38.0. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package mocks @@ -7,8 +7,11 @@ import ( common "github.com/ethereum/go-ethereum/common" chain "github.com/palomachain/pigeon/chain" + config "github.com/palomachain/pigeon/config" + mev "github.com/palomachain/pigeon/internal/mev" + mock "github.com/stretchr/testify/mock" ) @@ -17,9 +20,9 @@ type EvmFactorier struct { mock.Mock } -// Build provides a mock function with given fields: cfg, chainReferenceID, smartContractID, smartContractABIJson, smartContractAddress, chainID, blockHeight, blockHeightHash, minOnChainBalance, mevClient -func (_m *EvmFactorier) Build(cfg config.EVM, chainReferenceID string, smartContractID string, smartContractABIJson string, smartContractAddress string, chainID *big.Int, blockHeight int64, blockHeightHash common.Hash, minOnChainBalance *big.Int, mevClient mev.Client) (chain.Processor, error) { - ret := _m.Called(cfg, chainReferenceID, smartContractID, smartContractABIJson, smartContractAddress, chainID, blockHeight, blockHeightHash, minOnChainBalance, mevClient) +// Build provides a mock function with given fields: cfg, chainReferenceID, smartContractID, smartContractABIJson, smartContractAddress, feeMgrContractAddress, chainID, blockHeight, blockHeightHash, minOnChainBalance, mevClient +func (_m *EvmFactorier) Build(cfg config.EVM, chainReferenceID string, smartContractID string, smartContractABIJson string, smartContractAddress string, feeMgrContractAddress string, chainID *big.Int, blockHeight int64, blockHeightHash common.Hash, minOnChainBalance *big.Int, mevClient mev.Client) (chain.Processor, error) { + ret := _m.Called(cfg, chainReferenceID, smartContractID, smartContractABIJson, smartContractAddress, feeMgrContractAddress, chainID, blockHeight, blockHeightHash, minOnChainBalance, mevClient) if len(ret) == 0 { panic("no return value specified for Build") @@ -27,19 +30,19 @@ func (_m *EvmFactorier) Build(cfg config.EVM, chainReferenceID string, smartCont var r0 chain.Processor var r1 error - if rf, ok := ret.Get(0).(func(config.EVM, string, string, string, string, *big.Int, int64, common.Hash, *big.Int, mev.Client) (chain.Processor, error)); ok { - return rf(cfg, chainReferenceID, smartContractID, smartContractABIJson, smartContractAddress, chainID, blockHeight, blockHeightHash, minOnChainBalance, mevClient) + if rf, ok := ret.Get(0).(func(config.EVM, string, string, string, string, string, *big.Int, int64, common.Hash, *big.Int, mev.Client) (chain.Processor, error)); ok { + return rf(cfg, chainReferenceID, smartContractID, smartContractABIJson, smartContractAddress, feeMgrContractAddress, chainID, blockHeight, blockHeightHash, minOnChainBalance, mevClient) } - if rf, ok := ret.Get(0).(func(config.EVM, string, string, string, string, *big.Int, int64, common.Hash, *big.Int, mev.Client) chain.Processor); ok { - r0 = rf(cfg, chainReferenceID, smartContractID, smartContractABIJson, smartContractAddress, chainID, blockHeight, blockHeightHash, minOnChainBalance, mevClient) + if rf, ok := ret.Get(0).(func(config.EVM, string, string, string, string, string, *big.Int, int64, common.Hash, *big.Int, mev.Client) chain.Processor); ok { + r0 = rf(cfg, chainReferenceID, smartContractID, smartContractABIJson, smartContractAddress, feeMgrContractAddress, chainID, blockHeight, blockHeightHash, minOnChainBalance, mevClient) } else { if ret.Get(0) != nil { r0 = ret.Get(0).(chain.Processor) } } - if rf, ok := ret.Get(1).(func(config.EVM, string, string, string, string, *big.Int, int64, common.Hash, *big.Int, mev.Client) error); ok { - r1 = rf(cfg, chainReferenceID, smartContractID, smartContractABIJson, smartContractAddress, chainID, blockHeight, blockHeightHash, minOnChainBalance, mevClient) + if rf, ok := ret.Get(1).(func(config.EVM, string, string, string, string, string, *big.Int, int64, common.Hash, *big.Int, mev.Client) error); ok { + r1 = rf(cfg, chainReferenceID, smartContractID, smartContractABIJson, smartContractAddress, feeMgrContractAddress, chainID, blockHeight, blockHeightHash, minOnChainBalance, mevClient) } else { r1 = ret.Error(1) } diff --git a/relayer/mocks/PalomaClienter.go b/relayer/mocks/PalomaClienter.go index e4a689a6..b788241d 100644 --- a/relayer/mocks/PalomaClienter.go +++ b/relayer/mocks/PalomaClienter.go @@ -72,6 +72,31 @@ func (_m *PalomaClienter) AddMessageEvidence(ctx context.Context, queueTypeName return r0 } +// AddMessagesGasEstimate provides a mock function with given fields: ctx, queueTypeName, msgs +func (_m *PalomaClienter) AddMessagesGasEstimate(ctx context.Context, queueTypeName string, msgs ...chain.MessageWithEstimate) error { + _va := make([]interface{}, len(msgs)) + for _i := range msgs { + _va[_i] = msgs[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, queueTypeName) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for AddMessagesGasEstimate") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, string, ...chain.MessageWithEstimate) error); ok { + r0 = rf(ctx, queueTypeName, msgs...) + } else { + r0 = ret.Error(0) + } + + return r0 +} + // BlockHeight provides a mock function with given fields: _a0 func (_m *PalomaClienter) BlockHeight(_a0 context.Context) (int64, error) { ret := _m.Called(_a0) @@ -379,6 +404,36 @@ func (_m *PalomaClienter) QueryMessagesForAttesting(ctx context.Context, queueTy return r0, r1 } +// QueryMessagesForEstimating provides a mock function with given fields: ctx, queueTypeName +func (_m *PalomaClienter) QueryMessagesForEstimating(ctx context.Context, queueTypeName string) ([]chain.MessageWithSignatures, error) { + ret := _m.Called(ctx, queueTypeName) + + if len(ret) == 0 { + panic("no return value specified for QueryMessagesForEstimating") + } + + var r0 []chain.MessageWithSignatures + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, string) ([]chain.MessageWithSignatures, error)); ok { + return rf(ctx, queueTypeName) + } + if rf, ok := ret.Get(0).(func(context.Context, string) []chain.MessageWithSignatures); ok { + r0 = rf(ctx, queueTypeName) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]chain.MessageWithSignatures) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, string) error); ok { + r1 = rf(ctx, queueTypeName) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + // QueryMessagesForRelaying provides a mock function with given fields: ctx, queueTypeName func (_m *PalomaClienter) QueryMessagesForRelaying(ctx context.Context, queueTypeName string) ([]chain.MessageWithSignatures, error) { ret := _m.Called(ctx, queueTypeName) @@ -530,6 +585,31 @@ func (_m *PalomaClienter) SkywayConfirmBatches(ctx context.Context, signatures . return r0 } +// SkywayEstimateBatchGas provides a mock function with given fields: ctx, estimates +func (_m *PalomaClienter) SkywayEstimateBatchGas(ctx context.Context, estimates ...chain.EstimatedSkywayBatch) error { + _va := make([]interface{}, len(estimates)) + for _i := range estimates { + _va[_i] = estimates[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for SkywayEstimateBatchGas") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, ...chain.EstimatedSkywayBatch) error); ok { + r0 = rf(ctx, estimates...) + } else { + r0 = ret.Error(0) + } + + return r0 +} + // SkywayQueryBatchesForRelaying provides a mock function with given fields: ctx, chainReferenceID func (_m *PalomaClienter) SkywayQueryBatchesForRelaying(ctx context.Context, chainReferenceID string) ([]chain.SkywayBatchWithSignatures, error) { ret := _m.Called(ctx, chainReferenceID) @@ -560,6 +640,36 @@ func (_m *PalomaClienter) SkywayQueryBatchesForRelaying(ctx context.Context, cha return r0, r1 } +// SkywayQueryLastPendingBatchForGasEstimation provides a mock function with given fields: ctx, chainReferenceID +func (_m *PalomaClienter) SkywayQueryLastPendingBatchForGasEstimation(ctx context.Context, chainReferenceID string) ([]chain.SkywayBatchWithSignatures, error) { + ret := _m.Called(ctx, chainReferenceID) + + if len(ret) == 0 { + panic("no return value specified for SkywayQueryLastPendingBatchForGasEstimation") + } + + var r0 []chain.SkywayBatchWithSignatures + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, string) ([]chain.SkywayBatchWithSignatures, error)); ok { + return rf(ctx, chainReferenceID) + } + if rf, ok := ret.Get(0).(func(context.Context, string) []chain.SkywayBatchWithSignatures); ok { + r0 = rf(ctx, chainReferenceID) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]chain.SkywayBatchWithSignatures) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, string) error); ok { + r1 = rf(ctx, chainReferenceID) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + // SkywayQueryLastUnsignedBatch provides a mock function with given fields: ctx, chainReferenceID func (_m *PalomaClienter) SkywayQueryLastUnsignedBatch(ctx context.Context, chainReferenceID string) ([]skywaytypes.OutgoingTxBatch, error) { ret := _m.Called(ctx, chainReferenceID) @@ -595,7 +705,8 @@ func (_m *PalomaClienter) SkywayQueryLastUnsignedBatch(ctx context.Context, chai func NewPalomaClienter(t interface { mock.TestingT Cleanup(func()) -}) *PalomaClienter { +}, +) *PalomaClienter { mock := &PalomaClienter{} mock.Mock.Test(t) diff --git a/relayer/relayer.go b/relayer/relayer.go index 19dfd34b..8fc21576 100644 --- a/relayer/relayer.go +++ b/relayer/relayer.go @@ -27,10 +27,12 @@ type PalomaClienter interface { QueryValidatorInfo(ctx context.Context) ([]*valset.ExternalChainInfo, error) BroadcastMessageSignatures(ctx context.Context, signatures ...paloma.BroadcastMessageSignatureIn) error QueryMessagesForAttesting(ctx context.Context, queueTypeName string) ([]chain.MessageWithSignatures, error) + QueryMessagesForEstimating(ctx context.Context, queueTypeName string) ([]chain.MessageWithSignatures, error) QueryMessagesForRelaying(ctx context.Context, queueTypeName string) ([]chain.MessageWithSignatures, error) QueryMessagesForSigning(ctx context.Context, queueTypeName string) ([]chain.QueuedMessage, error) QueryGetEVMChainInfos(ctx context.Context) ([]*evmtypes.ChainInfo, error) AddMessageEvidence(ctx context.Context, queueTypeName string, messageID uint64, proof proto.Message) error + AddMessagesGasEstimate(ctx context.Context, queueTypeName string, msgs ...chain.MessageWithEstimate) error SetPublicAccessData(ctx context.Context, queueTypeName string, messageID, valsetID uint64, data []byte) error SetErrorData(ctx context.Context, queueTypeName string, messageID uint64, data []byte) error QueryGetEVMValsetByID(ctx context.Context, id uint64, chainID string) (*evmtypes.Valset, error) @@ -46,6 +48,8 @@ type PalomaClienter interface { SkywayQueryLastUnsignedBatch(ctx context.Context, chainReferenceID string) ([]skyway.OutgoingTxBatch, error) SkywayConfirmBatches(ctx context.Context, signatures ...chain.SignedSkywayOutgoingTxBatch) error SkywayQueryBatchesForRelaying(ctx context.Context, chainReferenceID string) ([]chain.SkywayBatchWithSignatures, error) + SkywayQueryLastPendingBatchForGasEstimation(ctx context.Context, chainReferenceID string) ([]chain.SkywayBatchWithSignatures, error) + SkywayEstimateBatchGas(ctx context.Context, estimates ...chain.EstimatedSkywayBatch) error } //go:generate mockery --name=EvmFactorier @@ -56,6 +60,7 @@ type EvmFactorier interface { smartContractID, smartContractABIJson, smartContractAddress string, + feeMgrContractAddress string, chainID *big.Int, blockHeight int64, blockHeightHash common.Hash, diff --git a/relayer/skyway_batch_estimator.go b/relayer/skyway_batch_estimator.go new file mode 100644 index 00000000..6b58fa1d --- /dev/null +++ b/relayer/skyway_batch_estimator.go @@ -0,0 +1,83 @@ +package relayer + +import ( + "context" + "sync" + + "github.com/palomachain/pigeon/chain" + "github.com/palomachain/pigeon/util/slice" + log "github.com/sirupsen/logrus" +) + +func (r *Relayer) SkywayEstimateBatchGas(ctx context.Context, locker sync.Locker) error { + log.Info("gas estimation loop") + if ctx.Err() != nil { + log.Info("exiting gas estimation loop as context has ended") + return ctx.Err() + } + + err := r.buildProcessors(ctx, locker) + if err != nil { + log.Error(err) + return err + } + + locker.Lock() + err = r.skywayEstimateBatchGas(ctx, r.processors) + locker.Unlock() + + return handleProcessError(ctx, err) +} + +func (r *Relayer) skywayEstimateBatchGas(ctx context.Context, processors []chain.Processor) error { + if len(processors) == 0 { + return nil + } + + for _, p := range processors { + chainReferenceID := p.GetChainReferenceID() + + logger := log.WithFields(log.Fields{ + "chain-reference-id": chainReferenceID, + "action": "gas-estimate-skyway-batches", + }) + + // Get all batches that we haven't estimated + batchesForEstimating, err := r.palomaClient.SkywayQueryLastPendingBatchForGasEstimation(ctx, chainReferenceID) + if err != nil { + logger.WithError(err).Error("failed getting batches to estimate") + return err + } + + logger = logger.WithFields(log.Fields{ + "batch-nonces": slice.Map(batchesForEstimating, func(batch chain.SkywayBatchWithSignatures) uint64 { + return batch.BatchNonce + }), + }) + + if len(batchesForEstimating) > 0 { + logger.Info("estimating ", len(batchesForEstimating), " batches") + estimatedBatches, err := p.SkywayEstimateBatches(ctx, batchesForEstimating) + if err != nil { + logger.WithError(err).Error("unable to estimate batches") + return err + } + logger = logger.WithFields(log.Fields{ + "estimated-batches": slice.Map(estimatedBatches, func(batch chain.EstimatedSkywayBatch) log.Fields { + return log.Fields{ + "nonce": batch.BatchNonce, + } + }), + }) + logger.Info("estimated batches") + + if err = r.palomaClient.SkywayEstimateBatchGas(ctx, estimatedBatches...); err != nil { + logger.WithError(err).Error("couldn't broadcast gas estimates for batch.") + return err + } + + } + } + + return nil +} diff --git a/relayer/start.go b/relayer/start.go index 55bad2c8..4dd09f83 100644 --- a/relayer/start.go +++ b/relayer/start.go @@ -15,12 +15,14 @@ const ( updateExternalChainsLoopInterval = 1 * time.Minute signMessagesLoopInterval = 500 * time.Millisecond relayMessagesLoopInterval = 500 * time.Millisecond + estimateMessagesLoopInterval = 500 * time.Millisecond attestMessagesLoopInterval = 500 * time.Millisecond checkStakingLoopInterval = 5 * time.Second - skywaySignBatchesLoopInterval = 5 * time.Second - skywayRelayBatchesLoopInterval = 5 * time.Second - skywayEventWatcherLoopInterval = 1 * time.Minute + skywaySignBatchesLoopInterval = 5 * time.Second + skywayEstimateBatchesLoopInterval = 5 * time.Second + skywayRelayBatchesLoopInterval = 5 * time.Second + skywayEventWatcherLoopInterval = 1 * time.Minute ) func (r *Relayer) checkStaking(ctx context.Context, locker sync.Locker) error { @@ -78,6 +80,7 @@ func (r *Relayer) Start(ctx context.Context) error { go r.startProcess(ctx, "Check staking", &locker, checkStakingLoopInterval, false, r.checkStaking) go r.startProcess(ctx, "Update external chain infos", &locker, updateExternalChainsLoopInterval, true, r.UpdateExternalChainInfos) go r.startProcess(ctx, "Sign messages", &locker, signMessagesLoopInterval, true, r.SignMessages) + go r.startProcess(ctx, "Estimate messages", &locker, estimateMessagesLoopInterval, true, r.EstimateMessages) go r.startProcess(ctx, "Relay messages", &locker, relayMessagesLoopInterval, true, r.RelayMessages) go r.startProcess(ctx, "Attest messages", &locker, attestMessagesLoopInterval, true, r.AttestMessages) @@ -87,6 +90,7 @@ func (r *Relayer) Start(ctx context.Context) error { // Start skyway background goroutines to run separately from each other go r.startProcess(ctx, "[Skyway] Sign batches", &locker, skywaySignBatchesLoopInterval, true, r.SkywaySignBatches) + go r.startProcess(ctx, "[Skyway] Estimate batches", &locker, skywayEstimateBatchesLoopInterval, true, r.SkywayEstimateBatchGas) go r.startProcess(ctx, "[Skyway] Relay batches", &locker, skywayRelayBatchesLoopInterval, true, r.SkywayRelayBatches) go r.startProcess(ctx, "[Skyway] Handle Events", &locker, skywayEventWatcherLoopInterval, true, r.SkywayHandleEvents) diff --git a/relayer/update_chain_infos_test.go b/relayer/update_chain_infos_test.go index f592878b..b0cc1cd1 100644 --- a/relayer/update_chain_infos_test.go +++ b/relayer/update_chain_infos_test.go @@ -102,7 +102,7 @@ func TestUpdateExternalChainInfos(t *testing.T) { }) factory := mocks.NewEvmFactorier(t) - factory.On("Build", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(p, nil) + factory.On("Build", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(p, nil) return New( &config.Config{ @@ -163,7 +163,7 @@ func TestUpdateExternalChainInfos(t *testing.T) { }) factory := mocks.NewEvmFactorier(t) - factory.On("Build", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(p, nil) + factory.On("Build", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(p, nil) r := New( &config.Config{ @@ -235,7 +235,7 @@ func TestUpdateExternalChainInfos(t *testing.T) { }) factory := mocks.NewEvmFactorier(t) - factory.On("Build", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(p, nil) + factory.On("Build", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(p, nil) r := New( &config.Config{ diff --git a/util/time/mocks/Time.go b/util/time/mocks/Time.go index 60c4d80e..2a45d778 100644 --- a/util/time/mocks/Time.go +++ b/util/time/mocks/Time.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package mocks @@ -17,6 +17,10 @@ type Time struct { func (_m *Time) Now() time.Time { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Now") + } + var r0 time.Time if rf, ok := ret.Get(0).(func() time.Time); ok { r0 = rf() From eb593e7d43ab66634b70d15649a75994243a819a Mon Sep 17 00:00:00 2001 From: Luis Carvalho Date: Fri, 9 Aug 2024 13:49:11 +0100 Subject: [PATCH 2/6] feat: add compass ID to all turnstone messages (#420) --- chain/evm/compass.go | 3 +++ go.mod | 5 +++-- go.sum | 4 ++-- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/chain/evm/compass.go b/chain/evm/compass.go index cd332b65..1b02379e 100644 --- a/chain/evm/compass.go +++ b/chain/evm/compass.go @@ -1058,6 +1058,7 @@ func (t compass) submitBatchSendToEVMClaim(ctx context.Context, event chain.Batc ChainReferenceId: t.ChainReferenceID, Orchestrator: orchestrator, SkywayNonce: event.SkywayNonce, + CompassId: t.CompassID, } return t.paloma.SendBatchSendToEVMClaim(ctx, msg) } @@ -1073,6 +1074,7 @@ func (t compass) submitSendToPalomaClaim(ctx context.Context, event chain.SendTo ChainReferenceId: t.ChainReferenceID, Orchestrator: orchestrator, SkywayNonce: event.SkywayNonce, + CompassId: t.CompassID, } return t.paloma.SendSendToPalomaClaim(ctx, msg) } @@ -1087,6 +1089,7 @@ func (t compass) submitLightNodeSaleClaim(ctx context.Context, event chain.Light Orchestrator: orchestrator, SkywayNonce: event.SkywayNonce, SmartContractAddress: event.SmartContractAddress, + CompassId: t.CompassID, } return t.paloma.SendLightNodeSaleClaim(ctx, msg) } diff --git a/go.mod b/go.mod index e1a09f12..d9224f32 100644 --- a/go.mod +++ b/go.mod @@ -22,7 +22,7 @@ require ( github.com/jarcoal/httpmock v1.3.1 github.com/onsi/ginkgo/v2 v2.19.0 github.com/onsi/gomega v1.33.1 - github.com/palomachain/paloma v1.15.5 + github.com/palomachain/paloma v1.15.6 github.com/roodeag/arbitrum v0.0.0-20230627104516-b95e4c8ebec0 github.com/rs/xid v1.5.0 github.com/sirupsen/logrus v1.9.3 @@ -229,7 +229,8 @@ require ( replace ( // Link to op-geth, which is built on top of go-ethereum github.com/ethereum/go-ethereum => github.com/ethereum-optimism/op-geth v1.101311.0 - github.com/palomachain/paloma => github.com/palomachain/paloma v1.3.1-next.0.20240808095442-ad824cc65492 github.com/roodeag/arbitrum => github.com/palomachain/arb-geth v0.0.0-20230824112942-8e77a580a936 ) + +replace github.com/palomachain/paloma => github.com/palomachain/paloma v1.3.1-next.0.20240809084129-00b863098ab7 diff --git a/go.sum b/go.sum index 3097ed63..b52544ca 100644 --- a/go.sum +++ b/go.sum @@ -949,8 +949,8 @@ github.com/ory/dockertest v3.3.5+incompatible/go.mod h1:1vX4m9wsvi00u5bseYwXaSnh github.com/pact-foundation/pact-go v1.0.4/go.mod h1:uExwJY4kCzNPcHRj+hCR/HBbOOIwwtUjcrb0b5/5kLM= github.com/palomachain/arb-geth v0.0.0-20230824112942-8e77a580a936 h1:fmQAgxcdYBxCZYczws/uxTVOYHZd4fNrOaoHp35HZMM= github.com/palomachain/arb-geth v0.0.0-20230824112942-8e77a580a936/go.mod h1:B2H2+2I4UiMR4hvAIaGLyYszNfSTYC8fWIw+kgfuFSQ= -github.com/palomachain/paloma v1.3.1-next.0.20240808095442-ad824cc65492 h1:BBqlRicqEoJTURM0z127RSc2ZXLZ8IGgSC83narQOg8= -github.com/palomachain/paloma v1.3.1-next.0.20240808095442-ad824cc65492/go.mod h1:91O0VRxBof+IXTZxSsSbk/lV2DSaWQIdUaoCBv6HXDo= +github.com/palomachain/paloma v1.3.1-next.0.20240809084129-00b863098ab7 h1:vW8TOXU16j8BRX8kpBAkVsbHnP0KlnL6Z65InVbfYyw= +github.com/palomachain/paloma v1.3.1-next.0.20240809084129-00b863098ab7/go.mod h1:91O0VRxBof+IXTZxSsSbk/lV2DSaWQIdUaoCBv6HXDo= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= From 02c99aea1e69913a6b026a8cbeef718cf7bad4f2 Mon Sep 17 00:00:00 2001 From: Christian Lohr Date: Mon, 12 Aug 2024 12:48:09 +0200 Subject: [PATCH 3/6] fix: use somewhat realistic dummy gas estimate (#421) --- chain/evm/compass.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/chain/evm/compass.go b/chain/evm/compass.go index 1b02379e..508dccd1 100644 --- a/chain/evm/compass.go +++ b/chain/evm/compass.go @@ -5,7 +5,6 @@ import ( "context" "errors" "fmt" - gomath "math" "math/big" "time" @@ -31,6 +30,7 @@ import ( const ( SignedMessagePrefix = "\x19Ethereum Signed Message:\n32" cEventQueryBlockHeightMinWindow = 10 + cConservativeDummyGasEstimate = 300_000 ) var ( @@ -172,7 +172,7 @@ func (t compass) updateValset( if opts.estimateOnly { // Simulate maximum gas estimate to ensure the transaction is not rejected - estimate = big.NewInt(gomath.MaxInt64) + estimate = big.NewInt(cConservativeDummyGasEstimate) } // TODO: Use generated contract code directly @@ -1319,7 +1319,7 @@ func (t compass) skywayRelayBatch( whoops.Assert(fmt.Errorf("failed to retrieve assignee eth address: %w", err)) } - var estimate *big.Int = big.NewInt(0).SetUint64(gomath.MaxUint64) + var estimate *big.Int = big.NewInt(cConservativeDummyGasEstimate) if !opts.estimateOnly { if batch.GasEstimate < 1 { logger.WithField("gas-estimate", batch.GasEstimate).Error("invalid gas estimate") From bf5272fc297553625087e3ea6c72d2ada2dc1fcc Mon Sep 17 00:00:00 2001 From: Christian Lohr Date: Tue, 13 Aug 2024 11:21:20 +0200 Subject: [PATCH 4/6] chore: refactor paloma address to bytes32 (#422) --- chain/evm/compass.go | 53 ++++++++++++++++++++++++++------------------ 1 file changed, 31 insertions(+), 22 deletions(-) diff --git a/chain/evm/compass.go b/chain/evm/compass.go index 508dccd1..1a2016c2 100644 --- a/chain/evm/compass.go +++ b/chain/evm/compass.go @@ -44,7 +44,7 @@ var ( "BatchSendEvent(address,uint256,uint256,uint256)", )) sendToPalomaEvent = crypto.Keccak256Hash([]byte( - "SendToPalomaEvent(address,address,string,uint256,uint256,uint256)", + "SendToPalomaEvent(address,address,bytes32,uint256,uint256,uint256)", )) ) @@ -899,9 +899,9 @@ func (t *compass) parseSendToPalomaEvent( return evt, fmt.Errorf("invalid sender address") } - palomaReceiver := event[2].(string) - if !ok { - return evt, fmt.Errorf("invalid paloma receiver") + palomaReceiver, err := compassBytesToPalomaAddress(event[2]) + if err != nil { + return evt, fmt.Errorf("invalid paloma receiver: %w", err) } amount, ok := event[3].(*big.Int) @@ -924,7 +924,7 @@ func (t *compass) parseSendToPalomaEvent( EventNonce: eventNonce.Uint64(), Amount: amount.Uint64(), EthereumSender: ethSender.String(), - PalomaReceiver: palomaReceiver, + PalomaReceiver: palomaReceiver.String(), TokenContract: tokenContract.String(), SkywayNonce: skywayNonce.Uint64(), }, nil @@ -982,23 +982,9 @@ func (t *compass) parseLightNodeSaleEvent( return evt, fmt.Errorf("invalid smart contract address") } - rawBytes, ok := event[2].([32]byte) - if !ok { - return evt, fmt.Errorf("invalid paloma address bytes") - } - - // Keep only the last 20 bytes, removing the first 12 zeroes - addrBytes := rawBytes[12:] - - // The Unmarshal function below does not check for errors, so we need to do - // it beforehand - if err := sdk.VerifyAddressFormat(addrBytes); err != nil { - return evt, err - } - - var clientAddress sdk.AccAddress - if err := clientAddress.Unmarshal(addrBytes); err != nil { - return evt, err + clientAddress, err := compassBytesToPalomaAddress(event[2]) + if err != nil { + return evt, fmt.Errorf("invalid client address: %w", err) } amount, ok := event[4].(*big.Int) @@ -1404,3 +1390,26 @@ func (t compass) findAssigneeEthAddress(ctx context.Context, return common.Address{}, errors.New("assignee's eth address not found") } + +func compassBytesToPalomaAddress(b any) (sdk.AccAddress, error) { + var addr sdk.AccAddress + rawBytes, ok := b.([32]byte) + if !ok { + return addr, fmt.Errorf("invalid paloma address bytes") + } + + // Keep only the last 20 bytes, removing the first 12 zeroes + addrBytes := rawBytes[12:] + + // The Unmarshal function below does not check for errors, so we need to do + // it beforehand + if err := sdk.VerifyAddressFormat(addrBytes); err != nil { + return addr, err + } + + if err := addr.Unmarshal(addrBytes); err != nil { + return addr, err + } + + return addr, nil +} From eb2c4af19e06338fcf6476823f1fc2c56ffc7cf5 Mon Sep 17 00:00:00 2001 From: Christian Lohr Date: Fri, 16 Aug 2024 18:57:51 +0200 Subject: [PATCH 5/6] Clohr/pf fixes (#424) * fix: pass estimate only flag when needed * fix: estimation on ARB * fix: send eth address for relayer * fix: register gas estimation message * fix: avoid panic in update_valset * chore: update valset_update keccak256 * chore: ignore messages we fail to estimate * chore: do not return errors from estimation * fix: register msg type * chore: fix typo * chore: update palomachain/paloma dependency --------- Co-authored-by: Luis Carvalho --- app/app.go | 3 ++- chain/evm/client.go | 48 +++++++++++++++++------------------- chain/evm/compass.go | 24 +++++++++--------- chain/evm/processor.go | 19 +++++++++----- go.mod | 4 +-- go.sum | 4 +-- relayer/message_estimator.go | 23 ++++++++++++++++- 7 files changed, 74 insertions(+), 51 deletions(-) diff --git a/app/app.go b/app/app.go index b8dd20b8..c0f21cee 100644 --- a/app/app.go +++ b/app/app.go @@ -188,9 +188,11 @@ func palomaClientConfig(palomaConfig config.Paloma) *ion.ChainClientConfig { &consensustypes.MsgAddEvidence{}, &consensustypes.MsgSetPublicAccessData{}, &consensustypes.MsgSetErrorData{}, + &consensustypes.MsgAddMessageGasEstimates{}, &palomatypes.MsgAddStatusUpdate{}, &skywaytypes.MsgSendToRemote{}, &skywaytypes.MsgConfirmBatch{}, + &skywaytypes.MsgEstimateBatchGas{}, &skywaytypes.MsgSendToPalomaClaim{}, &skywaytypes.MsgLightNodeSaleClaim{}, &skywaytypes.MsgBatchSendToRemoteClaim{}, @@ -206,7 +208,6 @@ func palomaClientConfig(palomaConfig config.Paloma) *ion.ChainClientConfig { &evmtypes.SmartContractExecutionErrorProof{}, &evmtypes.ValidatorBalancesAttestation{}, &evmtypes.ValidatorBalancesAttestationRes{}, - &evmtypes.TransferERC20Ownership{}, &evmtypes.ReferenceBlockAttestation{}, &evmtypes.ReferenceBlockAttestationRes{}, }, diff --git a/chain/evm/client.go b/chain/evm/client.go index fc0b25cb..1adc8ec2 100644 --- a/chain/evm/client.go +++ b/chain/evm/client.go @@ -36,7 +36,6 @@ import ( "github.com/palomachain/pigeon/chain/paloma" "github.com/palomachain/pigeon/config" "github.com/palomachain/pigeon/errors" - "github.com/palomachain/pigeon/internal/libchain" "github.com/palomachain/pigeon/internal/liblog" "github.com/palomachain/pigeon/util/slice" arbcommon "github.com/roodeag/arbitrum/common" @@ -336,23 +335,28 @@ func callSmartContract( txOpts.Nonce = big.NewInt(int64(nonce)) txOpts.From = args.signingAddr - if !libchain.IsArbitrum(args.chainID) { - // Leads to problems with arbitrum: - // both gasPrice and (maxFeePerGas or maxPriorityFeePerGas) specified - // Only set this on other chains. - // https://github.com/VolumeFi/paloma/issues/1048 - value := new(big.Int) - gasFeeCap := new(big.Int) - var gasLimit uint64 - if args.txType == 2 { - gasFeeCap = gasPrice - gasLimit, err = estimateGasLimit(ctx, args.ethClient, txOpts, &args.contract, packedBytes, nil, gasTipCap, gasFeeCap, value) - whoops.Assert(err) - } else { - gasLimit, err = estimateGasLimit(ctx, args.ethClient, txOpts, &args.contract, packedBytes, gasPrice, nil, nil, value) - whoops.Assert(err) - } - txOpts.GasLimit = uint64(float64(gasLimit) * 1.5) + value := new(big.Int) + gasFeeCap := new(big.Int) + var gasLimit uint64 + if args.txType == 2 { + gasFeeCap = gasPrice + gasLimit, err = estimateGasLimit(ctx, args.ethClient, txOpts, &args.contract, packedBytes, nil, gasTipCap, gasFeeCap, value) + whoops.Assert(err) + } else { + gasLimit, err = estimateGasLimit(ctx, args.ethClient, txOpts, &args.contract, packedBytes, gasPrice, nil, nil, value) + whoops.Assert(err) + } + logger.WithFields(log.Fields{ + "gas-limit": gasLimit, + }).Debug("estimated gas limit") + txOpts.GasLimit = uint64(float64(gasLimit) * 1.5) + + // In case we only want to estimate, now is the time to return. + if args.opts.estimateOnly { + return ethtypes.NewTx( + ðtypes.LegacyTx{ + Gas: txOpts.GasLimit, + }) } if args.txType == 2 { @@ -378,14 +382,6 @@ func callSmartContract( }).Debug("executing legacy tx") } - // In case we only want to estimate, now is the time to return. - if args.opts.estimateOnly { - return ethtypes.NewTx( - ðtypes.LegacyTx{ - Gas: txOpts.GasLimit, - }) - } - // In case we want to relay, don't actually send the constructed TX if args.opts.useMevRelay && args.mevClient != nil { logger.Info("MEV Client set - setting TX to not execute") diff --git a/chain/evm/compass.go b/chain/evm/compass.go index 1a2016c2..39372c70 100644 --- a/chain/evm/compass.go +++ b/chain/evm/compass.go @@ -28,9 +28,9 @@ import ( ) const ( - SignedMessagePrefix = "\x19Ethereum Signed Message:\n32" - cEventQueryBlockHeightMinWindow = 10 - cConservativeDummyGasEstimate = 300_000 + SignedMessagePrefix = "\x19Ethereum Signed Message:\n32" + cEventQueryBlockHeightMinWindow = 10 + cConservativeDummyGasEstimate uint64 = 300_000 ) var ( @@ -172,7 +172,7 @@ func (t compass) updateValset( if opts.estimateOnly { // Simulate maximum gas estimate to ensure the transaction is not rejected - estimate = big.NewInt(cConservativeDummyGasEstimate) + estimate = big.NewInt(0).SetUint64(cConservativeDummyGasEstimate) } // TODO: Use generated contract code directly @@ -196,7 +196,7 @@ func (t compass) updateValset( return nil, 0, nil } } - whoops.Assert(err) + return nil, 0, fmt.Errorf("call_compass error: %w", err) } return tx, currentValsetID, nil @@ -310,7 +310,7 @@ func (t compass) submitLogicCall( feeArgs, new(big.Int).SetInt64(int64(origMessage.ID)), new(big.Int).SetInt64(msg.GetDeadline()), - common.BytesToAddress(msg.ContractAddress), + ethSender, } if msg.ExecutionRequirements.EnforceMEVRelay { @@ -551,10 +551,10 @@ func BuildCompassConsensus( return con } -func (t compass) processMessages(ctx context.Context, queueTypeName string, msgs []chain.MessageWithSignatures, opts callOptions) ([]ethtypes.Transaction, error) { +func (t compass) processMessages(ctx context.Context, queueTypeName string, msgs []chain.MessageWithSignatures, opts callOptions) ([]*ethtypes.Transaction, error) { var gErr whoops.Group logger := liblog.WithContext(ctx).WithField("queue-type-name", queueTypeName) - res := make([]ethtypes.Transaction, 0, len(msgs)) + res := make([]*ethtypes.Transaction, 0, len(msgs)) for i, rawMsg := range msgs { logger = logger.WithField("message-id", rawMsg.ID) @@ -639,9 +639,9 @@ func (t compass) processMessages(ctx context.Context, queueTypeName string, msgs FieldMessageType.Val(msg.GetAction()), ) - if tx != nil { - res = append(res, *tx) - } + // Append all txs, even if they are nil + // These values will have to be filtered out by the caller + res = append(res, tx) switch { case processingErr == nil: @@ -1305,7 +1305,7 @@ func (t compass) skywayRelayBatch( whoops.Assert(fmt.Errorf("failed to retrieve assignee eth address: %w", err)) } - var estimate *big.Int = big.NewInt(cConservativeDummyGasEstimate) + var estimate *big.Int = big.NewInt(0).SetUint64(cConservativeDummyGasEstimate) if !opts.estimateOnly { if batch.GasEstimate < 1 { logger.WithField("gas-estimate", batch.GasEstimate).Error("invalid gas estimate") diff --git a/chain/evm/processor.go b/chain/evm/processor.go index 4e2c2ff2..cbe1cbb7 100644 --- a/chain/evm/processor.go +++ b/chain/evm/processor.go @@ -132,18 +132,25 @@ func (p Processor) EstimateMessages(ctx context.Context, queueTypeName queue.Typ ctx, queueTypeName.String(), msgs, - callOptions{}, + callOptions{ + estimateOnly: true, + }, ) if err != nil { - return nil, fmt.Errorf("processor::EstimateMessages: %w", err) - } - - if len(txs) != len(msgs) { - return nil, fmt.Errorf("processor::EstimateMessages: estimated %d messages, but got %d", len(msgs), len(txs)) + // Even if we fail to estimate messages, we must continue, so we just + // log the error + // If we fail to estimate them all, `txs` will be empty, and nothing + // will change anyway + log.WithField("error", err).Warn("Failed to estimate messages") } res := make([]chain.MessageWithEstimate, 0, len(txs)) for i, tx := range txs { + if tx == nil { + // We couldn't estimate this message, so we just ignore it + continue + } + res = append(res, chain.MessageWithEstimate{ MessageWithSignatures: msgs[i], Estimate: tx.Gas(), diff --git a/go.mod b/go.mod index d9224f32..9b14b1eb 100644 --- a/go.mod +++ b/go.mod @@ -22,7 +22,7 @@ require ( github.com/jarcoal/httpmock v1.3.1 github.com/onsi/ginkgo/v2 v2.19.0 github.com/onsi/gomega v1.33.1 - github.com/palomachain/paloma v1.15.6 + github.com/palomachain/paloma v1.3.1-next.0.20240816163105-fca35187f8e3 github.com/roodeag/arbitrum v0.0.0-20230627104516-b95e4c8ebec0 github.com/rs/xid v1.5.0 github.com/sirupsen/logrus v1.9.3 @@ -232,5 +232,3 @@ replace ( github.com/roodeag/arbitrum => github.com/palomachain/arb-geth v0.0.0-20230824112942-8e77a580a936 ) - -replace github.com/palomachain/paloma => github.com/palomachain/paloma v1.3.1-next.0.20240809084129-00b863098ab7 diff --git a/go.sum b/go.sum index b52544ca..8ebfeb81 100644 --- a/go.sum +++ b/go.sum @@ -949,8 +949,8 @@ github.com/ory/dockertest v3.3.5+incompatible/go.mod h1:1vX4m9wsvi00u5bseYwXaSnh github.com/pact-foundation/pact-go v1.0.4/go.mod h1:uExwJY4kCzNPcHRj+hCR/HBbOOIwwtUjcrb0b5/5kLM= github.com/palomachain/arb-geth v0.0.0-20230824112942-8e77a580a936 h1:fmQAgxcdYBxCZYczws/uxTVOYHZd4fNrOaoHp35HZMM= github.com/palomachain/arb-geth v0.0.0-20230824112942-8e77a580a936/go.mod h1:B2H2+2I4UiMR4hvAIaGLyYszNfSTYC8fWIw+kgfuFSQ= -github.com/palomachain/paloma v1.3.1-next.0.20240809084129-00b863098ab7 h1:vW8TOXU16j8BRX8kpBAkVsbHnP0KlnL6Z65InVbfYyw= -github.com/palomachain/paloma v1.3.1-next.0.20240809084129-00b863098ab7/go.mod h1:91O0VRxBof+IXTZxSsSbk/lV2DSaWQIdUaoCBv6HXDo= +github.com/palomachain/paloma v1.3.1-next.0.20240816163105-fca35187f8e3 h1:uo0oyLsZxyCy8gmEttE+GUCt0XyPqQdDdrh6AQPFOPQ= +github.com/palomachain/paloma v1.3.1-next.0.20240816163105-fca35187f8e3/go.mod h1:91O0VRxBof+IXTZxSsSbk/lV2DSaWQIdUaoCBv6HXDo= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= diff --git a/relayer/message_estimator.go b/relayer/message_estimator.go index f8264cb4..49e0bd45 100644 --- a/relayer/message_estimator.go +++ b/relayer/message_estimator.go @@ -69,7 +69,28 @@ func (r *Relayer) estimateMessages(ctx context.Context, processors []chain.Proce return err } - err = r.palomaClient.AddMessagesGasEstimate(ctx, queueName, estimates...) + filteredEstimates := make([]chain.MessageWithEstimate, 0, len(estimates)) + for _, v := range estimates { + logger. + WithField("message-id", v.ID). + WithField("estimate", v.Estimate). + Info("estimated message") + if v.Estimate < 1 { + logger. + WithField("message-id", v.ID). + WithField("estimate", v.Estimate). + Warn("Received an estimate of 0 or less, skipping") + continue + } + filteredEstimates = append(filteredEstimates, v) + } + + if len(filteredEstimates) == 0 { + logger.Info("No valid estimates, skipping") + continue + } + + err = r.palomaClient.AddMessagesGasEstimate(ctx, queueName, filteredEstimates...) if err != nil { logger.WithError(err).Error("failed to send estimates to Paloma") return err From 0a02dd9cc5694ff6713a648511fc6b268fb7f65c Mon Sep 17 00:00:00 2001 From: Christian Lohr Date: Fri, 16 Aug 2024 18:59:28 +0200 Subject: [PATCH 6/6] chore: update README --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index c7d0033d..3cb31fc6 100644 --- a/README.md +++ b/README.md @@ -82,7 +82,7 @@ This repo does not accept issues. Please use