@talismn/sapi 0.0.0-pr1876-20250414012202

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.
Files changed (30) hide show
  1. package/LICENSE +674 -0
  2. package/README.md +1 -0
  3. package/dist/declarations/src/helpers/errors.d.ts +2 -0
  4. package/dist/declarations/src/helpers/getCallDocs.d.ts +2 -0
  5. package/dist/declarations/src/helpers/getChainInfo.d.ts +7 -0
  6. package/dist/declarations/src/helpers/getConstantValue.d.ts +2 -0
  7. package/dist/declarations/src/helpers/getDecodedCall.d.ts +11 -0
  8. package/dist/declarations/src/helpers/getDryRunCall.d.ts +11 -0
  9. package/dist/declarations/src/helpers/getExtrinsicDispatchInfo.d.ts +7 -0
  10. package/dist/declarations/src/helpers/getFeeEstimate.d.ts +3 -0
  11. package/dist/declarations/src/helpers/getPayloadWithMetadataHash.d.ts +6 -0
  12. package/dist/declarations/src/helpers/getRuntimeCallResult.d.ts +2 -0
  13. package/dist/declarations/src/helpers/getSapiConnector.d.ts +3 -0
  14. package/dist/declarations/src/helpers/getSendRequestResult.d.ts +2 -0
  15. package/dist/declarations/src/helpers/getSignerPayloadJSON.d.ts +7 -0
  16. package/dist/declarations/src/helpers/getStorageValue.d.ts +2 -0
  17. package/dist/declarations/src/helpers/getTypeRegistry.d.ts +4 -0
  18. package/dist/declarations/src/helpers/isApiAvailable.d.ts +2 -0
  19. package/dist/declarations/src/helpers/papi.d.ts +5 -0
  20. package/dist/declarations/src/helpers/types.d.ts +26 -0
  21. package/dist/declarations/src/index.d.ts +2 -0
  22. package/dist/declarations/src/log.d.ts +2 -0
  23. package/dist/declarations/src/sapi.d.ts +50 -0
  24. package/dist/declarations/src/types.d.ts +18 -0
  25. package/dist/talismn-sapi.cjs.d.ts +1 -0
  26. package/dist/talismn-sapi.cjs.dev.js +535 -0
  27. package/dist/talismn-sapi.cjs.js +7 -0
  28. package/dist/talismn-sapi.cjs.prod.js +535 -0
  29. package/dist/talismn-sapi.esm.js +529 -0
  30. package/package.json +55 -0
@@ -0,0 +1,529 @@
1
+ import { assert, u8aConcatStrict } from '@polkadot/util';
2
+ import { decodeMetadata, getLookupFn as getLookupFn$1, getDynamicBuilder } from '@talismn/scale';
3
+ import anylogger from 'anylogger';
4
+ import { Enum, Binary } from 'polkadot-api';
5
+ import { getLookupFn } from '@polkadot-api/metadata-builders';
6
+ import { toHex, mergeUint8 } from '@polkadot-api/utils';
7
+ import { TypeRegistry, Metadata } from '@polkadot/types';
8
+ import { merkleizeMetadata } from '@polkadot-api/merkleize-metadata';
9
+ import { enhanceEncoder, Bytes, u16 } from '@polkadot-api/substrate-bindings';
10
+
11
+ var packageJson = {
12
+ name: "@talismn/sapi"};
13
+
14
+ var log = anylogger(packageJson.name);
15
+
16
+ const getCallDocs = (chain, pallet, method) => {
17
+ try {
18
+ const typeIdCalls = chain.metadata.pallets.find(({
19
+ name
20
+ }) => name === pallet)?.calls;
21
+ if (!typeIdCalls) return null;
22
+
23
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
24
+ let palletCalls = chain.metadata.lookup[typeIdCalls];
25
+ if (!palletCalls || palletCalls.id !== typeIdCalls) palletCalls = chain.metadata.lookup.find(v => v.id === typeIdCalls);
26
+ if (!palletCalls) return null;
27
+ const call = palletCalls.def.value.find(c => c.name === method);
28
+ return call?.docs?.join("\n") ?? null;
29
+ } catch (err) {
30
+ log.error("Failed to find call docs", {
31
+ pallet,
32
+ method,
33
+ chain
34
+ });
35
+ return null;
36
+ }
37
+ };
38
+
39
+ const getConstantValue = (chain, pallet, constant) => {
40
+ try {
41
+ const storageCodec = chain.builder.buildConstant(pallet, constant);
42
+ const encodedValue = chain.metadata.pallets.find(({
43
+ name
44
+ }) => name === pallet)?.constants.find(({
45
+ name
46
+ }) => name === constant)?.value;
47
+ if (!encodedValue) throw new Error(`Constant ${pallet}.${constant} not found`);
48
+ return storageCodec.dec(encodedValue);
49
+ } catch (err) {
50
+ log.error("Failed to get constant value", {
51
+ err,
52
+ chainId: chain.connector.chainId,
53
+ pallet,
54
+ constant
55
+ });
56
+ throw err;
57
+ }
58
+ };
59
+
60
+ const getChainInfo = chain => {
61
+ const {
62
+ spec_name: specName,
63
+ spec_version: specVersion,
64
+ transaction_version: transactionVersion
65
+ } = getConstantValue(chain, "System", "Version");
66
+ const base58Prefix = getConstantValue(chain, "System", "SS58Prefix");
67
+ return {
68
+ specName,
69
+ specVersion,
70
+ transactionVersion,
71
+ base58Prefix
72
+ };
73
+ };
74
+
75
+ const getDecodedCall = (palletName, methodName, args) => ({
76
+ type: palletName,
77
+ value: {
78
+ type: methodName,
79
+ value: args
80
+ }
81
+ });
82
+ const getDecodedCallFromPayload = (chain, payload) => {
83
+ const def = chain.builder.buildDefinition(chain.lookup.call);
84
+ const decoded = def.dec(payload.method);
85
+ return {
86
+ pallet: decoded.type,
87
+ method: decoded.value.type,
88
+ args: decoded.value.value
89
+ };
90
+ };
91
+
92
+ const getDispatchErrorMessage = (chain, err) => {
93
+ try {
94
+ if (!err) return null;
95
+ const error = err;
96
+ if (!error.type) throw new Error("Unknown dispatch error");
97
+ const lv1 = DISPATCH_ERROR[error.type];
98
+ if (!lv1) throw new Error("Unknown dispatch error");
99
+ if (lv1 === ERROR_METADATA_LOOKUP) return getModuleErrorMessage(chain, error.value);
100
+ if (typeof lv1 === "string") return lv1;
101
+ const lv2 = lv1[error.value?.type];
102
+ if (!lv2) throw new Error("Unknown dispatch error");
103
+ if (typeof lv2 === "string") return lv2;
104
+ throw new Error("Unknown dispatch error");
105
+ } catch (cause) {
106
+ log.error("Failed to parse runtime error", {
107
+ chainId: chain.connector.chainId,
108
+ cause,
109
+ err
110
+ });
111
+ return tryFormatError(err);
112
+ }
113
+ };
114
+ const ERROR_METADATA_LOOKUP = "METADATA_LOOKUP";
115
+
116
+ // only `Module` errors are part of the metadata
117
+ // errors below are defined as part of the runtime but their docs aren't included in the metadata
118
+ // so those are copy/pasted from the polkadot-sdk repo
119
+
120
+ // https://github.com/paritytech/polkadot-sdk/blob/56d97c3ad8c86e602bc7ac368751210517c4309f/substrate/primitives/runtime/src/lib.rs#L543
121
+ const ERRORS_TRANSACTIONAL = {
122
+ LimitReached: "Too many transactional layers have been spawned",
123
+ NoLayer: "A transactional layer was expected, but does not exist"
124
+ };
125
+
126
+ // https://github.com/paritytech/polkadot-sdk/blob/56d97c3ad8c86e602bc7ac368751210517c4309f/substrate/primitives/runtime/src/lib.rs#L672
127
+ const ERRORS_TOKEN = {
128
+ FundsUnavailable: "Funds are unavailable",
129
+ OnlyProvider: "Account that must exist would die",
130
+ BelowMinimum: "Account cannot exist with the funds that would be given",
131
+ CannotCreate: "Account cannot be created",
132
+ UnknownAsset: "The asset in question is unknown",
133
+ Frozen: "Funds exist but are frozen",
134
+ Unsupported: "Operation is not supported by the asset",
135
+ CannotCreateHold: "Account cannot be created for recording amount on hold",
136
+ NotExpendable: "Account that is desired to remain would die",
137
+ Blocked: "Account cannot receive the assets"
138
+ };
139
+
140
+ // https://github.com/paritytech/polkadot-sdk/blob/56d97c3ad8c86e602bc7ac368751210517c4309f/substrate/primitives/arithmetic/src/lib.rs#L76
141
+ const ERRORS_ARITHMETIC = {
142
+ Overflow: "An underflow would occur",
143
+ Underflow: "An overflow would occur",
144
+ DivisionByZero: "Division by zero"
145
+ };
146
+
147
+ // https://github.com/paritytech/polkadot-sdk/blob/56d97c3ad8c86e602bc7ac368751210517c4309f/substrate/primitives/runtime/src/lib.rs#L714
148
+ const DISPATCH_ERROR = {
149
+ CannotLookup: "Cannot lookup",
150
+ BadOrigin: "Bad origin",
151
+ Module: ERROR_METADATA_LOOKUP,
152
+ ConsumerRemaining: "Consumer remaining",
153
+ NoProviders: "No providers",
154
+ TooManyConsumers: "Too many consumers",
155
+ Token: ERRORS_TOKEN,
156
+ Arithmetic: ERRORS_ARITHMETIC,
157
+ Transactional: ERRORS_TRANSACTIONAL,
158
+ Exhausted: "Resources exhausted",
159
+ Corruption: "State corrupt",
160
+ Unavailable: "Resource unavailable",
161
+ RootNotAllowed: "Root not allowed",
162
+ Trie: "Unknown error",
163
+ // unsupported,
164
+ Other: "Unknown error" // unsupported,
165
+ };
166
+ const getModuleErrorMessage = (chain, error) => {
167
+ try {
168
+ if (!chain.metadata) throw new Error("Could not fetch metadata");
169
+ const pallet = chain.metadata.pallets.find(p => p.name === error.type);
170
+ if (typeof pallet?.errors !== "number") throw new Error("Unknown pallet");
171
+ const lookup = getLookupFn(chain.metadata);
172
+ const palletErrors = lookup(pallet.errors);
173
+ if (palletErrors.type !== "enum" || !palletErrors.innerDocs[error.value.type]?.length) throw new Error("Unknown error type");
174
+
175
+ // biome-ignore lint/style/noNonNullAssertion: <explanation>
176
+ return palletErrors.innerDocs[error.value.type].join(" ");
177
+ } catch (err) {
178
+ log.error("Failed to parse module error", {
179
+ chainId: chain.connector.chainId,
180
+ error,
181
+ err
182
+ });
183
+ return [error.type, error.value.type].join(": ");
184
+ }
185
+ };
186
+ const tryFormatError = err => {
187
+ try {
188
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
189
+ const unsafeErr = err;
190
+ if (unsafeErr.type && unsafeErr.value?.type) return [unsafeErr.type, unsafeErr.value.type].join(": ");
191
+ } catch (err) {
192
+ // ignore
193
+ }
194
+ return "Unknown error";
195
+ };
196
+
197
+ const getSendRequestResult = (chain, method, params, isCacheable) => {
198
+ return chain.connector.send(method, params, isCacheable);
199
+ };
200
+
201
+ const getRuntimeCallResult = async (chain, apiName, method, args) => {
202
+ const call = chain.builder.buildRuntimeCall(apiName, method);
203
+ const hex = await getSendRequestResult(chain, "state_call", [`${apiName}_${method}`, toHex(call.args.enc(args))]);
204
+ return call.value.dec(hex);
205
+ };
206
+
207
+ const isApiAvailable = (chain, name, method) => {
208
+ return chain.metadata.apis.some(a => a.name === name && a.methods.some(m => m.name === method));
209
+ };
210
+
211
+ const getDryRunCall = async (chain, from, decodedCall) => {
212
+ log.log(`[sapi] getDryRun begin: ${Date.now()}`);
213
+ try {
214
+ if (!isApiAvailable(chain, "DryRunApi", "dry_run_call")) return {
215
+ available: false,
216
+ data: null
217
+ };
218
+ const origin = Enum("system", Enum("Signed", from));
219
+ const {
220
+ pallet,
221
+ method,
222
+ args
223
+ } = decodedCall;
224
+ const call = {
225
+ type: pallet,
226
+ value: {
227
+ type: method,
228
+ value: args
229
+ }
230
+ };
231
+
232
+ // This will throw an error if the api is not available on that chain
233
+ const data = await getRuntimeCallResult(chain, "DryRunApi", "dry_run_call", [origin, call]);
234
+ const ok = data.success && data.value.execution_result.success;
235
+ const errorMessage = data.success && !data.value.execution_result.success ? getDispatchErrorMessage(chain, data.value.execution_result.value.error) : null;
236
+ return {
237
+ available: true,
238
+ // NOTE: we can't re-export `@polkadot-api/descriptors` from this package.
239
+ // So, the caller of this function must pass in their own instance of `type DryRunResult` as the generic argument `T`.
240
+ data: data,
241
+ ok,
242
+ errorMessage
243
+ };
244
+ } catch (err) {
245
+ // Note : err is null if chain doesnt have the api
246
+ log.error("Failed to dry run", {
247
+ chainId: chain.connector.chainId,
248
+ err
249
+ });
250
+ return {
251
+ available: false,
252
+ data: null
253
+ };
254
+ } finally {
255
+ log.log(`[sapi] getDryRun end: ${Date.now()}`);
256
+ }
257
+ };
258
+
259
+ // used for chains that dont have metadata v15 yet
260
+ const getExtrinsicDispatchInfo = async (chain, signedExtrinsic) => {
261
+ assert(signedExtrinsic.isSigned, "Extrinsic must be signed (or fakeSigned) in order to query fee");
262
+ const len = signedExtrinsic.registry.createType("u32", signedExtrinsic.encodedLength);
263
+ const dispatchInfo = await stateCall(chain.connector.send, "TransactionPaymentApi_query_info", "RuntimeDispatchInfo", [signedExtrinsic, len], undefined, true);
264
+ return {
265
+ partialFee: dispatchInfo.partialFee.toString()
266
+ };
267
+ };
268
+ const stateCall = async (request, method, resultType, args, blockHash, isCacheable) => {
269
+ // on a state call there are always arguments
270
+ const registry = args[0].registry;
271
+ const bytes = registry.createType("Raw", u8aConcatStrict(args.map(arg => arg.toU8a())));
272
+ const result = await request("state_call", [method, bytes.toHex(), blockHash], isCacheable);
273
+ return registry.createType(resultType, result);
274
+ };
275
+
276
+ const getTypeRegistry = (chain, payload) => {
277
+ log.log(`[sapi] getTypeRegistry begin: ${Date.now()}`);
278
+ const registry = new TypeRegistry();
279
+ if (chain.registryTypes) registry.register(chain.registryTypes);
280
+ const meta = new Metadata(registry, chain.hexMetadata);
281
+ registry.setMetadata(meta, payload.signedExtensions, chain.signedExtensions); // ~30ms
282
+
283
+ log.log(`[sapi] getTypeRegistry end: ${Date.now()}`);
284
+ return registry;
285
+ };
286
+
287
+ const getFeeEstimate = async (chain, payload, chainInfo) => {
288
+ // TODO do this without PJS / registry => waiting for @polkadot-api/tx-utils
289
+ const registry = getTypeRegistry(chain, payload);
290
+ const extrinsic = registry.createType("Extrinsic", payload);
291
+ extrinsic.signFake(payload.address, {
292
+ appId: 0,
293
+ nonce: payload.nonce,
294
+ blockHash: payload.blockHash,
295
+ genesisHash: payload.genesisHash,
296
+ runtimeVersion: {
297
+ specVersion: chainInfo.specVersion,
298
+ transactionVersion: chainInfo.transactionVersion
299
+ // other fields aren't necessary for signing
300
+ }
301
+ });
302
+ const bytes = extrinsic.toU8a(true);
303
+ const binary = Binary.fromBytes(bytes);
304
+ try {
305
+ const result = await getRuntimeCallResult(chain, "TransactionPaymentApi", "query_info", [binary, bytes.length]);
306
+ // Do not throw if partialFee is 0n. This is a valid response, eg: Bittensor remove_stake fee estimation is 0n.
307
+ if (!result?.partial_fee && result.partial_fee !== 0n) {
308
+ throw new Error("partialFee is not found");
309
+ }
310
+ return result.partial_fee;
311
+ } catch (err) {
312
+ log.error("Failed to get fee estimate using getRuntimeCallValue", {
313
+ err
314
+ });
315
+ }
316
+
317
+ // fallback to pjs encoded state call, in case the above fails (extracting runtime calls codecs might require metadata V15)
318
+ // Note: PAPI will consider TransactionPaymentApi as first class api so it should work even without V15, but this is not the case yet.
319
+ const {
320
+ partialFee
321
+ } = await getExtrinsicDispatchInfo(chain, extrinsic);
322
+ return BigInt(partialFee);
323
+ };
324
+
325
+ const getSapiConnector = ({
326
+ chainId,
327
+ send,
328
+ submit
329
+ }) => ({
330
+ chainId,
331
+ send,
332
+ submit: (...args) => {
333
+ if (submit) return submit(...args);
334
+ throw new Error("submit handler not provided");
335
+ }
336
+ });
337
+
338
+ const getPayloadWithMetadataHash = (chain, chainInfo, payload) => {
339
+ if (!chain.hasCheckMetadataHash || !payload.signedExtensions.includes("CheckMetadataHash")) return {
340
+ payload,
341
+ txMetadata: undefined
342
+ };
343
+ try {
344
+ const {
345
+ decimals,
346
+ symbol: tokenSymbol
347
+ } = chain.token;
348
+ const {
349
+ base58Prefix,
350
+ specName,
351
+ specVersion
352
+ } = chainInfo;
353
+
354
+ // since ultimately this needs a V15 object, would be nice if this accepted one directly as input
355
+ const merkleizedMetadata = merkleizeMetadata(chain.hexMetadata, {
356
+ tokenSymbol,
357
+ decimals,
358
+ base58Prefix,
359
+ specName,
360
+ specVersion
361
+ });
362
+ const metadataHash = toHex(merkleizedMetadata.digest());
363
+ const payloadWithMetadataHash = {
364
+ ...payload,
365
+ mode: 1,
366
+ metadataHash,
367
+ withSignedTransaction: true
368
+ };
369
+
370
+ // TODO do this without PJS / registry => waiting for @polkadot-api/tx-utils
371
+ // const { extra, additionalSigned } = getSignedExtensionValues(payload, metadata)
372
+ // const badExtPayload = mergeUint8(fromHex(payload.method), ...extra, ...additionalSigned)
373
+
374
+ const registry = getTypeRegistry(chain, payload);
375
+ const extPayload = registry.createType("ExtrinsicPayload", payloadWithMetadataHash);
376
+ const barePayload = extPayload.toU8a(true);
377
+ const txMetadata = merkleizedMetadata.getProofForExtrinsicPayload(barePayload);
378
+ return {
379
+ payload: payloadWithMetadataHash,
380
+ txMetadata
381
+ };
382
+ } catch (err) {
383
+ log.error("Failed to get shortened metadata", {
384
+ error: err
385
+ });
386
+ return {
387
+ payload,
388
+ txMetadata: undefined
389
+ };
390
+ }
391
+ };
392
+
393
+ const getStorageValue = async (chain, pallet, entry, keys, at) => {
394
+ const storageCodec = chain.builder.buildStorage(pallet, entry);
395
+ const stateKey = storageCodec.keys.enc(...keys);
396
+ const hexValue = await getSendRequestResult(chain, "state_getStorage", [stateKey, at]);
397
+ if (!hexValue) return null; // caller will need to expect null when applicable
398
+
399
+ return storageCodec.value.dec(hexValue);
400
+ };
401
+
402
+ //////////////////////////////////////////////////////////////////////////////////////////////////////////////
403
+ //////////////////////////// Utilities from PAPI /////////////////////////////
404
+ //////////////////////////////////////////////////////////////////////////////////////////////////////////////
405
+
406
+ const toPjsHex = (value, minByteLen) => {
407
+ let inner = value.toString(16);
408
+ inner = (inner.length % 2 ? "0" : "") + inner;
409
+ const nPaddedBytes = Math.max(0, (minByteLen || 0) - inner.length / 2);
410
+ return "0x" + "00".repeat(nPaddedBytes) + inner;
411
+ };
412
+ const mortal = enhanceEncoder(Bytes(2).enc, value => {
413
+ const factor = Math.max(value.period >> 12, 1);
414
+ const left = Math.min(Math.max(trailingZeroes(value.period) - 1, 1), 15);
415
+ const right = value.phase / factor << 4;
416
+ return u16.enc(left | right);
417
+ });
418
+ function trailingZeroes(n) {
419
+ let i = 0;
420
+ while (!(n & 1)) {
421
+ i++;
422
+ n >>= 1;
423
+ }
424
+ return i;
425
+ }
426
+
427
+ const getSignerPayloadJSON = async (chain, palletName, methodName, args, signerConfig, chainInfo) => {
428
+ const {
429
+ codec,
430
+ location
431
+ } = chain.builder.buildCall(palletName, methodName);
432
+ const method = Binary.fromBytes(mergeUint8(new Uint8Array(location), codec.enc(args)));
433
+ const blockNumber = await getStorageValue(chain, "System", "Number", []);
434
+ if (blockNumber === null) throw new Error("Block number not found");
435
+ const [account, genesisHash, blockHash] = await Promise.all([
436
+ // TODO if V15 available, use a runtime call instead : AccountNonceApi/account_nonce
437
+ // about nonce https://github.com/paritytech/json-rpc-interface-spec/issues/156
438
+ getStorageValue(chain, "System", "Account", [signerConfig.address]), getStorageValue(chain, "System", "BlockHash", [0]), getSendRequestResult(chain, "chain_getBlockHash", [blockNumber], false) // TODO find the right way to fetch this with new RPC api, this is not available in storage yet
439
+ ]);
440
+ if (!genesisHash) throw new Error("Genesis hash not found");
441
+ if (!blockHash) throw new Error("Block hash not found");
442
+ const nonce = account ? account.nonce : 0;
443
+ const era = mortal({
444
+ period: 16,
445
+ phase: blockNumber % 16
446
+ });
447
+ const signedExtensions = chain.metadata.extrinsic.signedExtensions.map(ext => ext.identifier.toString());
448
+ const basePayload = {
449
+ address: signerConfig.address,
450
+ genesisHash: genesisHash.asHex(),
451
+ blockHash,
452
+ method: method.asHex(),
453
+ signedExtensions,
454
+ nonce: toPjsHex(nonce, 4),
455
+ specVersion: toPjsHex(chainInfo.specVersion, 4),
456
+ transactionVersion: toPjsHex(chainInfo.transactionVersion, 4),
457
+ blockNumber: toPjsHex(blockNumber, 4),
458
+ era: toHex(era),
459
+ tip: toPjsHex(0, 16),
460
+ // TODO gas station (required for Astar)
461
+ assetId: undefined,
462
+ version: 4
463
+ };
464
+ const {
465
+ payload,
466
+ txMetadata
467
+ } = getPayloadWithMetadataHash(chain, chainInfo, basePayload);
468
+
469
+ // Avail support
470
+ if (payload.signedExtensions.includes("CheckAppId")) payload.appId = 0;
471
+ log.log("[sapi] payload", {
472
+ newPayload: payload,
473
+ txMetadata
474
+ });
475
+ return {
476
+ payload,
477
+ txMetadata
478
+ };
479
+ };
480
+
481
+ const getScaleApi = (connector, hexMetadata, token, hasCheckMetadataHash, signedExtensions, registryTypes) => {
482
+ const decoded = decodeMetadata(hexMetadata);
483
+ assert(decoded.metadata, `Missing Metadata V14+ for chain ${connector.chainId}`);
484
+ const {
485
+ metadata
486
+ } = decoded;
487
+ const lookup = getLookupFn$1(metadata);
488
+ const builder = getDynamicBuilder(lookup);
489
+ const chain = {
490
+ connector: getSapiConnector(connector),
491
+ hexMetadata,
492
+ token,
493
+ hasCheckMetadataHash,
494
+ signedExtensions,
495
+ registryTypes,
496
+ metadata,
497
+ lookup,
498
+ builder
499
+ };
500
+ const chainInfo = getChainInfo(chain);
501
+ const {
502
+ specName,
503
+ specVersion,
504
+ base58Prefix
505
+ } = chainInfo;
506
+ return {
507
+ id: `${connector.chainId}::${specName}::${specVersion}`,
508
+ chainId: connector.chainId,
509
+ specName,
510
+ specVersion,
511
+ hasCheckMetadataHash,
512
+ base58Prefix,
513
+ token: chain.token,
514
+ getConstant: (pallet, constant) => getConstantValue(chain, pallet, constant),
515
+ getStorage: (pallet, entry, keys, at) => getStorageValue(chain, pallet, entry, keys, at),
516
+ getDecodedCall: (pallet, method, args) => getDecodedCall(pallet, method, args),
517
+ getDecodedCallFromPayload: payload => getDecodedCallFromPayload(chain, payload),
518
+ getExtrinsicPayload: (pallet, method, args, config) => getSignerPayloadJSON(chain, pallet, method, args, config, chainInfo),
519
+ getFeeEstimate: payload => getFeeEstimate(chain, payload, chainInfo),
520
+ getRuntimeCallValue: (apiName, method, args) => getRuntimeCallResult(chain, apiName, method, args),
521
+ getTypeRegistry: payload => getTypeRegistry(chain, payload),
522
+ submit: (payload, signature) => chain.connector.submit(payload, signature),
523
+ getCallDocs: (pallet, method) => getCallDocs(chain, pallet, method),
524
+ getDryRunCall: (from, decodedCall) => getDryRunCall(chain, from, decodedCall),
525
+ isApiAvailable: (name, method) => isApiAvailable(chain, name, method)
526
+ };
527
+ };
528
+
529
+ export { getScaleApi };
package/package.json ADDED
@@ -0,0 +1,55 @@
1
+ {
2
+ "name": "@talismn/sapi",
3
+ "version": "0.0.0-pr1876-20250414012202",
4
+ "author": "Talisman",
5
+ "homepage": "https://talisman.xyz",
6
+ "license": "GPL-3.0-or-later",
7
+ "publishConfig": {
8
+ "access": "public"
9
+ },
10
+ "repository": {
11
+ "directory": "packages/sapi",
12
+ "type": "git",
13
+ "url": "https://github.com/talismansociety/talisman.git"
14
+ },
15
+ "main": "dist/talismn-sapi.cjs.js",
16
+ "module": "dist/talismn-sapi.esm.js",
17
+ "files": [
18
+ "/dist"
19
+ ],
20
+ "engines": {
21
+ "node": ">=18"
22
+ },
23
+ "dependencies": {
24
+ "@polkadot-api/merkleize-metadata": "1.1.14",
25
+ "@polkadot-api/metadata-builders": "0.10.2",
26
+ "@polkadot-api/substrate-bindings": "0.11.1",
27
+ "@polkadot-api/utils": "0.1.2",
28
+ "@polkadot/types": "15.8.1",
29
+ "@polkadot/types-codec": "15.8.1",
30
+ "@polkadot/util": "13.4.3",
31
+ "anylogger": "^1.0.11",
32
+ "polkadot-api": "1.7.6",
33
+ "@talismn/scale": "0.0.0-pr1876-20250414012202"
34
+ },
35
+ "devDependencies": {
36
+ "@types/jest": "^29.5.14",
37
+ "eslint": "^8.57.1",
38
+ "jest": "^29.7",
39
+ "ts-jest": "^29.2.5",
40
+ "typescript": "^5.6.3",
41
+ "@talismn/eslint-config": "0.0.3",
42
+ "@talismn/tsconfig": "0.0.2"
43
+ },
44
+ "eslintConfig": {
45
+ "root": true,
46
+ "extends": [
47
+ "@talismn/eslint-config/base"
48
+ ]
49
+ },
50
+ "scripts": {
51
+ "test": "jest",
52
+ "lint": "eslint src --max-warnings 0",
53
+ "clean": "rm -rf dist .turbo node_modules"
54
+ }
55
+ }