Transaction Hash:
Block:
18416909 at Oct-24-2023 01:40:47 AM +UTC
Transaction Fee:
0.00641408988068506 ETH
$16.11
Gas Used:
214,540 Gas / 29.896941739 Gwei
Emitted Events:
438 |
Compass-EVM.ValsetUpdated( checkpoint=52F749F2274E4E200FCE4FB02B8A8AA8765B25CF0542263F4FAA28F46B27998F, valset_id=29237 )
|
Account State Difference:
Address | Before | After | State Difference | ||
---|---|---|---|---|---|
0x1f9090aa...8e676c326
Miner
| 4.453038474852611803 Eth | 4.453040620252611803 Eth | 0.0000021454 | ||
0x44352095...56a7BcF63 |
0.04509065233518823 Eth
Nonce: 104
|
0.03867656245450317 Eth
Nonce: 105
| 0.00641408988068506 | ||
0xa00CF350...52d087157 |
Execution Trace
Compass-EVM.update_valset( consensus=[{name:valset, type:tuple, order:1, indexed:false, value:[{name:validators, type:address[], order:1, indexed:false, value:[0xa228292447064D5818BbC80b577C91f5212F9355, 0x092604a080524Eff1C875fF13A1b88cBDD41df37, 0xEe21301aF1d9562B5cBEdf520077Ea0a9bC9d535, 0x19f5911E4cA69E30449aD6BB71De341F01F118BB, 0x43E218f96A567DC26C6e65fCabF1fDE26Af69444, 0x1Dd71EE9e7b1CfF10CCb7E12520999c2d4fB45e5, 0x1ad90dB98da083E117D5F62a1673fC0f3A5930ca, 0x6dc59EE4bdFa2C791229004f29b08F783491a934, 0xADe5F5eFeAe72102d998F6C496ea59731a70eEb0, 0x443266026738061972012e62D5Ecd9D98da8B6F4, 0x1F6EF2784cbB2A5011d8CF12356fb5ee3eAeF372, 0x63f55bc560E981d53E1f5bb3643e3a96D26fc635, 0x7C3dE83D90E8d2001a7e3F38E6a7058334cB291E, 0x732fBb6018F2cB5b844055C9EB567447a3132833, 0x5A7C9FC846b18944FD2B8F8aE7255dB5af7b9c04, 0xDEea5b069208e0eE37b630A3e7672FC50e8fE24a, 0xeE83770168D4EE756e74562C17BDED88091519D0, 0x279fC7c0ebEf3328d3899FE73464347A764C5f2C, 0xAAc74d38c82c367b3dA7482E3Aecf6DD7A512eF2, 0x3aB643728bD503AE41561B4Bfe1D309A17255b8D, 0x0DAaBB4FF60423Eb1F14cC6731394e098ad51bcb, 0x4a89f96fdff3C161937CFBC3e22d2E325612aaEc, 0xcFBBF6341cf13a39ffCaF24B86dE09489116783b, 0x14Aa448C2C918C4427c5671028b63BC17f6132d5, 0x377D23948D41579f2c3cA40308e3bdd53f6dA7B2, 0xeB784b37365C302C97C9Ec8cB0933cE344e6dE42, 0xBBEFE691d2C3bbB835CE2958b453ccd05BdB27A5, 0x179206Cd9080A8ee77C2256A27050112da13b2f6], valueString:[0xa228292447064D5818BbC80b577C91f5212F9355, 0x092604a080524Eff1C875fF13A1b88cBDD41df37, 0xEe21301aF1d9562B5cBEdf520077Ea0a9bC9d535, 0x19f5911E4cA69E30449aD6BB71De341F01F118BB, 0x43E218f96A567DC26C6e65fCabF1fDE26Af69444, 0x1Dd71EE9e7b1CfF10CCb7E12520999c2d4fB45e5, 0x1ad90dB98da083E117D5F62a1673fC0f3A5930ca, 0x6dc59EE4bdFa2C791229004f29b08F783491a934, 0xADe5F5eFeAe72102d998F6C496ea59731a70eEb0, 0x443266026738061972012e62D5Ecd9D98da8B6F4, 0x1F6EF2784cbB2A5011d8CF12356fb5ee3eAeF372, 0x63f55bc560E981d53E1f5bb3643e3a96D26fc635, 0x7C3dE83D90E8d2001a7e3F38E6a7058334cB291E, 0x732fBb6018F2cB5b844055C9EB567447a3132833, 0x5A7C9FC846b18944FD2B8F8aE7255dB5af7b9c04, 0xDEea5b069208e0eE37b630A3e7672FC50e8fE24a, 0xeE83770168D4EE756e74562C17BDED88091519D0, 0x279fC7c0ebEf3328d3899FE73464347A764C5f2C, 0xAAc74d38c82c367b3dA7482E3Aecf6DD7A512eF2, 0x3aB643728bD503AE41561B4Bfe1D309A17255b8D, 0x0DAaBB4FF60423Eb1F14cC6731394e098ad51bcb, 0x4a89f96fdff3C161937CFBC3e22d2E325612aaEc, 0xcFBBF6341cf13a39ffCaF24B86dE09489116783b, 0x14Aa448C2C918C4427c5671028b63BC17f6132d5, 0x377D23948D41579f2c3cA40308e3bdd53f6dA7B2, 0xeB784b37365C302C97C9Ec8cB0933cE344e6dE42, 0xBBEFE691d2C3bbB835CE2958b453ccd05BdB27A5, 0x179206Cd9080A8ee77C2256A27050112da13b2f6]}, {name:powers, type:uint256[], order:2, indexed:false, value:[377084175, 235314280, 232682876, 194308259, 191145421, 180769369, 178304352, 178013853, 177130363, 176483556, 175800080, 172437759, 170517867, 168058762, 167619087, 146578773, 145745962, 140009707, 135215150, 129283106, 126192034, 126182317, 122927772, 119641898, 71875217, 54456773, 1005064, 183449], valueString:[377084175, 235314280, 232682876, 194308259, 191145421, 180769369, 178304352, 178013853, 177130363, 176483556, 175800080, 172437759, 170517867, 168058762, 167619087, 146578773, 145745962, 140009707, 135215150, 129283106, 126192034, 126182317, 122927772, 119641898, 71875217, 54456773, 1005064, 183449]}, {name:valset_id, type:uint256, order:3, indexed:false, value:29236, valueString:29236}], valueString:[{name:validators, type:address[], order:1, indexed:false, value:[0xa228292447064D5818BbC80b577C91f5212F9355, 0x092604a080524Eff1C875fF13A1b88cBDD41df37, 0xEe21301aF1d9562B5cBEdf520077Ea0a9bC9d535, 0x19f5911E4cA69E30449aD6BB71De341F01F118BB, 0x43E218f96A567DC26C6e65fCabF1fDE26Af69444, 0x1Dd71EE9e7b1CfF10CCb7E12520999c2d4fB45e5, 0x1ad90dB98da083E117D5F62a1673fC0f3A5930ca, 0x6dc59EE4bdFa2C791229004f29b08F783491a934, 0xADe5F5eFeAe72102d998F6C496ea59731a70eEb0, 0x443266026738061972012e62D5Ecd9D98da8B6F4, 0x1F6EF2784cbB2A5011d8CF12356fb5ee3eAeF372, 0x63f55bc560E981d53E1f5bb3643e3a96D26fc635, 0x7C3dE83D90E8d2001a7e3F38E6a7058334cB291E, 0x732fBb6018F2cB5b844055C9EB567447a3132833, 0x5A7C9FC846b18944FD2B8F8aE7255dB5af7b9c04, 0xDEea5b069208e0eE37b630A3e7672FC50e8fE24a, 0xeE83770168D4EE756e74562C17BDED88091519D0, 0x279fC7c0ebEf3328d3899FE73464347A764C5f2C, 0xAAc74d38c82c367b3dA7482E3Aecf6DD7A512eF2, 0x3aB643728bD503AE41561B4Bfe1D309A17255b8D, 0x0DAaBB4FF60423Eb1F14cC6731394e098ad51bcb, 0x4a89f96fdff3C161937CFBC3e22d2E325612aaEc, 0xcFBBF6341cf13a39ffCaF24B86dE09489116783b, 0x14Aa448C2C918C4427c5671028b63BC17f6132d5, 0x377D23948D41579f2c3cA40308e3bdd53f6dA7B2, 0xeB784b37365C302C97C9Ec8cB0933cE344e6dE42, 0xBBEFE691d2C3bbB835CE2958b453ccd05BdB27A5, 0x179206Cd9080A8ee77C2256A27050112da13b2f6], valueString:[0xa228292447064D5818BbC80b577C91f5212F9355, 0x092604a080524Eff1C875fF13A1b88cBDD41df37, 0xEe21301aF1d9562B5cBEdf520077Ea0a9bC9d535, 0x19f5911E4cA69E30449aD6BB71De341F01F118BB, 0x43E218f96A567DC26C6e65fCabF1fDE26Af69444, 0x1Dd71EE9e7b1CfF10CCb7E12520999c2d4fB45e5, 0x1ad90dB98da083E117D5F62a1673fC0f3A5930ca, 0x6dc59EE4bdFa2C791229004f29b08F783491a934, 0xADe5F5eFeAe72102d998F6C496ea59731a70eEb0, 0x443266026738061972012e62D5Ecd9D98da8B6F4, 0x1F6EF2784cbB2A5011d8CF12356fb5ee3eAeF372, 0x63f55bc560E981d53E1f5bb3643e3a96D26fc635, 0x7C3dE83D90E8d2001a7e3F38E6a7058334cB291E, 0x732fBb6018F2cB5b844055C9EB567447a3132833, 0x5A7C9FC846b18944FD2B8F8aE7255dB5af7b9c04, 0xDEea5b069208e0eE37b630A3e7672FC50e8fE24a, 0xeE83770168D4EE756e74562C17BDED88091519D0, 0x279fC7c0ebEf3328d3899FE73464347A764C5f2C, 0xAAc74d38c82c367b3dA7482E3Aecf6DD7A512eF2, 0x3aB643728bD503AE41561B4Bfe1D309A17255b8D, 0x0DAaBB4FF60423Eb1F14cC6731394e098ad51bcb, 0x4a89f96fdff3C161937CFBC3e22d2E325612aaEc, 0xcFBBF6341cf13a39ffCaF24B86dE09489116783b, 0x14Aa448C2C918C4427c5671028b63BC17f6132d5, 0x377D23948D41579f2c3cA40308e3bdd53f6dA7B2, 0xeB784b37365C302C97C9Ec8cB0933cE344e6dE42, 0xBBEFE691d2C3bbB835CE2958b453ccd05BdB27A5, 0x179206Cd9080A8ee77C2256A27050112da13b2f6]}, {name:powers, type:uint256[], order:2, indexed:false, value:[377084175, 235314280, 232682876, 194308259, 191145421, 180769369, 178304352, 178013853, 177130363, 176483556, 175800080, 172437759, 170517867, 168058762, 167619087, 146578773, 145745962, 140009707, 135215150, 129283106, 126192034, 126182317, 122927772, 119641898, 71875217, 54456773, 1005064, 183449], valueString:[377084175, 235314280, 232682876, 194308259, 191145421, 180769369, 178304352, 178013853, 177130363, 176483556, 175800080, 172437759, 170517867, 168058762, 167619087, 146578773, 145745962, 140009707, 135215150, 129283106, 126192034, 126182317, 122927772, 119641898, 71875217, 54456773, 1005064, 183449]}, {name:valset_id, type:uint256, order:3, indexed:false, value:29236, valueString:29236}]}, {name:signatures, type:tuple[], order:2, indexed:false}], new_valset=[{name:validators, type:address[], order:1, indexed:false, value:[0xa228292447064D5818BbC80b577C91f5212F9355, 0x092604a080524Eff1C875fF13A1b88cBDD41df37, 0xEe21301aF1d9562B5cBEdf520077Ea0a9bC9d535, 0x19f5911E4cA69E30449aD6BB71De341F01F118BB, 0x43E218f96A567DC26C6e65fCabF1fDE26Af69444, 0x1Dd71EE9e7b1CfF10CCb7E12520999c2d4fB45e5, 0x1ad90dB98da083E117D5F62a1673fC0f3A5930ca, 0x6dc59EE4bdFa2C791229004f29b08F783491a934, 0xADe5F5eFeAe72102d998F6C496ea59731a70eEb0, 0x443266026738061972012e62D5Ecd9D98da8B6F4, 0x1F6EF2784cbB2A5011d8CF12356fb5ee3eAeF372, 0x63f55bc560E981d53E1f5bb3643e3a96D26fc635, 0x7C3dE83D90E8d2001a7e3F38E6a7058334cB291E, 0x732fBb6018F2cB5b844055C9EB567447a3132833, 0x5A7C9FC846b18944FD2B8F8aE7255dB5af7b9c04, 0xDEea5b069208e0eE37b630A3e7672FC50e8fE24a, 0xeE83770168D4EE756e74562C17BDED88091519D0, 0x279fC7c0ebEf3328d3899FE73464347A764C5f2C, 0xAAc74d38c82c367b3dA7482E3Aecf6DD7A512eF2, 0x3aB643728bD503AE41561B4Bfe1D309A17255b8D, 0x0DAaBB4FF60423Eb1F14cC6731394e098ad51bcb, 0x4a89f96fdff3C161937CFBC3e22d2E325612aaEc, 0xcFBBF6341cf13a39ffCaF24B86dE09489116783b, 0x14Aa448C2C918C4427c5671028b63BC17f6132d5, 0x443520951d766456F2AC5578f3E7e4B56a7BcF63, 0x377D23948D41579f2c3cA40308e3bdd53f6dA7B2, 0xeB784b37365C302C97C9Ec8cB0933cE344e6dE42, 0xBBEFE691d2C3bbB835CE2958b453ccd05BdB27A5, 0x179206Cd9080A8ee77C2256A27050112da13b2f6], valueString:[0xa228292447064D5818BbC80b577C91f5212F9355, 0x092604a080524Eff1C875fF13A1b88cBDD41df37, 0xEe21301aF1d9562B5cBEdf520077Ea0a9bC9d535, 0x19f5911E4cA69E30449aD6BB71De341F01F118BB, 0x43E218f96A567DC26C6e65fCabF1fDE26Af69444, 0x1Dd71EE9e7b1CfF10CCb7E12520999c2d4fB45e5, 0x1ad90dB98da083E117D5F62a1673fC0f3A5930ca, 0x6dc59EE4bdFa2C791229004f29b08F783491a934, 0xADe5F5eFeAe72102d998F6C496ea59731a70eEb0, 0x443266026738061972012e62D5Ecd9D98da8B6F4, 0x1F6EF2784cbB2A5011d8CF12356fb5ee3eAeF372, 0x63f55bc560E981d53E1f5bb3643e3a96D26fc635, 0x7C3dE83D90E8d2001a7e3F38E6a7058334cB291E, 0x732fBb6018F2cB5b844055C9EB567447a3132833, 0x5A7C9FC846b18944FD2B8F8aE7255dB5af7b9c04, 0xDEea5b069208e0eE37b630A3e7672FC50e8fE24a, 0xeE83770168D4EE756e74562C17BDED88091519D0, 0x279fC7c0ebEf3328d3899FE73464347A764C5f2C, 0xAAc74d38c82c367b3dA7482E3Aecf6DD7A512eF2, 0x3aB643728bD503AE41561B4Bfe1D309A17255b8D, 0x0DAaBB4FF60423Eb1F14cC6731394e098ad51bcb, 0x4a89f96fdff3C161937CFBC3e22d2E325612aaEc, 0xcFBBF6341cf13a39ffCaF24B86dE09489116783b, 0x14Aa448C2C918C4427c5671028b63BC17f6132d5, 0x443520951d766456F2AC5578f3E7e4B56a7BcF63, 0x377D23948D41579f2c3cA40308e3bdd53f6dA7B2, 0xeB784b37365C302C97C9Ec8cB0933cE344e6dE42, 0xBBEFE691d2C3bbB835CE2958b453ccd05BdB27A5, 0x179206Cd9080A8ee77C2256A27050112da13b2f6]}, {name:powers, type:uint256[], order:2, indexed:false, value:[367390857, 229265296, 226701535, 189313375, 186231840, 176122515, 173720864, 173437833, 172577054, 171946873, 171280966, 168005078, 166134538, 163738647, 163310274, 142810822, 141999419, 136410620, 131739313, 125964543, 122948145, 122938677, 119767793, 116566385, 110401553, 70027594, 53056909, 979228, 178734], valueString:[367390857, 229265296, 226701535, 189313375, 186231840, 176122515, 173720864, 173437833, 172577054, 171946873, 171280966, 168005078, 166134538, 163738647, 163310274, 142810822, 141999419, 136410620, 131739313, 125964543, 122948145, 122938677, 119767793, 116566385, 110401553, 70027594, 53056909, 979228, 178734]}, {name:valset_id, type:uint256, order:3, indexed:false, value:29237, valueString:29237}] )
-
Null: 0x000...004.00000000( )
-
Null: 0x000...004.00000000( )
-
Null: 0x000...004.00000000( )
-
Null: 0x000...004.00000000( )
-
Null: 0x000...004.00000000( )
-
Null: 0x000...004.00000000( )
-
Null: 0x000...004.00000000( )
-
Null: 0x000...001.ab09a30e( )
-
Null: 0x000...001.ab09a30e( )
-
Null: 0x000...001.ab09a30e( )
-
Null: 0x000...001.ab09a30e( )
-
Null: 0x000...001.ab09a30e( )
-
Null: 0x000...001.ab09a30e( )
-
Null: 0x000...001.ab09a30e( )
-
Null: 0x000...001.ab09a30e( )
-
Null: 0x000...001.ab09a30e( )
-
Null: 0x000...001.ab09a30e( )
-
Null: 0x000...001.ab09a30e( )
-
Null: 0x000...001.ab09a30e( )
-
Null: 0x000...001.ab09a30e( )
-
Null: 0x000...001.ab09a30e( )
-
Null: 0x000...001.ab09a30e( )
-
Null: 0x000...001.ab09a30e( )
# @version 0.3.7 """ @title Compass-EVM @author Volume.Finance """ MAX_VALIDATORS: constant(uint256) = 320 MAX_PAYLOAD: constant(uint256) = 20480 MAX_BATCH: constant(uint256) = 64 POWER_THRESHOLD: constant(uint256) = 2_863_311_530 # 2/3 of 2^32, Validator powers will be normalized to sum to 2 ^ 32 in every valset update. COMPASS_ID: immutable(bytes32) interface ERC20: def balanceOf(_owner: address) -> uint256: view struct Valset: validators: DynArray[address, MAX_VALIDATORS] # Validator addresses powers: DynArray[uint256, MAX_VALIDATORS] # Powers of given validators, in the same order as validators array valset_id: uint256 # nonce of this validator set struct Signature: v: uint256 r: uint256 s: uint256 struct Consensus: valset: Valset # Valset data signatures: DynArray[Signature, MAX_VALIDATORS] # signatures in the same order as validator array in valset struct LogicCallArgs: logic_contract_address: address # the arbitrary contract address to external call payload: Bytes[MAX_PAYLOAD] # payloads struct TokenSendArgs: receiver: DynArray[address, MAX_BATCH] amount: DynArray[uint256, MAX_BATCH] event ValsetUpdated: checkpoint: bytes32 valset_id: uint256 event LogicCallEvent: logic_contract_address: address payload: Bytes[MAX_PAYLOAD] message_id: uint256 event SendToPalomaEvent: token: address sender: address receiver: String[64] amount: uint256 event BatchSendEvent: token: address message_id: uint256 event ERC20DeployedEvent: paloma_denom: String[64] token_contract: address name: String[64] symbol: String[32] decimals: uint8 last_checkpoint: public(bytes32) last_valset_id: public(uint256) message_id_used: public(HashMap[uint256, bool]) # compass_id: unique identifier for compass instance # valset: initial validator set @external def __init__(compass_id: bytes32, valset: Valset): COMPASS_ID = compass_id cumulative_power: uint256 = 0 i: uint256 = 0 # check cumulative power is enough for validator in valset.validators: cumulative_power += valset.powers[i] if cumulative_power >= POWER_THRESHOLD: break i += 1 assert cumulative_power >= POWER_THRESHOLD, "Insufficient Power" new_checkpoint: bytes32 = keccak256(_abi_encode(valset.validators, valset.powers, valset.valset_id, compass_id, method_id=method_id("checkpoint(address[],uint256[],uint256,bytes32)"))) self.last_checkpoint = new_checkpoint self.last_valset_id = valset.valset_id log ValsetUpdated(new_checkpoint, valset.valset_id) @external @pure def compass_id() -> bytes32: return COMPASS_ID # utility function to verify EIP712 signature @internal @pure def verify_signature(signer: address, hash: bytes32, sig: Signature) -> bool: message_digest: bytes32 = keccak256(concat(convert("\x19Ethereum Signed Message:\n32", Bytes[28]), hash)) return signer == ecrecover(message_digest, sig.v, sig.r, sig.s) # consensus: validator set and signatures # hash: what we are checking they have signed @internal def check_validator_signatures(consensus: Consensus, hash: bytes32): i: uint256 = 0 cumulative_power: uint256 = 0 for sig in consensus.signatures: if sig.v != 0: assert self.verify_signature(consensus.valset.validators[i], hash, sig), "Invalid Signature" cumulative_power += consensus.valset.powers[i] if cumulative_power >= POWER_THRESHOLD: break i += 1 assert cumulative_power >= POWER_THRESHOLD, "Insufficient Power" # Make a new checkpoint from the supplied validator set # A checkpoint is a hash of all relevant information about the valset. This is stored by the contract, # instead of storing the information directly. This saves on storage and gas. # The format of the checkpoint is: # keccak256 hash of abi_encoded checkpoint(validators[], powers[], valset_id, compass_id) # The validator powers must be decreasing or equal. This is important for checking the signatures on the # next valset, since it allows the caller to stop verifying signatures once a quorum of signatures have been verified. @internal @view def make_checkpoint(valset: Valset) -> bytes32: return keccak256(_abi_encode(valset.validators, valset.powers, valset.valset_id, COMPASS_ID, method_id=method_id("checkpoint(address[],uint256[],uint256,bytes32)"))) # This updates the valset by checking that the validators in the current valset have signed off on the # new valset. The signatures supplied are the signatures of the current valset over the checkpoint hash # generated from the new valset. # Anyone can call this function, but they must supply valid signatures of constant_powerThreshold of the current valset over # the new valset. # valset: new validator set to update with # consensus: current validator set and signatures @external def update_valset(consensus: Consensus, new_valset: Valset): # check if new valset_id is greater than current valset_id assert new_valset.valset_id > consensus.valset.valset_id, "Invalid Valset ID" cumulative_power: uint256 = 0 i: uint256 = 0 # check cumulative power is enough for validator in new_valset.validators: cumulative_power += new_valset.powers[i] if cumulative_power >= POWER_THRESHOLD: break i += 1 assert cumulative_power >= POWER_THRESHOLD, "Insufficient Power" # check if the supplied current validator set matches the saved checkpoint assert self.last_checkpoint == self.make_checkpoint(consensus.valset), "Incorrect Checkpoint" # calculate the new checkpoint new_checkpoint: bytes32 = self.make_checkpoint(new_valset) # check if enough validators signed new validator set (new checkpoint) self.check_validator_signatures(consensus, new_checkpoint) self.last_checkpoint = new_checkpoint self.last_valset_id = new_valset.valset_id log ValsetUpdated(new_checkpoint, new_valset.valset_id) # This makes calls to contracts that execute arbitrary logic # message_id is to prevent replay attack and every message_id can be used only once @external def submit_logic_call(consensus: Consensus, args: LogicCallArgs, message_id: uint256, deadline: uint256): assert block.timestamp <= deadline, "Timeout" assert not self.message_id_used[message_id], "Used Message_ID" self.message_id_used[message_id] = True # check if the supplied current validator set matches the saved checkpoint assert self.last_checkpoint == self.make_checkpoint(consensus.valset), "Incorrect Checkpoint" # signing data is keccak256 hash of abi_encoded logic_call(args, message_id, compass_id, deadline) args_hash: bytes32 = keccak256(_abi_encode(args, message_id, COMPASS_ID, deadline, method_id=method_id("logic_call((address,bytes),uint256,bytes32,uint256)"))) # check if enough validators signed args_hash self.check_validator_signatures(consensus, args_hash) # make call to logic contract raw_call(args.logic_contract_address, args.payload) log LogicCallEvent(args.logic_contract_address, args.payload, message_id) @internal def _safe_transfer_from(_token: address, _from: address, _to: address, _value: uint256): _response: Bytes[32] = raw_call( _token, _abi_encode( _from, _to, _value, method_id=method_id("transferFrom(address,address,uint256)")), max_outsize=32 ) # dev: failed transferFrom if len(_response) > 0: assert convert(_response, bool), "TransferFrom failed" @external def send_token_to_paloma(token: address, receiver: String[64], amount: uint256): _balance: uint256 = ERC20(token).balanceOf(self) self._safe_transfer_from(token, msg.sender, self, amount) _balance = ERC20(token).balanceOf(self) - _balance assert _balance > 0, "Zero Transfer" log SendToPalomaEvent(token, msg.sender, receiver, amount) @internal def _safe_transfer(_token: address, _to: address, _value: uint256): _response: Bytes[32] = raw_call( _token, _abi_encode( _to, _value, method_id=method_id("transfer(address,uint256)")), max_outsize=32 ) # dev: failed transferFrom if len(_response) > 0: assert convert(_response, bool), "TransferFrom failed" @external def submit_batch(consensus: Consensus, token: address, args: TokenSendArgs, message_id: uint256, deadline: uint256): assert block.timestamp <= deadline, "Timeout" assert not self.message_id_used[message_id], "Used Message_ID" length: uint256 = len(args.receiver) assert length == len(args.amount), "Unmatched Params" self.message_id_used[message_id] = True # check if the supplied current validator set matches the saved checkpoint assert self.last_checkpoint == self.make_checkpoint(consensus.valset), "Incorrect Checkpoint" # signing data is keccak256 hash of abi_encoded logic_call(args, message_id, compass_id, deadline) args_hash: bytes32 = keccak256(_abi_encode(token, args, message_id, COMPASS_ID, deadline, method_id=method_id("batch_call(address,(address[],uint256[]),uint256,bytes32,uint256)"))) # check if enough validators signed args_hash self.check_validator_signatures(consensus, args_hash) # make call to logic contract for i in range(MAX_BATCH): if i >= length: break self._safe_transfer(token, args.receiver[i], args.amount[i]) log BatchSendEvent(token, message_id) @external def deploy_erc20(_paloma_denom: String[64], _name: String[64], _symbol: String[32], _decimals: uint8, _blueprint: address): assert msg.sender == self, "Invalid" erc20: address = create_from_blueprint(_blueprint, self, _name, _symbol, _decimals, code_offset=3) log ERC20DeployedEvent(_paloma_denom, erc20, _name, _symbol, _decimals)