2

I am using substrate-contracts-node. I've uploaded and instantiated the smart contract. I would like to interact and query the function using py-substrate-interface. However, I ran into an error while following this guide - https://polkascan.github.io/py-substrate-interface/usage/ink-contract-interfacing/#deploy-a-contract

This is my code:

contract_address = '5Guya7pPPJC5bDy6yjpLZQ6Tw4D3pow8pvebEnFxMsyd5d31'
# Create contract instance from deterministic address
contract = ContractInstance.create_from_address(
    contract_address=contract_address,
    metadata_file=os.path.join(os.path.dirname(__file__), '/home/<name>/TODO-List/todo_list/target/ink', 'metadata.json'),
    substrate=substrate
)

result = contract.read(keypair, 'get_owner')

This is the error message:

Traceback (most recent call last):
  File "/home/<name>/TODO-List/myenv/lib/python3.8/site-packages/scalecodec/types.py", line 1232, in process
    enum_type_mapping = self.type_mapping[self.index]
IndexError: list index out of range

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "main.py", line 24, in <module>
    result = contract.read(keypair, 'get_owner')
  File "/home/<name>/TODO-List/myenv/lib/python3.8/site-packages/substrateinterface/contracts.py", line 766, in read
    call_result = self.substrate.runtime_call("ContractsApi", "call", {
  File "/home/<name>/TODO-List/myenv/lib/python3.8/site-packages/substrateinterface/base.py", line 1258, in runtime_call
    result_obj.decode(ScaleBytes(result_data['result']))
  File "/home/<name>/TODO-List/myenv/lib/python3.8/site-packages/scalecodec/base.py", line 874, in decode
    self.value_serialized = self.process()
  File "/home/<name>/TODO-List/myenv/lib/python3.8/site-packages/scalecodec/types.py", line 1755, in process
    value = super().process()
  File "/home/<name>/TODO-List/myenv/lib/python3.8/site-packages/scalecodec/types.py", line 1245, in process
    raise ValueError("Index '{}' not present in Enum type mapping".format(self.index))
ValueError: Index '202' not present in Enum type mapping

Smart contract was tested and built without any issue. get_owner() is a simple function in a smart contract that returns an AccountId.

0

1 Answer 1

1

Questions:

  • What version of substrate-interface are you using?
  • Where is the source code of the todo_list smart contract?

Perhaps you could try using a more recent version of both substrate-interface, and python even though you're using version 3.8 and the repo indicates that it's supported.

I understand that you used substrate-contracts-node to deploy the smart contract to a local testnet on your machine at '5Guya7pPPJC5bDy6yjpLZQ6Tw4D3pow8pvebEnFxMsyd5d31'.

I just tried to replicate your issue using the following recent versions:

  • substrate-interface 1.7.0
  • python 3.11
  • flipper example smart contract that I generated using cargo contract 2.2.1

I followed the same guide as you with the steps here.

First I got an error TypeError: ContractCode.deploy() got an unexpected keyword argument 'endowment'.

So I reviewed the substrate-interface 1.7.0 source code that I found at https://github.com/polkascan/py-substrate-interface/blob/v1.7.0/substrateinterface/contracts.py to discover that argument has been removed, so the guide appears to be outdated.

Then I got the following error:

Traceback (most recent call last):
  File "/usr/local/lib/python3.11/site-packages/scalecodec/types.py", line 592, in process_encode
    value = {key: value[idx] for idx, (key, _) in enumerate(self.type_mapping)}
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/scalecodec/types.py", line 592, in <dictcomp>
    value = {key: value[idx] for idx, (key, _) in enumerate(self.type_mapping)}
                  ~~~~~^^^^^
IndexError: tuple index out of range

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/app/docker/ink-python/src/app.py", line 52, in <module>
    contract = code.deploy(
               ^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/substrateinterface/contracts.py", line 658, in deploy
    call = self.substrate.compose_call(
... 
  File "/usr/local/lib/python3.11/site-packages/scalecodec/types.py", line 594, in process_encode
    raise ValueError("Not enough items in tuple to match type_mapping")
ValueError: Not enough items in tuple to match type_mapping

That was again caused because that guide is outdated since they are using an argument value of gas_limit=1000000000000, instead of a dictionary tuple like gas_limit={'ref_time': 25990000000, 'proof_size': 11990},. So after I changed that it fully deployed the smart contract to Contracts Rococo successfully and returned Current value of "get": {'Ok': True}.

This is the code I used. Note: I just made up any value for the ref_time and proof_size that worked without causing an OutOfGas error.

import os
from dotenv import load_dotenv
from substrateinterface import SubstrateInterface, Keypair, KeypairType, ContractCode, ContractInstance

load_dotenv()

MNEMONIC = os.getenv('MNEMONIC')

provider_rococo = "wss://rococo-contracts-rpc.polkadot.io"
substrate = SubstrateInterface(
    url=provider_rococo,
    ss58_format=42,
    type_registry_preset='substrate-node-template',
)
keypair_ls = Keypair.create_from_mnemonic(
    MNEMONIC,
    crypto_type=KeypairType.SR25519
)
print(keypair_ls.ss58_address)

# deploy contract
up = [os.pardir]*3
go_up = os.path.join(*up)
code = ContractCode.create_from_contract_files(
    metadata_file=os.path.join(os.path.dirname(__file__), go_up, 'target', 'ink', 'flipper', 'flipper.json'),
    wasm_file=os.path.join(os.path.dirname(__file__), go_up, 'target', 'ink', 'flipper', 'flipper.wasm'),
    substrate=substrate
)
contract = code.deploy(
    keypair=keypair_ls,
    constructor="new",
    args={'init_value': True},
    value=0,
    gas_limit={'ref_time': 25990000000, 'proof_size': 11990},
    deployment_salt="",
    upload_code=True,
    storage_deposit_limit=1000000000000
)
print(f'✅ Deployed @ {contract.contract_address}')

# create contract instance from deterministic address
contract_existing = ContractInstance.create_from_address(
    contract_address=contract.contract_address,
    metadata_file=os.path.join(os.path.dirname(__file__), go_up, 'target', 'ink', 'flipper', 'flipper.json'),
    substrate=substrate
)
print(f'Existing deployed @ {contract_existing.contract_address}')

# read data from contract
result = contract_existing.read(keypair_ls, 'get')
print('Current value of "get":', result.contract_result_data)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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