@parity/product-sdk-contracts 0.2.2 → 0.5.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.js CHANGED
@@ -1,8 +1,11 @@
1
- export { generateContractTypes } from './chunk-E7AP65D4.js';
2
- import { submitAndWatch } from '@parity/product-sdk-tx';
1
+ import { encodeFunctionData, decodeFunctionResult } from 'viem';
2
+ import { ensureAccountMapped, submitAndWatch } from '@parity/product-sdk-tx';
3
3
  import { seedToAccount } from '@parity/product-sdk-keys';
4
4
  import { createLogger } from '@parity/product-sdk-logger';
5
5
  import { DEV_PHRASE, ss58Address } from '@polkadot-labs/hdkd-helpers';
6
+ import { ss58ToH160 } from '@parity/product-sdk-address';
7
+
8
+ // src/wrap.ts
6
9
 
7
10
  // src/errors.ts
8
11
  var ContractError = class extends Error {
@@ -29,6 +32,18 @@ var ContractNotFoundError = class extends ContractError {
29
32
  this.targetHash = targetHash;
30
33
  }
31
34
  };
35
+ var ContractDryRunFailedError = class extends ContractError {
36
+ methodName;
37
+ dispatchError;
38
+ constructor(methodName, dispatchError) {
39
+ super(
40
+ `Dry-run failed for "${methodName}": ${typeof dispatchError === "string" ? dispatchError : JSON.stringify(dispatchError)}. The transaction was not submitted.`
41
+ );
42
+ this.name = "ContractDryRunFailedError";
43
+ this.methodName = methodName;
44
+ this.dispatchError = dispatchError;
45
+ }
46
+ };
32
47
 
33
48
  // src/wrap.ts
34
49
  var log = createLogger("contracts");
@@ -41,13 +56,6 @@ function buildMethodArgMap(abi) {
41
56
  }
42
57
  return map;
43
58
  }
44
- function positionalToNamed(argNames, values) {
45
- const data = {};
46
- for (let i = 0; i < argNames.length; i++) {
47
- data[argNames[i]] = values[i];
48
- }
49
- return data;
50
- }
51
59
  function extractOverrides(argNames, args) {
52
60
  if (args.length > argNames.length && args.length > 0) {
53
61
  const last = args[args.length - 1];
@@ -72,8 +80,81 @@ function resolveOrigin(defaults, override, forQuery) {
72
80
  function resolveSigner(defaults, override) {
73
81
  return override ?? defaults.signerManager?.getSigner() ?? defaults.signer;
74
82
  }
75
- function wrapContract(inkContract, abi, defaults) {
83
+ function normalizeContractAddress(address) {
84
+ const hex = address.startsWith("0x") ? address.slice(2) : address;
85
+ if (hex.length !== 40) {
86
+ throw new Error(`Expected 20-byte H160 contract address, got ${hex.length / 2} bytes`);
87
+ }
88
+ return `0x${hex.toLowerCase()}`;
89
+ }
90
+ function hexToBytes(hex) {
91
+ const stripped = hex.slice(2);
92
+ const out = new Uint8Array(stripped.length / 2);
93
+ for (let i = 0; i < out.length; i++) {
94
+ out[i] = Number.parseInt(stripped.slice(i * 2, i * 2 + 2), 16);
95
+ }
96
+ return out;
97
+ }
98
+ function encodeCalldata(abi, methodName, args) {
99
+ return encodeFunctionData({
100
+ abi,
101
+ functionName: methodName,
102
+ args
103
+ });
104
+ }
105
+ function decodeReturn(abi, methodName, returnData) {
106
+ if (returnData.byteLength === 0) return void 0;
107
+ let hex = "0x";
108
+ for (let i = 0; i < returnData.byteLength; i++) {
109
+ hex += returnData[i].toString(16).padStart(2, "0");
110
+ }
111
+ const decoded = decodeFunctionResult({
112
+ abi,
113
+ functionName: methodName,
114
+ data: hex
115
+ });
116
+ const entry = abi.find((e) => e.type === "function" && e.name === methodName);
117
+ const outputs = entry?.outputs ?? [];
118
+ if (outputs.length <= 1 || !Array.isArray(decoded)) return decoded;
119
+ const obj = {};
120
+ for (let i = 0; i < outputs.length; i++) {
121
+ obj[outputs[i].name || `_${i}`] = decoded[i];
122
+ }
123
+ return obj;
124
+ }
125
+ async function buildReviveCall(runtime, dest, abi, methodName, positionalArgs, origin, overrides) {
126
+ const value = overrides?.value ?? 0n;
127
+ const calldata = hexToBytes(encodeCalldata(abi, methodName, positionalArgs));
128
+ let weightLimit = overrides?.gasLimit;
129
+ let storageDepositLimit = overrides?.storageDepositLimit;
130
+ if (weightLimit === void 0 || storageDepositLimit === void 0) {
131
+ const dryRun = await runtime.dryRunCall(
132
+ origin,
133
+ dest,
134
+ value,
135
+ void 0,
136
+ void 0,
137
+ calldata
138
+ );
139
+ if (!dryRun.result.success) {
140
+ throw new ContractDryRunFailedError(methodName, dryRun.result.value);
141
+ }
142
+ weightLimit = weightLimit ?? dryRun.weight_required;
143
+ if (storageDepositLimit === void 0) {
144
+ storageDepositLimit = dryRun.storage_deposit.type === "Charge" ? dryRun.storage_deposit.value : 0n;
145
+ }
146
+ }
147
+ return runtime.api.tx.Revive.call({
148
+ dest,
149
+ value,
150
+ weight_limit: weightLimit,
151
+ storage_deposit_limit: storageDepositLimit,
152
+ data: calldata
153
+ });
154
+ }
155
+ function wrapContract(runtime, address, abi, defaults) {
76
156
  const methodArgs = buildMethodArgMap(abi);
157
+ const dest = normalizeContractAddress(address);
77
158
  return new Proxy({}, {
78
159
  get(_, methodName) {
79
160
  if (typeof methodName !== "string") return void 0;
@@ -85,17 +166,29 @@ function wrapContract(inkContract, abi, defaults) {
85
166
  argNames,
86
167
  args
87
168
  );
88
- const data = positionalToNamed(argNames, positionalArgs);
89
169
  const origin = resolveOrigin(defaults, overrides?.origin, true);
90
- const result = await inkContract.query(methodName, {
170
+ const value = overrides?.value ?? 0n;
171
+ const calldata = hexToBytes(encodeCalldata(abi, methodName, positionalArgs));
172
+ const dryRun = await runtime.dryRunCall(
91
173
  origin,
92
- data,
93
- ...overrides?.value !== void 0 && { value: overrides.value }
94
- });
174
+ dest,
175
+ value,
176
+ void 0,
177
+ void 0,
178
+ calldata
179
+ );
180
+ if (!dryRun.result.success) {
181
+ return {
182
+ success: false,
183
+ value: dryRun.result.value,
184
+ gasRequired: dryRun.weight_required
185
+ };
186
+ }
187
+ const decoded = decodeReturn(abi, methodName, dryRun.result.value.data);
95
188
  return {
96
- success: result.success,
97
- value: result.success ? result.value.response : void 0,
98
- gasRequired: result.value?.gasRequired
189
+ success: true,
190
+ value: decoded,
191
+ gasRequired: dryRun.weight_required
99
192
  };
100
193
  },
101
194
  tx: async (...args) => {
@@ -103,59 +196,82 @@ function wrapContract(inkContract, abi, defaults) {
103
196
  argNames,
104
197
  args
105
198
  );
106
- const data = positionalToNamed(argNames, positionalArgs);
107
199
  const signer = resolveSigner(defaults, overrides?.signer);
108
200
  if (!signer) {
109
201
  throw new ContractSignerMissingError();
110
202
  }
111
203
  const origin = resolveOrigin(defaults, overrides?.origin) ?? ss58Address(signer.publicKey);
112
- const inkTx = inkContract.send(methodName, {
113
- data,
204
+ const tx = await buildReviveCall(
205
+ runtime,
206
+ dest,
207
+ abi,
208
+ methodName,
209
+ positionalArgs,
114
210
  origin,
115
- ...overrides?.value !== void 0 && { value: overrides.value },
116
- ...overrides?.gasLimit && { gasLimit: overrides.gasLimit },
117
- ...overrides?.storageDepositLimit !== void 0 && {
118
- storageDepositLimit: overrides.storageDepositLimit
119
- }
120
- });
121
- return submitAndWatch(inkTx, signer, {
211
+ overrides
212
+ );
213
+ return submitAndWatch(tx, signer, {
122
214
  waitFor: overrides?.waitFor,
123
215
  timeoutMs: overrides?.timeoutMs,
124
216
  mortalityPeriod: overrides?.mortalityPeriod,
125
217
  onStatus: overrides?.onStatus
126
218
  });
127
219
  },
128
- prepare: (...args) => {
220
+ prepare: async (...args) => {
129
221
  const { positionalArgs, overrides } = extractOverrides(
130
222
  argNames,
131
223
  args
132
224
  );
133
- const data = positionalToNamed(argNames, positionalArgs);
134
225
  const origin = resolveOrigin(defaults, overrides?.origin, true);
135
- return inkContract.send(methodName, {
136
- data,
226
+ return buildReviveCall(
227
+ runtime,
228
+ dest,
229
+ abi,
230
+ methodName,
231
+ positionalArgs,
137
232
  origin,
138
- ...overrides?.value !== void 0 && { value: overrides.value },
139
- ...overrides?.gasLimit && { gasLimit: overrides.gasLimit },
140
- ...overrides?.storageDepositLimit !== void 0 && {
141
- storageDepositLimit: overrides.storageDepositLimit
142
- }
143
- });
233
+ overrides
234
+ );
144
235
  }
145
236
  };
146
237
  }
147
238
  });
148
239
  }
240
+ function createContractRuntime(api) {
241
+ return {
242
+ api,
243
+ dryRunCall: (origin, dest, value, gas, deposit, data) => api.apis.ReviveApi.call(origin, dest, value, gas, deposit, data)
244
+ };
245
+ }
246
+ function createContractRuntimeFromClient(client, descriptor) {
247
+ const typed = client.getTypedApi(
248
+ descriptor
249
+ );
250
+ const unsafe = client.getUnsafeApi();
251
+ return {
252
+ api: typed,
253
+ dryRunCall: (origin, dest, value, gas, deposit, data) => unsafe.apis.ReviveApi.call(origin, dest, value, gas, deposit, data)
254
+ };
255
+ }
256
+ async function ensureContractAccountMapped(runtime, address, signer, options) {
257
+ const checker = {
258
+ addressIsMapped: async (addr) => {
259
+ const h160 = ss58ToH160(addr);
260
+ return await runtime.api.query.Revive.OriginalAccount.getValue(h160) !== void 0;
261
+ }
262
+ };
263
+ return ensureAccountMapped(address, signer, checker, runtime.api, options);
264
+ }
149
265
 
150
266
  // src/manager.ts
151
267
  var ContractManager = class _ContractManager {
152
268
  cdmJson;
153
269
  targetHash;
154
- inkSdk;
270
+ runtime;
155
271
  defaults;
156
- constructor(cdmJson, inkSdk, options) {
272
+ constructor(cdmJson, runtime, options) {
157
273
  this.cdmJson = cdmJson;
158
- this.inkSdk = inkSdk;
274
+ this.runtime = runtime;
159
275
  if (options?.targetHash) {
160
276
  this.targetHash = options.targetHash;
161
277
  } else {
@@ -177,38 +293,24 @@ var ContractManager = class _ContractManager {
177
293
  if (defaults.signer !== void 0) this.defaults.signer = defaults.signer;
178
294
  }
179
295
  /**
180
- * Create a ContractManager from a raw `PolkadotClient`.
296
+ * Create a `ContractManager` from a raw `PolkadotClient`.
181
297
  *
182
- * Convenience factory that creates the InkSdk internally via dynamic import
183
- * of `@polkadot-api/sdk-ink`. The ~4 MB sdk-ink metadata is loaded lazily
184
- * only when this method is called.
185
- *
186
- * For size-sensitive apps, prefer the constructor with a pre-created `InkSdk`
187
- * to control exactly when `@polkadot-api/sdk-ink` is loaded.
298
+ * Convenience factory: builds a `ContractRuntime` internally from the
299
+ * client's typed API. Requires that the chain's typed API exposes the
300
+ * `Revive` pallet and `ReviveApi` runtime API (Asset Hub Paseo /
301
+ * Polkadot / Kusama).
188
302
  *
189
303
  * @param cdmJson - The CDM manifest.
190
- * @param client - A `PolkadotClient` for the chain where contracts are deployed (e.g., `client.raw.assetHub`).
304
+ * @param client - A `PolkadotClient` for the chain where contracts are deployed.
305
+ * @param descriptor - The chain descriptor used to derive the typed API.
191
306
  * @param options - Optional configuration (signerManager, defaults).
192
- *
193
- * @example
194
- * ```ts
195
- * import { createChainClient } from "@parity/product-sdk-chain-client";
196
- * import { paseo_asset_hub } from "@parity/product-sdk-descriptors/paseo-asset-hub";
197
- * import { ContractManager } from "@parity/product-sdk-contracts";
198
- *
199
- * const client = await createChainClient({
200
- * chains: { assetHub: paseo_asset_hub },
201
- * rpcs: { assetHub: ["wss://sys.ibp.network/asset-hub-paseo"] },
202
- * });
203
- * const manager = await ContractManager.fromClient(cdmJson, client.raw.assetHub, {
204
- * signerManager,
205
- * });
206
- * ```
207
307
  */
208
- static async fromClient(cdmJson, client, options) {
209
- const { createInkSdk } = await import('@polkadot-api/sdk-ink');
210
- const inkSdk = createInkSdk(client, { atBest: true });
211
- return new _ContractManager(cdmJson, inkSdk, options);
308
+ static fromClient(cdmJson, client, descriptor, options) {
309
+ return new _ContractManager(
310
+ cdmJson,
311
+ createContractRuntimeFromClient(client, descriptor),
312
+ options
313
+ );
212
314
  }
213
315
  getContractData(library) {
214
316
  const contractsForTarget = this.cdmJson.contracts?.[this.targetHash];
@@ -219,30 +321,41 @@ var ContractManager = class _ContractManager {
219
321
  }
220
322
  getContract(library) {
221
323
  const data = this.getContractData(library);
222
- const descriptor = { abi: data.abi };
223
- const inkContract = this.inkSdk.getContract(descriptor, data.address);
224
- return wrapContract(inkContract, data.abi, this.defaults);
324
+ return wrapContract(this.runtime, data.address, data.abi, this.defaults);
225
325
  }
226
326
  /** Get the on-chain address of an installed contract. */
227
327
  getAddress(library) {
228
328
  return this.getContractData(library).address;
229
329
  }
330
+ /**
331
+ * Get the underlying {@link ContractRuntime} backing this manager.
332
+ *
333
+ * Useful when a consumer needs to call helpers that take a runtime
334
+ * directly — most commonly {@link ensureContractAccountMapped} at app
335
+ * boot. Avoids the alternative of building a second runtime against the
336
+ * same client and descriptor.
337
+ */
338
+ getRuntime() {
339
+ return this.runtime;
340
+ }
230
341
  };
231
- function createContract(inkSdk, address, abi, options) {
232
- const inkContract = inkSdk.getContract({ abi }, address);
342
+ function createContract(runtime, address, abi, options) {
233
343
  const defaults = {
234
344
  signerManager: options?.signerManager,
235
345
  origin: options?.defaultOrigin,
236
346
  signer: options?.defaultSigner
237
347
  };
238
- return wrapContract(inkContract, abi, defaults);
348
+ return wrapContract(runtime, address, abi, defaults);
239
349
  }
240
- async function createContractFromClient(client, address, abi, options) {
241
- const { createInkSdk } = await import('@polkadot-api/sdk-ink');
242
- const inkSdk = createInkSdk(client, { atBest: true });
243
- return createContract(inkSdk, address, abi, options);
350
+ function createContractFromClient(client, descriptor, address, abi, options) {
351
+ return createContract(
352
+ createContractRuntimeFromClient(client, descriptor),
353
+ address,
354
+ abi,
355
+ options
356
+ );
244
357
  }
245
358
 
246
- export { ContractError, ContractManager, ContractNotFoundError, ContractSignerMissingError, createContract, createContractFromClient };
359
+ export { ContractDryRunFailedError, ContractError, ContractManager, ContractNotFoundError, ContractSignerMissingError, createContract, createContractFromClient, createContractRuntime, createContractRuntimeFromClient, ensureContractAccountMapped };
247
360
  //# sourceMappingURL=index.js.map
248
361
  //# sourceMappingURL=index.js.map