@d9-network/ink 0.0.4 → 0.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +631 -52
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +731 -49
- package/dist/index.d.mts +731 -49
- package/dist/index.mjs +627 -53
- package/dist/index.mjs.map +1 -1
- package/package.json +10 -5
package/dist/index.cjs
CHANGED
|
@@ -207,19 +207,19 @@ function buildCodecFromType(typeId, types, cache) {
|
|
|
207
207
|
const def = typeEntry.type.def;
|
|
208
208
|
const path = typeEntry.type.path;
|
|
209
209
|
if (def.primitive) {
|
|
210
|
-
const codec = buildPrimitiveCodec(def.primitive);
|
|
210
|
+
const codec = buildPrimitiveCodec$1(def.primitive);
|
|
211
211
|
cache.set(typeId, codec);
|
|
212
212
|
return codec;
|
|
213
213
|
}
|
|
214
214
|
if (path && path.length > 0) {
|
|
215
|
-
const specialCodec = buildSpecialTypeCodec(path, typeEntry, types, cache);
|
|
215
|
+
const specialCodec = buildSpecialTypeCodec$1(path, typeEntry, types, cache);
|
|
216
216
|
if (specialCodec) {
|
|
217
217
|
cache.set(typeId, specialCodec);
|
|
218
218
|
return specialCodec;
|
|
219
219
|
}
|
|
220
220
|
}
|
|
221
221
|
if (def.tuple) {
|
|
222
|
-
const codec = buildTupleCodec(def.tuple, types, cache);
|
|
222
|
+
const codec = buildTupleCodec$1(def.tuple, types, cache);
|
|
223
223
|
cache.set(typeId, codec);
|
|
224
224
|
return codec;
|
|
225
225
|
}
|
|
@@ -230,7 +230,7 @@ function buildCodecFromType(typeId, types, cache) {
|
|
|
230
230
|
}
|
|
231
231
|
if (def.array) {
|
|
232
232
|
const innerCodec = buildCodecFromType(def.array.type, types, cache);
|
|
233
|
-
if (def.array.type === findPrimitiveTypeId(types, "u8")) {
|
|
233
|
+
if (def.array.type === findPrimitiveTypeId$1(types, "u8")) {
|
|
234
234
|
const codec$1 = (0, _polkadot_api_substrate_bindings.Bytes)(def.array.len);
|
|
235
235
|
cache.set(typeId, codec$1);
|
|
236
236
|
return codec$1;
|
|
@@ -240,12 +240,12 @@ function buildCodecFromType(typeId, types, cache) {
|
|
|
240
240
|
return codec;
|
|
241
241
|
}
|
|
242
242
|
if (def.composite) {
|
|
243
|
-
const codec = buildCompositeCodec(def.composite, types, cache);
|
|
243
|
+
const codec = buildCompositeCodec$1(def.composite, types, cache);
|
|
244
244
|
cache.set(typeId, codec);
|
|
245
245
|
return codec;
|
|
246
246
|
}
|
|
247
247
|
if (def.variant) {
|
|
248
|
-
const codec = buildVariantCodec(def.variant, path, types, cache);
|
|
248
|
+
const codec = buildVariantCodec$1(def.variant, path, types, cache);
|
|
249
249
|
cache.set(typeId, codec);
|
|
250
250
|
return codec;
|
|
251
251
|
}
|
|
@@ -254,7 +254,7 @@ function buildCodecFromType(typeId, types, cache) {
|
|
|
254
254
|
/**
|
|
255
255
|
* Build codec for primitive types
|
|
256
256
|
*/
|
|
257
|
-
function buildPrimitiveCodec(primitive) {
|
|
257
|
+
function buildPrimitiveCodec$1(primitive) {
|
|
258
258
|
switch (primitive) {
|
|
259
259
|
case "u8": return _polkadot_api_substrate_bindings.u8;
|
|
260
260
|
case "u16": return _polkadot_api_substrate_bindings.u16;
|
|
@@ -274,7 +274,7 @@ function buildPrimitiveCodec(primitive) {
|
|
|
274
274
|
/**
|
|
275
275
|
* Build codec for special types based on path
|
|
276
276
|
*/
|
|
277
|
-
function buildSpecialTypeCodec(path, typeEntry, types, cache) {
|
|
277
|
+
function buildSpecialTypeCodec$1(path, typeEntry, types, cache) {
|
|
278
278
|
if (path.join("::").includes("AccountId")) return (0, _polkadot_api_substrate_bindings.AccountId)();
|
|
279
279
|
if (path[0] === "Option") {
|
|
280
280
|
const params = typeEntry.type.params;
|
|
@@ -296,7 +296,7 @@ function buildSpecialTypeCodec(path, typeEntry, types, cache) {
|
|
|
296
296
|
/**
|
|
297
297
|
* Build codec for tuple types
|
|
298
298
|
*/
|
|
299
|
-
function buildTupleCodec(tupleTypes, types, cache) {
|
|
299
|
+
function buildTupleCodec$1(tupleTypes, types, cache) {
|
|
300
300
|
if (tupleTypes.length === 0) return _polkadot_api_substrate_bindings._void;
|
|
301
301
|
const innerCodecs = tupleTypes.map((t) => buildCodecFromType(t, types, cache));
|
|
302
302
|
switch (innerCodecs.length) {
|
|
@@ -310,7 +310,7 @@ function buildTupleCodec(tupleTypes, types, cache) {
|
|
|
310
310
|
/**
|
|
311
311
|
* Build codec for composite (struct) types
|
|
312
312
|
*/
|
|
313
|
-
function buildCompositeCodec(composite, types, cache) {
|
|
313
|
+
function buildCompositeCodec$1(composite, types, cache) {
|
|
314
314
|
const fields = composite.fields;
|
|
315
315
|
if (fields.length === 1 && !fields[0]?.name) return buildCodecFromType(fields[0].type, types, cache);
|
|
316
316
|
const structDef = {};
|
|
@@ -323,7 +323,7 @@ function buildCompositeCodec(composite, types, cache) {
|
|
|
323
323
|
/**
|
|
324
324
|
* Build codec for variant (enum) types
|
|
325
325
|
*/
|
|
326
|
-
function buildVariantCodec(variant, path, types, cache) {
|
|
326
|
+
function buildVariantCodec$1(variant, path, types, cache) {
|
|
327
327
|
const variants = variant.variants;
|
|
328
328
|
const isLangError$1 = path?.includes("LangError");
|
|
329
329
|
const variantDef = {};
|
|
@@ -353,7 +353,7 @@ function buildVariantCodec(variant, path, types, cache) {
|
|
|
353
353
|
/**
|
|
354
354
|
* Find the type ID for a primitive type
|
|
355
355
|
*/
|
|
356
|
-
function findPrimitiveTypeId(types, primitive) {
|
|
356
|
+
function findPrimitiveTypeId$1(types, primitive) {
|
|
357
357
|
return types.find((t) => t.type.def.primitive === primitive)?.id ?? -1;
|
|
358
358
|
}
|
|
359
359
|
/**
|
|
@@ -470,7 +470,12 @@ function getEventSignature(eventLabel) {
|
|
|
470
470
|
//#endregion
|
|
471
471
|
//#region src/events.ts
|
|
472
472
|
/**
|
|
473
|
-
*
|
|
473
|
+
* Type-safe event parser for a specific contract
|
|
474
|
+
*
|
|
475
|
+
* @typeParam S - The storage descriptor type
|
|
476
|
+
* @typeParam M - The messages descriptor type
|
|
477
|
+
* @typeParam C - The constructors descriptor type
|
|
478
|
+
* @typeParam E - The event type representing all possible events for this contract
|
|
474
479
|
*/
|
|
475
480
|
var ContractEventParser = class {
|
|
476
481
|
eventDecoders;
|
|
@@ -478,21 +483,31 @@ var ContractEventParser = class {
|
|
|
478
483
|
contractAddressBytes;
|
|
479
484
|
contractAddress;
|
|
480
485
|
metadata;
|
|
481
|
-
constructor(
|
|
482
|
-
|
|
486
|
+
constructor(descriptor, contractAddress) {
|
|
487
|
+
if (!descriptor.metadata) throw new Error("Contract descriptor must include metadata");
|
|
488
|
+
this.metadata = descriptor.metadata;
|
|
483
489
|
this.contractAddress = contractAddress;
|
|
484
|
-
this.eventDecoders = buildAllEventDecoders(metadata);
|
|
490
|
+
this.eventDecoders = buildAllEventDecoders(this.metadata);
|
|
485
491
|
this.contractAddressBytes = (0, _polkadot_labs_hdkd_helpers.ss58Decode)(contractAddress)[0];
|
|
486
492
|
this.eventSignatures = /* @__PURE__ */ new Map();
|
|
487
|
-
const events = metadata.spec.events;
|
|
493
|
+
const events = this.metadata.spec.events;
|
|
488
494
|
for (const event of events) {
|
|
489
495
|
const sig = getEventSignature(event.label);
|
|
490
496
|
this.eventSignatures.set(event.label, sig);
|
|
491
497
|
}
|
|
492
498
|
}
|
|
493
499
|
/**
|
|
494
|
-
* Parse a raw chain event into a contract event (if it matches)
|
|
500
|
+
* Parse a raw chain event into a type-safe contract event (if it matches)
|
|
495
501
|
* Returns null if the event is not from this contract or cannot be parsed
|
|
502
|
+
*
|
|
503
|
+
* @example
|
|
504
|
+
* ```ts
|
|
505
|
+
* const event = parser.parseEvent(chainEvent);
|
|
506
|
+
* if (event?.type === "Transfer") {
|
|
507
|
+
* // event.value is now typed as { from: SS58String; to: SS58String; value: bigint }
|
|
508
|
+
* console.log(event.value.from);
|
|
509
|
+
* }
|
|
510
|
+
* ```
|
|
496
511
|
*/
|
|
497
512
|
parseEvent(chainEvent) {
|
|
498
513
|
const extracted = this.extractContractEmittedEvent(chainEvent);
|
|
@@ -518,8 +533,8 @@ var ContractEventParser = class {
|
|
|
518
533
|
try {
|
|
519
534
|
const decodedData = decoder(data);
|
|
520
535
|
return {
|
|
521
|
-
|
|
522
|
-
|
|
536
|
+
type: eventLabel,
|
|
537
|
+
value: decodedData,
|
|
523
538
|
raw: {
|
|
524
539
|
blockNumber,
|
|
525
540
|
blockHash,
|
|
@@ -535,14 +550,18 @@ var ContractEventParser = class {
|
|
|
535
550
|
}
|
|
536
551
|
}
|
|
537
552
|
/**
|
|
538
|
-
* Filter a batch of events
|
|
553
|
+
* Filter a batch of events and return type-safe results
|
|
554
|
+
*
|
|
555
|
+
* @param chainEvents - Array of chain events to filter
|
|
556
|
+
* @param options - Optional filter criteria
|
|
557
|
+
* @returns Array of type-safe contract events
|
|
539
558
|
*/
|
|
540
559
|
filterEvents(chainEvents, options) {
|
|
541
560
|
const results = [];
|
|
542
561
|
for (const chainEvent of chainEvents) {
|
|
543
562
|
const parsed = this.parseEvent(chainEvent);
|
|
544
563
|
if (!parsed) continue;
|
|
545
|
-
if (options?.eventLabels && !options.eventLabels.includes(parsed.
|
|
564
|
+
if (options?.eventLabels && !options.eventLabels.includes(parsed.type)) continue;
|
|
546
565
|
if (options?.fromBlock && parsed.raw.blockNumber < options.fromBlock) continue;
|
|
547
566
|
if (options?.toBlock && parsed.raw.blockNumber > options.toBlock) continue;
|
|
548
567
|
results.push(parsed);
|
|
@@ -550,6 +569,29 @@ var ContractEventParser = class {
|
|
|
550
569
|
return results;
|
|
551
570
|
}
|
|
552
571
|
/**
|
|
572
|
+
* Filter events by specific type with proper type narrowing
|
|
573
|
+
*
|
|
574
|
+
* This method provides better type safety than filterEvents with eventLabels
|
|
575
|
+
* because TypeScript can narrow the return type to only the specified event type.
|
|
576
|
+
*
|
|
577
|
+
* @param chainEvents - Array of chain events to filter
|
|
578
|
+
* @param label - The event label to filter by
|
|
579
|
+
* @returns Array of events narrowed to the specific type
|
|
580
|
+
*
|
|
581
|
+
* @example
|
|
582
|
+
* ```ts
|
|
583
|
+
* const transfers = parser.filterByType(events, "Transfer");
|
|
584
|
+
*
|
|
585
|
+
* for (const t of transfers) {
|
|
586
|
+
* // t.value is fully typed as Transfer event data
|
|
587
|
+
* console.log(t.value.from, "->", t.value.to, ":", t.value.value);
|
|
588
|
+
* }
|
|
589
|
+
* ```
|
|
590
|
+
*/
|
|
591
|
+
filterByType(chainEvents, label) {
|
|
592
|
+
return this.filterEvents(chainEvents).filter((e) => e.type === label);
|
|
593
|
+
}
|
|
594
|
+
/**
|
|
553
595
|
* Get the contract address as SS58 string
|
|
554
596
|
*/
|
|
555
597
|
getContractAddress() {
|
|
@@ -570,20 +612,31 @@ var ContractEventParser = class {
|
|
|
570
612
|
if (eventValue.type !== "ContractEmitted") return null;
|
|
571
613
|
const contractEmittedData = eventValue.value;
|
|
572
614
|
if (!contractEmittedData || typeof contractEmittedData !== "object") return null;
|
|
573
|
-
const
|
|
574
|
-
const
|
|
575
|
-
|
|
615
|
+
const contractRaw = contractEmittedData.contract;
|
|
616
|
+
const dataRaw = contractEmittedData.data;
|
|
617
|
+
let contract;
|
|
618
|
+
if (contractRaw instanceof Uint8Array) contract = contractRaw;
|
|
619
|
+
else if (typeof contractRaw === "string") contract = (0, _polkadot_labs_hdkd_helpers.ss58Decode)(contractRaw)[0];
|
|
620
|
+
else return null;
|
|
621
|
+
let data;
|
|
622
|
+
if (dataRaw instanceof Uint8Array) data = dataRaw;
|
|
623
|
+
else if (dataRaw && typeof dataRaw === "object" && "asBytes" in dataRaw && typeof dataRaw.asBytes === "function") data = dataRaw.asBytes();
|
|
624
|
+
else return null;
|
|
576
625
|
const topics = [];
|
|
577
626
|
if (record.topics && Array.isArray(record.topics)) {
|
|
578
627
|
for (const topic of record.topics) if (topic instanceof Uint8Array) topics.push(topic);
|
|
628
|
+
else if (topic && typeof topic === "object" && "asBytes" in topic && typeof topic.asBytes === "function") topics.push(topic.asBytes());
|
|
579
629
|
}
|
|
630
|
+
const blockNumber = typeof record.blockNumber === "number" ? record.blockNumber : 0;
|
|
631
|
+
const blockHash = typeof record.blockHash === "string" ? record.blockHash : "";
|
|
632
|
+
const eventIndex = typeof record.eventIndex === "number" ? record.eventIndex : 0;
|
|
580
633
|
return {
|
|
581
634
|
contract,
|
|
582
635
|
data,
|
|
583
636
|
topics,
|
|
584
|
-
blockNumber
|
|
585
|
-
blockHash
|
|
586
|
-
eventIndex
|
|
637
|
+
blockNumber,
|
|
638
|
+
blockHash,
|
|
639
|
+
eventIndex
|
|
587
640
|
};
|
|
588
641
|
}
|
|
589
642
|
/**
|
|
@@ -607,6 +660,34 @@ var ContractEventParser = class {
|
|
|
607
660
|
return signatures;
|
|
608
661
|
}
|
|
609
662
|
};
|
|
663
|
+
/**
|
|
664
|
+
* Type guard for narrowing event types
|
|
665
|
+
*
|
|
666
|
+
* Use this function when you have a `TypedContractEvent` and need to
|
|
667
|
+
* narrow it to a specific event type. This is useful when the type
|
|
668
|
+
* information is lost (e.g., after serialization or in generic functions).
|
|
669
|
+
*
|
|
670
|
+
* @typeParam E - The Enum type representing all possible events
|
|
671
|
+
* @typeParam L - The specific event label to check
|
|
672
|
+
* @param event - The event to check
|
|
673
|
+
* @param label - The event label to match
|
|
674
|
+
* @returns True if the event type matches the label
|
|
675
|
+
*
|
|
676
|
+
* @example
|
|
677
|
+
* ```ts
|
|
678
|
+
* const event = parser.parseEvent(chainEvent);
|
|
679
|
+
*
|
|
680
|
+
* if (event && isEventType(event, "Transfer")) {
|
|
681
|
+
* // TypeScript knows event.value is Transfer event data
|
|
682
|
+
* console.log(event.value.from);
|
|
683
|
+
* console.log(event.value.to);
|
|
684
|
+
* console.log(event.value.value);
|
|
685
|
+
* }
|
|
686
|
+
* ```
|
|
687
|
+
*/
|
|
688
|
+
function isEventType(event, label) {
|
|
689
|
+
return event.type === label;
|
|
690
|
+
}
|
|
610
691
|
|
|
611
692
|
//#endregion
|
|
612
693
|
//#region src/subscriptions.ts
|
|
@@ -617,12 +698,12 @@ var ContractEventParser = class {
|
|
|
617
698
|
* Create an observable stream of contract events
|
|
618
699
|
*
|
|
619
700
|
* @param client - Polkadot API client
|
|
620
|
-
* @param
|
|
701
|
+
* @param descriptor - Contract descriptor
|
|
621
702
|
* @param options - Subscription options
|
|
622
|
-
* @returns Observable stream of
|
|
703
|
+
* @returns Observable stream of type-safe contract events
|
|
623
704
|
*/
|
|
624
|
-
function createContractEventStream(client,
|
|
625
|
-
const parser = new ContractEventParser(
|
|
705
|
+
function createContractEventStream(client, descriptor, options) {
|
|
706
|
+
const parser = new ContractEventParser(descriptor, options.contractAddress);
|
|
626
707
|
return client.finalizedBlock$.pipe((0, rxjs.mergeMap)(async (block) => {
|
|
627
708
|
try {
|
|
628
709
|
return {
|
|
@@ -648,7 +729,7 @@ function createContractEventStream(client, metadata, options) {
|
|
|
648
729
|
}).filter((e) => e !== null);
|
|
649
730
|
}), (0, rxjs.mergeMap)((events) => (0, rxjs.from)(events)), (0, rxjs.filter)((event) => {
|
|
650
731
|
if (!options.eventLabels) return true;
|
|
651
|
-
return options.eventLabels.includes(event.
|
|
732
|
+
return options.eventLabels.includes(event.type);
|
|
652
733
|
}), (0, rxjs.catchError)((error) => {
|
|
653
734
|
console.error("Error in contract event stream:", error);
|
|
654
735
|
return (0, rxjs.of)();
|
|
@@ -658,21 +739,21 @@ function createContractEventStream(client, metadata, options) {
|
|
|
658
739
|
* Convenience helper to create a Transfer event stream for PSP22 tokens
|
|
659
740
|
*
|
|
660
741
|
* @param client - Polkadot API client
|
|
661
|
-
* @param
|
|
742
|
+
* @param descriptor - PSP22 contract descriptor
|
|
662
743
|
* @param contractAddress - PSP22 contract address
|
|
663
744
|
* @param getEvents - Function to fetch System.Events at a block hash
|
|
664
745
|
* @param watchAddress - Optional address to filter transfers (only events involving this address)
|
|
665
746
|
* @returns Observable stream of Transfer events
|
|
666
747
|
*/
|
|
667
|
-
function createPSP22TransferStream(client,
|
|
668
|
-
return createContractEventStream(client,
|
|
748
|
+
function createPSP22TransferStream(client, descriptor, contractAddress, getEvents, watchAddress) {
|
|
749
|
+
return createContractEventStream(client, descriptor, {
|
|
669
750
|
contractAddress,
|
|
670
751
|
eventLabels: ["Transfer"],
|
|
671
752
|
getEvents
|
|
672
753
|
}).pipe((0, rxjs.filter)((event) => {
|
|
673
754
|
if (!watchAddress) return true;
|
|
674
|
-
const
|
|
675
|
-
return
|
|
755
|
+
const value = event.value;
|
|
756
|
+
return value.from === watchAddress || value.to === watchAddress;
|
|
676
757
|
}));
|
|
677
758
|
}
|
|
678
759
|
/**
|
|
@@ -719,6 +800,91 @@ function createNativeTransferStream(client, getEvents, watchAddress) {
|
|
|
719
800
|
}), (0, rxjs.share)());
|
|
720
801
|
}
|
|
721
802
|
|
|
803
|
+
//#endregion
|
|
804
|
+
//#region src/message-builder.ts
|
|
805
|
+
/**
|
|
806
|
+
* Create a type-safe message builder from a contract descriptor
|
|
807
|
+
*
|
|
808
|
+
* @typeParam S - Storage descriptor type
|
|
809
|
+
* @typeParam M - Messages descriptor type
|
|
810
|
+
* @typeParam C - Constructors descriptor type
|
|
811
|
+
* @typeParam E - Events Enum type
|
|
812
|
+
* @param descriptor - The ink! contract descriptor containing metadata
|
|
813
|
+
* @returns A ContractMessageBuilder instance
|
|
814
|
+
*
|
|
815
|
+
* @example
|
|
816
|
+
* ```ts
|
|
817
|
+
* import { createMessageBuilder } from '@d9-network/ink';
|
|
818
|
+
* import { contracts } from '@polkadot-api/descriptors';
|
|
819
|
+
*
|
|
820
|
+
* const builder = createMessageBuilder(contracts.usdt);
|
|
821
|
+
*
|
|
822
|
+
* // Get a typed message interface
|
|
823
|
+
* const transfer = builder.message("PSP22::transfer");
|
|
824
|
+
*
|
|
825
|
+
* // Encode with full type checking on args
|
|
826
|
+
* const encoded = transfer.encode({
|
|
827
|
+
* to: recipientAddress, // Must be SS58String
|
|
828
|
+
* value: 1000000n, // Must be bigint
|
|
829
|
+
* data: new Uint8Array(), // Must be Uint8Array
|
|
830
|
+
* });
|
|
831
|
+
*
|
|
832
|
+
* // Decode response with full type inference
|
|
833
|
+
* const response = transfer.decode(resultBytes);
|
|
834
|
+
* ```
|
|
835
|
+
*/
|
|
836
|
+
function createMessageBuilder(descriptor) {
|
|
837
|
+
if (!descriptor.metadata) throw new Error("Contract descriptor must include metadata");
|
|
838
|
+
const metadata = descriptor.metadata;
|
|
839
|
+
const builder = (0, _polkadot_api_ink_contracts.getInkDynamicBuilder)((0, _polkadot_api_ink_contracts.getInkLookup)(metadata));
|
|
840
|
+
const codecCache = /* @__PURE__ */ new Map();
|
|
841
|
+
const messagesMetadata = /* @__PURE__ */ new Map();
|
|
842
|
+
for (const msg of metadata.spec.messages) messagesMetadata.set(msg.label, msg);
|
|
843
|
+
function getMessageCodec(label) {
|
|
844
|
+
const cached = codecCache.get(label);
|
|
845
|
+
if (cached) return cached;
|
|
846
|
+
const codec = builder.buildMessage(label);
|
|
847
|
+
codecCache.set(label, codec);
|
|
848
|
+
return codec;
|
|
849
|
+
}
|
|
850
|
+
function parseSelector(selectorHex) {
|
|
851
|
+
const hex = selectorHex.startsWith("0x") ? selectorHex.slice(2) : selectorHex;
|
|
852
|
+
return new Uint8Array(hex.match(/.{1,2}/g).map((byte) => parseInt(byte, 16)));
|
|
853
|
+
}
|
|
854
|
+
function message(label) {
|
|
855
|
+
const msgMeta = messagesMetadata.get(label);
|
|
856
|
+
if (!msgMeta) throw new Error(`Message "${label}" not found in metadata`);
|
|
857
|
+
const codec = getMessageCodec(label);
|
|
858
|
+
const selector = parseSelector(msgMeta.selector);
|
|
859
|
+
const encode = (args) => {
|
|
860
|
+
const encoded = codec.call.enc(args ?? {});
|
|
861
|
+
return polkadot_api.Binary.fromBytes(encoded);
|
|
862
|
+
};
|
|
863
|
+
const decode = (response) => {
|
|
864
|
+
const bytes = response instanceof Uint8Array ? response : response.asBytes();
|
|
865
|
+
return codec.value.dec(bytes);
|
|
866
|
+
};
|
|
867
|
+
return {
|
|
868
|
+
encode,
|
|
869
|
+
decode,
|
|
870
|
+
attributes: {
|
|
871
|
+
mutates: msgMeta.mutates,
|
|
872
|
+
payable: msgMeta.payable,
|
|
873
|
+
default: msgMeta.default
|
|
874
|
+
},
|
|
875
|
+
selector,
|
|
876
|
+
label
|
|
877
|
+
};
|
|
878
|
+
}
|
|
879
|
+
function getMessageLabels() {
|
|
880
|
+
return Array.from(messagesMetadata.keys());
|
|
881
|
+
}
|
|
882
|
+
return {
|
|
883
|
+
message,
|
|
884
|
+
getMessageLabels
|
|
885
|
+
};
|
|
886
|
+
}
|
|
887
|
+
|
|
722
888
|
//#endregion
|
|
723
889
|
//#region src/errors.ts
|
|
724
890
|
/**
|
|
@@ -937,6 +1103,10 @@ function createD9InkContract(descriptor, address, options) {
|
|
|
937
1103
|
if (!descriptor.metadata) throw new MetadataError("Contract descriptor must include metadata");
|
|
938
1104
|
const patchedMetadata = patchLangErrorInMetadata(descriptor.metadata);
|
|
939
1105
|
const builder = (0, _polkadot_api_ink_contracts.getInkDynamicBuilder)((0, _polkadot_api_ink_contracts.getInkLookup)(patchedMetadata));
|
|
1106
|
+
const patchedDescriptor = {
|
|
1107
|
+
...descriptor,
|
|
1108
|
+
metadata: patchedMetadata
|
|
1109
|
+
};
|
|
940
1110
|
let codecRegistry;
|
|
941
1111
|
try {
|
|
942
1112
|
codecRegistry = createCodecRegistry(patchedMetadata);
|
|
@@ -971,13 +1141,13 @@ function createD9InkContract(descriptor, address, options) {
|
|
|
971
1141
|
checkAborted(signal, method);
|
|
972
1142
|
const originBytes = ss58ToBytes(origin);
|
|
973
1143
|
const codec = getMessageCodec(method);
|
|
974
|
-
const message = encodeContractCall(originBytes, addressBytes, codec.call.enc(args ?? {}), value);
|
|
1144
|
+
const message$1 = encodeContractCall(originBytes, addressBytes, codec.call.enc(args ?? {}), value);
|
|
975
1145
|
const blockHash = at ?? (await client.getFinalizedBlock()).hash;
|
|
976
1146
|
checkAborted(signal, method);
|
|
977
1147
|
const executeCall = async () => {
|
|
978
1148
|
return (0, polkadot_api_utils.fromHex)(await client._request("state_call", [
|
|
979
1149
|
"ContractsApi_call",
|
|
980
|
-
message,
|
|
1150
|
+
message$1,
|
|
981
1151
|
blockHash
|
|
982
1152
|
]));
|
|
983
1153
|
};
|
|
@@ -1079,11 +1249,11 @@ function createD9InkContract(descriptor, address, options) {
|
|
|
1079
1249
|
try {
|
|
1080
1250
|
let gas = gasLimit;
|
|
1081
1251
|
if (!gas) {
|
|
1082
|
-
const message = encodeContractCall(originBytes, addressBytes, callData, value);
|
|
1252
|
+
const message$1 = encodeContractCall(originBytes, addressBytes, callData, value);
|
|
1083
1253
|
const blockHash = (await client.getFinalizedBlock()).hash;
|
|
1084
1254
|
gas = decodeContractCallResult((0, polkadot_api_utils.fromHex)(await client._request("state_call", [
|
|
1085
1255
|
"ContractsApi_call",
|
|
1086
|
-
message,
|
|
1256
|
+
message$1,
|
|
1087
1257
|
blockHash
|
|
1088
1258
|
]))).gas.gasRequired;
|
|
1089
1259
|
}
|
|
@@ -1152,7 +1322,20 @@ function createD9InkContract(descriptor, address, options) {
|
|
|
1152
1322
|
* Filter events for this contract
|
|
1153
1323
|
*/
|
|
1154
1324
|
function filterEvents(events) {
|
|
1155
|
-
return new ContractEventParser(
|
|
1325
|
+
return new ContractEventParser(patchedDescriptor, address).filterEvents(events);
|
|
1326
|
+
}
|
|
1327
|
+
/**
|
|
1328
|
+
* Filter events by specific type with proper type narrowing
|
|
1329
|
+
*/
|
|
1330
|
+
function filterEventsByType(events, label) {
|
|
1331
|
+
return new ContractEventParser(patchedDescriptor, address).filterByType(events, label);
|
|
1332
|
+
}
|
|
1333
|
+
const messageBuilder = createMessageBuilder(descriptor);
|
|
1334
|
+
/**
|
|
1335
|
+
* Get a type-safe message interface
|
|
1336
|
+
*/
|
|
1337
|
+
function message(label) {
|
|
1338
|
+
return messageBuilder.message(label);
|
|
1156
1339
|
}
|
|
1157
1340
|
/**
|
|
1158
1341
|
* Subscribe to contract events as an RxJS Observable
|
|
@@ -1163,7 +1346,7 @@ function createD9InkContract(descriptor, address, options) {
|
|
|
1163
1346
|
* @param options.fromBlock - Optional starting block number
|
|
1164
1347
|
*/
|
|
1165
1348
|
function subscribeToEvents(options$1) {
|
|
1166
|
-
return createContractEventStream(client,
|
|
1349
|
+
return createContractEventStream(client, patchedDescriptor, {
|
|
1167
1350
|
...options$1,
|
|
1168
1351
|
contractAddress: address
|
|
1169
1352
|
});
|
|
@@ -1175,10 +1358,43 @@ function createD9InkContract(descriptor, address, options) {
|
|
|
1175
1358
|
send,
|
|
1176
1359
|
getStorage,
|
|
1177
1360
|
filterEvents,
|
|
1361
|
+
filterEventsByType,
|
|
1362
|
+
message,
|
|
1178
1363
|
subscribeToEvents
|
|
1179
1364
|
};
|
|
1180
1365
|
}
|
|
1181
1366
|
|
|
1367
|
+
//#endregion
|
|
1368
|
+
//#region src/rpc.ts
|
|
1369
|
+
/**
|
|
1370
|
+
* Create a type-safe RPC request function from a PolkadotClient
|
|
1371
|
+
*
|
|
1372
|
+
* This wraps the client's `_request` method with proper TypeScript types,
|
|
1373
|
+
* providing autocomplete for known RPC methods and type inference for
|
|
1374
|
+
* parameters and return values.
|
|
1375
|
+
*
|
|
1376
|
+
* @param client - The PolkadotClient instance
|
|
1377
|
+
* @returns A type-safe RPC request function
|
|
1378
|
+
*
|
|
1379
|
+
* @example
|
|
1380
|
+
* ```ts
|
|
1381
|
+
* const rpc = createTypedRpc(client);
|
|
1382
|
+
*
|
|
1383
|
+
* // Autocomplete for method names, typed params and return
|
|
1384
|
+
* const hash = await rpc("chain_getBlockHash", [12345]);
|
|
1385
|
+
* // hash: HexString | null
|
|
1386
|
+
*
|
|
1387
|
+
* const header = await rpc("chain_getHeader", [hash]);
|
|
1388
|
+
* // header: BlockHeader | null
|
|
1389
|
+
*
|
|
1390
|
+
* // Custom methods still work with explicit types
|
|
1391
|
+
* const custom = await rpc<MyType>("my_custom_method", [arg]);
|
|
1392
|
+
* ```
|
|
1393
|
+
*/
|
|
1394
|
+
function createTypedRpc(client) {
|
|
1395
|
+
return ((method, params) => client._request(method, params));
|
|
1396
|
+
}
|
|
1397
|
+
|
|
1182
1398
|
//#endregion
|
|
1183
1399
|
//#region src/sdk.ts
|
|
1184
1400
|
/**
|
|
@@ -1222,22 +1438,381 @@ function createD9InkContract(descriptor, address, options) {
|
|
|
1222
1438
|
*
|
|
1223
1439
|
* @param client - The PolkadotClient instance
|
|
1224
1440
|
* @param options - Optional SDK configuration
|
|
1225
|
-
* @returns D9 Ink SDK instance
|
|
1441
|
+
* @returns D9 Ink SDK instance with typed RPC access
|
|
1226
1442
|
*/
|
|
1227
1443
|
function createD9InkSdk(client, options = {}) {
|
|
1228
1444
|
const { typedApi, defaultQueryOptions, defaultSendOptions } = options;
|
|
1229
|
-
return {
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1445
|
+
return {
|
|
1446
|
+
getContract(descriptor, address) {
|
|
1447
|
+
return createD9InkContract(descriptor, address, {
|
|
1448
|
+
client,
|
|
1449
|
+
typedApi,
|
|
1450
|
+
defaultQueryOptions,
|
|
1451
|
+
defaultSendOptions
|
|
1452
|
+
});
|
|
1453
|
+
},
|
|
1454
|
+
rpc: createTypedRpc(client)
|
|
1455
|
+
};
|
|
1456
|
+
}
|
|
1457
|
+
|
|
1458
|
+
//#endregion
|
|
1459
|
+
//#region src/codec-builder-internal.ts
|
|
1460
|
+
/**
|
|
1461
|
+
* Internal codec building utilities
|
|
1462
|
+
*
|
|
1463
|
+
* This module provides lower-level codec building from metadata type IDs.
|
|
1464
|
+
*/
|
|
1465
|
+
/**
|
|
1466
|
+
* Build a SCALE codec from ink metadata type definition
|
|
1467
|
+
*/
|
|
1468
|
+
function buildCodecFromTypeInternal(typeId, types, cache) {
|
|
1469
|
+
const cached = cache.get(typeId);
|
|
1470
|
+
if (cached) return cached;
|
|
1471
|
+
const typeEntry = types.find((t) => t.id === typeId);
|
|
1472
|
+
if (!typeEntry) throw new Error(`Type ${typeId} not found in metadata`);
|
|
1473
|
+
const def = typeEntry.type.def;
|
|
1474
|
+
const path = typeEntry.type.path;
|
|
1475
|
+
if (def.primitive) {
|
|
1476
|
+
const codec = buildPrimitiveCodec(def.primitive);
|
|
1477
|
+
cache.set(typeId, codec);
|
|
1478
|
+
return codec;
|
|
1479
|
+
}
|
|
1480
|
+
if (path && path.length > 0) {
|
|
1481
|
+
const specialCodec = buildSpecialTypeCodec(path, typeEntry, types, cache);
|
|
1482
|
+
if (specialCodec) {
|
|
1483
|
+
cache.set(typeId, specialCodec);
|
|
1484
|
+
return specialCodec;
|
|
1485
|
+
}
|
|
1486
|
+
}
|
|
1487
|
+
if (def.tuple) {
|
|
1488
|
+
const codec = buildTupleCodec(def.tuple, types, cache);
|
|
1489
|
+
cache.set(typeId, codec);
|
|
1490
|
+
return codec;
|
|
1491
|
+
}
|
|
1492
|
+
if (def.sequence) {
|
|
1493
|
+
const codec = (0, _polkadot_api_substrate_bindings.Vector)(buildCodecFromTypeInternal(def.sequence.type, types, cache));
|
|
1494
|
+
cache.set(typeId, codec);
|
|
1495
|
+
return codec;
|
|
1496
|
+
}
|
|
1497
|
+
if (def.array) {
|
|
1498
|
+
const innerCodec = buildCodecFromTypeInternal(def.array.type, types, cache);
|
|
1499
|
+
if (def.array.type === findPrimitiveTypeId(types, "u8")) {
|
|
1500
|
+
const codec$1 = (0, _polkadot_api_substrate_bindings.Bytes)(def.array.len);
|
|
1501
|
+
cache.set(typeId, codec$1);
|
|
1502
|
+
return codec$1;
|
|
1503
|
+
}
|
|
1504
|
+
const codec = (0, _polkadot_api_substrate_bindings.Vector)(innerCodec, def.array.len);
|
|
1505
|
+
cache.set(typeId, codec);
|
|
1506
|
+
return codec;
|
|
1507
|
+
}
|
|
1508
|
+
if (def.composite) {
|
|
1509
|
+
const codec = buildCompositeCodec(def.composite, types, cache);
|
|
1510
|
+
cache.set(typeId, codec);
|
|
1511
|
+
return codec;
|
|
1512
|
+
}
|
|
1513
|
+
if (def.variant) {
|
|
1514
|
+
const codec = buildVariantCodec(def.variant, path, types, cache);
|
|
1515
|
+
cache.set(typeId, codec);
|
|
1516
|
+
return codec;
|
|
1517
|
+
}
|
|
1518
|
+
throw new Error(`Unknown type definition for type ${typeId}`);
|
|
1519
|
+
}
|
|
1520
|
+
function buildPrimitiveCodec(primitive) {
|
|
1521
|
+
switch (primitive) {
|
|
1522
|
+
case "u8": return _polkadot_api_substrate_bindings.u8;
|
|
1523
|
+
case "u16": return _polkadot_api_substrate_bindings.u16;
|
|
1524
|
+
case "u32": return _polkadot_api_substrate_bindings.u32;
|
|
1525
|
+
case "u64": return _polkadot_api_substrate_bindings.u64;
|
|
1526
|
+
case "u128": return _polkadot_api_substrate_bindings.u128;
|
|
1527
|
+
case "i8": return _polkadot_api_substrate_bindings.i8;
|
|
1528
|
+
case "i16": return _polkadot_api_substrate_bindings.i16;
|
|
1529
|
+
case "i32": return _polkadot_api_substrate_bindings.i32;
|
|
1530
|
+
case "i64": return _polkadot_api_substrate_bindings.i64;
|
|
1531
|
+
case "i128": return _polkadot_api_substrate_bindings.i128;
|
|
1532
|
+
case "bool": return _polkadot_api_substrate_bindings.bool;
|
|
1533
|
+
case "str": return _polkadot_api_substrate_bindings.str;
|
|
1534
|
+
default: throw new Error(`Unknown primitive type: ${primitive}`);
|
|
1535
|
+
}
|
|
1536
|
+
}
|
|
1537
|
+
function buildSpecialTypeCodec(path, typeEntry, types, cache) {
|
|
1538
|
+
if (path.join("::").includes("AccountId")) return (0, _polkadot_api_substrate_bindings.AccountId)();
|
|
1539
|
+
if (path[0] === "Option") {
|
|
1540
|
+
const params = typeEntry.type.params;
|
|
1541
|
+
if (params && params.length > 0 && params[0]?.type !== void 0) return (0, _polkadot_api_substrate_bindings.Option)(buildCodecFromTypeInternal(params[0].type, types, cache));
|
|
1542
|
+
}
|
|
1543
|
+
if (path[0] === "Result") {
|
|
1544
|
+
const params = typeEntry.type.params;
|
|
1545
|
+
if (params && params.length >= 2) {
|
|
1546
|
+
const okTypeId = params[0]?.type;
|
|
1547
|
+
const errTypeId = params[1]?.type;
|
|
1548
|
+
if (okTypeId !== void 0 && errTypeId !== void 0) return (0, _polkadot_api_substrate_bindings.Variant)({
|
|
1549
|
+
Ok: buildCodecFromTypeInternal(okTypeId, types, cache),
|
|
1550
|
+
Err: buildCodecFromTypeInternal(errTypeId, types, cache)
|
|
1551
|
+
}, [0, 1]);
|
|
1552
|
+
}
|
|
1553
|
+
}
|
|
1554
|
+
return null;
|
|
1555
|
+
}
|
|
1556
|
+
function buildTupleCodec(tupleTypes, types, cache) {
|
|
1557
|
+
if (tupleTypes.length === 0) return _polkadot_api_substrate_bindings._void;
|
|
1558
|
+
const innerCodecs = tupleTypes.map((t) => buildCodecFromTypeInternal(t, types, cache));
|
|
1559
|
+
switch (innerCodecs.length) {
|
|
1560
|
+
case 1: return (0, _polkadot_api_substrate_bindings.Tuple)(innerCodecs[0]);
|
|
1561
|
+
case 2: return (0, _polkadot_api_substrate_bindings.Tuple)(innerCodecs[0], innerCodecs[1]);
|
|
1562
|
+
case 3: return (0, _polkadot_api_substrate_bindings.Tuple)(innerCodecs[0], innerCodecs[1], innerCodecs[2]);
|
|
1563
|
+
case 4: return (0, _polkadot_api_substrate_bindings.Tuple)(innerCodecs[0], innerCodecs[1], innerCodecs[2], innerCodecs[3]);
|
|
1564
|
+
default: return (0, _polkadot_api_substrate_bindings.Tuple)(...innerCodecs);
|
|
1565
|
+
}
|
|
1566
|
+
}
|
|
1567
|
+
function buildCompositeCodec(composite, types, cache) {
|
|
1568
|
+
const fields = composite.fields;
|
|
1569
|
+
if (fields.length === 1 && !fields[0]?.name) return buildCodecFromTypeInternal(fields[0].type, types, cache);
|
|
1570
|
+
const structDef = {};
|
|
1571
|
+
for (const field of fields) {
|
|
1572
|
+
const fieldName = field.name || `field${fields.indexOf(field)}`;
|
|
1573
|
+
structDef[fieldName] = buildCodecFromTypeInternal(field.type, types, cache);
|
|
1574
|
+
}
|
|
1575
|
+
return (0, _polkadot_api_substrate_bindings.Struct)(structDef);
|
|
1576
|
+
}
|
|
1577
|
+
function buildVariantCodec(variant, path, types, cache) {
|
|
1578
|
+
const variants = variant.variants;
|
|
1579
|
+
const isLangError$1 = path?.includes("LangError");
|
|
1580
|
+
const variantDef = {};
|
|
1581
|
+
const indices = [];
|
|
1582
|
+
if (isLangError$1 && !variants.some((v) => v.index === 0)) {
|
|
1583
|
+
variantDef["_Placeholder"] = _polkadot_api_substrate_bindings._void;
|
|
1584
|
+
indices.push(0);
|
|
1585
|
+
}
|
|
1586
|
+
for (const v of variants) {
|
|
1587
|
+
let fieldCodec;
|
|
1588
|
+
const fields = v.fields ?? [];
|
|
1589
|
+
if (fields.length === 0) fieldCodec = _polkadot_api_substrate_bindings._void;
|
|
1590
|
+
else if (fields.length === 1 && !fields[0]?.name) fieldCodec = buildCodecFromTypeInternal(fields[0].type, types, cache);
|
|
1591
|
+
else {
|
|
1592
|
+
const structDef = {};
|
|
1593
|
+
for (const field of fields) {
|
|
1594
|
+
const fieldName = field.name || `field${fields.indexOf(field)}`;
|
|
1595
|
+
structDef[fieldName] = buildCodecFromTypeInternal(field.type, types, cache);
|
|
1596
|
+
}
|
|
1597
|
+
fieldCodec = (0, _polkadot_api_substrate_bindings.Struct)(structDef);
|
|
1598
|
+
}
|
|
1599
|
+
variantDef[v.name] = fieldCodec;
|
|
1600
|
+
indices.push(v.index);
|
|
1601
|
+
}
|
|
1602
|
+
return (0, _polkadot_api_substrate_bindings.Variant)(variantDef, indices);
|
|
1603
|
+
}
|
|
1604
|
+
function findPrimitiveTypeId(types, primitive) {
|
|
1605
|
+
return types.find((t) => t.type.def.primitive === primitive)?.id ?? -1;
|
|
1606
|
+
}
|
|
1607
|
+
/**
|
|
1608
|
+
* Build a struct codec for message arguments
|
|
1609
|
+
*
|
|
1610
|
+
* @param metadata - The ink contract metadata
|
|
1611
|
+
* @param args - The argument definitions
|
|
1612
|
+
* @returns A struct codec
|
|
1613
|
+
*/
|
|
1614
|
+
function buildArgsCodec(metadata, args) {
|
|
1615
|
+
if (args.length === 0) return {
|
|
1616
|
+
enc: () => new Uint8Array(0),
|
|
1617
|
+
dec: () => ({})
|
|
1618
|
+
};
|
|
1619
|
+
const types = metadata.types;
|
|
1620
|
+
const cache = /* @__PURE__ */ new Map();
|
|
1621
|
+
const structDef = {};
|
|
1622
|
+
for (const arg of args) structDef[arg.label] = buildCodecFromTypeInternal(arg.type.type, types, cache);
|
|
1623
|
+
const codec = (0, _polkadot_api_substrate_bindings.Struct)(structDef);
|
|
1624
|
+
return {
|
|
1625
|
+
enc: (value) => codec.enc(value),
|
|
1626
|
+
dec: (data) => codec.dec(data)
|
|
1627
|
+
};
|
|
1628
|
+
}
|
|
1629
|
+
|
|
1630
|
+
//#endregion
|
|
1631
|
+
//#region src/calls.ts
|
|
1632
|
+
/**
|
|
1633
|
+
* Build argument decoders for all messages in the metadata
|
|
1634
|
+
*/
|
|
1635
|
+
function buildAllMessageDecodersFromMetadata(metadata) {
|
|
1636
|
+
const decoders = /* @__PURE__ */ new Map();
|
|
1637
|
+
const messages = metadata.spec.messages;
|
|
1638
|
+
for (const message of messages) try {
|
|
1639
|
+
const selectorHex = message.selector.startsWith("0x") ? message.selector.slice(2) : message.selector;
|
|
1640
|
+
const selector = new Uint8Array(selectorHex.match(/.{1,2}/g).map((byte) => parseInt(byte, 16)));
|
|
1641
|
+
const argsCodec = buildArgsCodec(metadata, message.args);
|
|
1642
|
+
const decoder = (data) => argsCodec.dec(data);
|
|
1643
|
+
decoders.set(message.label, {
|
|
1644
|
+
selector,
|
|
1645
|
+
decoder
|
|
1235
1646
|
});
|
|
1236
|
-
}
|
|
1647
|
+
} catch (error) {
|
|
1648
|
+
console.warn(`Failed to build decoder for message "${message.label}":`, error);
|
|
1649
|
+
}
|
|
1650
|
+
return decoders;
|
|
1651
|
+
}
|
|
1652
|
+
/**
|
|
1653
|
+
* Type-safe call parser for a specific contract
|
|
1654
|
+
*
|
|
1655
|
+
* @typeParam S - The storage descriptor type
|
|
1656
|
+
* @typeParam M - The InkCallableDescriptor type (message definitions)
|
|
1657
|
+
* @typeParam C - The constructors descriptor type
|
|
1658
|
+
* @typeParam E - The events Enum type
|
|
1659
|
+
*/
|
|
1660
|
+
var ContractCallParser = class {
|
|
1661
|
+
messageDecoders;
|
|
1662
|
+
selectorToLabel;
|
|
1663
|
+
metadata;
|
|
1664
|
+
constructor(descriptor) {
|
|
1665
|
+
if (!descriptor.metadata) throw new Error("Contract descriptor must include metadata");
|
|
1666
|
+
this.metadata = descriptor.metadata;
|
|
1667
|
+
this.messageDecoders = buildAllMessageDecodersFromMetadata(this.metadata);
|
|
1668
|
+
this.selectorToLabel = /* @__PURE__ */ new Map();
|
|
1669
|
+
for (const [label, { selector }] of this.messageDecoders) {
|
|
1670
|
+
const selectorHex = Array.from(selector).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
1671
|
+
this.selectorToLabel.set(selectorHex, label);
|
|
1672
|
+
}
|
|
1673
|
+
}
|
|
1674
|
+
/**
|
|
1675
|
+
* Parse raw call data into a type-safe contract call
|
|
1676
|
+
*
|
|
1677
|
+
* @param callData - The raw call data (selector + encoded args) or RawContractCall
|
|
1678
|
+
* @returns Parsed call or null if cannot parse
|
|
1679
|
+
*
|
|
1680
|
+
* @example
|
|
1681
|
+
* ```ts
|
|
1682
|
+
* const call = parser.parseCall(callData);
|
|
1683
|
+
* if (call?.type === "PSP22::transfer") {
|
|
1684
|
+
* // call.args is typed as { to: SS58String; value: bigint; data: Uint8Array }
|
|
1685
|
+
* console.log(call.args.to);
|
|
1686
|
+
* }
|
|
1687
|
+
* ```
|
|
1688
|
+
*/
|
|
1689
|
+
parseCall(callData) {
|
|
1690
|
+
const data = callData instanceof Uint8Array ? callData : callData.data;
|
|
1691
|
+
const raw = callData instanceof Uint8Array ? { data: callData } : callData;
|
|
1692
|
+
if (data.length < 4) return null;
|
|
1693
|
+
const selector = data.slice(0, 4);
|
|
1694
|
+
const selectorHex = Array.from(selector).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
1695
|
+
const label = this.selectorToLabel.get(selectorHex);
|
|
1696
|
+
if (!label) return null;
|
|
1697
|
+
const messageInfo = this.messageDecoders.get(label);
|
|
1698
|
+
if (!messageInfo) return null;
|
|
1699
|
+
const argsData = data.slice(4);
|
|
1700
|
+
try {
|
|
1701
|
+
return {
|
|
1702
|
+
type: label,
|
|
1703
|
+
args: messageInfo.decoder(argsData),
|
|
1704
|
+
selector,
|
|
1705
|
+
raw
|
|
1706
|
+
};
|
|
1707
|
+
} catch (error) {
|
|
1708
|
+
console.warn(`Failed to decode call "${label}":`, error);
|
|
1709
|
+
return null;
|
|
1710
|
+
}
|
|
1711
|
+
}
|
|
1712
|
+
/**
|
|
1713
|
+
* Parse multiple calls and optionally filter by message labels
|
|
1714
|
+
*
|
|
1715
|
+
* @param calls - Array of raw call data
|
|
1716
|
+
* @param options - Filter options
|
|
1717
|
+
* @returns Array of parsed calls
|
|
1718
|
+
*/
|
|
1719
|
+
parseCalls(calls, options) {
|
|
1720
|
+
const results = [];
|
|
1721
|
+
for (const call of calls) {
|
|
1722
|
+
const parsed = this.parseCall(call);
|
|
1723
|
+
if (!parsed) continue;
|
|
1724
|
+
if (options?.messageLabels && !options.messageLabels.includes(parsed.type)) continue;
|
|
1725
|
+
results.push(parsed);
|
|
1726
|
+
}
|
|
1727
|
+
return results;
|
|
1728
|
+
}
|
|
1729
|
+
/**
|
|
1730
|
+
* Filter calls by specific type with proper type narrowing
|
|
1731
|
+
*
|
|
1732
|
+
* This method provides better type safety than parseCalls with messageLabels
|
|
1733
|
+
* because TypeScript can narrow the return type to only the specified call type.
|
|
1734
|
+
*
|
|
1735
|
+
* @param calls - Array of raw call data
|
|
1736
|
+
* @param label - The message label to filter by
|
|
1737
|
+
* @returns Array of calls narrowed to the specific type
|
|
1738
|
+
*
|
|
1739
|
+
* @example
|
|
1740
|
+
* ```ts
|
|
1741
|
+
* const transfers = parser.filterByType(callDataArray, "PSP22::transfer");
|
|
1742
|
+
*
|
|
1743
|
+
* for (const t of transfers) {
|
|
1744
|
+
* // t.args is fully typed as PSP22::transfer args
|
|
1745
|
+
* console.log(t.args.to, t.args.value);
|
|
1746
|
+
* }
|
|
1747
|
+
* ```
|
|
1748
|
+
*/
|
|
1749
|
+
filterByType(calls, label) {
|
|
1750
|
+
return this.parseCalls(calls).filter((c) => c.type === label);
|
|
1751
|
+
}
|
|
1752
|
+
/**
|
|
1753
|
+
* Get information about a message by label
|
|
1754
|
+
*/
|
|
1755
|
+
getMessageInfo(label) {
|
|
1756
|
+
const info = this.messageDecoders.get(label);
|
|
1757
|
+
if (!info) return null;
|
|
1758
|
+
const message = this.metadata.spec.messages.find((m) => m.label === label);
|
|
1759
|
+
if (!message) return null;
|
|
1760
|
+
return {
|
|
1761
|
+
label: message.label,
|
|
1762
|
+
selector: info.selector,
|
|
1763
|
+
mutates: message.mutates,
|
|
1764
|
+
payable: message.payable,
|
|
1765
|
+
args: message.args
|
|
1766
|
+
};
|
|
1767
|
+
}
|
|
1768
|
+
/**
|
|
1769
|
+
* Get all available message labels
|
|
1770
|
+
*/
|
|
1771
|
+
getMessageLabels() {
|
|
1772
|
+
return Array.from(this.messageDecoders.keys());
|
|
1773
|
+
}
|
|
1774
|
+
/**
|
|
1775
|
+
* Check if a selector matches a specific message
|
|
1776
|
+
*/
|
|
1777
|
+
matchesMessage(selector, label) {
|
|
1778
|
+
const info = this.messageDecoders.get(label);
|
|
1779
|
+
if (!info) return false;
|
|
1780
|
+
if (selector.length !== info.selector.length) return false;
|
|
1781
|
+
for (let i = 0; i < selector.length; i++) if (selector[i] !== info.selector[i]) return false;
|
|
1782
|
+
return true;
|
|
1783
|
+
}
|
|
1784
|
+
};
|
|
1785
|
+
/**
|
|
1786
|
+
* Type guard for narrowing call types
|
|
1787
|
+
*
|
|
1788
|
+
* Use this function when you have a `TypedContractCall` and need to
|
|
1789
|
+
* narrow it to a specific call type. This is useful when the type
|
|
1790
|
+
* information is lost (e.g., after serialization or in generic functions).
|
|
1791
|
+
*
|
|
1792
|
+
* @typeParam M - The InkCallableDescriptor type (message definitions)
|
|
1793
|
+
* @typeParam L - The specific message label to check
|
|
1794
|
+
* @param call - The call to check
|
|
1795
|
+
* @param label - The message label to match
|
|
1796
|
+
* @returns True if the call type matches the label
|
|
1797
|
+
*
|
|
1798
|
+
* @example
|
|
1799
|
+
* ```ts
|
|
1800
|
+
* const call = parser.parseCall(callData);
|
|
1801
|
+
*
|
|
1802
|
+
* if (call && isCallType(call, "PSP22::transfer")) {
|
|
1803
|
+
* // TypeScript knows call.args is transfer args
|
|
1804
|
+
* console.log(call.args.to);
|
|
1805
|
+
* console.log(call.args.value);
|
|
1806
|
+
* }
|
|
1807
|
+
* ```
|
|
1808
|
+
*/
|
|
1809
|
+
function isCallType(call, label) {
|
|
1810
|
+
return call.type === label;
|
|
1237
1811
|
}
|
|
1238
1812
|
|
|
1239
1813
|
//#endregion
|
|
1240
1814
|
exports.AbortedError = AbortedError;
|
|
1815
|
+
exports.ContractCallParser = ContractCallParser;
|
|
1241
1816
|
exports.ContractError = ContractError;
|
|
1242
1817
|
exports.ContractEventParser = ContractEventParser;
|
|
1243
1818
|
exports.ContractExecutionError = ContractExecutionError;
|
|
@@ -1258,8 +1833,10 @@ exports.createCodecRegistry = createCodecRegistry;
|
|
|
1258
1833
|
exports.createContractEventStream = createContractEventStream;
|
|
1259
1834
|
exports.createD9InkContract = createD9InkContract;
|
|
1260
1835
|
exports.createD9InkSdk = createD9InkSdk;
|
|
1836
|
+
exports.createMessageBuilder = createMessageBuilder;
|
|
1261
1837
|
exports.createNativeTransferStream = createNativeTransferStream;
|
|
1262
1838
|
exports.createPSP22TransferStream = createPSP22TransferStream;
|
|
1839
|
+
exports.createTypedRpc = createTypedRpc;
|
|
1263
1840
|
exports.decodeContractCallResult = decodeContractCallResult;
|
|
1264
1841
|
exports.decodeInkValue = decodeInkValue;
|
|
1265
1842
|
exports.decodeResult = decodeResult;
|
|
@@ -1267,8 +1844,10 @@ exports.encodeCall = encodeCall;
|
|
|
1267
1844
|
exports.encodeContractCall = encodeContractCall;
|
|
1268
1845
|
exports.encodeContractCallWithLimits = encodeContractCallWithLimits;
|
|
1269
1846
|
exports.getEventSignature = getEventSignature;
|
|
1847
|
+
exports.isCallType = isCallType;
|
|
1270
1848
|
exports.isContractError = isContractError;
|
|
1271
1849
|
exports.isErrorType = isErrorType;
|
|
1850
|
+
exports.isEventType = isEventType;
|
|
1272
1851
|
exports.isLangError = isLangError;
|
|
1273
1852
|
exports.unwrapInkResult = unwrapInkResult;
|
|
1274
1853
|
//# sourceMappingURL=index.cjs.map
|