@d9-network/ink 1.2.5 → 1.3.0

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.d.cts CHANGED
@@ -570,15 +570,26 @@ type InkMessageResult<T$1> = {
570
570
  value: unknown;
571
571
  };
572
572
  /**
573
- * Type helper to unwrap ink! MessageResult (Result<T, LangError>)
574
- * 1. Extract T from { success: true; value: T } | { success: false; value: ... }
575
- * 2. Exclude LangError variants from T
573
+ * Runtime Result type emitted by Variant codecs.
574
+ * The generated TypeScript types often use `success/value`, while dynamic decoders
575
+ * return `{ type: "Ok" | "Err", value }`.
576
576
  */
577
- type UnwrapMessageResult<T$1> = T$1 extends InkMessageResult<infer U> ? Exclude<U, InkLangError> : T$1;
577
+ type InkVariantResult<T$1> = {
578
+ type: "Ok";
579
+ value: T$1;
580
+ } | {
581
+ type: "Err";
582
+ value: unknown;
583
+ };
584
+ /**
585
+ * Recursively unwrap Result-like payloads from both generated descriptor types and
586
+ * runtime Variant codec output.
587
+ */
588
+ type NormalizeResultPayload<T$1> = T$1 extends InkMessageResult<infer U> ? NormalizeResultPayload<Exclude<U, InkLangError>> : T$1 extends InkVariantResult<infer U> ? NormalizeResultPayload<U> : T$1;
578
589
  /**
579
590
  * Type helper to extract message response type (with MessageResult unwrapped)
580
591
  */
581
- type MessageResponse<M$1 extends InkCallableDescriptor, K$1 extends keyof M$1> = UnwrapMessageResult<M$1[K$1]["response"]>;
592
+ type MessageResponse<M$1 extends InkCallableDescriptor, K$1 extends keyof M$1> = NormalizeResultPayload<M$1[K$1]["response"]>;
582
593
  /**
583
594
  * D9 Ink Contract interface
584
595
  *
@@ -885,10 +896,10 @@ interface D9InkSdkWithRpc extends D9InkSdk {
885
896
  * });
886
897
  *
887
898
  * if (result.success) {
888
- * console.log("Balance:", result.value.response);
899
+ * console.log("Balance:", result.value);
889
900
  *
890
901
  * // Send transaction from the query result
891
- * const txResult = await result.value.send().signAndSubmit(aliceSigner);
902
+ * const txResult = await result.send().signAndSubmit(aliceSigner);
892
903
  * }
893
904
  *
894
905
  * // Or send directly
@@ -1129,6 +1140,8 @@ declare function createAsciiEventTopic(contractName: string, eventLabel: string)
1129
1140
  declare class ContractEventParser<S extends InkStorageDescriptor = InkStorageDescriptor, M$1 extends InkCallableDescriptor = InkCallableDescriptor, C extends InkCallableDescriptor = InkCallableDescriptor, E extends Event = Event> {
1130
1141
  private eventDecoders;
1131
1142
  private eventSignatures;
1143
+ /** Maps ink! variant index (first byte of event data) to event label */
1144
+ private eventVariantMap;
1132
1145
  private contractAddressBytes;
1133
1146
  private contractAddress;
1134
1147
  private metadata;
package/dist/index.d.mts CHANGED
@@ -570,15 +570,26 @@ type InkMessageResult<T$1> = {
570
570
  value: unknown;
571
571
  };
572
572
  /**
573
- * Type helper to unwrap ink! MessageResult (Result<T, LangError>)
574
- * 1. Extract T from { success: true; value: T } | { success: false; value: ... }
575
- * 2. Exclude LangError variants from T
573
+ * Runtime Result type emitted by Variant codecs.
574
+ * The generated TypeScript types often use `success/value`, while dynamic decoders
575
+ * return `{ type: "Ok" | "Err", value }`.
576
576
  */
577
- type UnwrapMessageResult<T$1> = T$1 extends InkMessageResult<infer U> ? Exclude<U, InkLangError> : T$1;
577
+ type InkVariantResult<T$1> = {
578
+ type: "Ok";
579
+ value: T$1;
580
+ } | {
581
+ type: "Err";
582
+ value: unknown;
583
+ };
584
+ /**
585
+ * Recursively unwrap Result-like payloads from both generated descriptor types and
586
+ * runtime Variant codec output.
587
+ */
588
+ type NormalizeResultPayload<T$1> = T$1 extends InkMessageResult<infer U> ? NormalizeResultPayload<Exclude<U, InkLangError>> : T$1 extends InkVariantResult<infer U> ? NormalizeResultPayload<U> : T$1;
578
589
  /**
579
590
  * Type helper to extract message response type (with MessageResult unwrapped)
580
591
  */
581
- type MessageResponse<M$1 extends InkCallableDescriptor, K$1 extends keyof M$1> = UnwrapMessageResult<M$1[K$1]["response"]>;
592
+ type MessageResponse<M$1 extends InkCallableDescriptor, K$1 extends keyof M$1> = NormalizeResultPayload<M$1[K$1]["response"]>;
582
593
  /**
583
594
  * D9 Ink Contract interface
584
595
  *
@@ -885,10 +896,10 @@ interface D9InkSdkWithRpc extends D9InkSdk {
885
896
  * });
886
897
  *
887
898
  * if (result.success) {
888
- * console.log("Balance:", result.value.response);
899
+ * console.log("Balance:", result.value);
889
900
  *
890
901
  * // Send transaction from the query result
891
- * const txResult = await result.value.send().signAndSubmit(aliceSigner);
902
+ * const txResult = await result.send().signAndSubmit(aliceSigner);
892
903
  * }
893
904
  *
894
905
  * // Or send directly
@@ -1129,6 +1140,8 @@ declare function createAsciiEventTopic(contractName: string, eventLabel: string)
1129
1140
  declare class ContractEventParser<S extends InkStorageDescriptor = InkStorageDescriptor, M$1 extends InkCallableDescriptor = InkCallableDescriptor, C extends InkCallableDescriptor = InkCallableDescriptor, E extends Event = Event> {
1130
1141
  private eventDecoders;
1131
1142
  private eventSignatures;
1143
+ /** Maps ink! variant index (first byte of event data) to event label */
1144
+ private eventVariantMap;
1132
1145
  private contractAddressBytes;
1133
1146
  private contractAddress;
1134
1147
  private metadata;
package/dist/index.mjs CHANGED
@@ -6,7 +6,7 @@ import { ss58Decode } from "@polkadot-labs/hdkd-helpers";
6
6
  import { HexSink, Src } from "@subsquid/scale-codec";
7
7
  import { AccountId, Bytes as Bytes$1, Option, Struct, Tuple, Variant, Vector, _void, bool, i128, i16, i32, i64, i8, str, u128, u16, u32, u64, u8 } from "@polkadot-api/substrate-bindings";
8
8
  import { blake2b } from "@noble/hashes/blake2.js";
9
- import { AbortedError, AbortedError as AbortedError$1, ContractError, ContractError as ContractError$1, ContractExecutionError, D9_SS58_PREFIX, DecodeError, DecodeError as DecodeError$1, EncodeError, LangError, LangError as LangError$1, MetadataError, MetadataError as MetadataError$1, NetworkError, SignerError, TimeoutError, TimeoutError as TimeoutError$1, TransactionError, TransactionError as TransactionError$1, isContractError, isErrorType, toD9Address } from "@d9-network/spec";
9
+ import { AbortedError, AbortedError as AbortedError$1, ContractError, ContractError as ContractError$1, ContractExecutionError, ContractExecutionError as ContractExecutionError$1, D9_SS58_PREFIX, DecodeError, DecodeError as DecodeError$1, EncodeError, LangError, LangError as LangError$1, MetadataError, MetadataError as MetadataError$1, NetworkError, SignerError, TimeoutError, TimeoutError as TimeoutError$1, TransactionError, TransactionError as TransactionError$1, isContractError, isErrorType, toD9Address } from "@d9-network/spec";
10
10
  import { catchError, filter, from, map, mergeMap, of, share } from "rxjs";
11
11
 
12
12
  //#region src/encode.ts
@@ -496,6 +496,8 @@ function createAsciiEventTopic(contractName, eventLabel) {
496
496
  var ContractEventParser = class {
497
497
  eventDecoders;
498
498
  eventSignatures;
499
+ /** Maps ink! variant index (first byte of event data) to event label */
500
+ eventVariantMap;
499
501
  contractAddressBytes;
500
502
  contractAddress;
501
503
  metadata;
@@ -506,10 +508,13 @@ var ContractEventParser = class {
506
508
  this.eventDecoders = buildAllEventDecoders(this.metadata);
507
509
  this.contractAddressBytes = ss58Decode(contractAddress)[0];
508
510
  this.eventSignatures = /* @__PURE__ */ new Map();
511
+ this.eventVariantMap = /* @__PURE__ */ new Map();
509
512
  const events = this.metadata.spec.events;
510
- for (const event of events) {
513
+ for (let i = 0; i < events.length; i++) {
514
+ const event = events[i];
511
515
  const sig = getEventSignature(event.label);
512
516
  this.eventSignatures.set(event.label, sig);
517
+ this.eventVariantMap.set(i, event.label);
513
518
  }
514
519
  }
515
520
  /**
@@ -541,6 +546,11 @@ var ContractEventParser = class {
541
546
  break;
542
547
  }
543
548
  }
549
+ if (!eventLabel && data.length > 0) {
550
+ const variantIndex = data[0];
551
+ const candidateLabel = this.eventVariantMap.get(variantIndex);
552
+ if (candidateLabel && this.eventDecoders.has(candidateLabel)) eventLabel = candidateLabel;
553
+ }
544
554
  if (!eventLabel) {
545
555
  console.warn("Unknown event signature:", signature);
546
556
  return null;
@@ -983,6 +993,88 @@ function createTypedRpc(client) {
983
993
  } });
984
994
  }
985
995
 
996
+ //#endregion
997
+ //#region src/result-normalization.ts
998
+ function getTypeEntry(types, typeId) {
999
+ const entry = types.find((item) => item.id === typeId);
1000
+ if (!entry) throw new Error(`Type ${typeId} not found in metadata`);
1001
+ return entry;
1002
+ }
1003
+ function getResultTypeIds(typeEntry) {
1004
+ const path = typeEntry.type.path;
1005
+ if (!path || path[0] !== "Result") return null;
1006
+ const params = typeEntry.type.params;
1007
+ if (!params || params.length < 2) return null;
1008
+ const okTypeId = params[0]?.type;
1009
+ const errTypeId = params[1]?.type;
1010
+ if (okTypeId === void 0 || errTypeId === void 0) return null;
1011
+ return {
1012
+ okTypeId,
1013
+ errTypeId
1014
+ };
1015
+ }
1016
+ function hasOkErrVariants(typeEntry) {
1017
+ const variants = typeEntry.type.def.variant?.variants;
1018
+ if (!variants) return false;
1019
+ const names = new Set(variants.map((variant) => variant.name));
1020
+ return names.has("Ok") && names.has("Err");
1021
+ }
1022
+ function isRecord(value) {
1023
+ return typeof value === "object" && value !== null;
1024
+ }
1025
+ function isRuntimeResult(value) {
1026
+ if (!isRecord(value)) return false;
1027
+ if ("success" in value) return typeof value.success === "boolean" && "value" in value;
1028
+ if ("type" in value) return (value.type === "Ok" || value.type === "Err") && "value" in value;
1029
+ return false;
1030
+ }
1031
+ function isRuntimeResultSuccess(value) {
1032
+ if ("success" in value) return value.success;
1033
+ return value.type === "Ok";
1034
+ }
1035
+ function analyzeMessageReturn(metadata, messageLabel) {
1036
+ const types = metadata.types;
1037
+ const message = metadata.spec.messages.find((item) => item.label === messageLabel);
1038
+ if (!message) throw new Error(`Message "${messageLabel}" not found in metadata`);
1039
+ let currentTypeId = getResultTypeIds(getTypeEntry(types, message.returnType.type))?.okTypeId ?? message.returnType.type;
1040
+ let businessResultDepth = 0;
1041
+ while (true) {
1042
+ const currentType = getTypeEntry(types, currentTypeId);
1043
+ const resultTypeIds = getResultTypeIds(currentType);
1044
+ if (!resultTypeIds || !hasOkErrVariants(currentType)) break;
1045
+ businessResultDepth += 1;
1046
+ currentTypeId = resultTypeIds.okTypeId;
1047
+ }
1048
+ return {
1049
+ businessResultDepth,
1050
+ finalTypeId: currentTypeId
1051
+ };
1052
+ }
1053
+ function buildMessageReturnAnalysisMap(metadata) {
1054
+ const analysisMap = /* @__PURE__ */ new Map();
1055
+ const messages = metadata.spec.messages;
1056
+ for (const message of messages) analysisMap.set(message.label, analyzeMessageReturn(metadata, message.label));
1057
+ return analysisMap;
1058
+ }
1059
+ function normalizeDecodedResponse(value, businessResultDepth) {
1060
+ let current = value;
1061
+ for (let index = 0; index < businessResultDepth; index += 1) {
1062
+ if (!isRuntimeResult(current)) return {
1063
+ success: false,
1064
+ error: /* @__PURE__ */ new Error(`Expected Result payload at depth ${index + 1}, received ${typeof current}`)
1065
+ };
1066
+ if (!isRuntimeResultSuccess(current)) return {
1067
+ success: false,
1068
+ error: current.value
1069
+ };
1070
+ current = current.value;
1071
+ }
1072
+ return {
1073
+ success: true,
1074
+ value: current
1075
+ };
1076
+ }
1077
+
986
1078
  //#endregion
987
1079
  //#region src/contract.ts
988
1080
  /**
@@ -1094,6 +1186,7 @@ function createD9InkContract(descriptor, address, options) {
1094
1186
  const addressBytes = ss58ToBytes(address);
1095
1187
  const rpc = createTypedRpc(client);
1096
1188
  const messageCodecCache = /* @__PURE__ */ new Map();
1189
+ const messageReturnAnalysis = buildMessageReturnAnalysisMap(patchedMetadata);
1097
1190
  function getMessageCodec(label) {
1098
1191
  const cached = messageCodecCache.get(label);
1099
1192
  if (cached) return cached;
@@ -1166,9 +1259,14 @@ function createD9InkContract(descriptor, address, options) {
1166
1259
  };
1167
1260
  decodedResponse = fallbackResult.value;
1168
1261
  }
1262
+ const normalizedResponse = normalizeDecodedResponse(decodedResponse, messageReturnAnalysis.get(method)?.businessResultDepth ?? 0);
1263
+ if (!normalizedResponse.success) return {
1264
+ success: false,
1265
+ error: normalizedResponse.error instanceof Error ? new DecodeError$1(method, normalizedResponse.error.message, normalizedResponse.error) : new ContractExecutionError$1(method, normalizedResponse.error)
1266
+ };
1169
1267
  return {
1170
1268
  success: true,
1171
- value: decodedResponse,
1269
+ value: normalizedResponse.value,
1172
1270
  events: [],
1173
1271
  gasConsumed: callResult.gas.gasConsumed,
1174
1272
  gasRequired: callResult.gas.gasRequired,
@@ -1354,10 +1452,10 @@ function createD9InkContract(descriptor, address, options) {
1354
1452
  * });
1355
1453
  *
1356
1454
  * if (result.success) {
1357
- * console.log("Balance:", result.value.response);
1455
+ * console.log("Balance:", result.value);
1358
1456
  *
1359
1457
  * // Send transaction from the query result
1360
- * const txResult = await result.value.send().signAndSubmit(aliceSigner);
1458
+ * const txResult = await result.send().signAndSubmit(aliceSigner);
1361
1459
  * }
1362
1460
  *
1363
1461
  * // Or send directly