@defillama/sdk 5.0.235 → 5.0.236

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 (60) hide show
  1. package/build/ChainApi.d.ts +23 -1
  2. package/build/chains/algorand.d.ts +277 -0
  3. package/build/chains/algorand.js +618 -0
  4. package/build/chains/aptos.d.ts +230 -0
  5. package/build/chains/aptos.js +612 -0
  6. package/build/chains/cardano.d.ts +242 -0
  7. package/build/chains/cardano.js +407 -0
  8. package/build/chains/cosmos.d.ts +252 -0
  9. package/build/chains/cosmos.js +618 -0
  10. package/build/chains/icp.d.ts +235 -0
  11. package/build/chains/icp.js +1040 -0
  12. package/build/chains/index.d.ts +23 -0
  13. package/build/chains/index.js +59 -0
  14. package/build/chains/near.d.ts +192 -0
  15. package/build/chains/near.js +446 -0
  16. package/build/chains/rpc.d.ts +125 -0
  17. package/build/chains/rpc.js +326 -0
  18. package/build/chains/starknet.d.ts +205 -0
  19. package/build/chains/starknet.js +884 -0
  20. package/build/chains/stellar.d.ts +410 -0
  21. package/build/chains/stellar.js +1082 -0
  22. package/build/chains/substrate.d.ts +333 -0
  23. package/build/chains/substrate.js +1042 -0
  24. package/build/chains/sui.d.ts +365 -0
  25. package/build/chains/sui.js +1135 -0
  26. package/build/chains/svm.d.ts +340 -0
  27. package/build/chains/svm.js +760 -0
  28. package/build/chains/tezos.d.ts +225 -0
  29. package/build/chains/tezos.js +412 -0
  30. package/build/chains/ton.d.ts +353 -0
  31. package/build/chains/ton.js +788 -0
  32. package/build/chains/tron.d.ts +45 -0
  33. package/build/chains/tron.js +110 -0
  34. package/build/chains/utxo.d.ts +202 -0
  35. package/build/chains/utxo.js +592 -0
  36. package/build/chains/xrpl.d.ts +179 -0
  37. package/build/chains/xrpl.js +467 -0
  38. package/build/index.d.ts +2 -1
  39. package/build/index.js +3 -1
  40. package/build/providers.json +1 -1
  41. package/build/util/chainUtils/data.json +11 -0
  42. package/build/util/chainUtils/index.d.ts +1 -0
  43. package/build/util/chainUtils/index.js +23 -0
  44. package/build/util/common.js +2 -3
  45. package/build/util/cosmos.d.ts +1 -11
  46. package/build/util/cosmos.js +6 -66
  47. package/build/util/env.js +1 -0
  48. package/build/util/indexer.compatibility.d.ts +6 -0
  49. package/build/util/indexer.compatibility.js +64 -0
  50. package/build/util/indexer.d.ts +24 -2
  51. package/build/util/indexer.js +215 -282
  52. package/build/util/indexerSql.d.ts +8 -1
  53. package/build/util/indexerSql.js +53 -22
  54. package/build/util/logs.decode.shared.js +5 -4
  55. package/build/util/transactions.d.ts +23 -1
  56. package/build/util/updateChainLabels.d.ts +1 -0
  57. package/build/util/updateChainLabels.js +5 -0
  58. package/build/util/updateProviderList.js +38 -17
  59. package/package.json +20 -7
  60. package/README.md +0 -41
@@ -0,0 +1,1135 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.sliceIntoChunks = exports.SuiGraphqlError = exports.fromU256 = exports.fromU128 = exports.fromU64 = exports.fromU32 = exports.fromU16 = exports.toU256 = exports.toU128 = exports.toU64 = exports.toU32 = exports.toU16 = exports.uleb128 = exports.EMPTY_STRUCT_BCS = exports.DUMMY_SENDER = exports.DEFAULT_RPC_ENDPOINTS = exports.DEFAULT_GRAPHQL_ENDPOINTS = exports.suiChains = void 0;
4
+ exports.getGraphqlEndpoints = getGraphqlEndpoints;
5
+ exports.getGraphqlEndpoint = getGraphqlEndpoint;
6
+ exports.getRpcEndpoints = getRpcEndpoints;
7
+ exports.getRpcEndpoint = getRpcEndpoint;
8
+ exports.hasGraphql = hasGraphql;
9
+ exports.hexToBytes = hexToBytes;
10
+ exports.bytesToHex = bytesToHex;
11
+ exports.textToBytes = textToBytes;
12
+ exports.bytesToBase64 = bytesToBase64;
13
+ exports.base64ToBytes = base64ToBytes;
14
+ exports.uleb128Encode = uleb128Encode;
15
+ exports.uleb128Decode = uleb128Decode;
16
+ exports.toLittleEndian = toLittleEndian;
17
+ exports.fromLittleEndian = fromLittleEndian;
18
+ exports.normalizeSuiAddress = normalizeSuiAddress;
19
+ exports.normalizeCoinType = normalizeCoinType;
20
+ exports.splitTypeArgs = splitTypeArgs;
21
+ exports.parseStructTag = parseStructTag;
22
+ exports.typeTagToBytes = typeTagToBytes;
23
+ exports.buildProgrammableMoveCallBytes = buildProgrammableMoveCallBytes;
24
+ exports.buildTransactionDataBytes = buildTransactionDataBytes;
25
+ exports.bcsDynamicFieldName = bcsDynamicFieldName;
26
+ exports.shortenTypeAddresses = shortenTypeAddresses;
27
+ exports.formatObject = formatObject;
28
+ exports.toAddr = toAddr;
29
+ exports.toParsedJson = toParsedJson;
30
+ exports.graphqlCall = graphqlCall;
31
+ exports.call = call;
32
+ exports.rpcGetObject = rpcGetObject;
33
+ exports.rpcGetObjects = rpcGetObjects;
34
+ exports.getObject = getObject;
35
+ exports.getObjects = getObjects;
36
+ exports.getObjectsByType = getObjectsByType;
37
+ exports.getOwnedObjects = getOwnedObjects;
38
+ exports.queryEvents = queryEvents;
39
+ exports.getDynamicFieldObject = getDynamicFieldObject;
40
+ exports.getDynamicFieldObjects = getDynamicFieldObjects;
41
+ exports.getCoinMetadata = getCoinMetadata;
42
+ exports.getTokenSupply = getTokenSupply;
43
+ exports.getAllBalances = getAllBalances;
44
+ exports.getBalance = getBalance;
45
+ exports.getCheckpoint = getCheckpoint;
46
+ exports.getLatestCheckpoint = getLatestCheckpoint;
47
+ exports.getCheckpointAtTimestamp = getCheckpointAtTimestamp;
48
+ exports.devInspectTransactionBlock = devInspectTransactionBlock;
49
+ exports.getInitialSharedVersion = getInitialSharedVersion;
50
+ exports.callViewFunction = callViewFunction;
51
+ /**
52
+ * Sui (GraphQL RPC + hand-rolled BCS codec) and IOTA (Sui fork, JSON-RPC) client.
53
+ *
54
+ * Replaces / consolidates:
55
+ * - DefiLlama-Adapters `projects/helper/chain/sui.js` (BCS codec, GraphQL object / event /
56
+ * dynamic-field readers, `devInspectTransactionBlock`, `getInitialSharedVersion`, `getTokenSupply`,
57
+ * `normalizeCoinType`; the TVL-specific `dexExport` / `sumTokens` are intentionally not ported)
58
+ * - DefiLlama-Adapters `projects/helper/chain/iota.js` (IOTA JSON-RPC `call` / `getObject` / `getObjects`)
59
+ * - defillama-server `coins/src/adapters/utils/sui.ts` (`getAllBalances`, `getTokenInfo`, `queryEvents`, `getObjects`)
60
+ * - peggedassets-server `src/adapters/peggedAssets/helper/sui.ts` (`getDynamicFieldObject` with `nameBcs`, `EMPTY_STRUCT_BCS`)
61
+ * - dimension-adapters `helpers/sui.ts` (`graphqlCall` retry, windowed `queryEvents`, `eventModule` filter, `toParsedJson`)
62
+ *
63
+ * Endpoints: `SUI_GRAPH_RPC` (GraphQL, default `https://graphql.mainnet.sui.io/graphql`), `SUI_RPC`
64
+ * (JSON-RPC, default `https://sui-rpc.publicnode.com`) and `IOTA_RPC` (default `https://api.mainnet.iota.cafe`).
65
+ * Chains without a GraphQL endpoint (iota) transparently fall back to JSON-RPC for the reader helpers.
66
+ *
67
+ * Usage: `sdk.chains.sui.getObject({ objectId: '0x6' })`, `sdk.chains.sui.call({ chain: 'iota', method: 'iota_getLatestCheckpointSequenceNumber', params: [] })`
68
+ *
69
+ * Refs: https://docs.sui.io/concepts/data-access/graphql-rpc, https://docs.sui.io/develop/accessing-data/json-rpc-migration#method-mapping
70
+ */
71
+ const rpc_1 = require("./rpc");
72
+ Object.defineProperty(exports, "sliceIntoChunks", { enumerable: true, get: function () { return rpc_1.sliceIntoChunks; } });
73
+ const debugLog_1 = require("../util/debugLog");
74
+ // ---------------------------------------------------------------------------
75
+ // config
76
+ // ---------------------------------------------------------------------------
77
+ exports.suiChains = ['sui', 'iota'];
78
+ exports.DEFAULT_GRAPHQL_ENDPOINTS = {
79
+ sui: 'https://graphql.mainnet.sui.io/graphql',
80
+ };
81
+ exports.DEFAULT_RPC_ENDPOINTS = {
82
+ sui: 'https://sui-rpc.publicnode.com',
83
+ iota: 'https://api.mainnet.iota.cafe',
84
+ };
85
+ exports.DUMMY_SENDER = '0x' + '0'.repeat(64);
86
+ /** BCS of a Move struct whose only member is `dummy_field: bool` (Wormhole-style `Key<T>` witness structs) */
87
+ exports.EMPTY_STRUCT_BCS = 'AA==';
88
+ const PAGE_SIZE = 50;
89
+ const OBJECTS_PER_QUERY = 50;
90
+ const RPC_OBJECTS_PER_QUERY = 9;
91
+ const GRAPHQL_TIMEOUT = 60000;
92
+ function getGraphqlEndpoints({ chain = 'sui' } = {}) {
93
+ return (0, rpc_1.getEndpoints)(chain, exports.DEFAULT_GRAPHQL_ENDPOINTS[chain], { envKey: `${chain.toUpperCase()}_GRAPH_RPC` });
94
+ }
95
+ function getGraphqlEndpoint(options = {}) {
96
+ return getGraphqlEndpoints(options)[0];
97
+ }
98
+ function getRpcEndpoints({ chain = 'sui' } = {}) {
99
+ return (0, rpc_1.getEndpoints)(chain, exports.DEFAULT_RPC_ENDPOINTS[chain]);
100
+ }
101
+ function getRpcEndpoint(options = {}) {
102
+ return getRpcEndpoints(options)[0];
103
+ }
104
+ /** true when the chain has a GraphQL endpoint (built-in default or `<CHAIN>_GRAPH_RPC`) */
105
+ function hasGraphql(chain = 'sui') {
106
+ try {
107
+ getGraphqlEndpoints({ chain });
108
+ return true;
109
+ }
110
+ catch {
111
+ return false;
112
+ }
113
+ }
114
+ function rpcPrefix(chain = 'sui') {
115
+ return chain === 'iota' ? 'iota' : 'sui';
116
+ }
117
+ const TYPE_TAG_INDEXES = {
118
+ bool: 0, u8: 1, u64: 2, u128: 3, address: 4, signer: 5, u16: 8, u32: 9, u256: 10,
119
+ };
120
+ /** Hex string (with or without 0x) to a fixed-size byte array, left padded with zeros. Default size is a 32 byte address. */
121
+ function hexToBytes(hex, size = 32) {
122
+ const normalized = String(hex).trim().replace(/^0x/i, '');
123
+ if (!/^[0-9a-fA-F]+$/.test(normalized) || normalized.length > size * 2)
124
+ throw new Error(`Invalid Sui hex value: ${hex}`);
125
+ return Array.from(Buffer.from(normalized.padStart(size * 2, '0'), 'hex'));
126
+ }
127
+ function bytesToHex(bytes) {
128
+ return '0x' + Buffer.from(bytes).toString('hex');
129
+ }
130
+ function textToBytes(value) {
131
+ return Array.from(Buffer.from(String(value), 'utf8'));
132
+ }
133
+ function bytesToBase64(bytes) {
134
+ return Buffer.from(bytes).toString('base64');
135
+ }
136
+ function base64ToBytes(value) {
137
+ return Array.from(Buffer.from(value, 'base64'));
138
+ }
139
+ function uleb128Encode(value) {
140
+ const bytes = [];
141
+ let num = Number(value);
142
+ if (!Number.isSafeInteger(num) || num < 0)
143
+ throw new Error(`Invalid uleb128 value: ${value}`);
144
+ do {
145
+ let byte = num % 0x80;
146
+ num = Math.floor(num / 0x80);
147
+ if (num > 0)
148
+ byte |= 0x80;
149
+ bytes.push(byte);
150
+ } while (num > 0);
151
+ return bytes;
152
+ }
153
+ /** Decode a uleb128 at `offset`; returns the value and how many bytes it consumed. */
154
+ function uleb128Decode(data, offset = 0) {
155
+ const source = Uint8Array.from(data);
156
+ let value = 0;
157
+ let shift = 0;
158
+ let i = offset;
159
+ for (;;) {
160
+ if (i >= source.length)
161
+ throw new RangeError(`uleb128: unexpected end of data at offset ${i}`);
162
+ const byte = source[i++];
163
+ value += (byte & 0x7f) * Math.pow(2, shift);
164
+ if (!(byte & 0x80))
165
+ break;
166
+ shift += 7;
167
+ if (shift > 49)
168
+ throw new RangeError('uleb128: value exceeds safe integer range');
169
+ }
170
+ return { value, length: i - offset };
171
+ }
172
+ /** Alias kept for parity with the adapters helper */
173
+ exports.uleb128 = uleb128Encode;
174
+ function toLittleEndian(value, size) {
175
+ const bits = size * 8;
176
+ let big;
177
+ try {
178
+ if (typeof value === 'number' && !Number.isInteger(value))
179
+ throw new Error();
180
+ big = BigInt(value);
181
+ }
182
+ catch {
183
+ throw new Error(`Invalid u${bits} value: ${value}`);
184
+ }
185
+ const max = BigInt(1) << BigInt(bits);
186
+ if (big < BigInt(0) || big >= max)
187
+ throw new Error(`Value out of range for u${bits}: ${value}`);
188
+ const result = new Array(size).fill(0);
189
+ let i = 0;
190
+ while (big > BigInt(0)) {
191
+ result[i] = Number(big % BigInt(256));
192
+ big /= BigInt(256);
193
+ i += 1;
194
+ }
195
+ return result;
196
+ }
197
+ const toU16 = (value) => toLittleEndian(value, 2);
198
+ exports.toU16 = toU16;
199
+ const toU32 = (value) => toLittleEndian(value, 4);
200
+ exports.toU32 = toU32;
201
+ const toU64 = (value) => toLittleEndian(value, 8);
202
+ exports.toU64 = toU64;
203
+ const toU128 = (value) => toLittleEndian(value, 16);
204
+ exports.toU128 = toU128;
205
+ const toU256 = (value) => toLittleEndian(value, 32);
206
+ exports.toU256 = toU256;
207
+ function fromLittleEndian(data, offset = 0, size = 8) {
208
+ if (!Number.isInteger(offset) || offset < 0)
209
+ throw new RangeError(`Invalid byte offset: ${offset}`);
210
+ if (!Number.isInteger(size) || size < 1)
211
+ throw new RangeError(`Invalid integer byte size: ${size}`);
212
+ const source = Uint8Array.from(data);
213
+ if (source.length < offset + size)
214
+ throw new RangeError(`Expected ${size} bytes at offset ${offset}, got ${source.length}`);
215
+ let value = BigInt(0);
216
+ for (let i = offset + size - 1; i >= offset; i--)
217
+ value = (value << BigInt(8)) + BigInt(source[i]);
218
+ return value;
219
+ }
220
+ const fromU16 = (data, offset = 0) => fromLittleEndian(data, offset, 2);
221
+ exports.fromU16 = fromU16;
222
+ const fromU32 = (data, offset = 0) => fromLittleEndian(data, offset, 4);
223
+ exports.fromU32 = fromU32;
224
+ const fromU64 = (data, offset = 0) => fromLittleEndian(data, offset, 8);
225
+ exports.fromU64 = fromU64;
226
+ const fromU128 = (data, offset = 0) => fromLittleEndian(data, offset, 16);
227
+ exports.fromU128 = fromU128;
228
+ const fromU256 = (data, offset = 0) => fromLittleEndian(data, offset, 32);
229
+ exports.fromU256 = fromU256;
230
+ /** Lower-cased, 0x-prefixed, zero padded 64 hex char address */
231
+ function normalizeSuiAddress(address) {
232
+ const hex = String(address).trim().replace(/^0x/i, '').toLowerCase();
233
+ if (!/^[0-9a-f]{1,64}$/.test(hex))
234
+ throw new Error(`Invalid Sui address: ${address}`);
235
+ return '0x' + hex.padStart(64, '0');
236
+ }
237
+ /**
238
+ * GraphQL returns coin types with the address zero padded to 64 hex chars (0x000...002::sui::SUI)
239
+ * while configs commonly use the short form (0x2::sui::SUI); this maps both to the padded form.
240
+ */
241
+ function normalizeCoinType(coinType) {
242
+ const [addr, ...rest] = String(coinType).trim().split('::');
243
+ return [normalizeSuiAddress(addr), ...rest].join('::');
244
+ }
245
+ /** Split a comma separated generic argument list, respecting nested `<...>` */
246
+ function splitTypeArgs(value) {
247
+ const items = [];
248
+ let depth = 0;
249
+ let start = 0;
250
+ for (let i = 0; i < value.length; i++) {
251
+ if (value[i] === '<')
252
+ depth++;
253
+ if (value[i] === '>') {
254
+ depth--;
255
+ if (depth < 0)
256
+ throw new Error(`Unbalanced type argument brackets: ${value}`);
257
+ }
258
+ if (value[i] === ',' && depth === 0) {
259
+ items.push(value.slice(start, i).trim());
260
+ start = i + 1;
261
+ }
262
+ }
263
+ if (depth !== 0)
264
+ throw new Error(`Unbalanced type argument brackets: ${value}`);
265
+ const last = value.slice(start).trim();
266
+ if (last)
267
+ items.push(last);
268
+ return items;
269
+ }
270
+ function parseStructTag(type) {
271
+ const match = String(type).trim().match(/^([^:<>]+)::([^:<>]+)::([^<>]+)(?:<(.+)>)?$/);
272
+ if (!match)
273
+ throw new Error(`Invalid Sui struct tag: ${type}`);
274
+ return {
275
+ address: match[1],
276
+ module: match[2],
277
+ name: match[3],
278
+ typeParams: match[4] ? splitTypeArgs(match[4]) : [],
279
+ };
280
+ }
281
+ /** BCS `TypeTag` */
282
+ function typeTagToBytes(type) {
283
+ const tag = String(type).trim();
284
+ if (TYPE_TAG_INDEXES[tag] !== undefined)
285
+ return [TYPE_TAG_INDEXES[tag]];
286
+ if (tag.startsWith('vector<') && tag.endsWith('>'))
287
+ return [6, ...typeTagToBytes(tag.slice(7, -1))];
288
+ const { address, module, name, typeParams } = parseStructTag(tag);
289
+ const moduleBytes = textToBytes(module);
290
+ const nameBytes = textToBytes(name);
291
+ const out = [
292
+ 7,
293
+ ...hexToBytes(address),
294
+ ...uleb128Encode(moduleBytes.length),
295
+ ...moduleBytes,
296
+ ...uleb128Encode(nameBytes.length),
297
+ ...nameBytes,
298
+ ...uleb128Encode(typeParams.length),
299
+ ];
300
+ typeParams.forEach(p => out.push(...typeTagToBytes(p)));
301
+ return out;
302
+ }
303
+ /**
304
+ * BCS `TransactionKind::ProgrammableTransaction` with a single `MoveCall` command whose inputs are
305
+ * shared objects (enough for read-only view functions inspected through `devInspectTransactionBlock`).
306
+ */
307
+ function buildProgrammableMoveCallBytes({ packageId, module, functionName, typeArguments = [], sharedObjects = [], arguments: moveArguments }) {
308
+ if (!packageId || !module || !functionName)
309
+ throw new Error('Missing packageId, module, or functionName');
310
+ const moduleBytes = textToBytes(module);
311
+ const functionBytes = textToBytes(functionName);
312
+ const args = moveArguments || sharedObjects.map((_, i) => ({ Input: i }));
313
+ const inputCount = sharedObjects.length;
314
+ const bytes = [0, ...uleb128Encode(sharedObjects.length)];
315
+ sharedObjects.forEach(({ objectId, initialSharedVersion, mutable = false }) => {
316
+ bytes.push(1, 1, ...hexToBytes(objectId), ...(0, exports.toU64)(initialSharedVersion), mutable ? 1 : 0);
317
+ });
318
+ bytes.push(...uleb128Encode(1), 0, ...hexToBytes(packageId), ...uleb128Encode(moduleBytes.length), ...moduleBytes, ...uleb128Encode(functionBytes.length), ...functionBytes, ...uleb128Encode(typeArguments.length));
319
+ typeArguments.forEach(t => bytes.push(...typeTagToBytes(t)));
320
+ bytes.push(...uleb128Encode(args.length));
321
+ args.forEach((arg) => {
322
+ var _a;
323
+ const input = typeof arg === 'number' ? arg : ((_a = arg.Input) !== null && _a !== void 0 ? _a : arg.input);
324
+ if (input === undefined || !Number.isInteger(input) || input < 0 || input > 0xffff)
325
+ throw new Error(`Unsupported Sui move call argument: ${JSON.stringify(arg)}`);
326
+ if (input >= inputCount)
327
+ throw new Error(`Sui move call argument input ${input} exceeds input count ${inputCount}`);
328
+ bytes.push(1, ...(0, exports.toU16)(input));
329
+ });
330
+ return Uint8Array.from(bytes);
331
+ }
332
+ /** BCS `TransactionData::V1` wrapping `kindBytes` with dummy gas data (gas payment left empty for `doGasSelection`) */
333
+ function buildTransactionDataBytes(kindBytes, { sender = exports.DUMMY_SENDER, gasPrice = 1000, gasBudget = 50000000000 } = {}) {
334
+ return Uint8Array.from([
335
+ 0, // TransactionData::V1
336
+ ...Array.from(kindBytes), // TransactionKind::ProgrammableTransaction
337
+ ...hexToBytes(sender), // sender
338
+ ...uleb128Encode(0), // GasData.payment: empty
339
+ ...hexToBytes(sender), // GasData.owner
340
+ ...(0, exports.toU64)(gasPrice), // GasData.price
341
+ ...(0, exports.toU64)(gasBudget), // GasData.budget
342
+ 0, // TransactionExpiration::None
343
+ ]);
344
+ }
345
+ /** BCS (base64) of a dynamic field name of the given Move type */
346
+ function bcsDynamicFieldName(nameType, value) {
347
+ const type = String(nameType).trim();
348
+ let bytes;
349
+ if (type === 'address' || type === 'signer' || type.endsWith('::object::ID') || type.endsWith('::object::UID'))
350
+ bytes = hexToBytes(value); // 32 byte address
351
+ else if (type === 'bool')
352
+ bytes = [value === true || value === 'true' || value === 1 ? 1 : 0];
353
+ else if (type === 'u8')
354
+ bytes = [Number(value) & 0xff];
355
+ else if (type === 'u16')
356
+ bytes = (0, exports.toU16)(value);
357
+ else if (type === 'u32')
358
+ bytes = (0, exports.toU32)(value);
359
+ else if (type === 'u64')
360
+ bytes = (0, exports.toU64)(value);
361
+ else if (type === 'u128')
362
+ bytes = (0, exports.toU128)(value);
363
+ else if (type === 'u256')
364
+ bytes = (0, exports.toU256)(value);
365
+ else if (type === 'vector<u8>') {
366
+ const b = Array.isArray(value) ? value.map(Number) : textToBytes(String(value));
367
+ bytes = [...uleb128Encode(b.length), ...b]; // length-prefixed
368
+ }
369
+ else if (type.endsWith('::string::String') || type.endsWith('::ascii::String') || type.endsWith('::type_name::TypeName')) {
370
+ const b = textToBytes(String(value));
371
+ bytes = [...uleb128Encode(b.length), ...b]; // String == vector<u8> of utf8
372
+ }
373
+ else
374
+ throw new Error(`[sui] unsupported dynamic field name type: ${nameType}`);
375
+ return bytesToBase64(bytes);
376
+ }
377
+ function normalizeFields(fields) {
378
+ if (!fields || typeof fields !== 'object')
379
+ return fields;
380
+ const normalized = {};
381
+ for (const [key, value] of Object.entries(fields)) {
382
+ if (key === 'id' && typeof value === 'string') {
383
+ normalized[key] = { id: value };
384
+ }
385
+ else if (Array.isArray(value)) {
386
+ normalized[key] = value.map((v) => (typeof v === 'object' && v !== null) ? wrapStruct(v) : v);
387
+ }
388
+ else if (typeof value === 'object' && value !== null) {
389
+ normalized[key] = wrapStruct(value);
390
+ }
391
+ else {
392
+ normalized[key] = value;
393
+ }
394
+ }
395
+ return normalized;
396
+ }
397
+ function wrapStruct(obj) {
398
+ if (!obj || typeof obj !== 'object' || Array.isArray(obj))
399
+ return obj;
400
+ return { fields: normalizeFields(obj) };
401
+ }
402
+ /** Mirror the JSON-RPC type display: strip leading zeros from addresses, but keep a single leading zero on 64-char addresses */
403
+ function shortenTypeAddresses(type) {
404
+ return String(type)
405
+ .replace(/0x0*([0-9a-fA-F])/g, '0x$1')
406
+ .replace(/0x([0-9a-fA-F]{63})(?![0-9a-fA-F])/g, '0x0$1');
407
+ }
408
+ function normalizeTypeRepr(type) {
409
+ return shortenTypeAddresses(String(type).replace(/,(?!\s)/g, ', '));
410
+ }
411
+ function rewrapWithLayout(value, layout) {
412
+ if (!layout || typeof layout === 'string') {
413
+ if (layout === 'address' && typeof value === 'string' && value && !value.startsWith('0x'))
414
+ return '0x' + value;
415
+ return value;
416
+ }
417
+ if (layout.vector !== undefined)
418
+ return Array.isArray(value) ? value.map((v) => rewrapWithLayout(v, layout.vector)) : value;
419
+ if (layout.struct) {
420
+ const { type, fields } = layout.struct;
421
+ if (type.endsWith('::object::UID'))
422
+ return { id: (value && typeof value === 'object') ? value.id : value };
423
+ if (type.endsWith('::object::ID') || type.endsWith('::string::String') || type.endsWith('::ascii::String'))
424
+ return (value && typeof value === 'object') ? Object.values(value)[0] : value;
425
+ const t = normalizeTypeRepr(type);
426
+ if (value !== null && typeof value === 'object' && !Array.isArray(value)) {
427
+ const f = {};
428
+ for (const fl of fields)
429
+ f[fl.name] = rewrapWithLayout(value[fl.name], fl.layout);
430
+ return { type: t, fields: f };
431
+ }
432
+ if (type.endsWith('::type_name::TypeName'))
433
+ return { type: t, fields: { [fields[0].name]: value } };
434
+ return value;
435
+ }
436
+ return value;
437
+ }
438
+ /**
439
+ * Shape GraphQL `MoveObject.contents` / `MoveValue` (`{ json, type: { repr, layout? } }`) like the
440
+ * JSON-RPC `content` (`{ dataType, type, fields }`), nested structs wrapped as `{ type, fields }`.
441
+ * With a layout, Option / TypeName / UID / ID / String are rewrapped exactly; without it (`skipLayout`)
442
+ * only the generic struct wrapping is applied.
443
+ */
444
+ function formatObject(contents, address) {
445
+ var _a, _b;
446
+ if (!contents || !contents.type)
447
+ return null;
448
+ const layout = contents.type.layout;
449
+ let out;
450
+ if (layout) {
451
+ const rewrapped = rewrapWithLayout(contents.json, layout);
452
+ if (!rewrapped || typeof rewrapped !== 'object')
453
+ throw new Error(`Unexpected Sui move object shape for type ${contents.type.repr}`);
454
+ out = { type: rewrapped.type, fields: rewrapped.fields, dataType: 'moveObject' };
455
+ }
456
+ else {
457
+ out = { type: normalizeTypeRepr(contents.type.repr), fields: normalizeFields(contents.json), dataType: 'moveObject' };
458
+ }
459
+ const id = address !== null && address !== void 0 ? address : (_b = (_a = out.fields) === null || _a === void 0 ? void 0 : _a.id) === null || _b === void 0 ? void 0 : _b.id;
460
+ if (id)
461
+ out.id = id;
462
+ return out;
463
+ }
464
+ /** Prefix a bare hex object id with 0x */
465
+ function toAddr(id) {
466
+ if (typeof id === 'string' && id && !id.startsWith('0x') && /^[0-9a-fA-F]+$/.test(id))
467
+ return '0x' + id;
468
+ return id;
469
+ }
470
+ /** Shape GraphQL `json` like the JSON-RPC `parsedJson` of an event (TypeName -> `{ name }`, String / ID unwrapped, UID -> `{ id }`) */
471
+ function toParsedJson(value, layout) {
472
+ var _a;
473
+ if (value === null || value === undefined)
474
+ return value;
475
+ if (!layout || typeof layout === 'string')
476
+ return value; // bool / uN / address
477
+ if (layout.vector !== undefined)
478
+ return Array.isArray(value) ? value.map((v) => toParsedJson(v, layout.vector)) : value;
479
+ if (layout.struct) {
480
+ const { type, fields } = layout.struct;
481
+ const unwrap = (v) => (v && typeof v === 'object' && !Array.isArray(v)) ? Object.values(v)[0] : v;
482
+ if (type.endsWith('::type_name::TypeName'))
483
+ return { name: unwrap(value) };
484
+ if (type.endsWith('::ascii::String') || type.endsWith('::string::String') || type.endsWith('::object::ID'))
485
+ return unwrap(value);
486
+ if (type.endsWith('::object::UID'))
487
+ return { id: (value && typeof value === 'object') ? ((_a = value.id) !== null && _a !== void 0 ? _a : unwrap(value)) : value };
488
+ if (value && typeof value === 'object' && !Array.isArray(value)) {
489
+ const out = {};
490
+ for (const f of fields)
491
+ out[f.name] = toParsedJson(value[f.name], f.layout);
492
+ return out;
493
+ }
494
+ return value;
495
+ }
496
+ return value;
497
+ }
498
+ /** Shape a JSON-RPC `getObject` response (`{ data: { objectId, type, content, owner, version } }`) like `formatObject` */
499
+ function formatRpcObject(data) {
500
+ var _a, _b;
501
+ if (!data)
502
+ return null;
503
+ const content = data.content;
504
+ if (!content)
505
+ return null;
506
+ const out = {
507
+ id: data.objectId,
508
+ type: (_a = content.type) !== null && _a !== void 0 ? _a : data.type,
509
+ fields: content.fields,
510
+ dataType: (_b = content.dataType) !== null && _b !== void 0 ? _b : 'moveObject',
511
+ };
512
+ if (data.version !== undefined)
513
+ out.version = data.version;
514
+ if (data.owner !== undefined)
515
+ out.owner = data.owner;
516
+ return out;
517
+ }
518
+ // ---------------------------------------------------------------------------
519
+ // GraphQL transport
520
+ // ---------------------------------------------------------------------------
521
+ class SuiGraphqlError extends Error {
522
+ constructor(message, errors = []) {
523
+ super(message);
524
+ this.name = 'SuiGraphqlError';
525
+ this.errors = errors;
526
+ }
527
+ }
528
+ exports.SuiGraphqlError = SuiGraphqlError;
529
+ const NON_RETRYABLE_GRAPHQL = /Unknown (field|argument|type)|Syntax Error|Cannot query field|Expected type|Invalid value|Variable ".*" of (required )?type/i;
530
+ /** POST a GraphQL query; returns `data`, throws `SuiGraphqlError` on `errors` / empty data. Rotates endpoints and retries. */
531
+ async function graphqlCall({ chain = 'sui', query, variables = {}, retries, timeout = GRAPHQL_TIMEOUT }) {
532
+ const endpoints = getGraphqlEndpoints({ chain });
533
+ const limiter = (0, rpc_1.getLimiter)(`${chain.toUpperCase()}_GRAPHQL`, 10);
534
+ const attempts = retries !== null && retries !== void 0 ? retries : Math.max(3, endpoints.length);
535
+ return (0, rpc_1.withRetry)(async (attempt) => {
536
+ var _a, _b, _c, _d, _e;
537
+ const endpoint = endpoints[attempt % endpoints.length];
538
+ const res = await limiter(() => (0, rpc_1.httpPost)(endpoint, { query, variables }, { timeout, retries: 1 }));
539
+ if (((_a = res === null || res === void 0 ? void 0 : res.errors) === null || _a === void 0 ? void 0 : _a.length) || !(res === null || res === void 0 ? void 0 : res.data)) {
540
+ const message = (_d = (_c = (_b = res === null || res === void 0 ? void 0 : res.errors) === null || _b === void 0 ? void 0 : _b[0]) === null || _c === void 0 ? void 0 : _c.message) !== null && _d !== void 0 ? _d : 'no data returned';
541
+ throw new SuiGraphqlError(`[${chain}] graphql: ${message}`, (_e = res === null || res === void 0 ? void 0 : res.errors) !== null && _e !== void 0 ? _e : []);
542
+ }
543
+ return res.data;
544
+ }, {
545
+ retries: attempts,
546
+ label: `${chain} graphql`,
547
+ shouldRetry: (e) => !(e instanceof SuiGraphqlError && NON_RETRYABLE_GRAPHQL.test(e.message)),
548
+ });
549
+ }
550
+ const CONTENTS_FULL = 'contents { json type { repr layout } }';
551
+ const CONTENTS_LITE = 'contents { json type { repr } }';
552
+ const contentsSelection = (skipLayout) => skipLayout ? CONTENTS_LITE : CONTENTS_FULL;
553
+ /** Raw JSON-RPC call (`sui_*` / `suix_*` / `iota_*` / `iotax_*`); returns `result` */
554
+ async function call({ chain = 'sui', method, params = [], retries, timeout }) {
555
+ if (!Array.isArray(params))
556
+ params = [params];
557
+ return (0, rpc_1.jsonRpc)(method, params, { chain, defaultEndpoints: exports.DEFAULT_RPC_ENDPOINTS[chain], retries, timeout });
558
+ }
559
+ const RPC_OBJECT_OPTIONS = { showType: true, showOwner: true, showContent: true };
560
+ /** `<prefix>_getObject` shaped like `getObject` (`{ id, type, fields, dataType, version, owner }`), null when missing */
561
+ async function rpcGetObject({ chain = 'sui', objectId }) {
562
+ const res = await call({ chain, method: `${rpcPrefix(chain)}_getObject`, params: [toAddr(objectId), RPC_OBJECT_OPTIONS] });
563
+ return formatRpcObject(res === null || res === void 0 ? void 0 : res.data);
564
+ }
565
+ /** `<prefix>_multiGetObjects` in chunks of 9, order preserving (null for missing objects) */
566
+ async function rpcGetObjects({ chain = 'sui', objectIds }) {
567
+ if (!objectIds.length)
568
+ return [];
569
+ const method = `${rpcPrefix(chain)}_multiGetObjects`;
570
+ return (0, rpc_1.runInChunks)(objectIds, async (chunk) => {
571
+ var _a;
572
+ const ids = chunk.map(toAddr);
573
+ const result = await call({ chain, method, params: [ids, RPC_OBJECT_OPTIONS] });
574
+ const byId = {};
575
+ for (const r of result !== null && result !== void 0 ? result : [])
576
+ if ((_a = r === null || r === void 0 ? void 0 : r.data) === null || _a === void 0 ? void 0 : _a.objectId)
577
+ byId[normalizeSuiAddress(r.data.objectId)] = r.data;
578
+ return ids.map((id, i) => { var _a, _b; return formatRpcObject((_a = byId[normalizeSuiAddress(id)]) !== null && _a !== void 0 ? _a : (_b = result === null || result === void 0 ? void 0 : result[i]) === null || _b === void 0 ? void 0 : _b.data); });
579
+ }, { chunkSize: RPC_OBJECTS_PER_QUERY });
580
+ }
581
+ /** Move object contents shaped like the JSON-RPC `content` (`{ id, type, fields, dataType }`), null when missing */
582
+ async function getObject({ chain = 'sui', objectId, skipLayout }) {
583
+ var _a, _b, _c, _d;
584
+ if (!hasGraphql(chain))
585
+ return rpcGetObject({ chain, objectId });
586
+ const data = await graphqlCall({
587
+ chain, query: `query ($address: SuiAddress!) {
588
+ object(address: $address) { address version asMoveObject { ${contentsSelection(skipLayout)} } }
589
+ }`, variables: { address: toAddr(objectId) }
590
+ });
591
+ const obj = formatObject((_b = (_a = data.object) === null || _a === void 0 ? void 0 : _a.asMoveObject) === null || _b === void 0 ? void 0 : _b.contents, (_c = data.object) === null || _c === void 0 ? void 0 : _c.address);
592
+ if (obj && ((_d = data.object) === null || _d === void 0 ? void 0 : _d.version) !== undefined)
593
+ obj.version = data.object.version;
594
+ return obj;
595
+ }
596
+ /** `multiGetObjects` in chunks of 50, order preserving (null for missing objects) */
597
+ async function getObjects({ chain = 'sui', objectIds, skipLayout, concurrency = 5, sleep: sleepTime }) {
598
+ if (!objectIds.length)
599
+ return [];
600
+ if (!hasGraphql(chain))
601
+ return rpcGetObjects({ chain, objectIds });
602
+ const sel = contentsSelection(skipLayout);
603
+ return (0, rpc_1.runInChunks)(objectIds, async (chunk) => {
604
+ var _a;
605
+ const ids = chunk.map(toAddr);
606
+ const keys = ids.map((id) => `{ address: ${JSON.stringify(id)} }`).join(', ');
607
+ const data = await graphqlCall({ chain, query: `{ multiGetObjects(keys: [${keys}]) { address asMoveObject { ${sel} } } }` });
608
+ const nodes = (_a = data.multiGetObjects) !== null && _a !== void 0 ? _a : [];
609
+ const byAddress = {};
610
+ for (const o of nodes)
611
+ if (o === null || o === void 0 ? void 0 : o.address)
612
+ byAddress[normalizeSuiAddress(o.address)] = o;
613
+ return ids.map((id, i) => {
614
+ var _a, _b;
615
+ const node = (_a = byAddress[normalizeSuiAddress(id)]) !== null && _a !== void 0 ? _a : nodes[i];
616
+ return formatObject((_b = node === null || node === void 0 ? void 0 : node.asMoveObject) === null || _b === void 0 ? void 0 : _b.contents, node === null || node === void 0 ? void 0 : node.address);
617
+ });
618
+ }, { chunkSize: OBJECTS_PER_QUERY, concurrency: sleepTime ? 1 : concurrency, sleepTime });
619
+ }
620
+ /** All live objects of a Move type (optionally owned by `owner`), walking every page */
621
+ async function getObjectsByType({ chain = 'sui', type, owner, skipLayout, limit, transform }) {
622
+ var _a;
623
+ if (!hasGraphql(chain)) {
624
+ if (!owner)
625
+ throw new Error(`[${chain}] getObjectsByType needs a GraphQL endpoint (set ${chain.toUpperCase()}_GRAPH_RPC) or an owner`);
626
+ return getOwnedObjects({ chain, owner, type, limit, transform });
627
+ }
628
+ const filter = owner ? `{ type: ${JSON.stringify(type)}, owner: ${JSON.stringify(toAddr(owner))} }` : `{ type: ${JSON.stringify(type)} }`;
629
+ const objects = [];
630
+ let after = null;
631
+ do {
632
+ const data = await graphqlCall({
633
+ chain, query: `query ($after: String) {
634
+ objects(first: ${PAGE_SIZE}, after: $after, filter: ${filter}) {
635
+ pageInfo { hasNextPage endCursor }
636
+ nodes { address asMoveObject { ${contentsSelection(skipLayout)} } }
637
+ }
638
+ }`, variables: { after }
639
+ });
640
+ const { pageInfo, nodes } = data.objects;
641
+ for (const n of nodes) {
642
+ const obj = formatObject((_a = n.asMoveObject) === null || _a === void 0 ? void 0 : _a.contents, n.address);
643
+ if (obj)
644
+ objects.push(obj);
645
+ }
646
+ after = pageInfo.hasNextPage ? pageInfo.endCursor : null;
647
+ if (limit && objects.length >= limit)
648
+ break;
649
+ } while (after);
650
+ const out = limit ? objects.slice(0, limit) : objects;
651
+ return (transform ? out.map(transform) : out);
652
+ }
653
+ /** Objects owned by an address, walking every page */
654
+ async function getOwnedObjects({ chain = 'sui', owner, type, skipLayout, limit, transform }) {
655
+ var _a, _b;
656
+ const objects = [];
657
+ if (!hasGraphql(chain)) {
658
+ let cursor = null;
659
+ do {
660
+ const query = { filter: type ? { StructType: type } : null, options: { showType: true, showContent: true } };
661
+ const res = await call({ chain, method: `${rpcPrefix(chain)}x_getOwnedObjects`, params: [toAddr(owner), query, cursor, PAGE_SIZE] });
662
+ for (const n of (_a = res === null || res === void 0 ? void 0 : res.data) !== null && _a !== void 0 ? _a : []) {
663
+ const obj = formatRpcObject(n === null || n === void 0 ? void 0 : n.data);
664
+ if (obj)
665
+ objects.push(obj);
666
+ }
667
+ cursor = (res === null || res === void 0 ? void 0 : res.hasNextPage) ? res.nextCursor : null;
668
+ if (limit && objects.length >= limit)
669
+ break;
670
+ } while (cursor);
671
+ }
672
+ else {
673
+ const filter = type ? `, filter: { type: ${JSON.stringify(type)} }` : '';
674
+ let after = null;
675
+ do {
676
+ const data = await graphqlCall({
677
+ chain, query: `query ($owner: SuiAddress!, $after: String) {
678
+ address(address: $owner) {
679
+ objects(first: ${PAGE_SIZE}, after: $after${filter}) {
680
+ pageInfo { hasNextPage endCursor }
681
+ nodes { address ${contentsSelection(skipLayout)} }
682
+ }
683
+ }
684
+ }`, variables: { owner: toAddr(owner), after }
685
+ });
686
+ const page = (_b = data.address) === null || _b === void 0 ? void 0 : _b.objects;
687
+ if (!page)
688
+ break;
689
+ for (const n of page.nodes) {
690
+ const obj = formatObject(n.contents, n.address);
691
+ if (obj)
692
+ objects.push(obj);
693
+ }
694
+ after = page.pageInfo.hasNextPage ? page.pageInfo.endCursor : null;
695
+ if (limit && objects.length >= limit)
696
+ break;
697
+ } while (after);
698
+ }
699
+ const out = limit ? objects.slice(0, limit) : objects;
700
+ return (transform ? out.map(transform) : out);
701
+ }
702
+ function buildEventFilter({ eventType, eventModule, sender }) {
703
+ const parts = [];
704
+ if (eventType)
705
+ parts.push(`type: ${JSON.stringify(eventType)}`);
706
+ if (eventModule) {
707
+ const mod = typeof eventModule === 'string' ? eventModule : `${eventModule.package}::${eventModule.module}`;
708
+ parts.push(`module: ${JSON.stringify(mod)}`);
709
+ }
710
+ if (sender)
711
+ parts.push(`sender: ${JSON.stringify(toAddr(sender))}`);
712
+ return parts.length ? `, filter: { ${parts.join(', ')} }` : '';
713
+ }
714
+ function toSeconds(value) {
715
+ return value > 1e12 ? value / 1e3 : value;
716
+ }
717
+ /**
718
+ * Events matching a type / module / sender filter, cursor walking all pages (oldest first).
719
+ * With `startTimestamp` / `endTimestamp` the newest events are walked backwards and only the
720
+ * half-open window `[start, end)` is returned (as dimension-adapters did).
721
+ */
722
+ async function queryEvents(options) {
723
+ const { chain = 'sui', limit, skipLayout, withMetadata, transform } = options;
724
+ if (!hasGraphql(chain))
725
+ throw new Error(`[${chain}] queryEvents needs a GraphQL endpoint (set ${chain.toUpperCase()}_GRAPH_RPC)`);
726
+ const filter = buildEventFilter(options);
727
+ const start = options.startTimestamp !== undefined ? toSeconds(options.startTimestamp) : undefined;
728
+ const end = options.endTimestamp !== undefined ? toSeconds(options.endTimestamp) : undefined;
729
+ const windowed = start !== undefined || end !== undefined;
730
+ const sel = `timestamp sender { address } ${contentsSelection(skipLayout)}`;
731
+ const items = [];
732
+ const shape = (node) => {
733
+ var _a, _b, _c;
734
+ const json = skipLayout ? node.contents.json : toParsedJson(node.contents.json, (_a = node.contents.type) === null || _a === void 0 ? void 0 : _a.layout);
735
+ if (!withMetadata)
736
+ return json;
737
+ const event = { type: (_b = node.contents.type) === null || _b === void 0 ? void 0 : _b.repr, timestamp: Date.parse(node.timestamp) / 1e3, sender: (_c = node.sender) === null || _c === void 0 ? void 0 : _c.address, json };
738
+ return event;
739
+ };
740
+ if (windowed) {
741
+ let before = null;
742
+ do {
743
+ const data = await graphqlCall({
744
+ chain, query: `query ($before: String) {
745
+ events(last: ${PAGE_SIZE}, before: $before${filter}) {
746
+ pageInfo { hasPreviousPage startCursor }
747
+ nodes { ${sel} }
748
+ }
749
+ }`, variables: { before }
750
+ });
751
+ const { pageInfo, nodes } = data.events; // ascending (oldest -> newest)
752
+ before = pageInfo.hasPreviousPage ? pageInfo.startCursor : null;
753
+ for (let i = nodes.length - 1; i >= 0; i--) {
754
+ const ts = Date.parse(nodes[i].timestamp) / 1e3;
755
+ if (end !== undefined && ts >= end)
756
+ continue;
757
+ if (start !== undefined && ts < start) {
758
+ before = null;
759
+ break;
760
+ }
761
+ items.push(shape(nodes[i]));
762
+ }
763
+ if (!nodes.length)
764
+ before = null;
765
+ if (limit && items.length >= limit)
766
+ before = null;
767
+ } while (before);
768
+ items.reverse(); // oldest first, like the forward walk
769
+ }
770
+ else {
771
+ let after = null;
772
+ do {
773
+ const data = await graphqlCall({
774
+ chain, query: `query ($after: String) {
775
+ events(first: ${PAGE_SIZE}, after: $after${filter}) {
776
+ pageInfo { hasNextPage endCursor }
777
+ nodes { ${sel} }
778
+ }
779
+ }`, variables: { after }
780
+ });
781
+ const { pageInfo, nodes } = data.events;
782
+ after = pageInfo.hasNextPage ? pageInfo.endCursor : null;
783
+ for (const n of nodes)
784
+ items.push(shape(n));
785
+ if (limit && items.length >= limit)
786
+ after = null;
787
+ } while (after);
788
+ }
789
+ const out = limit ? items.slice(0, limit) : items;
790
+ return (transform ? out.map(transform) : out);
791
+ }
792
+ // ---------------------------------------------------------------------------
793
+ // dynamic fields
794
+ // ---------------------------------------------------------------------------
795
+ /**
796
+ * Selects both the dynamic field's own object (`contents`, the `0x2::dynamic_field::Field<K, V>`
797
+ * wrapper with `fields.name` / `fields.value`) and its `value`. Dynamic *object* fields resolve to
798
+ * the child MoveObject; plain dynamic fields resolve to the Field wrapper, which is what the
799
+ * adapters historically read (`i.fields.value`) and the only shape that works for primitive values
800
+ * such as `0x2::object::ID`.
801
+ */
802
+ const DYNAMIC_FIELD_VALUE_SELECTION = (skipLayout) => `${contentsSelection(skipLayout)} value {
803
+ __typename
804
+ ... on MoveValue { json type { repr ${skipLayout ? '' : 'layout'} } }
805
+ ... on MoveObject { address ${contentsSelection(skipLayout)} }
806
+ }`;
807
+ function formatDynamicFieldValue(node, fallbackAddress) {
808
+ const { value, contents } = node !== null && node !== void 0 ? node : {};
809
+ if ((value === null || value === void 0 ? void 0 : value.__typename) === 'MoveObject' && value.contents)
810
+ return formatObject(value.contents, value.address);
811
+ if (contents)
812
+ return formatObject(contents, fallbackAddress);
813
+ if (!value)
814
+ return null;
815
+ return formatObject({ json: value.json, type: value.type }, fallbackAddress);
816
+ }
817
+ /** One dynamic field (or dynamic object field) of `parent` by name; null when missing */
818
+ async function getDynamicFieldObject({ chain = 'sui', parent, name, id, nameType, idType, nameBcs, skipLayout }) {
819
+ var _a, _b, _c, _d, _e;
820
+ const type = (_a = nameType !== null && nameType !== void 0 ? nameType : idType) !== null && _a !== void 0 ? _a : '0x2::object::ID';
821
+ const value = name !== null && name !== void 0 ? name : id;
822
+ const bcs = nameBcs !== null && nameBcs !== void 0 ? nameBcs : (value !== undefined ? bcsDynamicFieldName(type, value) : exports.EMPTY_STRUCT_BCS);
823
+ if (!hasGraphql(chain)) {
824
+ const res = await call({ chain, method: `${rpcPrefix(chain)}x_getDynamicFieldObject`, params: [toAddr(parent), { type, value: typeof value === 'bigint' ? value.toString() : value }] });
825
+ const obj = formatRpcObject(res === null || res === void 0 ? void 0 : res.data);
826
+ if (obj && value !== undefined)
827
+ obj.name = value;
828
+ return obj;
829
+ }
830
+ const sel = DYNAMIC_FIELD_VALUE_SELECTION(skipLayout);
831
+ const data = await graphqlCall({
832
+ chain, query: `query ($parent: SuiAddress!, $name: DynamicFieldName!) {
833
+ address(address: $parent) {
834
+ dynamicField(name: $name) { name { json } ${sel} }
835
+ dynamicObjectField(name: $name) { name { json } ${sel} }
836
+ }
837
+ }`, variables: { parent: toAddr(parent), name: { type, bcs } }
838
+ });
839
+ const df = (_c = (_b = data.address) === null || _b === void 0 ? void 0 : _b.dynamicObjectField) !== null && _c !== void 0 ? _c : (_d = data.address) === null || _d === void 0 ? void 0 : _d.dynamicField;
840
+ if (!df)
841
+ return null;
842
+ const obj = formatDynamicFieldValue(df);
843
+ if (obj)
844
+ obj.name = (_e = df.name) === null || _e === void 0 ? void 0 : _e.json;
845
+ return obj;
846
+ }
847
+ /** All dynamic fields of `parent` (Table / Bag / ObjectTable entries), walking every page. Each item carries `name` (the field key). */
848
+ async function getDynamicFieldObjects({ chain = 'sui', parent, cursor = null, limit, pageSize = PAGE_SIZE, idFilter, skipLayout, sleep: sleepTime, onPage }) {
849
+ var _a, _b, _c, _d, _e, _f;
850
+ const size = Math.min(Math.max(1, Number(pageSize) || PAGE_SIZE), 50);
851
+ const items = [];
852
+ const addedIds = new Set();
853
+ const useRpc = !hasGraphql(chain);
854
+ const parentAddr = toAddr(parent);
855
+ let after = cursor;
856
+ const push = async (pageItems) => {
857
+ if (onPage)
858
+ await onPage(pageItems); // let callers start downstream reads while paging continues
859
+ else
860
+ items.push(...pageItems);
861
+ };
862
+ let count = 0;
863
+ do {
864
+ if (sleepTime)
865
+ await (0, rpc_1.sleep)(sleepTime);
866
+ const pageItems = [];
867
+ if (useRpc) {
868
+ const prefix = rpcPrefix(chain);
869
+ const page = await call({ chain, method: `${prefix}x_getDynamicFields`, params: [parentAddr, after, size] });
870
+ const ids = ((_a = page === null || page === void 0 ? void 0 : page.data) !== null && _a !== void 0 ? _a : []).map((f) => f.objectId);
871
+ const objs = await rpcGetObjects({ chain, objectIds: ids });
872
+ (_b = page === null || page === void 0 ? void 0 : page.data) === null || _b === void 0 ? void 0 : _b.forEach((f, i) => {
873
+ var _a, _b;
874
+ const obj = objs[i];
875
+ if (!obj || addedIds.has(obj.id))
876
+ return;
877
+ obj.name = (_a = f.name) === null || _a === void 0 ? void 0 : _a.value;
878
+ if (idFilter && !idFilter({ objectId: obj.id, objectType: obj.type, name: (_b = obj.fields) === null || _b === void 0 ? void 0 : _b.name, key: obj.name }))
879
+ return;
880
+ addedIds.add(obj.id);
881
+ pageItems.push(obj);
882
+ });
883
+ after = (page === null || page === void 0 ? void 0 : page.hasNextPage) ? page.nextCursor : null;
884
+ }
885
+ else {
886
+ const data = await graphqlCall({
887
+ chain, query: `query ($parent: SuiAddress!, $after: String) {
888
+ address(address: $parent) {
889
+ dynamicFields(first: ${size}, after: $after) {
890
+ pageInfo { hasNextPage endCursor }
891
+ nodes { address name { json } ${DYNAMIC_FIELD_VALUE_SELECTION(skipLayout)} }
892
+ }
893
+ }
894
+ }`, variables: { parent: parentAddr, after }
895
+ });
896
+ const df = (_c = data.address) === null || _c === void 0 ? void 0 : _c.dynamicFields;
897
+ if (!df)
898
+ throw new Error(`[${chain}] dynamicFields not available for ${parent} (endpoint may not index this object)`);
899
+ (0, debugLog_1.debugLog)(`[${chain}] fetched dynamic fields`, df.nodes.length, df.pageInfo.hasNextPage);
900
+ for (const n of df.nodes) {
901
+ const obj = formatDynamicFieldValue(n, n.address);
902
+ const objectId = (_d = obj === null || obj === void 0 ? void 0 : obj.id) !== null && _d !== void 0 ? _d : n.address;
903
+ if (!obj || !objectId || addedIds.has(objectId))
904
+ continue;
905
+ obj.id = objectId;
906
+ obj.name = (_e = n.name) === null || _e === void 0 ? void 0 : _e.json; // the dynamic-field key (e.g. a coin TypeName), which the value object may not carry
907
+ if (idFilter && !idFilter({ objectId, objectType: obj.type, name: (_f = obj.fields) === null || _f === void 0 ? void 0 : _f.name, key: obj.name }))
908
+ continue;
909
+ addedIds.add(objectId);
910
+ pageItems.push(obj);
911
+ }
912
+ after = df.pageInfo.hasNextPage ? df.pageInfo.endCursor : null;
913
+ }
914
+ count += pageItems.length;
915
+ await push(limit && count > limit ? pageItems.slice(0, pageItems.length - (count - limit)) : pageItems);
916
+ if (limit && count >= limit)
917
+ after = null;
918
+ } while (after);
919
+ return items;
920
+ }
921
+ /** `coinMetadata` (GraphQL) or `<prefix>x_getCoinMetadata` + `<prefix>x_getTotalSupply` (JSON-RPC) */
922
+ async function getCoinMetadata({ chain = 'sui', coinType }) {
923
+ var _a, _b;
924
+ if (!hasGraphql(chain)) {
925
+ const prefix = rpcPrefix(chain);
926
+ const meta = await call({ chain, method: `${prefix}x_getCoinMetadata`, params: [coinType] });
927
+ if (!meta)
928
+ throw new Error(`[${chain}] Failed to fetch coin metadata for token: ${coinType}`);
929
+ let supply;
930
+ try {
931
+ const res = await call({ chain, method: `${prefix}x_getTotalSupply`, params: [coinType] });
932
+ supply = res === null || res === void 0 ? void 0 : res.value;
933
+ }
934
+ catch (e) {
935
+ (0, debugLog_1.debugLog)(`[${chain}] getTotalSupply failed for ${coinType}: ${e === null || e === void 0 ? void 0 : e.message}`);
936
+ }
937
+ return { decimals: meta.decimals, symbol: meta.symbol, name: meta.name, description: meta.description, iconUrl: meta.iconUrl, supply };
938
+ }
939
+ const data = await graphqlCall({
940
+ chain, query: `query ($coinType: String!) {
941
+ coinMetadata(coinType: $coinType) { decimals symbol name description iconUrl supply }
942
+ }`, variables: { coinType }
943
+ });
944
+ const meta = data.coinMetadata;
945
+ if (!meta)
946
+ throw new Error(`[${chain}] Failed to fetch coin metadata for token: ${coinType}`);
947
+ return { decimals: (_a = meta.decimals) !== null && _a !== void 0 ? _a : 0, symbol: meta.symbol, name: meta.name, description: meta.description, iconUrl: meta.iconUrl, supply: (_b = meta.supply) !== null && _b !== void 0 ? _b : undefined };
948
+ }
949
+ async function getTokenSupply({ chain = 'sui', coinType }) {
950
+ const { supply, decimals } = await getCoinMetadata({ chain, coinType });
951
+ if (supply === undefined || supply === null)
952
+ throw new Error(`[${chain}] supply not available for token: ${coinType}`);
953
+ return { supply: String(supply), decimals, normalized: Number(supply) / 10 ** decimals };
954
+ }
955
+ /** Every coin balance of `owner`, walking all pages */
956
+ async function getAllBalances({ chain = 'sui', owner }) {
957
+ var _a, _b, _c;
958
+ const out = [];
959
+ if (!hasGraphql(chain)) {
960
+ const res = await call({ chain, method: `${rpcPrefix(chain)}x_getAllBalances`, params: [toAddr(owner)] });
961
+ for (const b of res !== null && res !== void 0 ? res : [])
962
+ out.push({ coinType: b.coinType, totalBalance: String(b.totalBalance) });
963
+ return out;
964
+ }
965
+ let after = null;
966
+ do {
967
+ const data = await graphqlCall({
968
+ chain, query: `query ($owner: SuiAddress!, $after: String) {
969
+ address(address: $owner) {
970
+ balances(first: ${PAGE_SIZE}, after: $after) {
971
+ nodes { coinType { repr } totalBalance }
972
+ pageInfo { hasNextPage endCursor }
973
+ }
974
+ }
975
+ }`, variables: { owner: toAddr(owner), after }
976
+ });
977
+ const balances = (_a = data.address) === null || _a === void 0 ? void 0 : _a.balances;
978
+ if (!balances)
979
+ break;
980
+ for (const n of (_b = balances.nodes) !== null && _b !== void 0 ? _b : [])
981
+ out.push({ coinType: n.coinType.repr, totalBalance: String(n.totalBalance) });
982
+ after = ((_c = balances.pageInfo) === null || _c === void 0 ? void 0 : _c.hasNextPage) ? balances.pageInfo.endCursor : null;
983
+ } while (after);
984
+ return out;
985
+ }
986
+ /** Balance of one coin type for `owner` (base units, '0' when none) */
987
+ async function getBalance({ chain = 'sui', owner, coinType }) {
988
+ var _a, _b, _c, _d;
989
+ if (!hasGraphql(chain)) {
990
+ const res = await call({ chain, method: `${rpcPrefix(chain)}x_getBalance`, params: [toAddr(owner), coinType] });
991
+ return String((_a = res === null || res === void 0 ? void 0 : res.totalBalance) !== null && _a !== void 0 ? _a : '0');
992
+ }
993
+ const data = await graphqlCall({
994
+ chain, query: `query ($owner: SuiAddress!, $coinType: String!) {
995
+ address(address: $owner) { balance(coinType: $coinType) { totalBalance } }
996
+ }`, variables: { owner: toAddr(owner), coinType }
997
+ });
998
+ return String((_d = (_c = (_b = data.address) === null || _b === void 0 ? void 0 : _b.balance) === null || _c === void 0 ? void 0 : _c.totalBalance) !== null && _d !== void 0 ? _d : '0');
999
+ }
1000
+ function shapeGraphqlCheckpoint(c) {
1001
+ if (!c)
1002
+ return null;
1003
+ return { sequenceNumber: Number(c.sequenceNumber), timestamp: Math.floor(Date.parse(c.timestamp) / 1e3), digest: c.digest };
1004
+ }
1005
+ function shapeRpcCheckpoint(c) {
1006
+ if (!c)
1007
+ return null;
1008
+ return { sequenceNumber: Number(c.sequenceNumber), timestamp: Math.floor(Number(c.timestampMs) / 1e3), digest: c.digest };
1009
+ }
1010
+ /** A checkpoint by sequence number; null when the endpoint no longer has it */
1011
+ async function getCheckpoint({ chain = 'sui', sequenceNumber }) {
1012
+ if (!hasGraphql(chain)) {
1013
+ const res = await call({ chain, method: `${rpcPrefix(chain)}_getCheckpoint`, params: [String(sequenceNumber)] });
1014
+ return shapeRpcCheckpoint(res);
1015
+ }
1016
+ const data = await graphqlCall({
1017
+ chain, query: `query ($seq: UInt53!) { checkpoint(sequenceNumber: $seq) { sequenceNumber timestamp digest } }`,
1018
+ variables: { seq: Number(sequenceNumber) },
1019
+ });
1020
+ return shapeGraphqlCheckpoint(data.checkpoint);
1021
+ }
1022
+ async function getLatestCheckpoint({ chain = 'sui' } = {}) {
1023
+ if (!hasGraphql(chain)) {
1024
+ const prefix = rpcPrefix(chain);
1025
+ const seq = await call({ chain, method: `${prefix}_getLatestCheckpointSequenceNumber`, params: [] });
1026
+ const c = await getCheckpoint({ chain, sequenceNumber: seq });
1027
+ if (!c)
1028
+ throw new Error(`[${chain}] checkpoint ${seq} not found`);
1029
+ return c;
1030
+ }
1031
+ const data = await graphqlCall({ chain, query: `{ checkpoint { sequenceNumber timestamp digest } }` });
1032
+ const c = shapeGraphqlCheckpoint(data.checkpoint);
1033
+ if (!c)
1034
+ throw new Error(`[${chain}] latest checkpoint not available`);
1035
+ return c;
1036
+ }
1037
+ /** Last checkpoint with `timestamp <= target` (binary search over sequence numbers, ~30 requests) */
1038
+ async function getCheckpointAtTimestamp({ chain = 'sui', timestamp }) {
1039
+ const target = toSeconds(timestamp);
1040
+ const latest = await getLatestCheckpoint({ chain });
1041
+ if (latest.timestamp <= target)
1042
+ return latest;
1043
+ let lo = 0;
1044
+ let hi = latest.sequenceNumber;
1045
+ let best = null;
1046
+ while (lo < hi) {
1047
+ const mid = Math.floor((lo + hi + 1) / 2);
1048
+ const c = await getCheckpoint({ chain, sequenceNumber: mid });
1049
+ if (!c || c.timestamp <= target) {
1050
+ // missing (pruned) checkpoints are treated as older than the target
1051
+ if (c)
1052
+ best = c;
1053
+ lo = mid;
1054
+ }
1055
+ else {
1056
+ hi = mid - 1;
1057
+ }
1058
+ }
1059
+ if (best && best.sequenceNumber === lo)
1060
+ return best;
1061
+ const c = await getCheckpoint({ chain, sequenceNumber: lo });
1062
+ if (!c)
1063
+ throw new Error(`[${chain}] no checkpoint found at or before ${target}`);
1064
+ return c;
1065
+ }
1066
+ /** Simulate a transaction kind and return the BCS return values of every command (GraphQL `simulateTransaction`, JSON-RPC `devInspectTransactionBlock`) */
1067
+ async function devInspectTransactionBlock({ chain = 'sui', txBytes, sender = exports.DUMMY_SENDER }) {
1068
+ var _a, _b, _c, _d, _e;
1069
+ const kindBytes = Array.from(txBytes);
1070
+ if (!hasGraphql(chain)) {
1071
+ const res = await call({ chain, method: `${rpcPrefix(chain)}_devInspectTransactionBlock`, params: [sender, bytesToBase64(kindBytes)] });
1072
+ if (res === null || res === void 0 ? void 0 : res.error)
1073
+ throw new Error(`[${chain}] devInspectTransactionBlock failed: ${res.error}`);
1074
+ const status = (_b = (_a = res === null || res === void 0 ? void 0 : res.effects) === null || _a === void 0 ? void 0 : _a.status) === null || _b === void 0 ? void 0 : _b.status;
1075
+ if (status && status !== 'success')
1076
+ throw new Error(`[${chain}] devInspectTransactionBlock failed: ${(_c = res.effects.status.error) !== null && _c !== void 0 ? _c : status}`);
1077
+ const results = ((_d = res === null || res === void 0 ? void 0 : res.results) !== null && _d !== void 0 ? _d : []).map((cmd) => {
1078
+ var _a;
1079
+ return ({
1080
+ returnValues: ((_a = cmd.returnValues) !== null && _a !== void 0 ? _a : []).map((rv) => [Array.from(rv[0]), rv[1]]),
1081
+ });
1082
+ });
1083
+ return { results, effects: res === null || res === void 0 ? void 0 : res.effects };
1084
+ }
1085
+ const value = bytesToBase64(buildTransactionDataBytes(kindBytes, { sender }));
1086
+ const data = await graphqlCall({
1087
+ chain, query: `query ($tx: JSON!) {
1088
+ simulateTransaction(transaction: $tx, checksEnabled: false, doGasSelection: true) {
1089
+ effects { status }
1090
+ outputs { returnValues { value { bcs type { repr } } } }
1091
+ }
1092
+ }`, variables: { tx: { bcs: { value } } }
1093
+ });
1094
+ const sim = data.simulateTransaction;
1095
+ if (((_e = sim === null || sim === void 0 ? void 0 : sim.effects) === null || _e === void 0 ? void 0 : _e.status) && sim.effects.status !== 'SUCCESS')
1096
+ throw new Error(`[${chain}] simulateTransaction failed: ${sim.effects.status}`);
1097
+ const results = ((sim === null || sim === void 0 ? void 0 : sim.outputs) || []).map((cmd) => ({
1098
+ returnValues: (cmd.returnValues || []).map((rv) => { var _a; return [base64ToBytes(rv.value.bcs), (_a = rv.value.type) === null || _a === void 0 ? void 0 : _a.repr]; }),
1099
+ }));
1100
+ return { results, effects: sim === null || sim === void 0 ? void 0 : sim.effects };
1101
+ }
1102
+ /** `initialSharedVersion` of a shared object (needed to reference it as a transaction input) */
1103
+ async function getInitialSharedVersion({ chain = 'sui', objectId }) {
1104
+ var _a, _b, _c, _d, _e;
1105
+ if (!hasGraphql(chain)) {
1106
+ const res = await call({ chain, method: `${rpcPrefix(chain)}_getObject`, params: [toAddr(objectId), { showOwner: true }] });
1107
+ const version = (_c = (_b = (_a = res === null || res === void 0 ? void 0 : res.data) === null || _a === void 0 ? void 0 : _a.owner) === null || _b === void 0 ? void 0 : _b.Shared) === null || _c === void 0 ? void 0 : _c.initial_shared_version;
1108
+ if (version === undefined || version === null)
1109
+ throw new Error(`[${chain}] object ${objectId} is not a shared object`);
1110
+ return Number(version);
1111
+ }
1112
+ const data = await graphqlCall({
1113
+ chain, query: `query ($address: SuiAddress!) {
1114
+ object(address: $address) { owner { __typename ... on Shared { initialSharedVersion } } }
1115
+ }`, variables: { address: toAddr(objectId) }
1116
+ });
1117
+ const version = (_e = (_d = data.object) === null || _d === void 0 ? void 0 : _d.owner) === null || _e === void 0 ? void 0 : _e.initialSharedVersion;
1118
+ if (version === undefined || version === null)
1119
+ throw new Error(`[${chain}] object ${objectId} is not a shared object`);
1120
+ return Number(version);
1121
+ }
1122
+ /** Build a single MoveCall over shared objects, simulate it and return `[bcsBytes, typeRepr]` per return value */
1123
+ async function callViewFunction({ chain = 'sui', sharedObjects = [], sender, ...moveCall }) {
1124
+ var _a, _b;
1125
+ const refs = await Promise.all(sharedObjects.map(async (o) => {
1126
+ if (typeof o !== 'string' && o.initialSharedVersion !== undefined)
1127
+ return o;
1128
+ const objectId = typeof o === 'string' ? o : o.objectId;
1129
+ const initialSharedVersion = await getInitialSharedVersion({ chain, objectId });
1130
+ return { objectId, initialSharedVersion, mutable: typeof o === 'string' ? false : o.mutable };
1131
+ }));
1132
+ const txBytes = buildProgrammableMoveCallBytes({ ...moveCall, sharedObjects: refs });
1133
+ const { results } = await devInspectTransactionBlock({ chain, txBytes, sender });
1134
+ return (_b = (_a = results[0]) === null || _a === void 0 ? void 0 : _a.returnValues) !== null && _b !== void 0 ? _b : [];
1135
+ }