2

I have a solidity contract like the following:

contract MyToken {
    string public symbol;
    string public  name;
    uint8 public decimals;
    uint public _totalSupply;

    mapping(address => uint) balances;
    mapping(address => mapping(address => uint)) allowed;


    constructor() {
        symbol = "my";
        name = "My Token";
        decimals = 18;
        _totalSupply = 100000000000000000000000000;

        balances[0x364ca3F935E88Fbc9e041d2032F996CAc69452e6] = _totalSupply / 2; 
        balances[0x5506195d8111B5e150Fb68Ceba2806c546C5a28B] = _totalSupply / 2; 

        Transfer(address(0), 0x364ca3F935E88Fbc9e041d2032F996CAc69452e6,
                 _totalSupply / 2);
        Transfer(address(0), 0x5506195d8111B5e150Fb68Ceba2806c546C5a28B,
                 _totalSupply / 2);
    }



    // ------------------------------------------------------------------------
    // Transfer the balance from token owner's account to to account
    // - Owner's account must have sufficient balance to transfer
    // - 0 value transfers are allowed
    // ------------------------------------------------------------------------
    function transfer(address to, uint tokens) public returns (bool success) {
        // this isn't safe for the sake of minimal example
        balances[msg.sender] -= tokens;
        balances[to] += tokens;
        Transfer(msg.sender, to, tokens);
        return true;
    }

}

I'm using web3py to run tests against this contract but I'm having trouble transferring coins from 0x5506195d8111B5e150Fb68Ceba2806c546C5a28B to a dummy address which I declare in my tests. My tests are as follows:

import web3
import unittest


class TestMycroToken(unittest.TestCase):

    def setUp(self):
        self.w3 = web3.Web3(web3.EthereumTesterProvider())
        self.contract, self.contract_address, self.contract_instance = self.deploy_contract()

    def deploy_contract():
        compiled_sol = compile_files([])

        contract_interface = compiled_sol[f'{PATH_TO_MY_CONTRACT}:MyToken']

        # Instantiate and deploy contract
        contract = self.w3.eth.contract(abi=contract_interface['abi'], bytecode=contract_interface['bin'])

        # Get transaction hash from deployed contract
        tx_hash = contract.constructor().transact({'from': self.w3.eth.accounts[0]})

        # Get tx receipt to get contract address
        tx_receipt = self.w3.eth.getTransactionReceipt(tx_hash)
        contract_address = tx_receipt['contractAddress']

        # Contract instance in concise mode
        abi = contract_interface['abi']
        contract_instance = self.w3.eth.contract(address=contract_address, abi=abi,
                                            ContractFactoryClass=web3.contract.ConciseContract)

        return contract, contract_address, contract_instance

    def test_transfer(self):
        DUMMY_USER = "0x1111111111111111111111111111111111111112"
        USER_ADDRESS = "0x5506195d8111B5e150Fb68Ceba2806c546C5a28B"

        # this line fails
        self.contract_instance.transfer(DEFAULT_USER, 10, transact={'from': USER_ADDRESS})

When I try to transfer coins from USER_ADDRESS (who has coins sent to them during the constructor) I get the following failure:

Error
Traceback (most recent call last):
  File "/Users/paymahn/mycro/venv/lib/python3.6/site-packages/eth_tester/backends/pyethereum/v16/main.py", line 137, in _send_evm_transaction
    sender = tester.keys[tester.accounts.index(transaction['from'])]
ValueError: b'U\x06\x19]\x81\x11\xb5\xe1P\xfbh\xce\xba(\x06\xc5F\xc5\xa2\x8b' is not in list

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/usr/local/Cellar/python/3.6.4_4/Frameworks/Python.framework/Versions/3.6/lib/python3.6/unittest/case.py", line 59, in testPartExecutor
    yield
  File "/usr/local/Cellar/python/3.6.4_4/Frameworks/Python.framework/Versions/3.6/lib/python3.6/unittest/case.py", line 605, in run
    testMethod()
  File "/Users/paymahn/mycro/tests/test_mycro_token.py", line 129, in test_vote_then_move_balance_is_useless
    self.contract_instance.transfer(DEFAULT_USER, 10, transact={'from': AARON_ADDRESS})
  File "/Users/paymahn/mycro/venv/lib/python3.6/site-packages/web3/contract.py", line 777, in __call__
    return self.__prepared_function(*args, **kwargs)
  File "/Users/paymahn/mycro/venv/lib/python3.6/site-packages/web3/contract.py", line 790, in __prepared_function
    return getattr(self._function(*args), modifier)(modifier_dict)
  File "/Users/paymahn/mycro/venv/lib/python3.6/site-packages/web3/contract.py", line 1028, in transact
    **self.kwargs)
  File "/Users/paymahn/mycro/venv/lib/python3.6/site-packages/web3/contract.py", line 1305, in transact_with_contract_function
    txn_hash = web3.eth.sendTransaction(transact_transaction)
  File "/Users/paymahn/mycro/venv/lib/python3.6/site-packages/web3/eth.py", line 247, in sendTransaction
    get_buffered_gas_estimate(self.web3, transaction),
  File "/Users/paymahn/mycro/venv/lib/python3.6/site-packages/web3/utils/transactions.py", line 72, in get_buffered_gas_estimate
    gas_estimate = web3.eth.estimateGas(gas_estimate_transaction)
  File "/Users/paymahn/mycro/venv/lib/python3.6/site-packages/web3/eth.py", line 288, in estimateGas
    [transaction],
  File "/Users/paymahn/mycro/venv/lib/python3.6/site-packages/web3/manager.py", line 103, in request_blocking
    response = self._make_request(method, params)
  File "/Users/paymahn/mycro/venv/lib/python3.6/site-packages/web3/manager.py", line 86, in _make_request
    return request_func(method, params)
  File "/Users/paymahn/mycro/venv/lib/python3.6/site-packages/web3/middleware/gas_price_strategy.py", line 18, in middleware
    return make_request(method, params)
  File "/Users/paymahn/mycro/venv/lib/python3.6/site-packages/web3/middleware/formatting.py", line 21, in middleware
    response = make_request(method, formatted_params)
  File "/Users/paymahn/mycro/venv/lib/python3.6/site-packages/web3/middleware/attrdict.py", line 18, in middleware
    response = make_request(method, params)
  File "/Users/paymahn/mycro/venv/lib/python3.6/site-packages/web3/middleware/formatting.py", line 21, in middleware
    response = make_request(method, formatted_params)
  File "/Users/paymahn/mycro/venv/lib/python3.6/site-packages/web3/middleware/normalize_errors.py", line 9, in middleware
    result = make_request(method, params)
  File "/Users/paymahn/mycro/venv/lib/python3.6/site-packages/web3/middleware/validation.py", line 44, in middleware
    return make_request(method, post_validated_params)
  File "/Users/paymahn/mycro/venv/lib/python3.6/site-packages/web3/middleware/formatting.py", line 21, in middleware
    response = make_request(method, formatted_params)
  File "/Users/paymahn/mycro/venv/lib/python3.6/site-packages/web3/providers/eth_tester/middleware.py", line 315, in middleware
    return make_request(method, [filled_transaction] + params[1:])
  File "/Users/paymahn/mycro/venv/lib/python3.6/site-packages/web3/middleware/fixture.py", line 12, in middleware
    return make_request(method, params)
  File "/Users/paymahn/mycro/venv/lib/python3.6/site-packages/web3/middleware/formatting.py", line 21, in middleware
    response = make_request(method, formatted_params)
  File "/Users/paymahn/mycro/venv/lib/python3.6/site-packages/web3/providers/eth_tester/main.py", line 46, in make_request
    response = delegator(self.ethereum_tester, params)
  File "cytoolz/functoolz.pyx", line 232, in cytoolz.functoolz.curry.__call__
  File "/Users/paymahn/mycro/venv/lib/python3.6/site-packages/web3/providers/eth_tester/defaults.py", line 36, in call_eth_tester
    return getattr(eth_tester, fn_name)(*fn_args, **fn_kwargs)
  File "/Users/paymahn/mycro/venv/lib/python3.6/site-packages/eth_tester/main.py", line 466, in estimate_gas
    raw_gas_estimate = self.backend.estimate_gas(raw_transaction)
  File "/Users/paymahn/mycro/venv/lib/python3.6/site-packages/eth_tester/utils/formatting.py", line 85, in wrapper
    return to_wrap(*args, **kwargs)
  File "/Users/paymahn/mycro/venv/lib/python3.6/site-packages/eth_tester/backends/pyethereum/v16/main.py", line 439, in estimate_gas
    transaction=transaction,
  File "/Users/paymahn/mycro/venv/lib/python3.6/site-packages/eth_tester/backends/pyethereum/v16/main.py", line 157, in _estimate_evm_transaction
    return _send_evm_transaction(tester_module, evm, transaction_for_estimate)
  File "/Users/paymahn/mycro/venv/lib/python3.6/site-packages/eth_tester/backends/pyethereum/v16/main.py", line 139, in _send_evm_transaction
    sender = evm.extra_accounts[transaction['from']]
KeyError: b'U\x06\x19]\x81\x11\xb5\xe1P\xfbh\xce\xba(\x06\xc5F\xc5\xa2\x8b'

This makes sense to me, USER_ADDRESS was never registered as a sender in the test provider (I'm sure I got some of that terminology wrong). In the deploy_contract function, I send the constructor transaction from self.w3.eth.accounts[0].

My question is: how can I send currency in web3py from an address that gets coins during initialization?

1

Perhaps your best option here is to pass in the addresses as parameters to the constructor. Then during testing, you can send in w3.eth.accounts[1] as the account to pre-fund. Something like:

constructor(address recipient1, address recipient2) {
    symbol = "my";
    name = "My Token";
    decimals = 18;
    _totalSupply = 100000000000000000000000000;

    balances[recipient1] = _totalSupply / 2; 
    balances[recipient2] = _totalSupply / 2; 

    Transfer(address(0), recipient1, _totalSupply / 2);
    Transfer(address(0), recipient2, _totalSupply / 2);
}

You can then deploy the contract with:

    tx_hash = contract.constructor(
        w3.eth.accounts[1],
        w3.eth.accounts[2],
    ).transact({'from': self.w3.eth.accounts[0]})

Side note: probably the best backend to use for eth-tester is the py-evm one. It is the most actively maintained. They should all generally work, though.

  • That's exactly the solution I stumbled on myself but I forgot to post an answer! I'll look into using py-evm, I thought that the backend was automatically chosen by EthereumTesterProvider. I'm also thinking about switching away form web3py to web3js because web3js looks more actively developed. – Paymahn Moghadasian May 19 '18 at 16:14
  • 1
    Hah, glad you got it resolved! I'd say use whatever language you're more comfortable with. If you like Python more, but are still unsure because of missing features in web3py, I'd love to hear about it in the web3py chat room or on a web3py issue. – carver May 21 '18 at 18:14

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.