@zofai/zo-sdk 0.2.12 → 0.2.14

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 (34) hide show
  1. package/.claude/settings.local.json +11 -1
  2. package/dist/abstract/BaseAPI.cjs +65 -6
  3. package/dist/abstract/BaseAPI.cjs.map +1 -1
  4. package/dist/abstract/BaseAPI.d.cts +11 -0
  5. package/dist/abstract/BaseAPI.d.cts.map +1 -1
  6. package/dist/abstract/BaseAPI.d.mts +11 -0
  7. package/dist/abstract/BaseAPI.d.mts.map +1 -1
  8. package/dist/abstract/BaseAPI.mjs +66 -7
  9. package/dist/abstract/BaseAPI.mjs.map +1 -1
  10. package/dist/consts/deployments-usdz-mainnet.json +0 -30
  11. package/dist/implementations/SLPAPI.cjs +16 -18
  12. package/dist/implementations/SLPAPI.cjs.map +1 -1
  13. package/dist/implementations/SLPAPI.d.cts.map +1 -1
  14. package/dist/implementations/SLPAPI.d.mts.map +1 -1
  15. package/dist/implementations/SLPAPI.mjs +16 -18
  16. package/dist/implementations/SLPAPI.mjs.map +1 -1
  17. package/dist/implementations/USDZAPI.cjs +10 -15
  18. package/dist/implementations/USDZAPI.cjs.map +1 -1
  19. package/dist/implementations/USDZAPI.d.cts.map +1 -1
  20. package/dist/implementations/USDZAPI.d.mts.map +1 -1
  21. package/dist/implementations/USDZAPI.mjs +10 -15
  22. package/dist/implementations/USDZAPI.mjs.map +1 -1
  23. package/dist/implementations/ZLPAPI.cjs +16 -18
  24. package/dist/implementations/ZLPAPI.cjs.map +1 -1
  25. package/dist/implementations/ZLPAPI.d.cts.map +1 -1
  26. package/dist/implementations/ZLPAPI.d.mts.map +1 -1
  27. package/dist/implementations/ZLPAPI.mjs +16 -18
  28. package/dist/implementations/ZLPAPI.mjs.map +1 -1
  29. package/package.json +1 -1
  30. package/src/abstract/BaseAPI.ts +94 -8
  31. package/src/consts/deployments-usdz-mainnet.json +0 -30
  32. package/src/implementations/SLPAPI.ts +54 -24
  33. package/src/implementations/USDZAPI.ts +42 -21
  34. package/src/implementations/ZLPAPI.ts +56 -24
@@ -8,11 +8,11 @@ import type { KioskClient, KioskOwnerCap } from '@mysten/kiosk'
8
8
  import type { TransactionObjectArgument } from '@mysten/sui/transactions'
9
9
  import type { SuiClient } from '../suiClient'
10
10
  import { Transaction } from '@mysten/sui/transactions'
11
- import { SUI_CLOCK_OBJECT_ID } from '@mysten/sui/utils'
11
+ import { SUI_CLOCK_OBJECT_ID, SUI_TYPE_ARG } from '@mysten/sui/utils'
12
12
 
13
13
  import { createSpendableCoin, getCoinBalanceBreakdown, needsCoinWithBalanceFunding } from '../coins'
14
14
 
15
- import type { LPToken, Network } from '../consts'
15
+ import type { IConsts, LPToken, Network } from '../consts'
16
16
  import { ALLOW_TRADE_CAN_TRADE, ALLOW_TRADE_MUST_TRADE, ALLOW_TRADE_NO_TRADE } from '../consts'
17
17
  import type {
18
18
  IBaseAPI,
@@ -149,6 +149,27 @@ export abstract class BaseAPI extends BaseDataAPI implements IBaseAPI {
149
149
  * Processes coin objects for transactions
150
150
  * Handles SUI gas coin and merges multiple coin objects if needed
151
151
  */
152
+ /** LP tokens are not in `consts.coins`; resolve their Move type from the core package id. */
153
+ protected resolveCoinModule(token: string): string {
154
+ const coinConfig = this.consts.coins[token]
155
+ if (coinConfig) {
156
+ return coinConfig.module
157
+ }
158
+
159
+ const lpModules: Record<string, (consts: IConsts) => string> = {
160
+ zlp: c => `${c.zoCore.package}::zlp::ZLP`,
161
+ usdz: c => `${c.zoCore.package}::usdz::USDZ`,
162
+ slp: c => `${c.sudoCore.package}::slp::SLP`,
163
+ zbtcvc: c => `${c.zoCore.package}::zbtcvc::ZBTCVC`,
164
+ }
165
+ const resolveLp = lpModules[token]
166
+ if (resolveLp) {
167
+ return resolveLp(this.consts)
168
+ }
169
+
170
+ throw new Error(`Token configuration not found: ${token}`)
171
+ }
172
+
152
173
  protected processCoins(tx: Transaction, coin: string, coinObjects: string[], sponsoredTx = false) {
153
174
  if (coin === 'sui' && !sponsoredTx) {
154
175
  return tx.gas
@@ -173,6 +194,74 @@ export abstract class BaseAPI extends BaseDataAPI implements IBaseAPI {
173
194
  return tx.splitCoins(coinObject, amounts)
174
195
  }
175
196
 
197
+ /**
198
+ * Resolves a Coin<T> of `amount` from coin objects and/or address balance (coinWithBalance).
199
+ * Used for LP deposits, withdrawals, and collateral splits when funds may live in address balance.
200
+ */
201
+ protected async resolveSplitCoinObject(
202
+ tx: Transaction,
203
+ token: string,
204
+ amount: bigint,
205
+ coinObjects: string[],
206
+ options?: {
207
+ sponsoredTx?: boolean
208
+ suiCoinObject?: TransactionObjectArgument
209
+ sender?: string
210
+ },
211
+ ): Promise<TransactionObjectArgument> {
212
+ const { sponsoredTx, suiCoinObject, sender } = options ?? {}
213
+
214
+ if (token === 'sui') {
215
+ if (sponsoredTx && suiCoinObject) {
216
+ return tx.splitCoins(suiCoinObject, [tx.pure.u64(amount)])[0]
217
+ }
218
+ if (sender) {
219
+ const breakdown = await getCoinBalanceBreakdown(this.provider, sender, SUI_TYPE_ARG)
220
+ const useAddressBalance = coinObjects.length === 0 || needsCoinWithBalanceFunding(breakdown, amount)
221
+ if (useAddressBalance) {
222
+ if (breakdown.totalBalance < amount) {
223
+ throw new Error(
224
+ `Insufficient SUI balance: need ${amount} MIST, have ${breakdown.totalBalance} MIST`,
225
+ )
226
+ }
227
+ return createSpendableCoin(tx, SUI_TYPE_ARG, amount, false)
228
+ }
229
+ }
230
+ if (!sponsoredTx && coinObjects.length === 0) {
231
+ return tx.splitCoins(tx.gas, [tx.pure.u64(amount)])[0]
232
+ }
233
+ if (coinObjects.length === 0) {
234
+ throw new Error(`${this.constructor.name}: coinObjects or sender required for SUI`)
235
+ }
236
+ return tx.splitCoins(
237
+ this.processCoins(tx, 'sui', coinObjects, sponsoredTx ?? false),
238
+ [tx.pure.u64(amount)],
239
+ )[0]
240
+ }
241
+
242
+ const coinModule = this.resolveCoinModule(token)
243
+
244
+ if (sender) {
245
+ const breakdown = await getCoinBalanceBreakdown(this.provider, sender, coinModule)
246
+ const useAddressBalance = coinObjects.length === 0 || needsCoinWithBalanceFunding(breakdown, amount)
247
+ if (useAddressBalance) {
248
+ if (breakdown.totalBalance < amount) {
249
+ throw new Error(`Insufficient ${token} balance: need ${amount}, have ${breakdown.totalBalance}`)
250
+ }
251
+ return createSpendableCoin(tx, coinModule, amount, false)
252
+ }
253
+ }
254
+
255
+ if (coinObjects.length === 0) {
256
+ throw new Error(`${this.constructor.name}: coinObjects or sender required for ${token}`)
257
+ }
258
+
259
+ return tx.splitCoins(
260
+ this.processCoins(tx, token, coinObjects, sponsoredTx ?? false),
261
+ [tx.pure.u64(amount)],
262
+ )[0]
263
+ }
264
+
176
265
  /**
177
266
  * Resolves relayer fee coin from coin objects and/or address balance (coinWithBalance).
178
267
  */
@@ -189,19 +278,16 @@ export abstract class BaseAPI extends BaseDataAPI implements IBaseAPI {
189
278
  return tx.splitCoins(suiCoinObject, [tx.pure.u64(relayerFee)])[0]
190
279
  }
191
280
 
192
- const coinConfig = this.consts.coins[token]
193
- if (!coinConfig) {
194
- throw new Error(`Token configuration not found: ${token}`)
195
- }
281
+ const coinModule = this.resolveCoinModule(token)
196
282
 
197
283
  if (sender) {
198
- const breakdown = await getCoinBalanceBreakdown(this.provider, sender, coinConfig.module)
284
+ const breakdown = await getCoinBalanceBreakdown(this.provider, sender, coinModule)
199
285
  const useAddressBalance = coinObjects.length === 0 || needsCoinWithBalanceFunding(breakdown, relayerFee)
200
286
  if (useAddressBalance) {
201
287
  if (breakdown.totalBalance < relayerFee) {
202
288
  throw new Error(`Insufficient ${token} balance for relayer fee`)
203
289
  }
204
- const source = createSpendableCoin(tx, coinConfig.module, relayerFee, false)
290
+ const source = createSpendableCoin(tx, coinModule, relayerFee, false)
205
291
  // coinWithBalance already resolves to a Coin of `relayerFee` size — do not split again
206
292
  return source
207
293
  }
@@ -103,26 +103,6 @@
103
103
  "funding_fee_model": "0x1dc2b267562ad5de33e8fcbccf61b78298fa70e3a90f31802c8b9e483d659867",
104
104
  "position_config": "0xc7ca2acaf5531288afa2a117f598df71e785a2bd8e71a32b7439eef2dd0ebded"
105
105
  },
106
- "long_xpd": {
107
- "supported_collaterals": ["nusdc"],
108
- "funding_fee_model": "0x90f92c159f250bf95126be1faa5b33507b450ffd7243f7f64ea731ca18c8ce06",
109
- "position_config": "0xf2563fa5daa1b3437beb9957757483fb2d4291713944cf46efa6941d5e5a5fff"
110
- },
111
- "short_xpd": {
112
- "supported_collaterals": ["nusdc"],
113
- "funding_fee_model": "0xbde016bd76364eac36c2e5cc46a8304ce608063550cfb4ff80553b632db39f9c",
114
- "position_config": "0x2b00c2139bdfc9161a57ebe229e8284d716faf96a463a89e7c97710edcd95e84"
115
- },
116
- "long_xpt": {
117
- "supported_collaterals": ["nusdc"],
118
- "funding_fee_model": "0xbccdc226bee26a2775a96f9970d34eabb4d3bcdc4ba07d6244ca609a8ff2a93e",
119
- "position_config": "0xf112993df1fd45f562a7f712337f3c08538c6860f566ab5b702896ec351152a7"
120
- },
121
- "short_xpt": {
122
- "supported_collaterals": ["nusdc"],
123
- "funding_fee_model": "0x4858df0ed65e3c4cb17eddc176a53acb54ce239a48ba95188afc26a581976269",
124
- "position_config": "0x1dba9ed4e35e2e970b550cf47da07213df70986d45b4db4a97576ba556fc9d2f"
125
- },
126
106
  "long_usdjpy": {
127
107
  "supported_collaterals": ["nusdc"],
128
108
  "funding_fee_model": "0xade120b3341429561996dc4d9e1e00dc16353fe32f5bd99e87540b0580bbf831",
@@ -143,16 +123,6 @@
143
123
  "funding_fee_model": "0xc1c25c0402b1cee0af7c724aedee71fe64436bdee285a37f5a6dcca3004c6eba",
144
124
  "position_config": "0x4786e2d0688cfca6329952689f364a6c2ff928ab98262c6beb7aedb1186bc37d"
145
125
  },
146
- "long_wti": {
147
- "supported_collaterals": ["nusdc"],
148
- "funding_fee_model": "0xe04cce47722ad061de705e1f9c6527976d07879a5c08a3e35101ce70453f55ec",
149
- "position_config": "0x813bb7f519ff0148d1412ba87a3e1df4a44e5e60b756c623aafa8c1b9ebe3f49"
150
- },
151
- "short_wti": {
152
- "supported_collaterals": ["nusdc"],
153
- "funding_fee_model": "0x49d45eaed31f4c6b82f4d42204261d65e5fe26a15aec0a843fb75f40737709cd",
154
- "position_config": "0xfb3db7faf8fb3ed2550b46fa044b768f57382726f09a118ed7c6ef8be3c45278"
155
- },
156
126
  "long_pepe": {
157
127
  "supported_collaterals": ["nusdc"],
158
128
  "funding_fee_model": "0xe3ae3eea82c8220ed8fb30d64044d2700ab443cdf3435cc5d76f4dd585d03f80",
@@ -71,12 +71,14 @@ export class SLPAPI extends BaseAPI implements ISLPAPI {
71
71
  additionalSuiAmount: coin === 'sui' ? BigInt(amount) : 0n,
72
72
  })
73
73
  tx = oracle.tx
74
- const { suiCoinObject } = oracle
75
74
 
76
- // Process deposit coins
77
- const depositObject = coin === 'sui'
78
- ? tx.splitCoins(suiCoinObject!, [tx.pure.u64(amount)])[0]
79
- : tx.splitCoins(this.processCoins(tx, coin, coinObjects, true), [tx.pure.u64(amount)])[0]
75
+ const depositObject = await this.resolveSplitCoinObject(
76
+ tx,
77
+ coin,
78
+ BigInt(amount),
79
+ coinObjects,
80
+ { sponsoredTx: true, suiCoinObject: oracle.suiCoinObject, sender },
81
+ )
80
82
 
81
83
  const { vaultsValuation, symbolsValuation } = this.dataAPI.valuate(tx)
82
84
 
@@ -100,10 +102,13 @@ export class SLPAPI extends BaseAPI implements ISLPAPI {
100
102
 
101
103
  // Handle non-sponsored transaction case
102
104
  tx = (await this.initOracleTxb(pythFeederKeys, tx)).tx
103
- const depositObject = tx.splitCoins(
104
- this.processCoins(tx, coin, coinObjects, false),
105
- [tx.pure.u64(amount)],
106
- )[0]
105
+ const depositObject = await this.resolveSplitCoinObject(
106
+ tx,
107
+ coin,
108
+ BigInt(amount),
109
+ coinObjects,
110
+ { sender },
111
+ )
107
112
 
108
113
  const { vaultsValuation, symbolsValuation } = this.dataAPI.valuate(tx)
109
114
 
@@ -157,12 +162,14 @@ export class SLPAPI extends BaseAPI implements ISLPAPI {
157
162
  additionalSuiAmount: coin === 'sui' ? BigInt(amount) : 0n,
158
163
  })
159
164
  tx = oracle.tx
160
- const { suiCoinObject } = oracle
161
165
 
162
- // Process deposit coins
163
- const depositObject = coin === 'sui'
164
- ? tx.splitCoins(suiCoinObject!, [tx.pure.u64(amount)])[0]
165
- : tx.splitCoins(this.processCoins(tx, coin, coinObjects, true), [tx.pure.u64(amount)])[0]
166
+ const depositObject = await this.resolveSplitCoinObject(
167
+ tx,
168
+ coin,
169
+ BigInt(amount),
170
+ coinObjects,
171
+ { sponsoredTx: true, suiCoinObject: oracle.suiCoinObject, sender },
172
+ )
166
173
 
167
174
  const { vaultsValuation, symbolsValuation } = this.dataAPI.valuate(tx)
168
175
 
@@ -183,10 +190,13 @@ export class SLPAPI extends BaseAPI implements ISLPAPI {
183
190
 
184
191
  // Handle non-sponsored transaction case
185
192
  tx = (await this.initOracleTxb(pythFeederKeys, tx)).tx
186
- const depositObject = tx.splitCoins(
187
- this.processCoins(tx, coin, coinObjects, false),
188
- [tx.pure.u64(amount)],
189
- )[0]
193
+ const depositObject = await this.resolveSplitCoinObject(
194
+ tx,
195
+ coin,
196
+ BigInt(amount),
197
+ coinObjects,
198
+ { sender },
199
+ )
190
200
 
191
201
  const { vaultsValuation, symbolsValuation } = this.dataAPI.valuate(tx)
192
202
 
@@ -296,25 +306,35 @@ export class SLPAPI extends BaseAPI implements ISLPAPI {
296
306
  sponsoredTx?: boolean,
297
307
  sender?: string,
298
308
  ): Promise<Transaction> {
309
+ if (!lpCoinObjects?.length && !sender) {
310
+ throw new Error(`${this.constructor.name}: lpCoinObjects or sender is required`)
311
+ }
312
+
299
313
  let tx = new Transaction()
300
314
 
301
315
  // Initialize oracle transaction
302
316
  const pythFeederKeys = Object.keys(this.consts.pythFeeder.feeder)
303
317
 
318
+ let suiCoinObject
304
319
  if (sponsoredTx) {
305
320
  const oracle = await this.initOracleTxb(pythFeederKeys, tx, true, {
306
321
  sender: this.requireSenderForSponsored(sender),
307
322
  additionalSuiAmount: 0n,
308
323
  })
309
324
  tx = oracle.tx
310
- const { suiCoinObject } = oracle
325
+ suiCoinObject = oracle.suiCoinObject
311
326
  }
312
327
  else {
313
328
  tx = (await this.initOracleTxb(pythFeederKeys, tx)).tx
314
329
  }
315
330
 
316
- const slpCoinObject = this.processCoins(tx, 'slp', lpCoinObjects, false)
317
- const [withdrawObject] = tx.splitCoins(slpCoinObject, [tx.pure.u64(amount)])
331
+ const withdrawObject = await this.resolveSplitCoinObject(
332
+ tx,
333
+ 'slp',
334
+ BigInt(amount),
335
+ lpCoinObjects,
336
+ { sponsoredTx, suiCoinObject, sender },
337
+ )
318
338
  const { vaultsValuation, symbolsValuation } = this.dataAPI.valuate(tx)
319
339
 
320
340
  tx.moveCall({
@@ -381,6 +401,10 @@ export class SLPAPI extends BaseAPI implements ISLPAPI {
381
401
  sponsoredTx?: boolean,
382
402
  sender?: string,
383
403
  ): Promise<TransactionObjectArgument> {
404
+ if (!lpCoinObjects?.length && !sender) {
405
+ throw new Error(`${this.constructor.name}: lpCoinObjects or sender is required`)
406
+ }
407
+
384
408
  if (!tx) {
385
409
  tx = new Transaction()
386
410
  }
@@ -388,20 +412,26 @@ export class SLPAPI extends BaseAPI implements ISLPAPI {
388
412
  // Initialize oracle transaction
389
413
  const pythFeederKeys = Object.keys(this.consts.pythFeeder.feeder)
390
414
 
415
+ let suiCoinObject
391
416
  if (sponsoredTx) {
392
417
  const oracle = await this.initOracleTxb(pythFeederKeys, tx, true, {
393
418
  sender: this.requireSenderForSponsored(sender),
394
419
  additionalSuiAmount: 0n,
395
420
  })
396
421
  tx = oracle.tx
397
- const { suiCoinObject } = oracle
422
+ suiCoinObject = oracle.suiCoinObject
398
423
  }
399
424
  else {
400
425
  tx = (await this.initOracleTxb(pythFeederKeys, tx)).tx
401
426
  }
402
427
 
403
- const slpCoinObject = this.processCoins(tx, 'slp', lpCoinObjects, false)
404
- const [withdrawObject] = tx.splitCoins(slpCoinObject, [tx.pure.u64(amount)])
428
+ const withdrawObject = await this.resolveSplitCoinObject(
429
+ tx,
430
+ 'slp',
431
+ BigInt(amount),
432
+ lpCoinObjects,
433
+ { sponsoredTx, suiCoinObject, sender },
434
+ )
405
435
  const { vaultsValuation, symbolsValuation } = this.dataAPI.valuate(tx)
406
436
 
407
437
  const [withdrawCoin] = tx.moveCall({
@@ -1069,12 +1069,14 @@ export class USDZAPI extends BaseAPI implements IUSDZAPI {
1069
1069
  additionalSuiAmount: coin === 'sui' ? BigInt(amount) : 0n,
1070
1070
  })
1071
1071
  tx = oracle.tx
1072
- const { suiCoinObject } = oracle
1073
1072
 
1074
- // Process deposit coins
1075
- const depositObject = coin === 'sui'
1076
- ? tx.splitCoins(suiCoinObject!, [tx.pure.u64(amount)])[0]
1077
- : tx.splitCoins(this.processCoins(tx, coin, coinObjects, true), [tx.pure.u64(amount)])[0]
1073
+ const depositObject = await this.resolveSplitCoinObject(
1074
+ tx,
1075
+ coin,
1076
+ BigInt(amount),
1077
+ coinObjects,
1078
+ { sponsoredTx: true, suiCoinObject: oracle.suiCoinObject, sender },
1079
+ )
1078
1080
 
1079
1081
  const { vaultsValuation, symbolsValuation } = this.dataAPI.valuate(tx)
1080
1082
 
@@ -1095,10 +1097,13 @@ export class USDZAPI extends BaseAPI implements IUSDZAPI {
1095
1097
 
1096
1098
  // Handle non-sponsored transaction case
1097
1099
  tx = (await this.initOracleTxb(pythFeederKeys, tx)).tx
1098
- const depositObject = tx.splitCoins(
1099
- this.processCoins(tx, coin, coinObjects, false),
1100
- [tx.pure.u64(amount)],
1101
- )[0]
1100
+ const depositObject = await this.resolveSplitCoinObject(
1101
+ tx,
1102
+ coin,
1103
+ BigInt(amount),
1104
+ coinObjects,
1105
+ { sender },
1106
+ )
1102
1107
 
1103
1108
  const { vaultsValuation, symbolsValuation } = this.dataAPI.valuate(tx)
1104
1109
 
@@ -1152,12 +1157,14 @@ export class USDZAPI extends BaseAPI implements IUSDZAPI {
1152
1157
  additionalSuiAmount: coin === 'sui' ? BigInt(amount) : 0n,
1153
1158
  })
1154
1159
  tx = oracle.tx
1155
- const { suiCoinObject } = oracle
1156
1160
 
1157
- // Process deposit coins
1158
- const depositObject = coin === 'sui'
1159
- ? tx.splitCoins(suiCoinObject!, [tx.pure.u64(amount)])[0]
1160
- : tx.splitCoins(this.processCoins(tx, coin, coinObjects, true), [tx.pure.u64(amount)])[0]
1161
+ const depositObject = await this.resolveSplitCoinObject(
1162
+ tx,
1163
+ coin,
1164
+ BigInt(amount),
1165
+ coinObjects,
1166
+ { sponsoredTx: true, suiCoinObject: oracle.suiCoinObject, sender },
1167
+ )
1161
1168
 
1162
1169
  const { vaultsValuation, symbolsValuation } = this.dataAPI.valuate(tx)
1163
1170
 
@@ -1178,10 +1185,13 @@ export class USDZAPI extends BaseAPI implements IUSDZAPI {
1178
1185
 
1179
1186
  // Handle non-sponsored transaction case
1180
1187
  tx = (await this.initOracleTxb(pythFeederKeys, tx)).tx
1181
- const depositObject = tx.splitCoins(
1182
- this.processCoins(tx, coin, coinObjects, false),
1183
- [tx.pure.u64(amount)],
1184
- )[0]
1188
+ const depositObject = await this.resolveSplitCoinObject(
1189
+ tx,
1190
+ coin,
1191
+ BigInt(amount),
1192
+ coinObjects,
1193
+ { sender },
1194
+ )
1185
1195
 
1186
1196
  const { vaultsValuation, symbolsValuation } = this.dataAPI.valuate(tx)
1187
1197
 
@@ -1215,24 +1225,35 @@ export class USDZAPI extends BaseAPI implements IUSDZAPI {
1215
1225
  sponsoredTx?: boolean,
1216
1226
  sender?: string,
1217
1227
  ): Promise<Transaction> {
1228
+ if (!lpCoinObjects?.length && !sender) {
1229
+ throw new Error(`${this.constructor.name}: lpCoinObjects or sender is required`)
1230
+ }
1231
+
1218
1232
  let tx = new Transaction()
1219
1233
 
1220
1234
  // Initialize oracle transaction
1221
1235
  const pythFeederKeys = Object.keys(this.consts.pythFeeder.feeder)
1222
1236
 
1237
+ let suiCoinObject
1223
1238
  if (sponsoredTx) {
1224
1239
  const oracle = await this.initOracleTxb(pythFeederKeys, tx, true, {
1225
1240
  sender: this.requireSenderForSponsored(sender),
1226
1241
  additionalSuiAmount: 0n,
1227
1242
  })
1228
1243
  tx = oracle.tx
1229
- const { suiCoinObject } = oracle
1244
+ suiCoinObject = oracle.suiCoinObject
1230
1245
  }
1231
1246
  else {
1232
1247
  tx = (await this.initOracleTxb(pythFeederKeys, tx)).tx
1233
1248
  }
1234
- const usdzCoinObject = this.processCoins(tx, 'usdz', lpCoinObjects, false)
1235
- const [withdrawObject] = tx.splitCoins(usdzCoinObject, [tx.pure.u64(amount)])
1249
+
1250
+ const withdrawObject = await this.resolveSplitCoinObject(
1251
+ tx,
1252
+ 'usdz',
1253
+ BigInt(amount),
1254
+ lpCoinObjects,
1255
+ { sponsoredTx, suiCoinObject, sender },
1256
+ )
1236
1257
  const { vaultsValuation, symbolsValuation } = this.dataAPI.valuate(tx)
1237
1258
 
1238
1259
  tx.moveCall({
@@ -71,12 +71,14 @@ export class ZLPAPI extends BaseAPI implements IZLPAPI {
71
71
  additionalSuiAmount: coin === 'sui' ? BigInt(amount) : 0n,
72
72
  })
73
73
  tx = oracle.tx
74
- const { suiCoinObject } = oracle
75
74
 
76
- // Process deposit coins
77
- const depositObject = coin === 'sui'
78
- ? tx.splitCoins(suiCoinObject!, [tx.pure.u64(amount)])[0]
79
- : tx.splitCoins(this.processCoins(tx, coin, coinObjects, true), [tx.pure.u64(amount)])[0]
75
+ const depositObject = await this.resolveSplitCoinObject(
76
+ tx,
77
+ coin,
78
+ BigInt(amount),
79
+ coinObjects,
80
+ { sponsoredTx: true, suiCoinObject: oracle.suiCoinObject, sender },
81
+ )
80
82
 
81
83
  const { vaultsValuation, symbolsValuation } = this.dataAPI.valuate(tx)
82
84
 
@@ -97,10 +99,13 @@ export class ZLPAPI extends BaseAPI implements IZLPAPI {
97
99
 
98
100
  // Handle non-sponsored transaction case
99
101
  tx = (await this.initOracleTxb(pythFeederKeys, tx)).tx
100
- const depositObject = tx.splitCoins(
101
- this.processCoins(tx, coin, coinObjects, false),
102
- [tx.pure.u64(amount)],
103
- )[0]
102
+ const depositObject = await this.resolveSplitCoinObject(
103
+ tx,
104
+ coin,
105
+ BigInt(amount),
106
+ coinObjects,
107
+ { sender },
108
+ )
104
109
 
105
110
  const { vaultsValuation, symbolsValuation } = this.dataAPI.valuate(tx)
106
111
 
@@ -154,12 +159,14 @@ export class ZLPAPI extends BaseAPI implements IZLPAPI {
154
159
  additionalSuiAmount: coin === 'sui' ? BigInt(amount) : 0n,
155
160
  })
156
161
  tx = oracle.tx
157
- const { suiCoinObject } = oracle
158
162
 
159
- // Process deposit coins
160
- const depositObject = coin === 'sui'
161
- ? tx.splitCoins(suiCoinObject!, [tx.pure.u64(amount)])[0]
162
- : tx.splitCoins(this.processCoins(tx, coin, coinObjects, true), [tx.pure.u64(amount)])[0]
163
+ const depositObject = await this.resolveSplitCoinObject(
164
+ tx,
165
+ coin,
166
+ BigInt(amount),
167
+ coinObjects,
168
+ { sponsoredTx: true, suiCoinObject: oracle.suiCoinObject, sender },
169
+ )
163
170
 
164
171
  const { vaultsValuation, symbolsValuation } = this.dataAPI.valuate(tx)
165
172
 
@@ -180,10 +187,13 @@ export class ZLPAPI extends BaseAPI implements IZLPAPI {
180
187
 
181
188
  // Handle non-sponsored transaction case
182
189
  tx = (await this.initOracleTxb(pythFeederKeys, tx)).tx
183
- const depositObject = tx.splitCoins(
184
- this.processCoins(tx, coin, coinObjects, false),
185
- [tx.pure.u64(amount)],
186
- )[0]
190
+ const depositObject = await this.resolveSplitCoinObject(
191
+ tx,
192
+ coin,
193
+ BigInt(amount),
194
+ coinObjects,
195
+ { sender },
196
+ )
187
197
 
188
198
  const { vaultsValuation, symbolsValuation } = this.dataAPI.valuate(tx)
189
199
 
@@ -287,24 +297,35 @@ export class ZLPAPI extends BaseAPI implements IZLPAPI {
287
297
  sponsoredTx?: boolean,
288
298
  sender?: string,
289
299
  ): Promise<Transaction> {
300
+ if (!lpCoinObjects?.length && !sender) {
301
+ throw new Error(`${this.constructor.name}: lpCoinObjects or sender is required`)
302
+ }
303
+
290
304
  let tx = new Transaction()
291
305
 
292
306
  // Initialize oracle transaction
293
307
  const pythFeederKeys = Object.keys(this.consts.pythFeeder.feeder)
294
308
 
309
+ let suiCoinObject
295
310
  if (sponsoredTx) {
296
311
  const oracle = await this.initOracleTxb(pythFeederKeys, tx, true, {
297
312
  sender: this.requireSenderForSponsored(sender),
298
313
  additionalSuiAmount: 0n,
299
314
  })
300
315
  tx = oracle.tx
301
- const { suiCoinObject } = oracle
316
+ suiCoinObject = oracle.suiCoinObject
302
317
  }
303
318
  else {
304
319
  tx = (await this.initOracleTxb(pythFeederKeys, tx)).tx
305
320
  }
306
- const zlpCoinObject = this.processCoins(tx, 'zlp', lpCoinObjects, false)
307
- const [withdrawObject] = tx.splitCoins(zlpCoinObject, [tx.pure.u64(amount)])
321
+
322
+ const withdrawObject = await this.resolveSplitCoinObject(
323
+ tx,
324
+ 'zlp',
325
+ BigInt(amount),
326
+ lpCoinObjects,
327
+ { sponsoredTx, suiCoinObject, sender },
328
+ )
308
329
  const { vaultsValuation, symbolsValuation } = this.dataAPI.valuate(tx)
309
330
 
310
331
  tx.moveCall({
@@ -370,6 +391,10 @@ export class ZLPAPI extends BaseAPI implements IZLPAPI {
370
391
  sponsoredTx?: boolean,
371
392
  sender?: string,
372
393
  ): Promise<TransactionObjectArgument> {
394
+ if (!lpCoinObjects?.length && !sender) {
395
+ throw new Error(`${this.constructor.name}: lpCoinObjects or sender is required`)
396
+ }
397
+
373
398
  if (!tx) {
374
399
  tx = new Transaction()
375
400
  }
@@ -377,19 +402,26 @@ export class ZLPAPI extends BaseAPI implements IZLPAPI {
377
402
  // Initialize oracle transaction
378
403
  const pythFeederKeys = Object.keys(this.consts.pythFeeder.feeder)
379
404
 
405
+ let suiCoinObject
380
406
  if (sponsoredTx) {
381
407
  const oracle = await this.initOracleTxb(pythFeederKeys, tx, true, {
382
408
  sender: this.requireSenderForSponsored(sender),
383
409
  additionalSuiAmount: 0n,
384
410
  })
385
411
  tx = oracle.tx
386
- const { suiCoinObject } = oracle
412
+ suiCoinObject = oracle.suiCoinObject
387
413
  }
388
414
  else {
389
415
  tx = (await this.initOracleTxb(pythFeederKeys, tx)).tx
390
416
  }
391
- const zlpCoinObject = this.processCoins(tx, 'zlp', lpCoinObjects, false)
392
- const [withdrawObject] = tx.splitCoins(zlpCoinObject, [tx.pure.u64(amount)])
417
+
418
+ const withdrawObject = await this.resolveSplitCoinObject(
419
+ tx,
420
+ 'zlp',
421
+ BigInt(amount),
422
+ lpCoinObjects,
423
+ { sponsoredTx, suiCoinObject, sender },
424
+ )
393
425
  const { vaultsValuation, symbolsValuation } = this.dataAPI.valuate(tx)
394
426
 
395
427
  const [withdrawCoin] = tx.moveCall({