¿Cómo envío tokens con EthereumTesterProvider?

Tengo un contrato de solidez como el siguiente:

contrato MiToken {
    símbolo público de cadena;
    cadena nombre público;
    uint8 decimales públicos;
    uint public _totalSupply;

    mapeo(dirección => uint) saldos;
    mapeo (dirección => mapeo (dirección => uint)) permitido;


    constructor() {
        símbolo = "mi";
        nombre = "Mi token";
        decimales = 18;
        _totalSupply = 1000000000000000000000000000;

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

        Transferencia (dirección (0), 0x364ca3F935E88Fbc9e041d2032F996CAc69452e6,
                 _suministrototal / 2);
        Transferencia (dirección (0), 0x5506195d8111B5e150Fb68Ceba2806c546C5a28B,
                 _suministrototal / 2);
    }



    // ------------------------------------------------ ------------------------
    // Transferir el saldo de la cuenta del propietario del token a la cuenta
    // - La cuenta del propietario debe tener saldo suficiente para transferir
    // - Se permiten transferencias de valor 0
    // ------------------------------------------------ ------------------------
    transferencia de función (dirección a, tokens uint) devoluciones públicas (éxito bool) {
        // esto no es seguro por el bien de un ejemplo mínimo
        saldos[msg.sender] -= fichas;
        saldos[a] += fichas;
        Transferir (msg.sender, to, tokens);
        devolver verdadero;
    }

}

Estoy usando web3py para ejecutar pruebas contra este contrato, pero tengo problemas para transferir monedas desde 0x5506195d8111B5e150Fb68Ceba2806c546C5a28Buna dirección ficticia que declaro en mis pruebas. Mis pruebas son las siguientes:

importar web3
prueba unitaria de importación


clase TestMycroToken(unittest.TestCase):

    def configurar(auto):
        self.w3 = web3.Web3(web3.EthereumTesterProvider())
        self.contrato, self.dirección_contrato, self.instancia_contrato = self.deploy_contrato()

    def desplegar_contrato():
        compilado_sol = compilar_archivos([])

        interfaz_contrato = compilado_sol[f'{RUTA_A_MI_CONTRATO}:MiToken']

        # Instanciar e implementar contrato
        contrato = self.w3.eth.contrato(abi=contrato_interfaz['abi'], bytecode=contrato_interfaz['bin'])

        # Obtenga el hash de transacción del contrato implementado
        tx_hash = contrato.constructor().transact({'de': self.w3.eth.cuentas[0]})

        # Obtenga el recibo de tx para obtener la dirección del contrato
        tx_receipt = self.w3.eth.getTransactionReceipt(tx_hash)
        dirección_contrato = tx_receipt['dirección_contrato']

        # Instancia de contrato en modo conciso
        abi = interfaz_contrato['abi']
        instancia_contrato = self.w3.eth.contrato(dirección=dirección_contrato, abi=abi,
                                            ContractFactoryClass=web3.contract.ConciseContract)

        contrato de devolución, dirección_contrato, instancia_contrato

    def test_transfer(auto):
        DUMMY_USER = "0x11111111111111111111111111111111111111112"
        DIRECCIÓN_USUARIO = "0x5506195d8111B5e150Fb68Ceba2806c546C5a28B"

        # esta linea falla
        self.contract_instance.transfer(DEFAULT_USER, 10, transact={'from': USER_ADDRESS})

Cuando trato de transferir monedas de USER_ADDRESS(a quién se le enviaron monedas durante el constructor) obtengo el siguiente error:

Error
Rastreo (llamadas recientes más última):
  Archivo "/Users/paymahn/mycro/venv/lib/python3.6/site-packages/eth_tester/backends/pyethereum/v16/main.py", línea 137, en _send_evm_transaction
    remitente = tester.keys[tester.accounts.index(transacción['de'])]
ValueError: b'U\x06\x19]\x81\x11\xb5\xe1P\xfbh\xce\xba(\x06\xc5F\xc5\xa2\x8b' no está en la lista

Durante el manejo de la excepción anterior, ocurrió otra excepción:

Rastreo (llamadas recientes más última):
  Archivo "/usr/local/Cellar/python/3.6.4_4/Frameworks/Python.framework/Versions/3.6/lib/python3.6/unittest/case.py", línea 59, en testPartExecutor
    producir
  Archivo "/usr/local/Cellar/python/3.6.4_4/Frameworks/Python.framework/Versions/3.6/lib/python3.6/unittest/case.py", línea 605, en ejecución
    método de prueba()
  Archivo "/Users/paymahn/mycro/tests/test_mycro_token.py", línea 129, en test_vote_then_move_balance_is_useless
    self.contract_instance.transfer(DEFAULT_USER, 10, transact={'from': AARON_ADDRESS})
  Archivo "/Users/paymahn/mycro/venv/lib/python3.6/site-packages/web3/contract.py", línea 777, en __call__
    return self.__prepared_function(*args, **kwargs)
  Archivo "/Users/paymahn/mycro/venv/lib/python3.6/site-packages/web3/contract.py", línea 790, en __prepared_function
    devuelve getattr(self._function(*args), modificador)(modifier_dict)
  Archivo "/Users/paymahn/mycro/venv/lib/python3.6/site-packages/web3/contract.py", línea 1028, en transacción
    **auto.kwargs)
  Archivo "/Users/paymahn/mycro/venv/lib/python3.6/site-packages/web3/contract.py", línea 1305, en transact_with_contract_function
    txn_hash = web3.eth.sendTransaction(transact_transaction)
  Archivo "/Users/paymahn/mycro/venv/lib/python3.6/site-packages/web3/eth.py", línea 247, en sendTransaction
    get_buffered_gas_estimate(self.web3, transacción),
  Archivo "/Users/paymahn/mycro/venv/lib/python3.6/site-packages/web3/utils/transactions.py", línea 72, en get_buffered_gas_estimate
    gas_estimate = web3.eth.estimateGas(gas_estimate_transaction)
  Archivo "/Users/paymahn/mycro/venv/lib/python3.6/site-packages/web3/eth.py", línea 288, en la estimación de Gas
    [transacción],
  Archivo "/Users/paymahn/mycro/venv/lib/python3.6/site-packages/web3/manager.py", línea 103, en request_blocking
    respuesta = self._make_request(método, parámetros)
  Archivo "/Users/paymahn/mycro/venv/lib/python3.6/site-packages/web3/manager.py", línea 86, en _make_request
    devuelve request_func (método, parámetros)
  Archivo "/Users/paymahn/mycro/venv/lib/python3.6/site-packages/web3/middleware/gas_price_strategy.py", línea 18, en middleware
    volver make_request(método, parámetros)
  Archivo "/Users/paymahn/mycro/venv/lib/python3.6/site-packages/web3/middleware/formatting.py", línea 21, en middleware
    respuesta = make_request(método, formatted_params)
  Archivo "/Users/paymahn/mycro/venv/lib/python3.6/site-packages/web3/middleware/attrdict.py", línea 18, en middleware
    respuesta = make_request(método, parámetros)
  Archivo "/Users/paymahn/mycro/venv/lib/python3.6/site-packages/web3/middleware/formatting.py", línea 21, en middleware
    respuesta = make_request(método, formatted_params)
  Archivo "/Users/paymahn/mycro/venv/lib/python3.6/site-packages/web3/middleware/normalize_errors.py", línea 9, en middleware
    resultado = make_request(método, parámetros)
  Archivo "/Users/paymahn/mycro/venv/lib/python3.6/site-packages/web3/middleware/validation.py", línea 44, en middleware
    volver make_request(método, post_validated_params)
  Archivo "/Users/paymahn/mycro/venv/lib/python3.6/site-packages/web3/middleware/formatting.py", línea 21, en middleware
    respuesta = make_request(método, formatted_params)
  Archivo "/Users/paymahn/mycro/venv/lib/python3.6/site-packages/web3/providers/eth_tester/middleware.py", línea 315, en middleware
    return make_request(método, [llenado_transacción] + params[1:])
  Archivo "/Users/paymahn/mycro/venv/lib/python3.6/site-packages/web3/middleware/fixture.py", línea 12, en middleware
    volver make_request(método, parámetros)
  Archivo "/Users/paymahn/mycro/venv/lib/python3.6/site-packages/web3/middleware/formatting.py", línea 21, en middleware
    respuesta = make_request(método, formatted_params)
  Archivo "/Users/paymahn/mycro/venv/lib/python3.6/site-packages/web3/providers/eth_tester/main.py", línea 46, en make_request
    respuesta = delegador(self.ethereum_tester, params)
  Archivo "cytoolz/functoolz.pyx", línea 232, en cytoolz.functoolz.curry.__call__
  Archivo "/Users/paymahn/mycro/venv/lib/python3.6/site-packages/web3/providers/eth_tester/defaults.py", línea 36, ​​en call_eth_tester
    devuelve getattr(eth_tester, fn_name)(*fn_args, **fn_kwargs)
  Archivo "/Users/paymahn/mycro/venv/lib/python3.6/site-packages/eth_tester/main.py", línea 466, en estimación_gas
    raw_gas_estimate = self.backend.estimate_gas(raw_transaction)
  Archivo "/Users/paymahn/mycro/venv/lib/python3.6/site-packages/eth_tester/utils/formatting.py", línea 85, en contenedor
    return to_wrap(*argumentos, **kwargs)
  Archivo "/Users/paymahn/mycro/venv/lib/python3.6/site-packages/eth_tester/backends/pyethereum/v16/main.py", línea 439, en estimación_gas
    transacción=transacción,
  Archivo "/Users/paymahn/mycro/venv/lib/python3.6/site-packages/eth_tester/backends/pyethereum/v16/main.py", línea 157, en _estimate_evm_transaction
    volver _send_evm_transaction(tester_module, evm, transaction_for_estimate)
  Archivo "/Users/paymahn/mycro/venv/lib/python3.6/site-packages/eth_tester/backends/pyethereum/v16/main.py", línea 139, en _send_evm_transaction
    remitente = evm.cuentas_extra[transacción['de']]
Error de tecla: b'U\x06\x19]\x81\x11\xb5\xe1P\xfbh\xce\xba(\x06\xc5F\xc5\xa2\x8b'

Esto tiene sentido para mí, USER_ADDRESSnunca se registró como remitente en el proveedor de prueba (estoy seguro de que me equivoqué en parte de esa terminología). En la deploy_contractfunción, envío la transacción del constructor desde self.w3.eth.accounts[0].

Mi pregunta es: ¿cómo puedo enviar moneda en web3py desde una dirección que recibe monedas durante la inicialización?

Respuestas (1)

Quizás su mejor opción aquí sea pasar las direcciones como parámetros al constructor. Luego, durante la prueba, puede enviar w3.eth.accounts[1]como cuenta para prefinanciar. Algo como:

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);
}

A continuación, puede implementar el contrato con:

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

Nota al margen: probablemente el mejor backend para usar para eth-tester es el py-evmuno. Es el más activamente mantenido. Sin embargo, todos deberían funcionar en general.

¡Esa es exactamente la solución con la que me topé pero olvidé publicar una respuesta! Buscaré usar py-evm, pensé que el backend fue elegido automáticamente por EthereumTesterProvider. También estoy pensando en cambiar de forma web3pyporque web3jsse web3jsve más activamente desarrollado.
Hah, me alegro de que lo hayas resuelto. Yo diría que use cualquier idioma con el que se sienta más cómodo. Si le gusta más Python, pero aún no está seguro debido a la falta de funciones en web3py, me encantaría saberlo en la sala de chat de web3py o en un problema de web3py .