@exodus/sui-api 0.1.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.
Files changed (44) hide show
  1. package/README.md +20 -0
  2. package/package.json +53 -0
  3. package/src/api.js +198 -0
  4. package/src/balances.js +22 -0
  5. package/src/basic-account-state.js +11 -0
  6. package/src/create-unsigned-tx.js +60 -0
  7. package/src/get-fee-async.js +62 -0
  8. package/src/get-fee.js +10 -0
  9. package/src/index.js +9 -0
  10. package/src/sui-no-history-monitor.js +277 -0
  11. package/src/transform-tx.js +100 -0
  12. package/src/tx-send.js +249 -0
  13. package/src/vendors/client/client.js +891 -0
  14. package/src/vendors/client/errors.js +38 -0
  15. package/src/vendors/client/http-transport.js +108 -0
  16. package/src/vendors/client/index.js +1 -0
  17. package/src/vendors/client/rpc-websocket-client.js +178 -0
  18. package/src/vendors/experimental/cache.js +89 -0
  19. package/src/vendors/experimental/client.js +27 -0
  20. package/src/vendors/experimental/core.js +105 -0
  21. package/src/vendors/experimental/errors.js +32 -0
  22. package/src/vendors/experimental/index.js +5 -0
  23. package/src/vendors/experimental/mvr.js +443 -0
  24. package/src/vendors/experimental/transports/json-rpc-resolver.js +359 -0
  25. package/src/vendors/experimental/transports/jsonRPC.js +504 -0
  26. package/src/vendors/experimental/transports/utils.js +90 -0
  27. package/src/vendors/transactions/Arguments.js +22 -0
  28. package/src/vendors/transactions/Commands.js +108 -0
  29. package/src/vendors/transactions/Inputs.js +59 -0
  30. package/src/vendors/transactions/ObjectCache.js +272 -0
  31. package/src/vendors/transactions/Transaction.js +843 -0
  32. package/src/vendors/transactions/TransactionData.js +293 -0
  33. package/src/vendors/transactions/data/internal.js +218 -0
  34. package/src/vendors/transactions/data/v1.js +538 -0
  35. package/src/vendors/transactions/data/v2.js +119 -0
  36. package/src/vendors/transactions/hash.js +12 -0
  37. package/src/vendors/transactions/index.js +1 -0
  38. package/src/vendors/transactions/object.js +22 -0
  39. package/src/vendors/transactions/plugins/NamedPackagesPlugin.js +49 -0
  40. package/src/vendors/transactions/pure.js +40 -0
  41. package/src/vendors/transactions/resolve.js +95 -0
  42. package/src/vendors/transactions/serializer.js +203 -0
  43. package/src/vendors/transactions/utils.js +67 -0
  44. package/src/vendors/valibot.js +7920 -0
@@ -0,0 +1,293 @@
1
+ /* eslint-disable @exodus/mutable/no-param-reassign-prop-only */
2
+ import { vendorLib } from '@exodus/sui-lib'
3
+
4
+ import { parse } from '../valibot.js'
5
+ import { TransactionData } from './data/internal.js'
6
+ import { transactionDataFromV1 } from './data/v1.js'
7
+ import { hashTypedData } from './hash.js'
8
+
9
+ const { bcs } = vendorLib
10
+
11
+ const { toBase58, normalizeSuiAddress } = vendorLib.utils
12
+
13
+ function prepareSuiAddress(address) {
14
+ return normalizeSuiAddress(address).replace('0x', '')
15
+ }
16
+
17
+ class TransactionDataBuilder {
18
+ constructor(clone) {
19
+ this.version = 2
20
+ this.sender = clone?.sender ?? null
21
+ this.expiration = clone?.expiration ?? null
22
+ this.inputs = clone?.inputs ?? []
23
+ this.commands = clone?.commands ?? []
24
+ this.gasData = clone?.gasData ?? {
25
+ budget: null,
26
+ price: null,
27
+ owner: null,
28
+ payment: null,
29
+ }
30
+ }
31
+
32
+ static fromKindBytes(bytes) {
33
+ const kind = bcs.TransactionKind.parse(bytes)
34
+ const programmableTx = kind.ProgrammableTransaction
35
+ if (!programmableTx) {
36
+ throw new Error('Unable to deserialize from bytes.')
37
+ }
38
+
39
+ return TransactionDataBuilder.restore({
40
+ version: 2,
41
+ sender: null,
42
+ expiration: null,
43
+ gasData: {
44
+ budget: null,
45
+ owner: null,
46
+ payment: null,
47
+ price: null,
48
+ },
49
+ inputs: programmableTx.inputs,
50
+ commands: programmableTx.commands,
51
+ })
52
+ }
53
+
54
+ static fromBytes(bytes) {
55
+ const rawData = bcs.TransactionData.parse(bytes)
56
+ const data = rawData?.V1
57
+ const programmableTx = data.kind.ProgrammableTransaction
58
+ if (!data || !programmableTx) {
59
+ throw new Error('Unable to deserialize from bytes.')
60
+ }
61
+
62
+ return TransactionDataBuilder.restore({
63
+ version: 2,
64
+ sender: data.sender,
65
+ expiration: data.expiration,
66
+ gasData: data.gasData,
67
+ inputs: programmableTx.inputs,
68
+ commands: programmableTx.commands,
69
+ })
70
+ }
71
+
72
+ static restore(data) {
73
+ if (data.version === 2) {
74
+ return new TransactionDataBuilder(parse(TransactionData, data))
75
+ }
76
+
77
+ return new TransactionDataBuilder(parse(TransactionData, transactionDataFromV1(data)))
78
+ }
79
+
80
+ /**
81
+ * Generate transaction digest.
82
+ *
83
+ * @param bytes BCS serialized transaction data
84
+ * @returns transaction digest.
85
+ */
86
+ static getDigestFromBytes(bytes) {
87
+ const hash = hashTypedData('TransactionData', bytes)
88
+ return toBase58(hash)
89
+ }
90
+
91
+ // @deprecated use gasData instead
92
+ get gasConfig() {
93
+ return this.gasData
94
+ }
95
+
96
+ // @deprecated use gasData instead
97
+ set gasConfig(value) {
98
+ this.gasData = value
99
+ }
100
+
101
+ build({ maxSizeBytes = Infinity, overrides, onlyTransactionKind } = Object.create(null)) {
102
+ const inputs = this.inputs
103
+ const commands = this.commands
104
+ const kind = {
105
+ ProgrammableTransaction: {
106
+ inputs,
107
+ commands,
108
+ },
109
+ }
110
+ if (onlyTransactionKind) {
111
+ return bcs.TransactionKind.serialize(kind, { maxSize: maxSizeBytes }).toBytes()
112
+ }
113
+
114
+ const expiration = overrides?.expiration ?? this.expiration
115
+ const sender = overrides?.sender ?? this.sender
116
+ const gasData = { ...this.gasData, ...overrides?.gasConfig, ...overrides?.gasData }
117
+ if (!sender) {
118
+ throw new Error('Missing transaction sender')
119
+ }
120
+
121
+ if (!gasData.budget) {
122
+ throw new Error('Missing gas budget')
123
+ }
124
+
125
+ if (!gasData.payment) {
126
+ throw new Error('Missing gas payment')
127
+ }
128
+
129
+ if (!gasData.price) {
130
+ throw new Error('Missing gas price')
131
+ }
132
+
133
+ const transactionData = {
134
+ sender: prepareSuiAddress(sender),
135
+ expiration: expiration || { None: true },
136
+ gasData: {
137
+ payment: gasData.payment,
138
+ owner: prepareSuiAddress(this.gasData.owner ?? sender),
139
+ price: BigInt(gasData.price),
140
+ budget: BigInt(gasData.budget),
141
+ },
142
+ kind: {
143
+ ProgrammableTransaction: {
144
+ inputs,
145
+ commands,
146
+ },
147
+ },
148
+ }
149
+ return bcs.TransactionData.serialize(
150
+ { V1: transactionData },
151
+ { maxSize: maxSizeBytes }
152
+ ).toBytes()
153
+ }
154
+
155
+ addInput(type, arg) {
156
+ const index = this.inputs.length
157
+ this.inputs.push(arg)
158
+ return { Input: index, type, $kind: 'Input' }
159
+ }
160
+
161
+ getInputUses(index, fn) {
162
+ this.mapArguments((arg, command) => {
163
+ if (arg.$kind === 'Input' && arg.Input === index) {
164
+ fn(arg, command)
165
+ }
166
+
167
+ return arg
168
+ })
169
+ }
170
+
171
+ mapCommandArguments(index, fn) {
172
+ const command = this.commands[index]
173
+ switch (command.$kind) {
174
+ case 'MoveCall':
175
+ command.MoveCall.arguments = command.MoveCall.arguments.map((arg) =>
176
+ fn(arg, command, index)
177
+ )
178
+ break
179
+ case 'TransferObjects':
180
+ command.TransferObjects.objects = command.TransferObjects.objects.map((arg) =>
181
+ fn(arg, command, index)
182
+ )
183
+ command.TransferObjects.address = fn(command.TransferObjects.address, command, index)
184
+ break
185
+ case 'SplitCoins':
186
+ command.SplitCoins.coin = fn(command.SplitCoins.coin, command, index)
187
+ command.SplitCoins.amounts = command.SplitCoins.amounts.map((arg) =>
188
+ fn(arg, command, index)
189
+ )
190
+ break
191
+ case 'MergeCoins':
192
+ command.MergeCoins.destination = fn(command.MergeCoins.destination, command, index)
193
+ command.MergeCoins.sources = command.MergeCoins.sources.map((arg) =>
194
+ fn(arg, command, index)
195
+ )
196
+ break
197
+ case 'MakeMoveVec':
198
+ command.MakeMoveVec.elements = command.MakeMoveVec.elements.map((arg) =>
199
+ fn(arg, command, index)
200
+ )
201
+ break
202
+ case 'Upgrade':
203
+ command.Upgrade.ticket = fn(command.Upgrade.ticket, command, index)
204
+ break
205
+ case '$Intent':
206
+ const inputs = command.$Intent.inputs
207
+ command.$Intent.inputs = Object.create(null)
208
+ for (const [key, value] of Object.entries(inputs)) {
209
+ command.$Intent.inputs[key] = Array.isArray(value)
210
+ ? value.map((arg) => fn(arg, command, index))
211
+ : fn(value, command, index)
212
+ }
213
+
214
+ break
215
+ case 'Publish':
216
+ break
217
+ default:
218
+ throw new Error(`Unexpected transaction kind: ${command.$kind}`)
219
+ }
220
+ }
221
+
222
+ mapArguments(fn) {
223
+ for (const commandIndex of this.commands.keys()) {
224
+ this.mapCommandArguments(commandIndex, fn)
225
+ }
226
+ }
227
+
228
+ replaceCommand(index, replacement, resultIndex = index) {
229
+ if (!Array.isArray(replacement)) {
230
+ this.commands[index] = replacement
231
+ return
232
+ }
233
+
234
+ const sizeDiff = replacement.length - 1
235
+ this.commands.splice(index, 1, ...replacement)
236
+ if (sizeDiff !== 0) {
237
+ this.mapArguments((arg, _command, commandIndex) => {
238
+ if (commandIndex < index + replacement.length) {
239
+ return arg
240
+ }
241
+
242
+ switch (arg.$kind) {
243
+ case 'Result':
244
+ if (arg.Result === index) {
245
+ arg.Result = resultIndex
246
+ }
247
+
248
+ if (arg.Result > index) {
249
+ arg.Result += sizeDiff
250
+ }
251
+
252
+ break
253
+ case 'NestedResult':
254
+ if (arg.NestedResult[0] === index) {
255
+ arg.NestedResult[0] = resultIndex
256
+ }
257
+
258
+ if (arg.NestedResult[0] > index) {
259
+ arg.NestedResult[0] += sizeDiff
260
+ }
261
+
262
+ break
263
+ }
264
+
265
+ return arg
266
+ })
267
+ }
268
+ }
269
+
270
+ getDigest() {
271
+ const bytes = this.build({ onlyTransactionKind: false })
272
+ return TransactionDataBuilder.getDigestFromBytes(bytes)
273
+ }
274
+
275
+ snapshot() {
276
+ return parse(TransactionData, this)
277
+ }
278
+
279
+ shallowClone() {
280
+ return new TransactionDataBuilder({
281
+ version: this.version,
282
+ sender: this.sender,
283
+ expiration: this.expiration,
284
+ gasData: {
285
+ ...this.gasData,
286
+ },
287
+ inputs: [...this.inputs],
288
+ commands: [...this.commands],
289
+ })
290
+ }
291
+ }
292
+ export { TransactionDataBuilder }
293
+ // # sourceMappingURL=TransactionData.js.map
@@ -0,0 +1,218 @@
1
+ import { vendorLib } from '@exodus/sui-lib'
2
+
3
+ import {
4
+ array,
5
+ boolean,
6
+ check,
7
+ integer,
8
+ lazy,
9
+ literal,
10
+ nullable,
11
+ nullish,
12
+ number,
13
+ object,
14
+ optional,
15
+ pipe,
16
+ record,
17
+ string,
18
+ transform,
19
+ tuple,
20
+ union,
21
+ unknown,
22
+ } from '../../valibot.js'
23
+
24
+ const { isValidSuiAddress, normalizeSuiAddress } = vendorLib.utils
25
+
26
+ function safeEnum(options) {
27
+ const unionOptions = Object.entries(options).map(([key, value]) => object({ [key]: value }))
28
+ return pipe(
29
+ union(unionOptions),
30
+ transform((value) => ({
31
+ ...value,
32
+ $kind: Object.keys(value)[0],
33
+ }))
34
+ )
35
+ }
36
+
37
+ const SuiAddress = pipe(
38
+ string(),
39
+ transform((value) => normalizeSuiAddress(value)),
40
+ check(isValidSuiAddress)
41
+ )
42
+ const ObjectID = SuiAddress
43
+ const BCSBytes = string()
44
+ const JsonU64 = pipe(
45
+ union([string(), pipe(number(), integer())]),
46
+ check((val) => {
47
+ try {
48
+ BigInt(val)
49
+ return BigInt(val) >= 0 && BigInt(val) <= BigInt(18_446_744_073_709_551_615)
50
+ } catch {
51
+ return false
52
+ }
53
+ }, 'Invalid u64')
54
+ )
55
+ const ObjectRef = object({
56
+ objectId: SuiAddress,
57
+ version: JsonU64,
58
+ digest: string(),
59
+ })
60
+ const Argument = pipe(
61
+ union([
62
+ object({ GasCoin: literal(true) }),
63
+ object({ Input: pipe(number(), integer()), type: optional(literal('pure')) }),
64
+ object({ Input: pipe(number(), integer()), type: optional(literal('object')) }),
65
+ object({ Result: pipe(number(), integer()) }),
66
+ object({ NestedResult: tuple([pipe(number(), integer()), pipe(number(), integer())]) }),
67
+ ]),
68
+ transform((value) => ({
69
+ ...value,
70
+ $kind: Object.keys(value)[0],
71
+ }))
72
+ // Defined manually to add `type?: 'pure' | 'object'` to Input
73
+ )
74
+ const GasData = object({
75
+ budget: nullable(JsonU64),
76
+ price: nullable(JsonU64),
77
+ owner: nullable(SuiAddress),
78
+ payment: nullable(array(ObjectRef)),
79
+ })
80
+ const StructTag = object({
81
+ address: string(),
82
+ module: string(),
83
+ name: string(),
84
+ // type_params in rust, should be updated to use camelCase
85
+ typeParams: array(string()),
86
+ })
87
+ const OpenMoveTypeSignatureBody = union([
88
+ literal('address'),
89
+ literal('bool'),
90
+ literal('u8'),
91
+ literal('u16'),
92
+ literal('u32'),
93
+ literal('u64'),
94
+ literal('u128'),
95
+ literal('u256'),
96
+ object({ vector: lazy(() => OpenMoveTypeSignatureBody) }),
97
+ object({
98
+ datatype: object({
99
+ package: string(),
100
+ module: string(),
101
+ type: string(),
102
+ typeParameters: array(lazy(() => OpenMoveTypeSignatureBody)),
103
+ }),
104
+ }),
105
+ object({ typeParameter: pipe(number(), integer()) }),
106
+ ])
107
+ const OpenMoveTypeSignature = object({
108
+ ref: nullable(union([literal('&'), literal('&mut')])),
109
+ body: OpenMoveTypeSignatureBody,
110
+ })
111
+ const ProgrammableMoveCall = object({
112
+ package: ObjectID,
113
+ module: string(),
114
+ function: string(),
115
+ // snake case in rust
116
+ typeArguments: array(string()),
117
+ arguments: array(Argument),
118
+ _argumentTypes: optional(nullable(array(OpenMoveTypeSignature))),
119
+ })
120
+ const $Intent = object({
121
+ name: string(),
122
+ inputs: record(string(), union([Argument, array(Argument)])),
123
+ data: record(string(), unknown()),
124
+ })
125
+ const Command = safeEnum({
126
+ MoveCall: ProgrammableMoveCall,
127
+ TransferObjects: object({
128
+ objects: array(Argument),
129
+ address: Argument,
130
+ }),
131
+ SplitCoins: object({
132
+ coin: Argument,
133
+ amounts: array(Argument),
134
+ }),
135
+ MergeCoins: object({
136
+ destination: Argument,
137
+ sources: array(Argument),
138
+ }),
139
+ Publish: object({
140
+ modules: array(BCSBytes),
141
+ dependencies: array(ObjectID),
142
+ }),
143
+ MakeMoveVec: object({
144
+ type: nullable(string()),
145
+ elements: array(Argument),
146
+ }),
147
+ Upgrade: object({
148
+ modules: array(BCSBytes),
149
+ dependencies: array(ObjectID),
150
+ package: ObjectID,
151
+ ticket: Argument,
152
+ }),
153
+ $Intent,
154
+ })
155
+ const ObjectArg = safeEnum({
156
+ ImmOrOwnedObject: ObjectRef,
157
+ SharedObject: object({
158
+ objectId: ObjectID,
159
+ // snake case in rust
160
+ initialSharedVersion: JsonU64,
161
+ mutable: boolean(),
162
+ }),
163
+ Receiving: ObjectRef,
164
+ })
165
+ const CallArg = safeEnum({
166
+ Object: ObjectArg,
167
+ Pure: object({
168
+ bytes: BCSBytes,
169
+ }),
170
+ UnresolvedPure: object({
171
+ value: unknown(),
172
+ }),
173
+ UnresolvedObject: object({
174
+ objectId: ObjectID,
175
+ version: optional(nullable(JsonU64)),
176
+ digest: optional(nullable(string())),
177
+ initialSharedVersion: optional(nullable(JsonU64)),
178
+ }),
179
+ })
180
+ const NormalizedCallArg = safeEnum({
181
+ Object: ObjectArg,
182
+ Pure: object({
183
+ bytes: BCSBytes,
184
+ }),
185
+ })
186
+ const TransactionExpiration = safeEnum({
187
+ None: literal(true),
188
+ Epoch: JsonU64,
189
+ })
190
+ const TransactionData = object({
191
+ version: literal(2),
192
+ sender: nullish(SuiAddress),
193
+ expiration: nullish(TransactionExpiration),
194
+ gasData: GasData,
195
+ inputs: array(CallArg),
196
+ commands: array(Command),
197
+ })
198
+
199
+ export {
200
+ $Intent,
201
+ Argument,
202
+ BCSBytes,
203
+ Command,
204
+ GasData,
205
+ JsonU64,
206
+ NormalizedCallArg,
207
+ ObjectArg,
208
+ ObjectID,
209
+ ObjectRef,
210
+ OpenMoveTypeSignature,
211
+ OpenMoveTypeSignatureBody,
212
+ StructTag,
213
+ SuiAddress,
214
+ TransactionData,
215
+ TransactionExpiration,
216
+ safeEnum,
217
+ }
218
+ // # sourceMappingURL=internal.js.map