Closed deep-ink-ventures closed 7 months ago
What is the definition of type with id: 0
in the metadata.json?
Also, which version of Ink! is in language
property?
Is there a way for me to reproduce this with the metadata.json and an ws endpoint where the contract is deployed (or WASM code)? Then I can do some debugging for you.
I'm not able at all to parse events at all. First of all, the Events are within the
ContractEmitted
part of the dict, notContractExecution
as mentioned in the str docs.
This is the part of the code where the bytes of the ContractEmitted
get decoded into a ContractEvent
ScaleType.
Thanks!
Yes, you can do that here: https://polkadot.js.org/apps/?rpc=wss%3A%2F%2Fnode.genesis-dao.org#/explorer
https://github.com/deep-ink-ventures/genesis-dao-service/blob/main/wasm/dao_asset_contract.json is the metadata. https://github.com/deep-ink-ventures/genesis-dao-service/blob/main/wasm/dao_asset_contract.wasm is the wasm https://github.com/deep-ink-ventures/genesis-dao-node/blob/main/contracts/extensions/dao-assets-contract/src/lib.rs is creating the problem
I use this code, everything is setup:
contract_code = ContractCode.create_from_contract_files(
wasm_file=wasm_path,
metadata_file=json_path,
substrate=substrate_service.substrate_interface,
)
data = contract_code.metadata.generate_constructor_data(name="new", args={"asset_id": 1})
call = .substrate_interface.compose_call(
call_module="Contracts",
call_function="instantiate_with_code",
call_params={
"value": 0,
"gas_limit": {"ref_time": 2599000000, "proof_size": 1199038364791120855},
"storage_deposit_limit": None,
"code": "0x{}".format(contract_code.wasm_bytes.hex()),
"data": data.to_hex(),
"salt": uuid4().hex,
},
)
I'm not able at all to parse events at all. First of all, the Events are within the
ContractEmitted
part of the dict, notContractExecution
as mentioned in the str docs.This is the part of the code where the bytes of the
ContractEmitted
get decoded into aContractEvent
ScaleType.
This is for parsing the receipt, isn't it? I want to parse events.
I'm not able at all to parse events at all. First of all, the Events are within the
ContractEmitted
part of the dict, notContractExecution
as mentioned in the str docs.This is the part of the code where the bytes of the
ContractEmitted
get decoded into aContractEvent
ScaleType.This is for parsing the receipt, isn't it? I want to parse events.
This is for the contract events. The triggered events of an (contract call) extrinsic are part of the receipt
Ok I tested a deployment and the processing of contract events. It was successful in the end, but did found a bug when creating a contract receipt from an on-chain extrinsic (which can be found here: https://polkadot.js.org/apps/?rpc=wss%3A%2F%2Fnode.genesis-dao.org#/explorer/query/230) .
First I deployed basically with the example found in the docs, I didn't encounter much problems:
# Upload WASM code
code = ContractCode.create_from_contract_files(
metadata_file=os.path.join(os.path.dirname(__file__), 'assets', 'dao_asset_contract.json'),
wasm_file=os.path.join(os.path.dirname(__file__), 'assets', 'dao_asset_contract.wasm'),
substrate=substrate
)
# Deploy contract
print('Deploy contract...')
contract = code.deploy(
keypair=keypair,
constructor="new",
args={'asset_id': 1},
value=0,
gas_limit={'ref_time': 2599000000, 'proof_size': 1199038364791120855},
upload_code=True
)
print(f'✅ Deployed @ {contract.contract_address}')
Then I retrieved the extrinsic on-chain with the identifier and tried to output the contract events. There I encountered a bug, the extrinsic index is not passed on successfully and had to manually set the extrinsic hash.
# retrieve extrinsic on-chain previously deployed on
receipt = substrate.retrieve_extrinsic_by_identifier("230-1")
contract_metadata = ContractMetadata.create_from_file(
os.path.join(os.path.dirname(__file__), 'assets', 'dao_asset_contract.json'),
substrate=substrate
)
contract_receipt = ContractExecutionReceipt.create_from_extrinsic_receipt(receipt, contract_metadata)
# bug found: exintric index is not passed to contract receipt, must be set manually
contract_receipt.extrinsic_hash = '0x96c7552c6711e48a6fb8793dd22586dadc7ac32c3d7fff09fc8c3c3fcf871e97'
print(contract_receipt.contract_events)
I'll make a note for this bug.
When you perform a contract call, this should all work fine btw, for example:
# Read current value
result = contract.read(keypair, 'get')
print('Current value of "get":', result.contract_result_data)
# Do a gas estimation of the message
gas_predit_result = contract.read(keypair, 'flip')
print('Result of dry-run: ', gas_predit_result.value)
print('Gas estimate: ', gas_predit_result.gas_required)
# Do the actual call
print('Executing contract call...')
contract_receipt = contract.exec(keypair, 'flip', args={
}, gas_limit=gas_predit_result.gas_required)
if contract_receipt.is_success:
print(f'Events triggered in contract: {contract_receipt.contract_events}')
else:
print(f'Error message: {contract_receipt.error_message}')
I fundamentally do not understand what you are doing here.
I have an event listener via the get_block()
method and want to parse the event contained within. I don't want to look at receipts nor doing a call.
Can you enlighten me what I'm missing here?
Ok gotcha, you are trying to observe and decode all contract events as they occur per block. I made a event subscription example, hope this helps!
The tricky part is to extract the bytes from the data
attribute, this is currently indeed a bit cumbersome. obj.value
is the 'human readable' version of the data and seems not always consistent. obj.value_object
retains original type information.
import os
from scalecodec import ScaleBytes
from substrateinterface import SubstrateInterface, ContractEvent, ContractMetadata
substrate = SubstrateInterface(url="ws://127.0.0.1:9944")
contract_metadata = ContractMetadata.create_from_file(
metadata_file=os.path.join(os.path.dirname(__file__), 'assets', 'metadata.json'),
substrate=substrate
)
def subscription_handler(storage_key, updated_obj, update_nr, subscription_id):
# print(f"Update for {storage_key}: {updated_obj.value}")
for event in updated_obj.value_object:
if event.value['module_id'] == 'Contracts':
print (f". Contract related event: {event.value['event_id']}: {event.value['attributes']}")
if event.value['event_id'] == 'ContractEmitted':
# Trying to decode Contract event:
contract_event_obj = ContractEvent(
data=ScaleBytes(event.value_object['event'][1][1]['data'].value_object),
runtime_config=substrate.runtime_config,
contract_metadata=contract_metadata
)
print('* Event in Contract triggered:', contract_event_obj.decode())
# Storage keys to track
storage_keys = [
substrate.create_storage_key(
"System", "Events"
),
]
result = substrate.subscribe_storage(
storage_keys=storage_keys, subscription_handler=subscription_handler
)
Yay! It works. Thank you.
I am facing multiple problems on parsing events.
That is not happen all the times and so far I think it only occurs on
u32
, but I am not sure. The event data is then astr
, e.g.\x00\x01\x00\x00\x00
that I then have to convert viabytes(x, 'utf-8'))
in order to feed it toScaleBytes
.It's hacky but seems to work, however, more seriously:
NotImplementedError: Decoder class for "ink::<source/hash from json goes here>::0" not found
is happening all the timeI'm not able at all to parse events at all. First of all, the Events are within the
ContractEmitted
part of the dict, notContractExecution
as mentioned in the str docs.Is there an example on how to actually do this? I'm fetching a block and want to parse the event. I have the json metadata and can instantiate a contract code with is.