@exodus/sui-api 1.3.1 → 1.4.1

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/src/balances.js CHANGED
@@ -1,29 +1,29 @@
1
1
  import { getStakingBalances } from './staking/staking-balances.js'
2
2
 
3
+ const getAddressBalance = ({ asset, accountState }) =>
4
+ asset.currency.baseUnit(accountState.addressBalances[asset.name] ?? 0)
5
+
3
6
  export const getBalances = ({ asset, accountState }) => {
4
7
  const isBaseAsset = asset.name === asset.baseAssetName
8
+ const addressBalance = getAddressBalance({ asset, accountState })
5
9
 
6
10
  if (isBaseAsset) {
7
11
  const spendable = accountState.utxos.value
8
12
  const stakingBalances = getStakingBalances({ asset, stakingInfo: accountState.stakingInfo })
9
13
  const { staking, staked, unstaked } = stakingBalances
10
14
  return {
11
- total: spendable.add(staking).add(staked).add(unstaked),
15
+ total: spendable.add(addressBalance).add(staking).add(staked).add(unstaked),
12
16
  spendable,
13
17
  stakeable: spendable,
18
+ unspendable: addressBalance,
14
19
  ...stakingBalances,
15
20
  }
16
21
  }
17
22
 
18
- if (accountState.tokenUtxos[asset.name]) {
19
- return {
20
- total: accountState.tokenUtxos[asset.name].value,
21
- spendable: accountState.tokenUtxos[asset.name].value,
22
- }
23
- }
24
-
23
+ const spendable = accountState.tokenUtxos[asset.name]?.value ?? asset.currency.ZERO
25
24
  return {
26
- total: asset.currency.ZERO,
27
- spendable: asset.currency.ZERO,
25
+ total: spendable.add(addressBalance),
26
+ spendable,
27
+ unspendable: addressBalance,
28
28
  }
29
29
  }
@@ -8,6 +8,7 @@ export const createBasicAccountState = () => {
8
8
  static defaults = {
9
9
  utxos: UtxoCollection.createEmpty({ currency: asset.currency }),
10
10
  tokenUtxos: Object.create(null),
11
+ addressBalances: Object.create(null),
11
12
  stakingInfo: EMPTY_STAKING_INFO,
12
13
  }
13
14
  }
@@ -0,0 +1,8 @@
1
+ export class SuiBroadcastError extends Error {
2
+ constructor({ message, digest, outcome, cause }) {
3
+ super(`${message} (tx ${digest})`, { cause })
4
+ this.name = 'SuiBroadcastError'
5
+ this.digest = digest
6
+ this.outcome = outcome
7
+ }
8
+ }
@@ -28,7 +28,7 @@ export const createUnsignedTxFactory = ({ assetClientInterface, serverApi }) =>
28
28
  txb.setSender(senderAddress)
29
29
 
30
30
  return {
31
- txData: await txb.build({ client: serverApi.client, ...buildOptions }),
31
+ txData: await serverApi.buildTransaction({ transaction: txb, ...buildOptions }),
32
32
  txMeta: Object.create(null),
33
33
  }
34
34
  }
@@ -53,7 +53,7 @@ export const createUnsignedTxFactory = ({ assetClientInterface, serverApi }) =>
53
53
  txb.setSender(senderAddress)
54
54
 
55
55
  return {
56
- txData: await txb.build({ client: serverApi.client, ...buildOptions }),
56
+ txData: await serverApi.buildTransaction({ transaction: txb, ...buildOptions }),
57
57
  txMeta: Object.create(null),
58
58
  }
59
59
  }
@@ -27,7 +27,7 @@ export const getFeeAsyncFactory = ({ assetClientInterface, serverApi, createUnsi
27
27
  },
28
28
  })
29
29
 
30
- const simulation = await serverApi.client.devInspectTransactionBlock({
30
+ const simulation = await serverApi.devInspectTransaction({
31
31
  sender: senderAddress,
32
32
  transactionBlock: txData,
33
33
  })
@@ -0,0 +1,82 @@
1
+ import ms from 'ms'
2
+
3
+ const MAX_ERROR_BODY_LENGTH = 100
4
+ const DEFAULT_TIMEOUT_MS = ms('30s')
5
+
6
+ export class GraphQLTimeoutError extends Error {
7
+ constructor({ url, timeoutMs }) {
8
+ super(`${url} timed out after ${timeoutMs}ms`)
9
+ this.name = 'GraphQLTimeoutError'
10
+ }
11
+ }
12
+
13
+ export class GraphQLTransportError extends Error {
14
+ constructor(message, { cause } = Object.create(null)) {
15
+ super(message, { cause })
16
+ this.name = 'GraphQLTransportError'
17
+ }
18
+ }
19
+
20
+ const SERVER_ERROR_STATUS = 500
21
+
22
+ const readErrorBody = async (response) => {
23
+ try {
24
+ const text = await response.text()
25
+ return text.slice(0, MAX_ERROR_BODY_LENGTH)
26
+ } catch {
27
+ return ''
28
+ }
29
+ }
30
+
31
+ export class GraphQLClient {
32
+ #url
33
+ #timeoutMs
34
+
35
+ constructor({ url, timeoutMs = DEFAULT_TIMEOUT_MS }) {
36
+ this.#url = url
37
+ this.#timeoutMs = timeoutMs
38
+ }
39
+
40
+ async #post({ query, variables, timeoutMs }) {
41
+ const controller = new AbortController()
42
+ const timeout = setTimeout(() => controller.abort(), timeoutMs)
43
+ try {
44
+ const response = await fetch(this.#url, {
45
+ method: 'POST',
46
+ headers: { Accept: 'application/json', 'Content-Type': 'application/json' },
47
+ body: JSON.stringify({ query, variables }),
48
+ signal: controller.signal,
49
+ }).catch((error) => {
50
+ if (controller.signal.aborted) throw error
51
+ throw new GraphQLTransportError(`${this.#url} request failed: ${error.message}`, {
52
+ cause: error,
53
+ })
54
+ })
55
+
56
+ if (!response.ok) {
57
+ const message = `${this.#url} returned ${response.status}: ${
58
+ response.statusText || 'Unknown Status Text'
59
+ }. Body: ${await readErrorBody(response)}`
60
+ if (response.status >= SERVER_ERROR_STATUS) throw new GraphQLTransportError(message)
61
+ throw new Error(message)
62
+ }
63
+
64
+ return await response.json()
65
+ } catch (error) {
66
+ if (controller.signal.aborted) throw new GraphQLTimeoutError({ url: this.#url, timeoutMs })
67
+ throw error
68
+ } finally {
69
+ clearTimeout(timeout)
70
+ }
71
+ }
72
+
73
+ async query({ query, variables = Object.create(null), timeoutMs = this.#timeoutMs }) {
74
+ const { data, errors } = await this.#post({ query, variables, timeoutMs })
75
+ if (errors?.length > 0) {
76
+ throw new Error(`Bad graphql response: ${errors.map(({ message }) => message).join('; ')}`)
77
+ }
78
+
79
+ if (!data) throw new Error('Bad graphql response: no data')
80
+ return data
81
+ }
82
+ }
@@ -0,0 +1,342 @@
1
+ import { vendorLib } from '@exodus/sui-lib'
2
+
3
+ import { getPureBcsSchema } from '../vendors/transactions/serializer.js'
4
+
5
+ const { fromBase64, normalizeSuiAddress } = vendorLib.utils
6
+
7
+ const SPECIAL_ADDRESS_REGEX = /0x0{63}([\dA-Fa-f])(?![\dA-Fa-f])/g
8
+ const NO_GAS_OBJECT_ID = `0x${'0'.repeat(64)}`
9
+
10
+ export const toJsonRpcTypeTag = (typeTag) =>
11
+ typeTag.replaceAll(SPECIAL_ADDRESS_REGEX, '0x$1').replaceAll(/,\s*/g, ', ')
12
+
13
+ export const toMoveFunctionKey = ({ package: pkg, module, function: fn }) =>
14
+ `${normalizeSuiAddress(pkg)}::${module}::${fn}`
15
+
16
+ const toOwner = (owner) => {
17
+ switch (owner?.kind) {
18
+ case 'ADDRESS':
19
+ return { AddressOwner: owner.address }
20
+ case 'OBJECT':
21
+ return { ObjectOwner: owner.address }
22
+ case 'SHARED':
23
+ return { Shared: { initial_shared_version: Number(owner.version) } }
24
+ case 'IMMUTABLE':
25
+ return 'Immutable'
26
+ case 'CONSENSUS_ADDRESS':
27
+ return {
28
+ ConsensusAddressOwner: { owner: owner.address, start_version: Number(owner.version) },
29
+ }
30
+ default:
31
+ return { Unknown: owner?.kind ?? null }
32
+ }
33
+ }
34
+
35
+ const toArgument = (argument) => {
36
+ switch (argument?.kind) {
37
+ case 'GAS':
38
+ return 'GasCoin'
39
+ case 'INPUT':
40
+ return { Input: argument.input }
41
+ case 'RESULT':
42
+ return argument.subresult === undefined
43
+ ? { Result: argument.result }
44
+ : { NestedResult: [argument.result, argument.subresult] }
45
+ default:
46
+ return { Unknown: argument?.kind ?? null }
47
+ }
48
+ }
49
+
50
+ const toCommand = (command) => {
51
+ if (command.moveCall) {
52
+ const { package: pkg, module, function: fn, typeArguments, arguments: args } = command.moveCall
53
+ return {
54
+ MoveCall: {
55
+ package: pkg,
56
+ module,
57
+ function: fn,
58
+ ...(typeArguments?.length > 0 && { type_arguments: typeArguments.map(toJsonRpcTypeTag) }),
59
+ arguments: (args ?? []).map(toArgument),
60
+ },
61
+ }
62
+ }
63
+
64
+ if (command.splitCoins) {
65
+ const { coin, amounts = [] } = command.splitCoins
66
+ return { SplitCoins: [toArgument(coin), amounts.map(toArgument)] }
67
+ }
68
+
69
+ if (command.transferObjects) {
70
+ const { objects = [], address } = command.transferObjects
71
+ return { TransferObjects: [objects.map(toArgument), toArgument(address)] }
72
+ }
73
+
74
+ if (command.mergeCoins) {
75
+ const { coin, coinsToMerge = [] } = command.mergeCoins
76
+ return { MergeCoins: [toArgument(coin), coinsToMerge.map(toArgument)] }
77
+ }
78
+
79
+ if (command.makeMoveVector) {
80
+ const { elementType, elements = [] } = command.makeMoveVector
81
+ return {
82
+ MakeMoveVec: [elementType ? toJsonRpcTypeTag(elementType) : null, elements.map(toArgument)],
83
+ }
84
+ }
85
+
86
+ if (command.publish) {
87
+ return { Publish: command.publish.dependencies ?? [] }
88
+ }
89
+
90
+ if (command.upgrade) {
91
+ const { dependencies, package: pkg, ticket } = command.upgrade
92
+ return { Upgrade: [dependencies ?? [], pkg, toArgument(ticket)] }
93
+ }
94
+
95
+ return { Unknown: Object.keys(command) }
96
+ }
97
+
98
+ const getInputTypes = ({ commands, moveFunctionParameters }) => {
99
+ const types = new Map()
100
+ const setType = (argument, type) => {
101
+ if (argument?.kind === 'INPUT' && !types.has(argument.input)) types.set(argument.input, type)
102
+ }
103
+
104
+ for (const command of commands) {
105
+ if (command.splitCoins) {
106
+ ;(command.splitCoins.amounts ?? []).forEach((amount) => setType(amount, 'u64'))
107
+ }
108
+
109
+ if (command.transferObjects) setType(command.transferObjects.address, 'address')
110
+ if (command.moveCall) {
111
+ const parameters = moveFunctionParameters.get(toMoveFunctionKey(command.moveCall)) ?? []
112
+ command.moveCall.arguments?.forEach((argument, index) =>
113
+ setType(argument, parameters[index]?.body)
114
+ )
115
+ }
116
+ }
117
+
118
+ return types
119
+ }
120
+
121
+ const toRawPureInput = (bytes) => ({ type: 'pure', valueType: null, value: [...bytes] })
122
+
123
+ const toPureInput = ({ bytes, type }) => {
124
+ if (typeof type !== 'string') return toRawPureInput(bytes)
125
+
126
+ try {
127
+ return { type: 'pure', valueType: type, value: getPureBcsSchema(type).parse(bytes) }
128
+ } catch {
129
+ return toRawPureInput(bytes)
130
+ }
131
+ }
132
+
133
+ const toInput = ({ input, type }) => {
134
+ switch (input.kind) {
135
+ case 'PURE':
136
+ return toPureInput({ bytes: fromBase64(input.pure), type })
137
+ case 'IMMUTABLE_OR_OWNED':
138
+ return {
139
+ type: 'object',
140
+ objectType: 'immOrOwnedObject',
141
+ objectId: input.objectId,
142
+ version: input.version,
143
+ digest: input.digest,
144
+ }
145
+ case 'SHARED':
146
+ return {
147
+ type: 'object',
148
+ objectType: 'sharedObject',
149
+ objectId: input.objectId,
150
+ initialSharedVersion: input.version,
151
+ mutable: input.mutable,
152
+ }
153
+ case 'RECEIVING':
154
+ return {
155
+ type: 'object',
156
+ objectType: 'receiving',
157
+ objectId: input.objectId,
158
+ version: input.version,
159
+ digest: input.digest,
160
+ }
161
+ default:
162
+ return { type: 'unknown', kind: input.kind }
163
+ }
164
+ }
165
+
166
+ const toTransactionKind = ({ kind, moveFunctionParameters }) => {
167
+ if (kind.kind !== 'PROGRAMMABLE_TRANSACTION') return { kind: kind.kind }
168
+
169
+ const { inputs = [], commands = [] } = kind.programmableTransaction
170
+ const inputTypes = getInputTypes({ commands, moveFunctionParameters })
171
+ return {
172
+ kind: 'ProgrammableTransaction',
173
+ inputs: inputs.map((input, index) => toInput({ input, type: inputTypes.get(index) })),
174
+ transactions: commands.map(toCommand),
175
+ }
176
+ }
177
+
178
+ export const getMoveCalls = (transactionJson) =>
179
+ (transactionJson?.kind?.programmableTransaction?.commands ?? [])
180
+ .map((command) => command.moveCall)
181
+ .filter(Boolean)
182
+
183
+ const toTransactionData = ({ transactionJson, moveFunctionParameters }) => {
184
+ const { sender, gasPayment, kind } = transactionJson
185
+ return {
186
+ messageVersion: 'v1',
187
+ transaction: toTransactionKind({ kind, moveFunctionParameters }),
188
+ sender,
189
+ gasData: {
190
+ payment: (gasPayment.objects ?? []).map(({ objectId, version, digest }) => ({
191
+ objectId,
192
+ version: Number(version),
193
+ digest,
194
+ })),
195
+ owner: gasPayment.owner,
196
+ price: gasPayment.price,
197
+ budget: gasPayment.budget,
198
+ },
199
+ }
200
+ }
201
+
202
+ const toStatus = ({ success, error }) =>
203
+ success
204
+ ? { status: 'success' }
205
+ : { status: 'failure', error: error?.description ?? error?.kind ?? 'unknown' }
206
+
207
+ const toGasObject = (gasObject) => {
208
+ if (!gasObject) {
209
+ return {
210
+ owner: { AddressOwner: NO_GAS_OBJECT_ID },
211
+ reference: {
212
+ objectId: NO_GAS_OBJECT_ID,
213
+ version: 0,
214
+ digest: '11111111111111111111111111111111',
215
+ },
216
+ }
217
+ }
218
+
219
+ return {
220
+ owner: toOwner(gasObject.outputOwner),
221
+ reference: {
222
+ objectId: gasObject.objectId,
223
+ version: Number(gasObject.outputVersion),
224
+ digest: gasObject.outputDigest,
225
+ },
226
+ }
227
+ }
228
+
229
+ const toEffects = (effectsJson) => ({
230
+ messageVersion: 'v1',
231
+ status: toStatus(effectsJson.status),
232
+ executedEpoch: effectsJson.epoch,
233
+ gasUsed: effectsJson.gasUsed,
234
+ transactionDigest: effectsJson.transactionDigest,
235
+ gasObject: toGasObject(effectsJson.gasObject),
236
+ dependencies: effectsJson.dependencies ?? [],
237
+ })
238
+
239
+ const toObjectChange = ({ change, sender, lamportVersion }) => {
240
+ const { objectId, inputState, outputState, idOperation } = change
241
+ const objectType = change.objectType && toJsonRpcTypeTag(change.objectType)
242
+ const inputExists = inputState === 'INPUT_OBJECT_STATE_EXISTS'
243
+
244
+ if (outputState === 'OUTPUT_OBJECT_STATE_ACCUMULATOR_WRITE') return
245
+
246
+ if (outputState === 'OUTPUT_OBJECT_STATE_PACKAGE_WRITE') {
247
+ return {
248
+ type: 'published',
249
+ packageId: objectId,
250
+ version: change.outputVersion,
251
+ digest: change.outputDigest,
252
+ }
253
+ }
254
+
255
+ if (
256
+ idOperation === 'DELETED' ||
257
+ (inputExists && outputState !== 'OUTPUT_OBJECT_STATE_OBJECT_WRITE')
258
+ ) {
259
+ return {
260
+ type: idOperation === 'DELETED' ? 'deleted' : 'wrapped',
261
+ sender,
262
+ objectType,
263
+ objectId,
264
+ version: lamportVersion,
265
+ }
266
+ }
267
+
268
+ const written = {
269
+ sender,
270
+ owner: toOwner(change.outputOwner),
271
+ objectType,
272
+ objectId,
273
+ version: change.outputVersion,
274
+ ...(inputExists && { previousVersion: change.inputVersion }),
275
+ digest: change.outputDigest,
276
+ }
277
+
278
+ return { type: inputExists ? 'mutated' : 'created', ...written }
279
+ }
280
+
281
+ const toObjectChanges = ({ effectsJson, sender }) =>
282
+ (effectsJson.changedObjects ?? [])
283
+ .map((change) => toObjectChange({ change, sender, lamportVersion: effectsJson.lamportVersion }))
284
+ .filter(Boolean)
285
+
286
+ const toBalanceChanges = (balanceChangesJson) =>
287
+ (balanceChangesJson ?? []).map(({ address, coinType, amount }) => ({
288
+ owner: { AddressOwner: address },
289
+ coinType: toJsonRpcTypeTag(coinType),
290
+ amount,
291
+ }))
292
+
293
+ export const toTransactionBlockResponse = ({
294
+ digest,
295
+ transactionJson,
296
+ effects,
297
+ moveFunctionParameters,
298
+ }) => {
299
+ const { effectsJson, balanceChangesJson, timestamp, checkpoint } = effects
300
+ return {
301
+ digest,
302
+ transaction: { data: toTransactionData({ transactionJson, moveFunctionParameters }) },
303
+ effects: toEffects(effectsJson),
304
+ objectChanges: toObjectChanges({ effectsJson, sender: transactionJson.sender }),
305
+ balanceChanges: toBalanceChanges(balanceChangesJson),
306
+ ...(timestamp && { timestampMs: String(Date.parse(timestamp)) }),
307
+ ...(checkpoint && { checkpoint: String(checkpoint.sequenceNumber) }),
308
+ }
309
+ }
310
+
311
+ export const toCoin = (node) => {
312
+ const coinObjectType = toJsonRpcTypeTag(node.contents.type.repr)
313
+ const [, coinType] = coinObjectType.match(/^0x2::coin::Coin<(.+)>$/) ?? []
314
+ if (!coinType) throw new Error(`Unexpected sui coin type ${coinObjectType}`)
315
+
316
+ return {
317
+ coinType,
318
+ coinObjectId: node.address,
319
+ version: String(node.version),
320
+ digest: node.digest,
321
+ balance: node.contents.json.balance,
322
+ previousTransaction: node.previousTransaction?.digest,
323
+ }
324
+ }
325
+
326
+ const getInitialSharedVersion = (owner) => {
327
+ if (owner?.__typename === 'Shared') return String(owner.initialSharedVersion)
328
+ if (owner?.__typename === 'ConsensusAddressOwner') return String(owner.startVersion)
329
+ return null
330
+ }
331
+
332
+ export const toObjectRef = (object) => ({
333
+ objectId: object.address,
334
+ digest: object.digest,
335
+ version: String(object.version),
336
+ initialSharedVersion: getInitialSharedVersion(object.owner),
337
+ })
338
+
339
+ export const toSimulationEffects = (effectsJson) => ({
340
+ status: toStatus(effectsJson.status),
341
+ gasUsed: effectsJson.gasUsed,
342
+ })
@@ -0,0 +1,166 @@
1
+ const TRANSACTION_EFFECTS_FIELDS = `
2
+ digest
3
+ timestamp
4
+ checkpoint { sequenceNumber }
5
+ effectsJson
6
+ balanceChangesJson
7
+ `
8
+
9
+ export const MULTI_GET_TRANSACTIONS = `
10
+ query ($digests: [String!]!) {
11
+ multiGetTransactions(keys: $digests) {
12
+ digest
13
+ transactionJson
14
+ effects { ${TRANSACTION_EFFECTS_FIELDS} }
15
+ }
16
+ }
17
+ `
18
+
19
+ export const EXECUTE_TRANSACTION = `
20
+ mutation ($transactionDataBcs: Base64!, $signatures: [Base64!]!) {
21
+ executeTransaction(transactionDataBcs: $transactionDataBcs, signatures: $signatures) {
22
+ effects {
23
+ ${TRANSACTION_EFFECTS_FIELDS}
24
+ transaction { digest transactionJson }
25
+ }
26
+ }
27
+ }
28
+ `
29
+
30
+ export const SIMULATE_TRANSACTION = `
31
+ query ($transaction: JSON!, $checksEnabled: Boolean) {
32
+ simulateTransaction(transaction: $transaction, checksEnabled: $checksEnabled) {
33
+ effects { effectsJson }
34
+ }
35
+ }
36
+ `
37
+
38
+ export const OWNED_OBJECTS = `
39
+ query ($owner: SuiAddress!, $type: String!, $cursor: String) {
40
+ address(address: $owner) {
41
+ objects(first: 50, after: $cursor, filter: { type: $type }) {
42
+ pageInfo { hasNextPage endCursor }
43
+ nodes {
44
+ address
45
+ version
46
+ digest
47
+ previousTransaction { digest }
48
+ contents { type { repr } json }
49
+ }
50
+ }
51
+ }
52
+ }
53
+ `
54
+
55
+ export const BALANCE = `
56
+ query ($owner: SuiAddress!, $coinType: String!) {
57
+ address(address: $owner) {
58
+ balance(coinType: $coinType) { coinType { repr } totalBalance }
59
+ }
60
+ }
61
+ `
62
+
63
+ export const ALL_BALANCES = `
64
+ query ($owner: SuiAddress!, $cursor: String) {
65
+ address(address: $owner) {
66
+ balances(first: 50, after: $cursor) {
67
+ pageInfo { hasNextPage endCursor }
68
+ nodes { coinType { repr } totalBalance addressBalance }
69
+ }
70
+ }
71
+ }
72
+ `
73
+
74
+ export const MULTI_GET_OBJECTS = `
75
+ query ($keys: [ObjectKey!]!) {
76
+ multiGetObjects(keys: $keys) {
77
+ address
78
+ version
79
+ digest
80
+ owner {
81
+ __typename
82
+ ... on Shared { initialSharedVersion }
83
+ ... on ConsensusAddressOwner { startVersion }
84
+ }
85
+ }
86
+ }
87
+ `
88
+
89
+ export const MOVE_FUNCTION_PARAMETERS = `
90
+ query ($package: SuiAddress!, $module: String!, $function: String!) {
91
+ package(address: $package) {
92
+ module(name: $module) {
93
+ function(name: $function) { parameters { signature } }
94
+ }
95
+ }
96
+ }
97
+ `
98
+
99
+ export const LATEST_EPOCH = `
100
+ query {
101
+ epoch {
102
+ epochId
103
+ referenceGasPrice
104
+ systemState {
105
+ startMs: extract(path: "epoch_start_timestamp_ms") { json }
106
+ durationMs: extract(path: "parameters.epoch_duration_ms") { json }
107
+ }
108
+ }
109
+ }
110
+ `
111
+
112
+ export const ACTIVE_VALIDATOR_POOLS = `
113
+ query ($cursor: String) {
114
+ epoch {
115
+ epochId
116
+ validatorSet {
117
+ inactivePoolsId: contents { extract(path: "inactive_validators.id") { json } }
118
+ activeValidators(first: 50, after: $cursor) {
119
+ pageInfo { hasNextPage endCursor }
120
+ nodes {
121
+ contents {
122
+ validatorAddress: extract(path: "metadata.sui_address") { json }
123
+ stakingPool: extract(path: "staking_pool") { json }
124
+ }
125
+ }
126
+ }
127
+ }
128
+ }
129
+ }
130
+ `
131
+
132
+ export const INACTIVE_VALIDATOR_WRAPPER = `
133
+ query ($table: SuiAddress!, $poolId: Base64!) {
134
+ address(address: $table) {
135
+ dynamicField(name: { type: "0x2::object::ID", bcs: $poolId }) {
136
+ value { ... on MoveValue { json } }
137
+ }
138
+ }
139
+ }
140
+ `
141
+
142
+ export const VERSIONED_VALIDATOR = `
143
+ query ($versioned: SuiAddress!, $version: String!) {
144
+ address(address: $versioned) {
145
+ dynamicField(name: { literal: $version }) {
146
+ value {
147
+ ... on MoveValue {
148
+ validatorAddress: extract(path: "metadata.sui_address") { json }
149
+ stakingPool: extract(path: "staking_pool") { json }
150
+ }
151
+ }
152
+ }
153
+ }
154
+ }
155
+ `
156
+
157
+ export const EXCHANGE_RATES = `
158
+ query ($table: SuiAddress!, $keys: [DynamicFieldName!]!) {
159
+ address(address: $table) {
160
+ multiGetDynamicFields(keys: $keys) {
161
+ name { json }
162
+ value { ... on MoveValue { json } }
163
+ }
164
+ }
165
+ }
166
+ `
package/src/index.js CHANGED
@@ -1,4 +1,5 @@
1
1
  export { SuiApi } from './api.js'
2
+ export { SuiBroadcastError } from './broadcast-error.js'
2
3
 
3
4
  export { getFeeFactory } from './get-fee.js'
4
5
  export { createBasicAccountState } from './basic-account-state.js'