def allocate_transaction(self, broadcast_account: _BroadcastAccount, receiver: Optional[str], contract_address: Optional[str], contract_deployment: bool, nonce: int, note: str, unsigned_payload: dict, gas_price: Optional[int], gas_limit: Optional[int]) -> _PreparedTransaction: """Put a transaction to the pending queue of the current broadcast list.""" if receiver: assert receiver.startswith("0x") assert contract_deployment in (True, False) assert broadcast_account.current_nonce == nonce assert type(unsigned_payload) == dict assert_valid_fields(unsigned_payload) tx = self.prepared_tx_model() # type: _PreparedTransaction tx.nonce = nonce tx.human_readable_description = note tx.receiver = receiver tx.contract_address = contract_address tx.contract_deployment = contract_deployment tx.unsigned_payload = unsigned_payload broadcast_account.txs.append(tx) broadcast_account.current_nonce += 1 return tx
def test_player_roll_dice(self): """ Verifies the transaction is properly built and sent. """ # simplified contract ABI contract_abi = [self.player_roll_dice_abi] with mock.patch('etherscan.contracts.Contract.get_abi') \ as m_get_abi: m_get_abi.return_value = json.dumps(contract_abi) etheroll = Etheroll() bet_size_ether = 0.1 chances = 50 wallet_password = '******' account = self.create_account_helper(wallet_password) wallet_path = account.path with \ mock.patch('web3.eth.Eth.sendRawTransaction') \ as m_sendRawTransaction, mock.patch( 'web3.eth.Eth.getTransactionCount' ) as m_getTransactionCount, mock.patch( 'eth_account.account.Account.signTransaction' ) as m_signTransaction: m_getTransactionCount.return_value = 0 transaction = etheroll.player_roll_dice( bet_size_ether, chances, wallet_path, wallet_password) # the method should return a transaction hash self.assertIsNotNone(transaction) # a second one with custom gas (in gwei), refs #23 gas_price_gwei = 12 transaction = etheroll.player_roll_dice( bet_size_ether, chances, wallet_path, wallet_password, gas_price_gwei) self.assertIsNotNone(transaction) # the nonce was retrieved self.assertTrue(m_getTransactionCount.called) # the transaction was sent self.assertTrue(m_sendRawTransaction.called) # the transaction should be built that way expected_transaction1 = { 'nonce': 0, 'chainId': 1, 'to': Etheroll.CONTRACT_ADDRESSES[ChainID.MAINNET], 'data': ( '0xdc6dd152000000000000000000000000000' '0000000000000000000000000000000000032'), 'gas': 310000, 'value': 100000000000000000, 'gasPrice': 4000000000 } expected_transaction2 = expected_transaction1.copy() expected_transaction2['gasPrice'] = 12*1e9 expected_call1 = mock.call(expected_transaction1, account.privkey) expected_call2 = mock.call(expected_transaction2, account.privkey) # the method should have been called only once expected_calls = [expected_call1, expected_call2] self.assertEqual(m_signTransaction.call_args_list, expected_calls) # also make sure the transaction dict is passing the validation # e.g. scientific notation 1e+17 is not accepted transaction_dict = m_signTransaction.call_args[0][0] assert_valid_fields(transaction_dict) # even though below values are equal self.assertTrue(transaction_dict['value'] == 0.1 * 1e18 == 1e17) # this is not accepted by `assert_valid_fields()` transaction_dict['value'] = 0.1 * 1e18 with self.assertRaises(TypeError): assert_valid_fields(transaction_dict) # because float are not accepted self.assertEqual(type(transaction_dict['value']), float)