Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
db3822d
adds definitions and types according to ink v5 changes
peetzweg Feb 1, 2024
9f93a19
adds toV5 boilerplate code draft
peetzweg Feb 1, 2024
0cf749e
adds v5 flipper test contract code
peetzweg Feb 1, 2024
cfba268
fix license dates
peetzweg Feb 1, 2024
7d404f4
adds test v5 toLatest test
peetzweg Feb 1, 2024
1f9e6f5
implements new scheme to determine event
peetzweg Feb 1, 2024
985365f
apply linter changes
peetzweg Feb 1, 2024
5db72af
adds test result outputs
peetzweg Feb 1, 2024
cc946da
change `EventRecord['topics'][0]` type to plain `Hash`
peetzweg Feb 16, 2024
54fd609
adds testcases for decoding payload data of a ink!v4 and ink!v5 event
peetzweg Feb 23, 2024
013ea59
changes `Abi.decodeEvent(data:Bytes)` method interface to `Abi.decode…
peetzweg Feb 26, 2024
a028c55
draft implementation with version metadata
peetzweg Feb 26, 2024
3e0d8d1
cleaner implementation of versioned Metadata by actually leveraging t…
peetzweg Feb 27, 2024
ada84b3
Merge branch 'polkadot-js:master' into pz/ink-v5
peetzweg Feb 27, 2024
0029e18
trying to make linter happy
peetzweg Feb 27, 2024
f000f24
Merge branch 'pz/ink-v5' of github.com:peetzweg/pjs-api into pz/ink-v5
peetzweg Feb 27, 2024
0124e14
makes `ContractMetadataSupported` in internal to `Abi` type and not e…
peetzweg Feb 27, 2024
fcb684d
properly types unused parameter for tsc :shrug:
peetzweg Feb 27, 2024
64feb63
adds `@polkadot/types-support` dev dependency
peetzweg Feb 27, 2024
df9956c
merge master
peetzweg Feb 27, 2024
f1a1b9d
Update yarn.lock
peetzweg Feb 27, 2024
1cda4b9
references `types-support` in `api-contract
peetzweg Feb 27, 2024
246570d
resolving change requests
peetzweg Feb 28, 2024
f88fcf7
resolves linter warnings
peetzweg Feb 28, 2024
f67a88a
changes ContractMetadataV5 field to `u64` from `Text`
peetzweg Feb 28, 2024
27d6b46
adds contracts and contract metadata compiled with the most recent in…
peetzweg Feb 28, 2024
0e039e7
implements decoding of anonymous events if possible
peetzweg Mar 1, 2024
3b48940
removes done todo comments
peetzweg Mar 1, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
changes Abi.decodeEvent(data:Bytes) method interface to `Abi.decode…
…Event(record:EventRecord)` which includes the event and the topic for decoding.
  • Loading branch information
peetzweg committed Feb 26, 2024
commit 013ea59f70b265c7038936dbf8fa85729559a4a2
106 changes: 58 additions & 48 deletions packages/api-contract/src/Abi/Abi.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,10 @@ import fs from 'node:fs';
import process from 'node:process';

import { TypeDefInfo } from '@polkadot/types/types';
import { hexToU8a } from '@polkadot/util';
import rpcMetadata from '@polkadot/types-support/metadata/static-substrate-contracts-node';
import { blake2AsHex } from '@polkadot/util-crypto';

import { Metadata, TypeRegistry } from '../../../types/src/bundle.js';
import abis from '../test/contracts/index.js';
import { Abi } from './index.js';

Expand Down Expand Up @@ -124,68 +125,77 @@ describe('Abi', (): void => {
expect(bundle.source.hash).toEqual(abi.info.source.wasmHash.toHex());
});

it('decoding <=ink!v4 events', (): void => {
const abi = new Abi(abis['ink_v4_erc20Metadata']);
describe('Events', (): void => {
const registry = new TypeRegistry();

const dataHex = '0x0001d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d018eaf04151687736326c9fea17e25fc5287613693c912909cb226aa4794f26a4800505a4f7e9f4eb10600000000000000';
const dataU8A = hexToU8a(dataHex);
beforeAll((): void => {
const metadata = new Metadata(registry, rpcMetadata);

const decodedEvent = abi.decodeEvent(dataU8A);
registry.setMetadata(metadata);
});

expect(decodedEvent.event.args.length).toEqual(3);
expect(decodedEvent.args.length).toEqual(3);
expect(decodedEvent.event.identifier).toEqual('Transfer');
it('decoding <=ink!v4 events', (): void => {
const abiJson = abis['ink_v4_erc20Metadata'];

const decodedEventHuman = decodedEvent.event.args.reduce((prev, cur, index) => {
return {
...prev,
[cur.name]: decodedEvent.args[index].toHuman()
};
}, {});
expect(abiJson).toBeDefined();
const abi = new Abi(abiJson);

const expectedEvent = {
from: '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY',
to: '5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty',
value: '123.4567 MUnit'
};
const eventRecordHex =
'0x0001000000080360951b8baf569bca905a279c12d6ce17db7cdce23a42563870ef585129ce5dc64d010001d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d018eaf04151687736326c9fea17e25fc5287613693c912909cb226aa4794f26a4800505a4f7e9f4eb106000000000000000c0045726332303a3a5472616e7366657200000000000000000000000000000000da2d695d3b5a304e0039e7fc4419c34fa0c1f239189c99bb72a6484f1634782b2b00c7d40fe6d84d660f3e6bed90f218e022a0909f7e1a7ea35ada8b6e003564';
const record = registry.createType('EventRecord', eventRecordHex);

expect(decodedEventHuman).toEqual(expectedEvent);
});
const decodedEvent = abi.decodeEvent(record);

expect(decodedEvent.event.args.length).toEqual(3);
expect(decodedEvent.args.length).toEqual(3);
expect(decodedEvent.event.identifier).toEqual('Transfer');

const decodedEventHuman = decodedEvent.event.args.reduce((prev, cur, index) => {
return {
...prev,
[cur.name]: decodedEvent.args[index].toHuman()
};
}, {});

it('decoding <=ink!v5 events', (): void => {
const metadataJson = abis['ink_v5_erc20Metadata'];
const expectedEvent = {
from: '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY',
to: '5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty',
value: '123.4567 MUnit'
};

expect(metadataJson).toBeDefined();
const abi = new Abi(metadataJson);
expect(decodedEventHuman).toEqual(expectedEvent);
});

const dataHex = '0x01d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d018eaf04151687736326c9fea17e25fc5287613693c912909cb226aa4794f26a4800505a4f7e9f4eb10600000000000000';
const dataU8A = hexToU8a(dataHex);
it('decoding <=ink!v5 events', (): void => {
const abiJson = abis['ink_v5_erc20Metadata'];

const signatureTopicHex = '0xb5b61a3e6a21a16be4f044b517c28ac692492f73c5bfd3f60178ad98c767f4cb';
expect(abiJson).toBeDefined();
const abi = new Abi(abiJson);

expect(abi.events.length).toEqual(2);
expect(abi.events[0].signatureTopic).toEqual(signatureTopicHex);
const eventRecordHex =
'0x00010000000803da17150e96b3955a4db6ad35ddeb495f722f9c1d84683113bfb096bf3faa30f2490101d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d018eaf04151687736326c9fea17e25fc5287613693c912909cb226aa4794f26a4800505a4f7e9f4eb106000000000000000cb5b61a3e6a21a16be4f044b517c28ac692492f73c5bfd3f60178ad98c767f4cbd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d8eaf04151687736326c9fea17e25fc5287613693c912909cb226aa4794f26a48';
const record = registry.createType('EventRecord', eventRecordHex);

const signatureTopicHash = abi.registry.createType('Hash', signatureTopicHex);
const decodedEvent = abi.decodeEvent(dataU8A, signatureTopicHash);
const decodedEvent = abi.decodeEvent(record);

expect(decodedEvent.event.args.length).toEqual(3);
expect(decodedEvent.args.length).toEqual(3);
expect(decodedEvent.event.identifier).toEqual('erc20::erc20::Transfer');
expect(decodedEvent.event.args.length).toEqual(3);
expect(decodedEvent.args.length).toEqual(3);
expect(decodedEvent.event.identifier).toEqual('erc20::erc20::Transfer');

const decodedEventHuman = decodedEvent.event.args.reduce((prev, cur, index) => {
return {
...prev,
[cur.name]: decodedEvent.args[index].toHuman()
};
}, {});
const decodedEventHuman = decodedEvent.event.args.reduce((prev, cur, index) => {
return {
...prev,
[cur.name]: decodedEvent.args[index].toHuman()
};
}, {});

const expectedEvent = {
from: '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY',
to: '5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty',
value: '123.4567 MUnit'
};
const expectedEvent = {
from: '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY',
to: '5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty',
value: '123.4567 MUnit'
};

expect(decodedEventHuman).toEqual(expectedEvent);
expect(decodedEventHuman).toEqual(expectedEvent);
});
});
});
16 changes: 12 additions & 4 deletions packages/api-contract/src/Abi/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@
// SPDX-License-Identifier: Apache-2.0

import type { Bytes } from '@polkadot/types';
import type { ChainProperties, ContractConstructorSpecLatest, ContractEventSpecLatest, ContractMessageParamSpecLatest, ContractMessageSpecLatest, ContractMetadata, ContractMetadataLatest, ContractProjectInfo, ContractTypeSpec } from '@polkadot/types/interfaces';
import type { Hash } from '@polkadot/types/interfaces/runtime';
import type { ChainProperties, ContractConstructorSpecLatest, ContractEventSpecLatest, ContractMessageParamSpecLatest, ContractMessageSpecLatest, ContractMetadata, ContractMetadataLatest, ContractProjectInfo, ContractTypeSpec, EventRecord } from '@polkadot/types/interfaces';
import type { Codec, Registry, TypeDef } from '@polkadot/types/types';
import type { AbiConstructor, AbiEvent, AbiMessage, AbiParam, DecodedEvent, DecodedMessage } from '../types.js';

Expand Down Expand Up @@ -163,7 +162,12 @@ export class Abi {
/**
* Warning: Unstable API, bound to change
*/
public decodeEvent (data: Bytes | Uint8Array, signatureTopic?: Hash): DecodedEvent {
public decodeEvent (record: EventRecord): DecodedEvent {
// TODO we could double check here if record is actually section `contract` and type `ContractExecution` or `ContractEmitted`
const data = record.event.data[1] as Bytes;

const signatureTopic = record.topics[0];

if (signatureTopic !== undefined) {
const event = this.events.find((e) => e.signatureTopic !== undefined && e.signatureTopic === signatureTopic.toHex());

Expand All @@ -173,7 +177,11 @@ export class Abi {
throw new Error(`Unable to find event with signature_topic ${signatureTopic.toHex()}`);
}
} else {
// otherwise fallback to using the index to determine event - ink! v4 downwards
if (!data) {
throw new Error('Unable to find event data');
}

// otherwise fallback to using the index to determine event - ink! v4 downwards
const index = data[0];

const event = this.events[index];
Expand Down
5 changes: 2 additions & 3 deletions packages/api-contract/src/base/Contract.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
import type { ApiBase } from '@polkadot/api/base';
import type { SubmittableExtrinsic } from '@polkadot/api/submittable/types';
import type { ApiTypes, DecorateMethod } from '@polkadot/api/types';
import type { Bytes } from '@polkadot/types';
import type { AccountId, ContractExecResult, EventRecord, Weight, WeightV2 } from '@polkadot/types/interfaces';
import type { ISubmittableResult } from '@polkadot/types/types';
import type { Abi } from '../Abi/index.js';
Expand Down Expand Up @@ -115,9 +114,9 @@ export class Contract<ApiType extends ApiTypes> extends Base<ApiType> {
// ContractEmitted is the current generation, ContractExecution is the previous generation
new ContractSubmittableResult(result, applyOnEvent(result, ['ContractEmitted', 'ContractExecution'], (records: EventRecord[]) =>
records
.map(({ event: { data: [, data] }, topics }): DecodedEvent | null => {
.map((record): DecodedEvent | null => {
try {
return this.abi.decodeEvent(data as Bytes, topics[0]);
return this.abi.decodeEvent(record);
} catch (error) {
l.error(`Unable to decode contract event: ${(error as Error).message}`);

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// Copyright 2017-2024 @polkadot/types-support authors & contributors
// SPDX-License-Identifier: Apache-2.0

import metadata from './v14/substrate-contracts-node-hex.js';
import rpc from './v14/substrate-contracts-node-rpc.js';
import version from './v14/substrate-contracts-node-ver.js';

export { rpc, version };

export default metadata;

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
// Copyright 2017-2024 @polkadot/types-support authors & contributors
// SPDX-License-Identifier: Apache-2.0

/* eslint-disable */

// cargo run --release -- purge-chain -y --dev && cargo run --release -- --dev

export default {
"methods": [
"account_nextIndex",
"author_hasKey",
"author_hasSessionKeys",
"author_insertKey",
"author_pendingExtrinsics",
"author_removeExtrinsic",
"author_rotateKeys",
"author_submitAndWatchExtrinsic",
"author_submitExtrinsic",
"author_unwatchExtrinsic",
"chainHead_unstable_body",
"chainHead_unstable_call",
"chainHead_unstable_continue",
"chainHead_unstable_follow",
"chainHead_unstable_genesisHash",
"chainHead_unstable_header",
"chainHead_unstable_stopOperation",
"chainHead_unstable_storage",
"chainHead_unstable_unfollow",
"chainHead_unstable_unpin",
"chain_getBlock",
"chain_getBlockHash",
"chain_getFinalisedHead",
"chain_getFinalizedHead",
"chain_getHead",
"chain_getHeader",
"chain_getRuntimeVersion",
"chain_subscribeAllHeads",
"chain_subscribeFinalisedHeads",
"chain_subscribeFinalizedHeads",
"chain_subscribeNewHead",
"chain_subscribeNewHeads",
"chain_subscribeRuntimeVersion",
"chain_unsubscribeAllHeads",
"chain_unsubscribeFinalisedHeads",
"chain_unsubscribeFinalizedHeads",
"chain_unsubscribeNewHead",
"chain_unsubscribeNewHeads",
"chain_unsubscribeRuntimeVersion",
"childstate_getKeys",
"childstate_getKeysPaged",
"childstate_getKeysPagedAt",
"childstate_getStorage",
"childstate_getStorageEntries",
"childstate_getStorageHash",
"childstate_getStorageSize",
"offchain_localStorageGet",
"offchain_localStorageSet",
"payment_queryFeeDetails",
"payment_queryInfo",
"state_call",
"state_callAt",
"state_getChildReadProof",
"state_getKeys",
"state_getKeysPaged",
"state_getKeysPagedAt",
"state_getMetadata",
"state_getPairs",
"state_getReadProof",
"state_getRuntimeVersion",
"state_getStorage",
"state_getStorageAt",
"state_getStorageHash",
"state_getStorageHashAt",
"state_getStorageSize",
"state_getStorageSizeAt",
"state_queryStorage",
"state_queryStorageAt",
"state_subscribeRuntimeVersion",
"state_subscribeStorage",
"state_traceBlock",
"state_unsubscribeRuntimeVersion",
"state_unsubscribeStorage",
"subscribe_newHead",
"system_accountNextIndex",
"system_addLogFilter",
"system_addReservedPeer",
"system_chain",
"system_chainType",
"system_dryRun",
"system_dryRunAt",
"system_health",
"system_localListenAddresses",
"system_localPeerId",
"system_name",
"system_nodeRoles",
"system_peers",
"system_properties",
"system_removeReservedPeer",
"system_reservedPeers",
"system_resetLogFilter",
"system_syncState",
"system_unstable_networkState",
"system_version",
"transaction_unstable_submitAndWatch",
"transaction_unstable_unwatch",
"unsubscribe_newHead"
]
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
// Copyright 2017-2024 @polkadot/types-support authors & contributors
// SPDX-License-Identifier: Apache-2.0

/* eslint-disable */

// cargo run --release -- purge-chain -y --dev && cargo run --release -- --dev

export default {
"specName": "substrate-contracts-node",
"implName": "substrate-contracts-node",
"authoringVersion": 1,
"specVersion": 100,
"implVersion": 1,
"apis": [
[
"0xdf6acb689907609b",
4
],
[
"0x37e397fc7c91f5e4",
2
],
[
"0x40fe3ad401f8959a",
6
],
[
"0xd2bc9897eed08f15",
3
],
[
"0xf78b278be53f454c",
2
],
[
"0xab3c0572291feb8b",
1
],
[
"0xbc9d89904f5b923f",
1
],
[
"0x37c8bb1350a9a2a8",
4
],
[
"0xf3ff14d5ab527059",
3
],
[
"0x68b66ba122c93fa7",
2
]
],
"transactionVersion": 1,
"stateVersion": 1
};
3 changes: 2 additions & 1 deletion scripts/metadata-get.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ const PREAMBLE = '// Copyright 2017-2024 @polkadot/types-support authors & contr
const CMD = {
kusama: `${PREAMBLE}// cargo run --release -- purge-chain -y --chain kusama-dev && cargo run --release -- --chain kusama-dev --alice --force-authoring\n\nexport default`,
polkadot: `${PREAMBLE}// cargo run --release -- purge-chain -y --dev && cargo run --release -- --dev\n\nexport default`,
substrate: `${PREAMBLE}// cargo run --release -- purge-chain -y --dev && cargo run --release -- --dev\n\nexport default`
substrate: `${PREAMBLE}// cargo run --release -- purge-chain -y --dev && cargo run --release -- --dev\n\nexport default`,
'substrate-contracts-node': `${PREAMBLE}// cargo run --release -- purge-chain -y --dev && cargo run --release -- --dev\n\nexport default`
};

let requestId = 0;
Expand Down