fix(api-contracts): correctly decode pallet_revive events (#6181)

* fix: revive events

* chore: format
This commit is contained in:
Alex Bean
2025-07-08 11:24:44 -03:00
committed by GitHub
parent 3e231e206a
commit cb76a1db74
5 changed files with 50 additions and 6 deletions
+44 -1
View File
@@ -194,12 +194,55 @@ export class Abi {
// earlier version are hoisted to v4
case '4':
return this.#decodeEventV4(record);
case '5':
return this.#decodeEventV5(record);
// Latest
default:
return this.#decodeEventV5(record);
return this.#decodeEventV6(record);
}
}
#decodeEventV6 = (record: EventRecord): DecodedEvent => {
const topics = record.event.data[2] as unknown as { toHex: () => string }[];
// Try to match by signature topic (first topic)
const signatureTopic = topics[0];
const data = record.event.data[1] as Bytes;
if (signatureTopic) {
const event = this.events.find((e) => e.signatureTopic !== undefined && e.signatureTopic !== null && e.signatureTopic === signatureTopic.toHex());
// Early return if event found by signature topic
if (event) {
return event.fromU8a(data);
}
}
// If no event returned yet, it might be anonymous
const amountOfTopics = topics.length;
const potentialEvents = this.events.filter((e) => {
// event can't have a signature topic
if (e.signatureTopic !== null && e.signatureTopic !== undefined) {
return false;
}
// event should have same amount of indexed fields as emitted topics
const amountIndexed = e.args.filter((a) => a.indexed).length;
if (amountIndexed !== amountOfTopics) {
return false;
}
// If all conditions met, it's a potential event
return true;
});
if (potentialEvents.length === 1) {
return potentialEvents[0].fromU8a(data);
}
throw new Error('Unable to determine event');
};
#decodeEventV5 = (record: EventRecord): DecodedEvent => {
// Find event by first topic, which potentially is the signature_topic
const signatureTopic = record.topics[0];
+1 -1
View File
@@ -85,7 +85,7 @@ export class Blueprint<ApiType extends ApiTypes> extends Base<ApiType> {
: undefined
)
: applyOnEvent(result, ['Instantiated'], ([record]: EventRecord[]) =>
new Contract<ApiType>(this.api, this.abi, record.event.data[1] as AccountId, this._decorateMethod)
new Contract<ApiType>(this.api, this.abi, record.event.data[1] as AccountId, this._decorateMethod), this._isRevive
)
)
);
+1 -1
View File
@@ -110,7 +110,7 @@ export class Code<ApiType extends ApiTypes> extends Base<ApiType> {
: this.api.events.contracts.CodeStored.is(event)
? [new Blueprint<ApiType>(this.api, this.abi, (event as unknown as { data: [AccountId] }).data[0], this._decorateMethod), contract]
: [blueprint, contract],
[undefined, undefined])
[undefined, undefined]), this._isRevive
) || [undefined, undefined]))
);
};
+1 -1
View File
@@ -125,7 +125,7 @@ export class Contract<ApiType extends ApiTypes> extends Base<ApiType> {
return null;
}
})
.filter((decoded): decoded is DecodedEvent => !!decoded)
.filter((decoded): decoded is DecodedEvent => !!decoded), this._isRevive
))
);
};
+3 -2
View File
@@ -6,9 +6,10 @@ import type { EventRecord } from '@polkadot/types/interfaces';
type ContractEvents = 'CodeStored' | 'ContractEmitted' | 'ContractExecution' | 'Instantiated';
export function applyOnEvent <T> (result: SubmittableResult, types: ContractEvents[], fn: (records: EventRecord[]) => T): T | undefined {
export function applyOnEvent <T> (result: SubmittableResult, types: ContractEvents[], fn: (records: EventRecord[]) => T, isRevive: boolean): T | undefined {
if (result.isInBlock || result.isFinalized) {
const records = result.filterRecords('contracts', types);
const section = isRevive ? 'revive' : 'contracts';
const records = result.filterRecords(section, types);
if (records.length) {
return fn(records);