@exodus/sui-api 1.3.1 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +9 -0
- package/package.json +3 -7
- package/src/api.js +401 -151
- package/src/broadcast-error.js +8 -0
- package/src/create-unsigned-tx.js +2 -2
- package/src/get-fee-async.js +1 -1
- package/src/graphql/graphql-client.js +82 -0
- package/src/graphql/json-rpc-shapes.js +342 -0
- package/src/graphql/queries.js +166 -0
- package/src/index.js +1 -0
- package/src/staking/delegated-stakes.js +66 -0
- package/src/staking/staking-transactions.js +10 -1
- package/src/tx-send.js +51 -2
- package/src/vendors/transactions/resolve.js +2 -3
- package/src/vendors/{experimental/transports/json-rpc-resolver.js → transactions/resolver.js} +18 -56
- package/src/vendors/client/client.js +0 -680
- package/src/vendors/client/errors.js +0 -38
- package/src/vendors/client/http-transport.js +0 -71
- package/src/vendors/client/index.js +0 -1
- package/src/vendors/experimental/cache.js +0 -90
- package/src/vendors/experimental/client.js +0 -27
- package/src/vendors/experimental/core.js +0 -11
- package/src/vendors/experimental/transports/jsonRPC.js +0 -106
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Transaction } from '../vendors/transactions/index.js'
|
|
2
|
+
import { getPureBcsSchema } from '../vendors/transactions/serializer.js'
|
|
2
3
|
import {
|
|
3
4
|
ADD_STAKE_FUNCTION,
|
|
4
5
|
ADD_STAKE_TARGET,
|
|
@@ -49,6 +50,14 @@ const getInput = ({ inputs, argument }) =>
|
|
|
49
50
|
? inputs[argument.Input]
|
|
50
51
|
: undefined
|
|
51
52
|
|
|
53
|
+
const ADDRESS_LENGTH = 32
|
|
54
|
+
|
|
55
|
+
const getAddressValue = (input) => {
|
|
56
|
+
if (input?.valueType !== null) return input?.value
|
|
57
|
+
if (input.value.length !== ADDRESS_LENGTH) return
|
|
58
|
+
return getPureBcsSchema('address').parse(Uint8Array.from(input.value))
|
|
59
|
+
}
|
|
60
|
+
|
|
52
61
|
const getSplitAmount = ({ inputs, commands, argument }) => {
|
|
53
62
|
const resultIndex = argument?.NestedResult?.[0] ?? argument?.Result
|
|
54
63
|
const amountArgument = commands[resultIndex]?.SplitCoins?.[1]?.[0]
|
|
@@ -74,7 +83,7 @@ export const parseStakingCommands = (programmableTransaction) => {
|
|
|
74
83
|
const amount = getSplitAmount({ inputs, commands, argument: coinArgument })
|
|
75
84
|
return {
|
|
76
85
|
operation,
|
|
77
|
-
validator: getInput({ inputs, argument: validatorArgument })
|
|
86
|
+
validator: getAddressValue(getInput({ inputs, argument: validatorArgument })),
|
|
78
87
|
...(amount && { amount }),
|
|
79
88
|
}
|
|
80
89
|
}
|
package/src/tx-send.js
CHANGED
|
@@ -1,11 +1,48 @@
|
|
|
1
1
|
import { UtxoCollection } from '@exodus/models'
|
|
2
2
|
import { coinTypes, objectTypes, toCoinType } from '@exodus/sui-lib'
|
|
3
3
|
import assert from 'minimalistic-assert'
|
|
4
|
+
import ms from 'ms'
|
|
4
5
|
|
|
6
|
+
import { SuiBroadcastError } from './broadcast-error.js'
|
|
5
7
|
import { applyStakingTx } from './staking/staking-info.js'
|
|
6
8
|
import { parseStakingCommands } from './staking/staking-transactions.js'
|
|
7
9
|
import { getFeeAmount } from './transform-tx.js'
|
|
8
10
|
|
|
11
|
+
const LOOKUP_ATTEMPTS = 5
|
|
12
|
+
const LOOKUP_DELAY_MS = ms('3s')
|
|
13
|
+
|
|
14
|
+
const wait = (delayMs) => new Promise((resolve) => setTimeout(resolve, delayMs))
|
|
15
|
+
|
|
16
|
+
const findExecutedTransaction = async ({ serverApi, digest, lookupAttempts, lookupDelayMs }) => {
|
|
17
|
+
for (let attempt = 0; attempt < lookupAttempts; attempt++) {
|
|
18
|
+
await wait(lookupDelayMs)
|
|
19
|
+
const [transaction] = await serverApi.getTransactions({ txIds: [digest] }).catch(() => [])
|
|
20
|
+
if (transaction) return transaction
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const broadcastTransaction = async ({
|
|
25
|
+
asset,
|
|
26
|
+
plainTx,
|
|
27
|
+
serverApi,
|
|
28
|
+
lookupAttempts,
|
|
29
|
+
lookupDelayMs,
|
|
30
|
+
}) => {
|
|
31
|
+
try {
|
|
32
|
+
return await asset.baseAsset.api.broadcastTx(plainTx)
|
|
33
|
+
} catch (error) {
|
|
34
|
+
if (!(error instanceof SuiBroadcastError)) throw error
|
|
35
|
+
const transaction = await findExecutedTransaction({
|
|
36
|
+
serverApi,
|
|
37
|
+
digest: error.digest,
|
|
38
|
+
lookupAttempts,
|
|
39
|
+
lookupDelayMs,
|
|
40
|
+
})
|
|
41
|
+
if (!transaction) throw error
|
|
42
|
+
return transaction
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
9
46
|
const deriveNewUtxos = ({ mutatedObject, balanceChange, deletedObjects, utxos, asset }) => {
|
|
10
47
|
const utxoArray = utxos.toArray()
|
|
11
48
|
|
|
@@ -252,7 +289,13 @@ const getStateChanges = async ({ aci, asset, walletAccount, result }) => {
|
|
|
252
289
|
}
|
|
253
290
|
}
|
|
254
291
|
|
|
255
|
-
export const txSendFactory = ({
|
|
292
|
+
export const txSendFactory = ({
|
|
293
|
+
assetClientInterface: aci,
|
|
294
|
+
serverApi,
|
|
295
|
+
createTx,
|
|
296
|
+
lookupAttempts = LOOKUP_ATTEMPTS,
|
|
297
|
+
lookupDelayMs = LOOKUP_DELAY_MS,
|
|
298
|
+
}) => {
|
|
256
299
|
assert(aci, 'assetClientInterface is required')
|
|
257
300
|
assert(serverApi, 'serverApi is required')
|
|
258
301
|
assert(createTx, 'createTx is required')
|
|
@@ -268,7 +311,13 @@ export const txSendFactory = ({ assetClientInterface: aci, serverApi, createTx }
|
|
|
268
311
|
walletAccount,
|
|
269
312
|
})
|
|
270
313
|
|
|
271
|
-
const result = await
|
|
314
|
+
const result = await broadcastTransaction({
|
|
315
|
+
asset,
|
|
316
|
+
plainTx,
|
|
317
|
+
serverApi,
|
|
318
|
+
lookupAttempts,
|
|
319
|
+
lookupDelayMs,
|
|
320
|
+
})
|
|
272
321
|
|
|
273
322
|
const { accountStateData: newData, txLogsByAssetName } = await getStateChanges({
|
|
274
323
|
asset,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { vendorLib } from '@exodus/sui-lib'
|
|
2
2
|
|
|
3
|
-
import { suiClientResolveTransactionPlugin } from '../experimental/transports/json-rpc-resolver.js'
|
|
4
3
|
import { Inputs } from './Inputs.js'
|
|
4
|
+
import { suiClientResolveTransactionPlugin } from './resolver.js'
|
|
5
5
|
|
|
6
6
|
const { bcs } = vendorLib
|
|
7
7
|
|
|
@@ -33,8 +33,7 @@ async function resolveTransactionPlugin(transactionData, options, next) {
|
|
|
33
33
|
}
|
|
34
34
|
|
|
35
35
|
const client = getClient(options)
|
|
36
|
-
const plugin =
|
|
37
|
-
client.core?.resolveTransactionPlugin() ?? suiClientResolveTransactionPlugin(client)
|
|
36
|
+
const plugin = suiClientResolveTransactionPlugin(client)
|
|
38
37
|
return plugin(transactionData, options, async () => {
|
|
39
38
|
await validate(transactionData)
|
|
40
39
|
await next()
|
package/src/vendors/{experimental/transports/json-rpc-resolver.js → transactions/resolver.js}
RENAMED
|
@@ -2,14 +2,10 @@
|
|
|
2
2
|
/* eslint-disable no-return-await */
|
|
3
3
|
import { vendorLib } from '@exodus/sui-lib'
|
|
4
4
|
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
|
|
9
|
-
isTxContext,
|
|
10
|
-
normalizedTypeToMoveTypeSignature,
|
|
11
|
-
} from '../../transactions/serializer.js'
|
|
12
|
-
import { parse } from '../../valibot.js'
|
|
5
|
+
import { parse } from '../valibot.js'
|
|
6
|
+
import { ObjectRef } from './data/internal.js'
|
|
7
|
+
import { Inputs } from './Inputs.js'
|
|
8
|
+
import { getPureBcsSchema, isTxContext } from './serializer.js'
|
|
13
9
|
|
|
14
10
|
const { normalizeSuiAddress, normalizeSuiObjectId, SUI_TYPE_ARG } = vendorLib.utils
|
|
15
11
|
|
|
@@ -18,6 +14,7 @@ const { chunk } = vendorLib.utils
|
|
|
18
14
|
const MAX_OBJECTS_PER_FETCH = 50
|
|
19
15
|
const GAS_SAFE_OVERHEAD = BigInt(1000)
|
|
20
16
|
const MAX_GAS = 5e10
|
|
17
|
+
const MAX_GAS_OBJECTS = 256
|
|
21
18
|
|
|
22
19
|
function suiClientResolveTransactionPlugin(client) {
|
|
23
20
|
return async function resolveTransactionData(transactionData, options, next) {
|
|
@@ -35,7 +32,7 @@ function suiClientResolveTransactionPlugin(client) {
|
|
|
35
32
|
|
|
36
33
|
async function setGasPrice(transactionData, client) {
|
|
37
34
|
if (!transactionData.gasConfig.price) {
|
|
38
|
-
transactionData.gasConfig.price =
|
|
35
|
+
transactionData.gasConfig.price = await client.getReferenceGasPrice()
|
|
39
36
|
}
|
|
40
37
|
}
|
|
41
38
|
|
|
@@ -44,7 +41,7 @@ async function setGasBudget(transactionData, client) {
|
|
|
44
41
|
return
|
|
45
42
|
}
|
|
46
43
|
|
|
47
|
-
const dryRunResult = await client.
|
|
44
|
+
const dryRunResult = await client.dryRunTransaction({
|
|
48
45
|
transactionBlock: transactionData.build({
|
|
49
46
|
overrides: {
|
|
50
47
|
gasData: {
|
|
@@ -79,7 +76,7 @@ async function setGasPayment(transactionData, client) {
|
|
|
79
76
|
owner: transactionData.gasConfig.owner || transactionData.sender,
|
|
80
77
|
coinType: SUI_TYPE_ARG,
|
|
81
78
|
})
|
|
82
|
-
const paymentCoins = coins
|
|
79
|
+
const paymentCoins = coins
|
|
83
80
|
.filter((coin) => {
|
|
84
81
|
const matchingInput = transactionData.inputs.find((input) => {
|
|
85
82
|
if (input.Object?.ImmOrOwnedObject) {
|
|
@@ -90,6 +87,8 @@ async function setGasPayment(transactionData, client) {
|
|
|
90
87
|
})
|
|
91
88
|
return !matchingInput
|
|
92
89
|
})
|
|
90
|
+
.sort((a, b) => (BigInt(b.balance) > BigInt(a.balance) ? 1 : -1))
|
|
91
|
+
.slice(0, MAX_GAS_OBJECTS)
|
|
93
92
|
.map((coin) => ({
|
|
94
93
|
objectId: coin.coinObjectId,
|
|
95
94
|
digest: coin.digest,
|
|
@@ -117,47 +116,13 @@ async function resolveObjectReferences(transactionData, client) {
|
|
|
117
116
|
]
|
|
118
117
|
const objectChunks = dedupedIds.length > 0 ? chunk(dedupedIds, MAX_OBJECTS_PER_FETCH) : []
|
|
119
118
|
const resolvedChunks = await Promise.all(
|
|
120
|
-
objectChunks.map((chunk2) =>
|
|
121
|
-
client.multiGetObjects({
|
|
122
|
-
ids: chunk2,
|
|
123
|
-
options: { showOwner: true },
|
|
124
|
-
})
|
|
125
|
-
)
|
|
126
|
-
)
|
|
127
|
-
const resolved = resolvedChunks.flat()
|
|
128
|
-
const responsesById = new Map(
|
|
129
|
-
dedupedIds.map((id, index) => {
|
|
130
|
-
return [id, resolved[index]]
|
|
131
|
-
})
|
|
119
|
+
objectChunks.map((chunk2) => client.getObjectRefs({ ids: chunk2 }))
|
|
132
120
|
)
|
|
133
|
-
const
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
throw new Error(`The following input objects are invalid: ${invalidObjects.join(', ')}`)
|
|
121
|
+
const objects = resolvedChunks.flat()
|
|
122
|
+
const missing = dedupedIds.filter((id, index) => !objects[index])
|
|
123
|
+
if (missing.length > 0) {
|
|
124
|
+
throw new Error(`The following input objects are invalid: ${missing.join(', ')}`)
|
|
138
125
|
}
|
|
139
|
-
|
|
140
|
-
const objects = resolved.map((object) => {
|
|
141
|
-
if (object.error || !object.data) {
|
|
142
|
-
throw new Error(`Failed to fetch object: ${object.error}`)
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
const owner = object.data.owner
|
|
146
|
-
const initialSharedVersion =
|
|
147
|
-
owner && typeof owner === 'object'
|
|
148
|
-
? 'Shared' in owner
|
|
149
|
-
? owner.Shared.initial_shared_version
|
|
150
|
-
: 'ConsensusAddressOwner' in owner
|
|
151
|
-
? owner.ConsensusAddressOwner.start_version
|
|
152
|
-
: null
|
|
153
|
-
: null
|
|
154
|
-
return {
|
|
155
|
-
objectId: object.data.objectId,
|
|
156
|
-
digest: object.data.digest,
|
|
157
|
-
version: object.data.version,
|
|
158
|
-
initialSharedVersion,
|
|
159
|
-
}
|
|
160
|
-
})
|
|
161
126
|
const objectsById = new Map(
|
|
162
127
|
dedupedIds.map((id, index) => {
|
|
163
128
|
return [id, objects[index]]
|
|
@@ -228,15 +193,12 @@ async function normalizeInputs(transactionData, client) {
|
|
|
228
193
|
await Promise.all(
|
|
229
194
|
[...moveFunctionsToResolve].map(async (functionName) => {
|
|
230
195
|
const [packageId, moduleId, functionId] = functionName.split('::')
|
|
231
|
-
const
|
|
196
|
+
const parameters = await client.getMoveFunctionParameters({
|
|
232
197
|
package: packageId,
|
|
233
198
|
module: moduleId,
|
|
234
199
|
function: functionId,
|
|
235
200
|
})
|
|
236
|
-
moveFunctionParameters.set(
|
|
237
|
-
functionName,
|
|
238
|
-
def.parameters.map((param) => normalizedTypeToMoveTypeSignature(param))
|
|
239
|
-
)
|
|
201
|
+
moveFunctionParameters.set(functionName, parameters)
|
|
240
202
|
})
|
|
241
203
|
)
|
|
242
204
|
}
|
|
@@ -346,7 +308,7 @@ function isReceivingType(type) {
|
|
|
346
308
|
}
|
|
347
309
|
|
|
348
310
|
return (
|
|
349
|
-
type.body.datatype.package === '0x2' &&
|
|
311
|
+
normalizeSuiAddress(type.body.datatype.package) === normalizeSuiAddress('0x2') &&
|
|
350
312
|
type.body.datatype.module === 'transfer' &&
|
|
351
313
|
type.body.datatype.type === 'Receiving'
|
|
352
314
|
)
|