def test_send_same_function_call_twice_without_nonce_tracking( each_identity, test_contract, delegate): """Test that we can send two similar transactions to a contract by selecting a random nonce > 2**255""" to = test_contract.address argument = 10 function_call = test_contract.functions.testFunction(argument) max_nonce = 2**255 random_gap = 123456 meta_transaction = MetaTransaction.from_function_call(function_call, to=to, nonce=max_nonce) meta_transaction = each_identity.filled_and_signed_meta_transaction( meta_transaction) delegate.send_signed_meta_transaction(meta_transaction) meta_transaction = MetaTransaction.from_function_call(function_call, to=to, nonce=max_nonce + random_gap) meta_transaction = each_identity.filled_and_signed_meta_transaction( meta_transaction) delegate.send_signed_meta_transaction(meta_transaction) events = test_contract.events.TestEvent.createFilter( fromBlock=0).get_all_entries() for event in events: assert event["args"]["from"] == each_identity.address assert event["args"]["value"] == 0 assert event["args"]["argument"] == argument
def test_validate_valid_nonce_increase(each_identity, delegate, accounts): to = accounts[2] value = 1000 meta_transaction1 = each_identity.filled_and_signed_meta_transaction( MetaTransaction(to=to, value=value, nonce=1)) meta_transaction2 = each_identity.filled_and_signed_meta_transaction( MetaTransaction(to=to, value=value, nonce=2)) delegate.send_signed_meta_transaction(meta_transaction1) assert delegate.validate_meta_transaction(meta_transaction2)
def test_next_nonce(each_identity, delegate, accounts): to = accounts[2] value = 1000 meta_transaction1 = each_identity.filled_and_signed_meta_transaction( MetaTransaction(to=to, value=value, nonce=1)) meta_transaction2 = each_identity.filled_and_signed_meta_transaction( MetaTransaction(to=to, value=value, nonce=2)) delegate.send_signed_meta_transaction(meta_transaction1) delegate.send_signed_meta_transaction(meta_transaction2) assert delegate.get_next_nonce(each_identity.address) == 3
def test_delegated_transaction_invalid_nonce(identity, delegate, accounts): to = accounts[2] value = 1000 meta_transaction1 = identity.filled_and_signed_meta_transaction( MetaTransaction(to=to, value=value, nonce=1)) meta_transaction2 = identity.filled_and_signed_meta_transaction( MetaTransaction(to=to, value=value, nonce=1)) delegate.send_signed_meta_transaction(meta_transaction1) with pytest.raises(InvalidMetaTransactionException): delegate.send_signed_meta_transaction(meta_transaction2)
def test_delegated_transaction_nonce_gap_fails(each_identity, delegate, web3, accounts): to = accounts[2] value = 1000 meta_transaction1 = each_identity.filled_and_signed_meta_transaction( MetaTransaction(to=to, value=value, nonce=1)) meta_transaction2 = each_identity.filled_and_signed_meta_transaction( MetaTransaction(to=to, value=value, nonce=3)) delegate.send_signed_meta_transaction(meta_transaction1) with pytest.raises(TransactionFailed): delegate.send_signed_meta_transaction(meta_transaction2)
def test_meta_transaction_fee_recipient(currency_network_contract, each_identity, delegate, delegate_address, accounts): A = each_identity.address B = accounts[3] to = currency_network_contract.address base_fee = 123 function_call = currency_network_contract.functions.updateCreditlimits( B, 100, 100) meta_transaction = MetaTransaction.from_function_call(function_call, to=to, base_fee=base_fee) meta_transaction = attr.evolve(meta_transaction, fee_recipient=B) meta_transaction = each_identity.filled_and_signed_meta_transaction( meta_transaction) delegate.send_signed_meta_transaction(meta_transaction) debt_A_B = currency_network_contract.functions.getDebt(A, B).call() debt_A_delegate = currency_network_contract.functions.getDebt( A, delegate_address).call() assert debt_A_B == base_fee assert debt_A_delegate == 0 fee_payment_event = each_identity.contract.events.FeePayment().getLogs( )[-1] assert fee_payment_event["args"]["value"] == base_fee assert fee_payment_event["args"]["recipient"] == B
def test_delegated_transaction_hash(each_identity_contract, test_contract, accounts): to = accounts[3] from_ = each_identity_contract.address argument = 10 function_call = test_contract.functions.testFunction(argument) meta_transaction = MetaTransaction.from_function_call(function_call, from_=from_, to=to, nonce=0) hash_by_contract = each_identity_contract.functions.transactionHash( meta_transaction.to, meta_transaction.value, meta_transaction.data, meta_transaction.base_fee, meta_transaction.gas_price, meta_transaction.gas_limit, meta_transaction.fee_recipient, meta_transaction.currency_network_of_fees, meta_transaction.nonce, meta_transaction.time_limit, meta_transaction.operation_type.value, ).call() hash = meta_transaction.hash assert hash == HexBytes(hash_by_contract)
def test_proxy_overhead(web3, table, test_contract, proxied_identity, identity, delegate): """Tests the overhead of using an identity proxy compared to a regular identity""" to = test_contract.address argument = 10 function_call = test_contract.functions.testFunction(argument) meta_transaction = MetaTransaction.from_function_call(function_call, to=to) proxied_meta_transaction = proxied_identity.filled_and_signed_meta_transaction( meta_transaction) not_proxied_meta_transaction = identity.filled_and_signed_meta_transaction( meta_transaction) proxied_meta_tx_id = delegate.send_signed_meta_transaction( proxied_meta_transaction) not_proxied_meta_tx_id = delegate.send_signed_meta_transaction( not_proxied_meta_transaction) gas_cost_proxied_meta_tx = get_gas_costs(web3, proxied_meta_tx_id) gas_cost_not_proxied_tx = get_gas_costs(web3, not_proxied_meta_tx_id) overhead = gas_cost_proxied_meta_tx - gas_cost_not_proxied_tx report_gas_costs(table, "Overhead of a proxy over non-proxy meta-tx", overhead, limit=1500)
def test_meta_tx_over_regular_tx_overhead( web3, gas_values_snapshot, test_contract, identity, delegate ): """Tests the overhead of using a meta-tx compared to a regular tx""" # The test sends two meta-tx as the first meta-tx of an identity is more expensive than all the next ones # due to storage allocation to = test_contract.address argument = 10 function_call = test_contract.functions.testFunction(argument) # first meta-tx meta_transaction = MetaTransaction.from_function_call(function_call, to=to) filled_meta_tx = identity.filled_and_signed_meta_transaction(meta_transaction) delegate.send_signed_meta_transaction(filled_meta_tx) # second meta-tx we meter second_filled_meta_transaction = identity.filled_and_signed_meta_transaction( meta_transaction ) meta_tx_id = delegate.send_signed_meta_transaction(second_filled_meta_transaction) regular_tx_id = test_contract.functions.testFunction(argument).transact() gas_cost_meta_tx = get_gas_costs(web3, meta_tx_id) gas_cost_regular_tx = get_gas_costs(web3, regular_tx_id) overhead = gas_cost_meta_tx - gas_cost_regular_tx gas_values_snapshot.assert_gas_costs_match( "UNPROXIED_META_TRANSACTION_OVERHEAD", overhead )
def test_meta_transaction_create_contract_fails(each_identity, delegate, non_payable_contract_inticode, web3, operation_type): """Test that the status in the event is False when deployment fails""" # To make the deployment fail we deploy a contract whose constructor is not payable # and transfer it eth during deployment deployed_contract_balance = 123 meta_transaction = MetaTransaction( operation_type=operation_type, data=non_payable_contract_inticode, value=deployed_contract_balance, ) meta_transaction = each_identity.filled_and_signed_meta_transaction( meta_transaction) tx_id = delegate.send_signed_meta_transaction(meta_transaction) execution_event = each_identity.contract.events.TransactionExecution.createFilter( fromBlock=0).get_all_entries()[0]["args"] # assert that the create failed assert get_transaction_status(web3, tx_id) assert execution_event["hash"] == meta_transaction.hash assert execution_event["status"] is False deploy_events = each_identity.contract.events.ContractDeployment.createFilter( fromBlock=0).get_all_entries() assert len(deploy_events) == 0
def test_meta_tx_over_own_identity_tx_overhead(web3, table, test_contract, identity, owner, delegate): """Tests the overhead of using a meta-tx compared to an owned identity tx""" # The test sends two meta-tx as the first meta-tx of an identity is more expensive than all the next ones # due to storage allocation to = test_contract.address argument = 10 function_call = test_contract.functions.testFunction(argument) # first meta-tx meta_transaction = MetaTransaction.from_function_call(function_call, to=to) filled_meta_tx = identity.filled_and_signed_meta_transaction( meta_transaction) delegate.send_signed_meta_transaction(filled_meta_tx) # second meta-tx we meter second_filled_meta_transaction = identity.filled_and_signed_meta_transaction( meta_transaction) meta_tx_id = delegate.send_signed_meta_transaction( second_filled_meta_transaction) owner_tx_id = identity.contract.functions.execute( to, 0, meta_transaction.data, 0, 0).transact({"from": owner}) gas_cost_meta_tx = get_gas_costs(web3, meta_tx_id) gas_cost_owner_tx = get_gas_costs(web3, owner_tx_id) overhead = gas_cost_meta_tx - gas_cost_owner_tx report_gas_costs( table, "Overhead of unproxied meta-tx over owned transaction", overhead, limit=22000, )
def test_delegated_transaction_wrong_from(each_identity_contract, delegate_address, accounts, owner_key, chain_id): from_ = accounts[3] to = accounts[2] value = 1000 meta_transaction = MetaTransaction(from_=from_, to=to, value=value, nonce=0, chain_id=chain_id).signed(owner_key) with pytest.raises(TransactionFailed): each_identity_contract.functions.executeTransaction( meta_transaction.to, meta_transaction.value, meta_transaction.data, meta_transaction.base_fee, meta_transaction.gas_price, meta_transaction.gas_limit, meta_transaction.fee_recipient, meta_transaction.currency_network_of_fees, meta_transaction.nonce, meta_transaction.time_limit, meta_transaction.operation_type.value, meta_transaction.signature, ).transact({"from": delegate_address})
def test_own_identity_meta_tx_overhead(web3, table, test_contract, identity, owner, delegate): """Tests the overhead of using an owned meta-tx compared to a regular tx""" to = test_contract.address argument = 10 function_call = test_contract.functions.testFunction(argument) meta_transaction = MetaTransaction.from_function_call(function_call, to=to) owner_tx_id = identity.contract.functions.execute( to, 0, meta_transaction.data, 0, 0).transact({"from": owner}) regular_tx_id = test_contract.functions.testFunction(argument).transact() gas_cost_owner_meta_tx = get_gas_costs(web3, owner_tx_id) gas_cost_regular_tx = get_gas_costs(web3, regular_tx_id) overhead = gas_cost_owner_meta_tx - gas_cost_regular_tx report_gas_costs( table, "Overhead of owned unproxied meta-tx over regular transaction", overhead, limit=5000, )
def test_tracking_delegation_fee_in_different_network( currency_network_contract, second_currency_network_contract, each_identity, delegate, delegate_address, accounts, ): A = each_identity.address B = accounts[3] to = currency_network_contract.address base_fee = 123 function_call = currency_network_contract.functions.updateCreditlimits( B, 100, 100) meta_transaction = each_identity.filled_and_signed_meta_transaction( MetaTransaction.from_function_call( function_call, to=to, base_fee=base_fee, currency_network_of_fees=second_currency_network_contract.address, )) delegate.send_signed_meta_transaction(meta_transaction) assert currency_network_contract.functions.getDebt( A, delegate_address).call() == 0 assert (second_currency_network_contract.functions.getDebt( A, delegate_address).call() == base_fee)
def test_meta_tx_over_regular_tx_overhead(web3, table, test_contract, identity, delegate): """Tests the overhead of using a meta-tx compared to a regular tx""" # The test sends two meta-tx as the first meta-tx of an identity is more expensive than all the next ones # due to storage allocation to = test_contract.address argument = 10 function_call = test_contract.functions.testFunction(argument) # first meta-tx meta_transaction = MetaTransaction.from_function_call(function_call, to=to) filled_meta_tx = identity.filled_and_signed_meta_transaction( meta_transaction) delegate.send_signed_meta_transaction(filled_meta_tx) # second meta-tx we meter second_filled_meta_transaction = identity.filled_and_signed_meta_transaction( meta_transaction) meta_tx_id = delegate.send_signed_meta_transaction( second_filled_meta_transaction) regular_tx_id = test_contract.functions.testFunction(argument).transact() gas_cost_meta_tx = get_gas_costs(web3, meta_tx_id) gas_cost_regular_tx = get_gas_costs(web3, regular_tx_id) overhead = gas_cost_meta_tx - gas_cost_regular_tx report_gas_costs(table, "Overhead of unproxied meta-tx over regular tx", overhead, limit=26750)
def test_proxy_overhead( web3, gas_values_snapshot, test_contract, proxied_identity, identity, delegate ): """Tests the overhead of using an identity proxy compared to a regular identity""" to = test_contract.address argument = 10 function_call = test_contract.functions.testFunction(argument) meta_transaction = MetaTransaction.from_function_call(function_call, to=to) proxied_meta_transaction = proxied_identity.filled_and_signed_meta_transaction( meta_transaction ) not_proxied_meta_transaction = identity.filled_and_signed_meta_transaction( meta_transaction ) proxied_meta_tx_id = delegate.send_signed_meta_transaction(proxied_meta_transaction) not_proxied_meta_tx_id = delegate.send_signed_meta_transaction( not_proxied_meta_transaction ) gas_cost_proxied_meta_tx = get_gas_costs(web3, proxied_meta_tx_id) gas_cost_not_proxied_tx = get_gas_costs(web3, not_proxied_meta_tx_id) overhead = gas_cost_proxied_meta_tx - gas_cost_not_proxied_tx gas_values_snapshot.assert_gas_costs_match( "PROXIED_META_TRANSACTION_OVERHEAD_OVER_NONPROXY_METATRANSACTION", overhead )
def test_gas_pricing(delegate, delegate_config, gas_price_config, gas_price): config = dict(**delegate_config) config.update(gas_price_config) delegate.config = config assert delegate._calculate_gas_price(MetaTransaction()) == gas_price
def test_meta_transaction_delegate_call(each_identity, delegate, delegate_address, web3, test_contract): to = test_contract.address argument = 123 function_call = test_contract.functions.testFunction(argument) meta_transaction = MetaTransaction.from_function_call(function_call, to=to) meta_transaction = attr.evolve( meta_transaction, operation_type=MetaTransaction.OperationType.DELEGATE_CALL) meta_transaction = each_identity.filled_and_signed_meta_transaction( meta_transaction) tx_id = delegate.send_signed_meta_transaction(meta_transaction) execution_event = each_identity.contract.events.TransactionExecution.createFilter( fromBlock=0).get_all_entries()[0]["args"] # assert that the delegate call was successful assert get_transaction_status(web3, tx_id) assert execution_event["hash"] == meta_transaction.hash assert execution_event["status"] is True proxied_test_contract = web3.eth.contract(each_identity.contract.address, abi=test_contract.abi) test_event = proxied_test_contract.events.TestEvent.createFilter( fromBlock=0).get_all_entries()[0]["args"] # assert that the successful operation was indeed a delegate call # by checking that `from` is delegate_address and not identity_address assert test_event["from"] == delegate_address assert test_event["value"] == 0 assert test_event["argument"] == argument
def test_revoke_meta_transaction_nonce(each_identity, delegate, test_contract): """Test that we can revoke a meta-tx that uses nonce anti-replay mechanism via using the nonce""" to = test_contract.address argument = 10 function_call = test_contract.functions.testFunction(argument) meta_transaction = each_identity.filled_and_signed_meta_transaction( MetaTransaction.from_function_call(function_call, to=to)) revoke_meta_transaction = each_identity.filled_and_signed_meta_transaction( MetaTransaction(to=each_identity.address, nonce=meta_transaction.nonce)) delegate.send_signed_meta_transaction(revoke_meta_transaction) assert not delegate.validate_meta_transaction(meta_transaction) with pytest.raises(TransactionFailed): delegate.send_signed_meta_transaction(meta_transaction)
def transfer_meta_transaction(self, value, max_fee, path, extra_data=b""): function_call = self._proxy.functions.transfer(value, max_fee, path, extra_data) meta_transaction = MetaTransaction.from_function_call( function_call, to=self.address ) return meta_transaction
def test_validate_valid_transfer(each_identity, delegate, accounts): to = accounts[2] value = 1000 meta_transaction = each_identity.filled_and_signed_meta_transaction( MetaTransaction(to=to, value=value)) assert delegate.validate_meta_transaction(meta_transaction)
def test_get_not_found_meta_transaction_status(each_identity, delegate): meta_transaction = each_identity.filled_and_signed_meta_transaction( MetaTransaction(to=each_identity.address)) meta_tx_status = delegate.get_meta_transaction_status( each_identity.address, meta_transaction.hash) assert meta_tx_status == MetaTransactionStatus.NOT_FOUND
def test_delegated_transaction_nonce_increase(each_identity, delegate, web3, accounts): to = accounts[2] value = 1000 balance_before = web3.eth.getBalance(to) meta_transaction1 = each_identity.filled_and_signed_meta_transaction( MetaTransaction(to=to, value=value, nonce=1)) meta_transaction2 = each_identity.filled_and_signed_meta_transaction( MetaTransaction(to=to, value=value, nonce=2)) delegate.send_signed_meta_transaction(meta_transaction1) delegate.send_signed_meta_transaction(meta_transaction2) balance_after = web3.eth.getBalance(to) assert balance_after - balance_before == value + value
def test_estimate_gas(each_identity, delegate, accounts): to = accounts[2] value = 1000 meta_transaction = each_identity.filled_and_signed_meta_transaction( MetaTransaction(to=to, value=value)) assert isinstance( delegate.estimate_gas_signed_meta_transaction(meta_transaction), int)
def test_get_successful_meta_transaction_status(each_identity, delegate): meta_transaction = each_identity.filled_and_signed_meta_transaction( MetaTransaction(to=each_identity.address)) delegate.send_signed_meta_transaction(meta_transaction) meta_tx_status = delegate.get_meta_transaction_status( each_identity.address, meta_transaction.hash) assert meta_tx_status == MetaTransactionStatus.SUCCESS
def _deserialize(self, value, attr, data, **kwargs): # deserialize into the OperationType enum instance corresponding to the value try: return MetaTransaction.OperationType(value) except ValueError: raise ValidationError( f"Could not parse attribute {attr}: {value} has to be one of " f"{[operation_type.value for operation_type in MetaTransaction.OperationType]}" )
def test_cannot_revoke_executed_transaction(each_identity, delegate, test_contract): """Test that we can not revoke a meta-tx that was already executed""" to = test_contract.address argument = 10 function_call = test_contract.functions.testFunction(argument) meta_transaction = each_identity.filled_and_signed_meta_transaction( MetaTransaction.from_function_call(function_call, to=to, nonce=0)) delegate.send_signed_meta_transaction(meta_transaction) revoke_function_call = each_identity.contract.functions.cancelTransaction( meta_transaction.hash) revoke_meta_transaction = each_identity.filled_and_signed_meta_transaction( MetaTransaction.from_function_call(revoke_function_call, to=each_identity.address)) delegate.send_signed_meta_transaction(revoke_meta_transaction) events = each_identity.contract.events.TransactionCancellation().getLogs() assert len(events) == 0
def test_reveoke_meta_transaction_nonce_via_hash(each_identity, delegate, test_contract): """Test that we can revoke a meta-tx that uses nonce anti-replay mechanism via canceling the hash""" to = test_contract.address argument = 10 function_call = test_contract.functions.testFunction(argument) meta_transaction = each_identity.filled_and_signed_meta_transaction( MetaTransaction.from_function_call(function_call, to=to)) revoke_function_call = each_identity.contract.functions.cancelTransaction( meta_transaction.hash) revoke_meta_transaction = each_identity.filled_and_signed_meta_transaction( MetaTransaction.from_function_call(revoke_function_call, to=each_identity.address)) delegate.send_signed_meta_transaction(revoke_meta_transaction) assert not delegate.validate_meta_transaction(meta_transaction) with pytest.raises(SolidityError): delegate.send_signed_meta_transaction(meta_transaction)
def test_delegated_transaction_same_tx_fails(each_identity, delegate, accounts, web3): to = accounts[2] value = 1000 meta_transaction = MetaTransaction(to=to, value=value) meta_transaction = each_identity.filled_and_signed_meta_transaction( meta_transaction) delegate.send_signed_meta_transaction(meta_transaction) with pytest.raises(TransactionFailed): delegate.send_signed_meta_transaction(meta_transaction)
def test_meta_transaction_gas_limit(each_identity, delegate, web3, accounts): to = accounts[2] value = 1000 gas_limit = 456 meta_transaction = MetaTransaction(to=to, value=value, gas_limit=gas_limit) meta_transaction = each_identity.filled_and_signed_meta_transaction( meta_transaction) with pytest.raises(TransactionFailed): delegate.send_signed_meta_transaction(meta_transaction)