defi-dash-sdk 0.1.3 → 0.1.4

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 (181) hide show
  1. package/LICENSE +7 -0
  2. package/README.md +199 -97
  3. package/dist/__tests__/deleverageEstimate.unit.test.d.ts +10 -0
  4. package/dist/__tests__/deleverageEstimate.unit.test.d.ts.map +1 -0
  5. package/dist/__tests__/deleverageEstimate.unit.test.js +116 -0
  6. package/dist/__tests__/deleverageEstimate.unit.test.js.map +1 -0
  7. package/dist/__tests__/findBestLeverageRoute.test.d.ts +12 -0
  8. package/dist/__tests__/findBestLeverageRoute.test.d.ts.map +1 -0
  9. package/dist/__tests__/findBestLeverageRoute.test.js +177 -0
  10. package/dist/__tests__/findBestLeverageRoute.test.js.map +1 -0
  11. package/dist/__tests__/getAssetApy.test.d.ts +2 -0
  12. package/dist/__tests__/getAssetApy.test.d.ts.map +1 -0
  13. package/dist/__tests__/getAssetApy.test.js +133 -0
  14. package/dist/__tests__/getAssetApy.test.js.map +1 -0
  15. package/dist/__tests__/getAssetRiskParams.test.d.ts +11 -0
  16. package/dist/__tests__/getAssetRiskParams.test.d.ts.map +1 -0
  17. package/dist/__tests__/getAssetRiskParams.test.js +183 -0
  18. package/dist/__tests__/getAssetRiskParams.test.js.map +1 -0
  19. package/dist/__tests__/internal.getAssetApy.test.d.ts +2 -0
  20. package/dist/__tests__/internal.getAssetApy.test.d.ts.map +1 -0
  21. package/dist/__tests__/internal.getAssetApy.test.js +140 -0
  22. package/dist/__tests__/internal.getAssetApy.test.js.map +1 -0
  23. package/dist/__tests__/internal.getAssetRiskParams.test.d.ts +22 -0
  24. package/dist/__tests__/internal.getAssetRiskParams.test.d.ts.map +1 -0
  25. package/dist/__tests__/internal.getAssetRiskParams.test.js +194 -0
  26. package/dist/__tests__/internal.getAssetRiskParams.test.js.map +1 -0
  27. package/dist/__tests__/internal.getPosition.test.d.ts +22 -0
  28. package/dist/__tests__/internal.getPosition.test.d.ts.map +1 -0
  29. package/dist/__tests__/internal.getPosition.test.js +153 -0
  30. package/dist/__tests__/internal.getPosition.test.js.map +1 -0
  31. package/dist/__tests__/leveragePreview.unit.test.d.ts +10 -0
  32. package/dist/__tests__/leveragePreview.unit.test.d.ts.map +1 -0
  33. package/dist/__tests__/leveragePreview.unit.test.js +168 -0
  34. package/dist/__tests__/leveragePreview.unit.test.js.map +1 -0
  35. package/dist/__tests__/leverageRoute.unit.test.d.ts +10 -0
  36. package/dist/__tests__/leverageRoute.unit.test.d.ts.map +1 -0
  37. package/dist/__tests__/leverageRoute.unit.test.js +159 -0
  38. package/dist/__tests__/leverageRoute.unit.test.js.map +1 -0
  39. package/dist/__tests__/previewLeverage.test.d.ts +13 -0
  40. package/dist/__tests__/previewLeverage.test.d.ts.map +1 -0
  41. package/dist/__tests__/previewLeverage.test.js +217 -0
  42. package/dist/__tests__/previewLeverage.test.js.map +1 -0
  43. package/dist/__tests__/sdk.bestRoute.test.d.ts +22 -0
  44. package/dist/__tests__/sdk.bestRoute.test.d.ts.map +1 -0
  45. package/dist/__tests__/sdk.bestRoute.test.js +186 -0
  46. package/dist/__tests__/sdk.bestRoute.test.js.map +1 -0
  47. package/dist/__tests__/sdk.bestRoute.unit.test.d.ts +16 -0
  48. package/dist/__tests__/sdk.bestRoute.unit.test.d.ts.map +1 -0
  49. package/dist/__tests__/sdk.bestRoute.unit.test.js +165 -0
  50. package/dist/__tests__/sdk.bestRoute.unit.test.js.map +1 -0
  51. package/dist/__tests__/sdk.deleverage.test.d.ts +21 -0
  52. package/dist/__tests__/sdk.deleverage.test.d.ts.map +1 -0
  53. package/dist/__tests__/sdk.deleverage.test.js +130 -0
  54. package/dist/__tests__/sdk.deleverage.test.js.map +1 -0
  55. package/dist/__tests__/sdk.deleverage.unit.test.d.ts +21 -0
  56. package/dist/__tests__/sdk.deleverage.unit.test.d.ts.map +1 -0
  57. package/dist/__tests__/sdk.deleverage.unit.test.js +141 -0
  58. package/dist/__tests__/sdk.deleverage.unit.test.js.map +1 -0
  59. package/dist/__tests__/sdk.leverage.test.d.ts +19 -0
  60. package/dist/__tests__/sdk.leverage.test.d.ts.map +1 -0
  61. package/dist/__tests__/sdk.leverage.test.js +188 -0
  62. package/dist/__tests__/sdk.leverage.test.js.map +1 -0
  63. package/dist/__tests__/sdk.portfolio.test.d.ts +17 -0
  64. package/dist/__tests__/sdk.portfolio.test.d.ts.map +1 -0
  65. package/dist/__tests__/sdk.portfolio.test.js +162 -0
  66. package/dist/__tests__/sdk.portfolio.test.js.map +1 -0
  67. package/dist/__tests__/sdk.position.test.d.ts +16 -0
  68. package/dist/__tests__/sdk.position.test.d.ts.map +1 -0
  69. package/dist/__tests__/sdk.position.test.js +193 -0
  70. package/dist/__tests__/sdk.position.test.js.map +1 -0
  71. package/dist/__tests__/sdk.preview.test.d.ts +23 -0
  72. package/dist/__tests__/sdk.preview.test.d.ts.map +1 -0
  73. package/dist/__tests__/sdk.preview.test.js +226 -0
  74. package/dist/__tests__/sdk.preview.test.js.map +1 -0
  75. package/dist/__tests__/sdk.preview.unit.test.d.ts +18 -0
  76. package/dist/__tests__/sdk.preview.unit.test.d.ts.map +1 -0
  77. package/dist/__tests__/sdk.preview.unit.test.js +175 -0
  78. package/dist/__tests__/sdk.preview.unit.test.js.map +1 -0
  79. package/dist/__tests__/utils.normalizeCoinType.test.d.ts +7 -0
  80. package/dist/__tests__/utils.normalizeCoinType.test.d.ts.map +1 -0
  81. package/dist/__tests__/utils.normalizeCoinType.test.js +42 -0
  82. package/dist/__tests__/utils.normalizeCoinType.test.js.map +1 -0
  83. package/dist/index.d.ts +19 -11
  84. package/dist/index.d.ts.map +1 -1
  85. package/dist/index.js +24 -40
  86. package/dist/index.js.map +1 -1
  87. package/dist/protocols/base-adapter.d.ts +42 -75
  88. package/dist/protocols/base-adapter.d.ts.map +1 -1
  89. package/dist/protocols/base-adapter.js +34 -77
  90. package/dist/protocols/base-adapter.js.map +1 -1
  91. package/dist/protocols/navi/adapter.d.ts +22 -2
  92. package/dist/protocols/navi/adapter.d.ts.map +1 -1
  93. package/dist/protocols/navi/adapter.js +145 -11
  94. package/dist/protocols/navi/adapter.js.map +1 -1
  95. package/dist/protocols/scallop/adapter.d.ts +26 -6
  96. package/dist/protocols/scallop/adapter.d.ts.map +1 -1
  97. package/dist/protocols/scallop/adapter.js +206 -43
  98. package/dist/protocols/scallop/adapter.js.map +1 -1
  99. package/dist/protocols/scallop/flash-loan.d.ts +18 -3
  100. package/dist/protocols/scallop/flash-loan.d.ts.map +1 -1
  101. package/dist/protocols/scallop/flash-loan.js +79 -20
  102. package/dist/protocols/scallop/flash-loan.js.map +1 -1
  103. package/dist/protocols/scallop/types.d.ts.map +1 -1
  104. package/dist/protocols/scallop/types.js +4 -1
  105. package/dist/protocols/scallop/types.js.map +1 -1
  106. package/dist/protocols/suilend/adapter.d.ts +19 -1
  107. package/dist/protocols/suilend/adapter.d.ts.map +1 -1
  108. package/dist/protocols/suilend/adapter.js +196 -51
  109. package/dist/protocols/suilend/adapter.js.map +1 -1
  110. package/dist/sdk.d.ts +107 -148
  111. package/dist/sdk.d.ts.map +1 -1
  112. package/dist/sdk.js +171 -523
  113. package/dist/sdk.js.map +1 -1
  114. package/dist/strategies/common.d.ts +42 -0
  115. package/dist/strategies/common.d.ts.map +1 -0
  116. package/dist/strategies/common.js +81 -0
  117. package/dist/strategies/common.js.map +1 -0
  118. package/dist/strategies/deleverage.d.ts.map +1 -1
  119. package/dist/strategies/deleverage.js +44 -62
  120. package/dist/strategies/deleverage.js.map +1 -1
  121. package/dist/strategies/index.d.ts +9 -1
  122. package/dist/strategies/index.d.ts.map +1 -1
  123. package/dist/strategies/index.js +11 -2
  124. package/dist/strategies/index.js.map +1 -1
  125. package/dist/strategies/leverage-preview.d.ts +27 -0
  126. package/dist/strategies/leverage-preview.d.ts.map +1 -0
  127. package/dist/strategies/leverage-preview.js +120 -0
  128. package/dist/strategies/leverage-preview.js.map +1 -0
  129. package/dist/strategies/leverage-route.d.ts +29 -0
  130. package/dist/strategies/leverage-route.d.ts.map +1 -0
  131. package/dist/strategies/leverage-route.js +112 -0
  132. package/dist/strategies/leverage-route.js.map +1 -0
  133. package/dist/strategies/leverage.d.ts +4 -44
  134. package/dist/strategies/leverage.d.ts.map +1 -1
  135. package/dist/strategies/leverage.js +43 -112
  136. package/dist/strategies/leverage.js.map +1 -1
  137. package/dist/strategies/scallop-leverage.d.ts +34 -0
  138. package/dist/strategies/scallop-leverage.d.ts.map +1 -0
  139. package/dist/strategies/scallop-leverage.js +143 -0
  140. package/dist/strategies/scallop-leverage.js.map +1 -0
  141. package/dist/types/config.d.ts +0 -7
  142. package/dist/types/config.d.ts.map +1 -1
  143. package/dist/types/constants.d.ts +8 -0
  144. package/dist/types/constants.d.ts.map +1 -1
  145. package/dist/types/constants.js +9 -1
  146. package/dist/types/constants.js.map +1 -1
  147. package/dist/types/index.d.ts +3 -3
  148. package/dist/types/index.d.ts.map +1 -1
  149. package/dist/types/index.js +2 -1
  150. package/dist/types/index.js.map +1 -1
  151. package/dist/types/position.d.ts +7 -3
  152. package/dist/types/position.d.ts.map +1 -1
  153. package/dist/types/protocol.d.ts +101 -0
  154. package/dist/types/protocol.d.ts.map +1 -1
  155. package/dist/types/strategy.d.ts +82 -38
  156. package/dist/types/strategy.d.ts.map +1 -1
  157. package/dist/utils/calculations.d.ts +10 -137
  158. package/dist/utils/calculations.d.ts.map +1 -1
  159. package/dist/utils/calculations.js +11 -162
  160. package/dist/utils/calculations.js.map +1 -1
  161. package/dist/utils/coin.d.ts +16 -7
  162. package/dist/utils/coin.d.ts.map +1 -1
  163. package/dist/utils/coin.js +32 -25
  164. package/dist/utils/coin.js.map +1 -1
  165. package/dist/utils/errors.d.ts +0 -18
  166. package/dist/utils/errors.d.ts.map +1 -1
  167. package/dist/utils/errors.js +2 -40
  168. package/dist/utils/errors.js.map +1 -1
  169. package/dist/utils/execution.d.ts +38 -0
  170. package/dist/utils/execution.d.ts.map +1 -0
  171. package/dist/utils/execution.js +110 -0
  172. package/dist/utils/execution.js.map +1 -0
  173. package/dist/utils/gas.d.ts +0 -37
  174. package/dist/utils/gas.d.ts.map +1 -1
  175. package/dist/utils/gas.js +2 -60
  176. package/dist/utils/gas.js.map +1 -1
  177. package/dist/utils/index.d.ts +1 -1
  178. package/dist/utils/index.d.ts.map +1 -1
  179. package/dist/utils/index.js +1 -1
  180. package/dist/utils/index.js.map +1 -1
  181. package/package.json +15 -45
package/dist/sdk.js CHANGED
@@ -7,41 +7,40 @@
7
7
  */
8
8
  Object.defineProperty(exports, "__esModule", { value: true });
9
9
  exports.DefiDashSDK = void 0;
10
- const transactions_1 = require("@mysten/sui/transactions");
11
10
  const sdk_ts_1 = require("@7kprotocol/sdk-ts");
12
11
  const types_1 = require("./types");
13
- const sui_scallop_sdk_1 = require("@scallop-io/sui-scallop-sdk");
14
12
  const adapter_1 = require("./protocols/suilend/adapter");
15
13
  const adapter_2 = require("./protocols/navi/adapter");
16
14
  const adapter_3 = require("./protocols/scallop/adapter");
17
15
  const flash_loan_1 = require("./protocols/scallop/flash-loan");
18
16
  const utils_1 = require("./utils");
19
- const gas_1 = require("./utils/gas");
20
17
  const errors_1 = require("./utils/errors");
18
+ const execution_1 = require("./utils/execution");
21
19
  const leverage_1 = require("./strategies/leverage");
22
20
  const deleverage_1 = require("./strategies/deleverage");
23
- const constants_1 = require("./protocols/suilend/constants");
21
+ const leverage_preview_1 = require("./strategies/leverage-preview");
22
+ const leverage_route_1 = require("./strategies/leverage-route");
24
23
  /**
25
24
  * DeFi Dash SDK - Main entry point
26
25
  *
27
- * @example Node.js usage:
26
+ * @example Node.js usage (build + execute):
28
27
  * ```typescript
29
- * const sdk = new DefiDashSDK();
30
- * await sdk.initialize(suiClient, keypair);
31
- * const result = await sdk.leverage({ protocol: LendingProtocol.Suilend, ... });
28
+ * const sdk = await DefiDashSDK.create(suiClient, keypair);
29
+ *
30
+ * const tx = new Transaction();
31
+ * tx.setSender(address);
32
+ * await sdk.buildLeverageTransaction(tx, { protocol, depositAsset, ... });
33
+ * const result = await sdk.execute(tx); // or sdk.dryRun(tx)
32
34
  * ```
33
35
  *
34
36
  * @example Browser usage:
35
37
  * ```typescript
36
- * const sdk = new DefiDashSDK();
37
- * await sdk.initialize(suiClient, userAddress); // No keypair needed
38
+ * const sdk = await DefiDashSDK.create(suiClient, userAddress);
38
39
  *
39
40
  * const tx = new Transaction();
40
41
  * tx.setSender(userAddress);
41
42
  * await sdk.buildLeverageTransaction(tx, { protocol, depositAsset, ... });
42
- *
43
- * // Sign with wallet adapter
44
- * await signAndExecute({ transaction: tx });
43
+ * await signAndExecute({ transaction: tx }); // wallet adapter
45
44
  * ```
46
45
  */
47
46
  class DefiDashSDK {
@@ -51,25 +50,34 @@ class DefiDashSDK {
51
50
  this.options = options;
52
51
  }
53
52
  /**
54
- * Initialize the SDK
53
+ * Create and initialize the SDK in one step (recommended).
55
54
  *
56
55
  * @param suiClient - Sui client instance
57
56
  * @param keypairOrAddress - Ed25519Keypair (Node.js) or user address string (Browser)
57
+ * @param options - SDK options
58
58
  *
59
59
  * @example Node.js
60
60
  * ```typescript
61
- * await sdk.initialize(suiClient, keypair);
61
+ * const sdk = await DefiDashSDK.create(suiClient, keypair);
62
62
  * ```
63
63
  *
64
64
  * @example Browser
65
65
  * ```typescript
66
- * await sdk.initialize(suiClient, account.address);
66
+ * const sdk = await DefiDashSDK.create(suiClient, account.address);
67
67
  * ```
68
68
  */
69
+ static async create(suiClient, keypairOrAddress, options = {}) {
70
+ const sdk = new DefiDashSDK(options);
71
+ await sdk.initialize(suiClient, keypairOrAddress);
72
+ return sdk;
73
+ }
74
+ /**
75
+ * Initialize the SDK (internal — use `DefiDashSDK.create()`)
76
+ */
69
77
  async initialize(suiClient, keypairOrAddress) {
70
78
  this.suiClient = suiClient;
71
79
  // Detect if keypair or address
72
- if (typeof keypairOrAddress === "string") {
80
+ if (typeof keypairOrAddress === 'string') {
73
81
  // Browser mode: address only
74
82
  this._userAddress = keypairOrAddress;
75
83
  }
@@ -119,21 +127,9 @@ class DefiDashSDK {
119
127
  }
120
128
  return this._userAddress;
121
129
  }
122
- /**
123
- * Resolve asset symbol to coin type
124
- */
130
+ /** Resolve asset symbol to coin type */
125
131
  resolveCoinType(asset) {
126
- // If already a full coin type, normalize it
127
- if (asset.includes("::")) {
128
- return (0, utils_1.normalizeCoinType)(asset);
129
- }
130
- // Look up by symbol
131
- const upperSymbol = asset.toUpperCase();
132
- const coinType = types_1.COIN_TYPES[upperSymbol];
133
- if (coinType) {
134
- return (0, utils_1.normalizeCoinType)(coinType);
135
- }
136
- throw new errors_1.UnknownAssetError(asset);
132
+ return (0, utils_1.resolveCoinType)(asset);
137
133
  }
138
134
  // ============================================================================
139
135
  // Browser-Compatible Transaction Builder Methods
@@ -166,11 +162,13 @@ class DefiDashSDK {
166
162
  async buildLeverageTransaction(tx, params) {
167
163
  this.ensureInitialized();
168
164
  // Validate that exactly one of depositAmount or depositValueUsd is provided
169
- if (!params.depositAmount && !params.depositValueUsd) {
170
- throw new errors_1.InvalidParameterError("Either depositAmount or depositValueUsd must be provided");
165
+ const hasAmount = params.depositAmount != null;
166
+ const hasValueUsd = params.depositValueUsd != null;
167
+ if (!hasAmount && !hasValueUsd) {
168
+ throw new errors_1.InvalidParameterError('Either depositAmount or depositValueUsd must be provided');
171
169
  }
172
- if (params.depositAmount && params.depositValueUsd) {
173
- throw new errors_1.InvalidParameterError("Cannot provide both depositAmount and depositValueUsd. Choose one.");
170
+ if (hasAmount && hasValueUsd) {
171
+ throw new errors_1.InvalidParameterError('Cannot provide both depositAmount and depositValueUsd. Choose one.');
174
172
  }
175
173
  const protocol = this.getProtocol(params.protocol);
176
174
  // Clear adapter state for new transaction (Scallop tracks unstaked obligations)
@@ -178,11 +176,21 @@ class DefiDashSDK {
178
176
  protocol.clearPendingState?.();
179
177
  }
180
178
  const coinType = this.resolveCoinType(params.depositAsset);
181
- const reserve = (0, constants_1.getReserveByCoinType)(coinType);
182
- const decimals = reserve?.decimals || 8;
179
+ const decimals = (0, utils_1.getDecimals)(coinType);
180
+ // Validate multiplier against protocol limits
181
+ if (params.multiplier <= 1) {
182
+ throw new errors_1.InvalidParameterError(`Multiplier must be greater than 1 (got ${params.multiplier})`);
183
+ }
184
+ const riskParams = await protocol.getAssetRiskParams(coinType);
185
+ if (params.multiplier > riskParams.maxMultiplier) {
186
+ throw new errors_1.InvalidParameterError(`Multiplier ${params.multiplier}x exceeds protocol max ${riskParams.maxMultiplier.toFixed(2)}x (LTV ${(riskParams.ltv * 100).toFixed(0)}%)`);
187
+ }
183
188
  // Convert depositValueUsd to depositAmount if needed
184
189
  let depositAmountStr;
185
- if (params.depositValueUsd) {
190
+ if (hasValueUsd) {
191
+ if (params.depositValueUsd <= 0) {
192
+ throw new errors_1.InvalidParameterError('depositValueUsd must be positive');
193
+ }
186
194
  const price = await (0, sdk_ts_1.getTokenPrice)(coinType);
187
195
  const amountInToken = params.depositValueUsd / price;
188
196
  depositAmountStr = amountInToken.toFixed(decimals);
@@ -191,6 +199,9 @@ class DefiDashSDK {
191
199
  depositAmountStr = params.depositAmount;
192
200
  }
193
201
  const depositAmount = (0, utils_1.parseUnits)(depositAmountStr, decimals);
202
+ if (depositAmount <= 0n) {
203
+ throw new errors_1.InvalidParameterError('depositAmount must be positive');
204
+ }
194
205
  await (0, leverage_1.buildLeverageTransaction)(tx, {
195
206
  protocol,
196
207
  flashLoanClient: this.flashLoanClient,
@@ -249,193 +260,66 @@ class DefiDashSDK {
249
260
  });
250
261
  }
251
262
  // ============================================================================
252
- // Node.js Strategy Methods (with execution)
263
+ // Position Methods
253
264
  // ============================================================================
254
265
  /**
255
- * Execute leverage strategy (Node.js only)
256
- *
257
- * Opens a leveraged position by:
258
- * 1. Taking a flash loan
259
- * 2. Swapping borrowed USDC for deposit asset
260
- * 3. Depositing total collateral (user deposit + swapped amount)
261
- * 4. Borrowing USDC to repay flash loan
262
- *
263
- * @param params - Leverage parameters
264
- * @param params.protocol - Lending protocol to use (Suilend, Scallop, or Navi)
265
- * @param params.depositAsset - Asset symbol (e.g., "SUI", "LBTC") or full coin type
266
- * @param params.depositAmount - Amount to deposit (required if depositValueUsd not provided)
267
- * @param params.depositValueUsd - USD value to deposit (required if depositAmount not provided)
268
- * @param params.multiplier - Leverage multiplier (e.g., 2.0 for 2x leverage)
269
- * @param params.dryRun - If true, simulates transaction and returns gas estimate without executing
266
+ * Get position for a single protocol
270
267
  *
271
- * @returns Strategy result with success status, transaction digest (if executed), and gas used
272
- *
273
- * @throws {SDKNotInitializedError} If SDK not initialized
274
- * @throws {KeypairRequiredError} If keypair not provided (Node.js mode required)
275
- * @throws {InvalidParameterError} If both or neither depositAmount and depositValueUsd provided
276
- * @throws {UnknownAssetError} If asset symbol not recognized
268
+ * @param protocol - Lending protocol to query
269
+ * @returns Position info or null if no active position
277
270
  *
278
271
  * @example
279
272
  * ```typescript
280
- * // Leverage with fixed amount
281
- * const result = await sdk.leverage({
282
- * protocol: LendingProtocol.Suilend,
283
- * depositAsset: 'LBTC',
284
- * depositAmount: '0.001',
285
- * multiplier: 2.0,
286
- * dryRun: true
287
- * });
288
- *
289
- * // Leverage with USD value
290
- * const result = await sdk.leverage({
291
- * protocol: LendingProtocol.Scallop,
292
- * depositAsset: 'SUI',
293
- * depositValueUsd: 100, // $100 worth of SUI
294
- * multiplier: 3.0,
295
- * dryRun: false
296
- * });
273
+ * const position = await sdk.getPosition(LendingProtocol.Navi);
274
+ * if (position) {
275
+ * console.log(`Collateral: ${position.collateral.symbol} $${position.collateral.valueUsd}`);
276
+ * console.log(`Debt: ${position.debt.symbol} $${position.debt.valueUsd}`);
277
+ * }
297
278
  * ```
298
- *
299
- * @remarks
300
- * - Requires SDK to be initialized with keypair (Node.js mode)
301
- * - For browser usage, use {@link buildLeverageTransaction} instead
302
- * - Scallop protocol uses optimized native SDK for oracle updates
303
- * - Gas is automatically optimized via dry run (20% buffer added)
304
279
  */
305
- async leverage(params) {
280
+ async getPosition(protocol) {
306
281
  this.ensureInitialized();
307
- if (!this.keypair) {
308
- return {
309
- success: false,
310
- error: "Keypair required for execution. Use buildLeverageTransaction for browser.",
311
- };
312
- }
313
- // Scallop uses its own SDK builder for oracle updates
314
- if (params.protocol === types_1.LendingProtocol.Scallop) {
315
- return this.executeScallopLeverage(params);
316
- }
317
- const tx = new transactions_1.Transaction();
318
- tx.setSender(this.userAddress);
319
- try {
320
- await this.buildLeverageTransaction(tx, params);
321
- if (params.dryRun) {
322
- return this.dryRunWithGasOptimization(tx);
323
- }
324
- // execute() runs dryrun first and optimizes gas budget
325
- return this.execute(tx);
326
- }
327
- catch (error) {
328
- return {
329
- success: false,
330
- error: error.message || String(error),
331
- };
332
- }
282
+ return this.getProtocol(protocol).getPosition(this.userAddress);
333
283
  }
334
284
  /**
335
- * Execute deleverage strategy (Node.js only)
285
+ * Get all open positions across all supported protocols
336
286
  *
337
- * Closes or reduces a leveraged position by:
338
- * 1. Taking a flash loan to repay debt
339
- * 2. Withdrawing collateral
340
- * 3. Swapping portion of collateral to USDC
341
- * 4. Repaying flash loan
342
- * 5. Keeping remaining collateral
343
- *
344
- * @param params - Deleverage parameters
345
- * @param params.protocol - Lending protocol where position exists
346
- * @param params.dryRun - If true, simulates transaction without executing
287
+ * Queries Suilend, Navi, and Scallop in parallel and returns
288
+ * only the protocols that have an active position (collateral > 0 or debt > 0).
347
289
  *
348
- * @returns Strategy result with success status, transaction digest, and gas used
349
- *
350
- * @throws {SDKNotInitializedError} If SDK not initialized
351
- * @throws {KeypairRequiredError} If keypair not provided (Node.js mode required)
352
- * @throws {PositionNotFoundError} If no position exists on the protocol
353
- * @throws {NoDebtError} If position has no debt (use withdraw instead)
290
+ * @returns Array of open positions with protocol identifier
354
291
  *
355
292
  * @example
356
293
  * ```typescript
357
- * // Dry run first to preview
358
- * const preview = await sdk.deleverage({
359
- * protocol: LendingProtocol.Suilend,
360
- * dryRun: true
361
- * });
362
- *
363
- * if (preview.success) {
364
- * console.log(`Estimated gas: ${preview.gasUsed}`);
365
- *
366
- * // Execute for real
367
- * const result = await sdk.deleverage({
368
- * protocol: LendingProtocol.Suilend,
369
- * dryRun: false
370
- * });
294
+ * const positions = await sdk.getOpenPositions();
371
295
  *
372
- * if (result.success) {
373
- * console.log(`Position closed: ${result.txDigest}`);
296
+ * for (const { protocol, position } of positions) {
297
+ * console.log(`${protocol}: ${position.collateral.symbol} $${position.collateral.valueUsd.toFixed(2)}`);
298
+ * if (position.debt.amount > 0n) {
299
+ * console.log(` Debt: ${position.debt.symbol} $${position.debt.valueUsd.toFixed(2)}`);
374
300
  * }
301
+ * console.log(` Net: $${position.netValueUsd.toFixed(2)}`);
375
302
  * }
376
303
  * ```
377
- *
378
- * @remarks
379
- * - Requires SDK to be initialized with keypair (Node.js mode)
380
- * - For browser usage, use {@link buildDeleverageTransaction} instead
381
- * - Automatically fetches current position and calculates optimal swap amounts
382
- * - Gas is automatically optimized via dry run (20% buffer added)
383
304
  */
384
- async deleverage(params) {
305
+ async getOpenPositions() {
385
306
  this.ensureInitialized();
386
- if (!this.keypair) {
387
- return {
388
- success: false,
389
- error: "Keypair required for execution. Use buildDeleverageTransaction for browser.",
390
- };
391
- }
392
- const tx = new transactions_1.Transaction();
393
- tx.setSender(this.userAddress);
394
- try {
395
- await this.buildDeleverageTransaction(tx, params);
396
- if (params.dryRun) {
397
- return this.dryRunWithGasOptimization(tx);
307
+ const allProtocols = [
308
+ types_1.LendingProtocol.Suilend,
309
+ types_1.LendingProtocol.Navi,
310
+ types_1.LendingProtocol.Scallop,
311
+ ];
312
+ const results = await Promise.all(allProtocols.map(async (p) => {
313
+ try {
314
+ const position = await this.getProtocol(p).getPosition(this.userAddress);
315
+ return position ? { protocol: p, position } : null;
398
316
  }
399
- // execute() runs dryrun first and optimizes gas budget
400
- return this.execute(tx);
401
- }
402
- catch (error) {
403
- return {
404
- success: false,
405
- error: error.message || String(error),
406
- };
407
- }
408
- }
409
- // ============================================================================
410
- // Position Methods
411
- // ============================================================================
412
- /**
413
- * Get current lending position on a specific protocol
414
- *
415
- * @param protocol - The lending protocol to query
416
- *
417
- * @returns Position information including collateral, debt, and metrics, or null if no position exists
418
- *
419
- * @throws {SDKNotInitializedError} If SDK not initialized
420
- * @throws {UnsupportedProtocolError} If protocol not supported
421
- *
422
- * @example
423
- * ```typescript
424
- * const position = await sdk.getPosition(LendingProtocol.Suilend);
425
- *
426
- * if (position) {
427
- * console.log(`Collateral: ${position.collateral.amount} ${position.collateral.symbol}`);
428
- * console.log(`Debt: ${position.debt.amount} ${position.debt.symbol}`);
429
- * console.log(`Health Factor: ${position.healthFactor}`);
430
- * console.log(`Net Value: $${position.netValueUsd}`);
431
- * } else {
432
- * console.log('No position found');
433
- * }
434
- * ```
435
- */
436
- async getPosition(protocol) {
437
- this.ensureInitialized();
438
- return this.getProtocol(protocol).getPosition(this.userAddress);
317
+ catch (e) {
318
+ console.warn(`[DefiDashSDK] Failed to fetch position for ${p}:`, e);
319
+ return null;
320
+ }
321
+ }));
322
+ return results.filter((r) => r !== null);
439
323
  }
440
324
  // ============================================================================
441
325
  // Aggregation Methods
@@ -488,7 +372,7 @@ class DefiDashSDK {
488
372
  }
489
373
  }
490
374
  catch (e) {
491
- // Silently skip failed protocol fetches
375
+ console.warn(`[DefiDashSDK] Failed to fetch portfolio for ${p}:`, e);
492
376
  }
493
377
  // Return resilient default
494
378
  return {
@@ -513,6 +397,7 @@ class DefiDashSDK {
513
397
  * Useful for showing users what their leveraged position will look like.
514
398
  *
515
399
  * @param params - Preview parameters
400
+ * @param params.protocol - Lending protocol to use (suilend, navi, scallop)
516
401
  * @param params.depositAsset - Asset symbol (e.g., "SUI", "LBTC") or full coin type
517
402
  * @param params.depositAmount - Amount to deposit (required if depositValueUsd not provided)
518
403
  * @param params.depositValueUsd - USD value to deposit (required if depositAmount not provided)
@@ -521,12 +406,14 @@ class DefiDashSDK {
521
406
  * @returns Preview containing position metrics, flash loan details, and risk parameters
522
407
  *
523
408
  * @throws {InvalidParameterError} If both or neither depositAmount and depositValueUsd provided
409
+ * @throws {InvalidParameterError} If multiplier exceeds protocol's max multiplier
524
410
  * @throws {UnknownAssetError} If asset symbol not recognized
525
411
  *
526
412
  * @example
527
413
  * ```typescript
528
414
  * // Preview with fixed amount
529
415
  * const preview = await sdk.previewLeverage({
416
+ * protocol: 'suilend',
530
417
  * depositAsset: 'LBTC',
531
418
  * depositAmount: '0.001',
532
419
  * multiplier: 2.0
@@ -536,11 +423,13 @@ class DefiDashSDK {
536
423
  * console.log(`Flash Loan: ${preview.flashLoanUsdc / 1e6} USDC`);
537
424
  * console.log(`Total Position: $${preview.totalPositionUsd}`);
538
425
  * console.log(`Position LTV: ${preview.ltvPercent.toFixed(1)}%`);
426
+ * console.log(`Max Multiplier: ${preview.maxMultiplier.toFixed(2)}x`);
539
427
  * console.log(`Liquidation Price: $${preview.liquidationPrice}`);
540
428
  * console.log(`Price Drop Buffer: ${preview.priceDropBuffer.toFixed(1)}%`);
541
429
  *
542
430
  * // Preview with USD value
543
431
  * const preview2 = await sdk.previewLeverage({
432
+ * protocol: 'scallop',
544
433
  * depositAsset: 'SUI',
545
434
  * depositValueUsd: 100, // $100 worth
546
435
  * multiplier: 3.0
@@ -548,37 +437,59 @@ class DefiDashSDK {
548
437
  * ```
549
438
  *
550
439
  * @remarks
551
- * - Does not require SDK initialization (standalone utility)
440
+ * - Queries protocol-specific LTV to calculate accurate max multiplier
441
+ * - Max multiplier = 1 / (1 - LTV), e.g., 65% LTV → 2.857x max
552
442
  * - Fetches current market prices from 7k Protocol
553
443
  * - Calculations are estimates; actual execution may differ slightly
554
444
  * - Higher multipliers increase both returns and liquidation risk
555
445
  */
556
446
  async previewLeverage(params) {
557
- // Validate that exactly one is provided
558
- if (!params.depositAmount && !params.depositValueUsd) {
559
- throw new errors_1.InvalidParameterError("Either depositAmount or depositValueUsd must be provided");
560
- }
561
- if (params.depositAmount && params.depositValueUsd) {
562
- throw new errors_1.InvalidParameterError("Cannot provide both depositAmount and depositValueUsd. Choose one.");
563
- }
447
+ const protocol = this.getProtocol(params.protocol);
564
448
  const coinType = this.resolveCoinType(params.depositAsset);
565
- const reserve = (0, constants_1.getReserveByCoinType)(coinType);
566
- const decimals = reserve?.decimals || 8;
567
- // Convert depositValueUsd to depositAmount if needed
568
- let depositAmountStr;
569
- if (params.depositValueUsd) {
570
- const price = await (0, sdk_ts_1.getTokenPrice)(coinType);
571
- const amountInToken = params.depositValueUsd / price;
572
- depositAmountStr = amountInToken.toFixed(decimals);
573
- }
574
- else {
575
- depositAmountStr = params.depositAmount;
576
- }
577
- const depositAmount = (0, utils_1.parseUnits)(depositAmountStr, decimals);
578
- return (0, leverage_1.calculateLeveragePreview)({
579
- depositCoinType: coinType,
580
- depositAmount,
449
+ return (0, leverage_preview_1.previewLeverage)({
450
+ coinType,
451
+ depositAmount: params.depositAmount,
452
+ depositValueUsd: params.depositValueUsd,
581
453
  multiplier: params.multiplier,
454
+ }, {
455
+ protocol,
456
+ swapClient: this.swapClient,
457
+ suiClient: this.suiClient,
458
+ });
459
+ }
460
+ // ============================================================================
461
+ // Route Finding
462
+ // ============================================================================
463
+ /**
464
+ * Find the best leverage route across all initialized protocols for a given asset.
465
+ *
466
+ * Returns two recommendations:
467
+ * 1. **bestMaxMultiplier** — the protocol offering the highest possible leverage
468
+ * 2. **bestApy** — the protocol with the highest net APY at a safe multiplier
469
+ *
470
+ * The safe multiplier = min(maxMultiplier across protocols) - LEVERAGE_MULTIPLIER_BUFFER
471
+ *
472
+ * @example
473
+ * ```typescript
474
+ * const route = await sdk.findBestLeverageRoute({
475
+ * depositAsset: 'SUI',
476
+ * depositValueUsd: 100,
477
+ * });
478
+ *
479
+ * console.log(route.bestMaxMultiplier.protocol); // e.g. 'scallop'
480
+ * console.log(route.bestApy.protocol); // e.g. 'suilend'
481
+ * console.log(route.safeMultiplier); // e.g. 2.83
482
+ * ```
483
+ */
484
+ async findBestLeverageRoute(params) {
485
+ this.ensureInitialized();
486
+ return (0, leverage_route_1.findBestLeverageRoute)(params, {
487
+ protocols: this.protocols,
488
+ previewFn: (protocol, previewParams) => this.previewLeverage({
489
+ protocol,
490
+ ...previewParams,
491
+ }),
492
+ resolveCoinType: (asset) => this.resolveCoinType(asset),
582
493
  });
583
494
  }
584
495
  // ============================================================================
@@ -605,34 +516,31 @@ class DefiDashSDK {
605
516
  return this.userAddress;
606
517
  }
607
518
  // ============================================================================
608
- // Internal Methods
519
+ // Execution Methods
609
520
  // ============================================================================
610
521
  /**
611
- * Dry run with gas optimization
522
+ * Dry run a transaction with gas optimization
523
+ *
524
+ * Simulates the transaction and returns estimated gas usage.
525
+ * Does NOT execute the transaction on-chain.
612
526
  *
613
- * Uses small fixed budget for dryrun, returns actual gas estimation.
527
+ * @param tx - Built transaction to simulate
528
+ * @returns Strategy result with gas estimate
529
+ *
530
+ * @example
531
+ * ```typescript
532
+ * const tx = new Transaction();
533
+ * tx.setSender(address);
534
+ * await sdk.buildLeverageTransaction(tx, params);
535
+ * const result = await sdk.dryRun(tx);
536
+ * console.log(`Estimated gas: ${result.gasUsed}`);
537
+ * ```
614
538
  */
615
- async dryRunWithGasOptimization(tx) {
616
- // Use small fixed budget for dryrun simulation
617
- tx.setGasBudget(gas_1.DRYRUN_GAS_BUDGET);
618
- const result = await this.suiClient.dryRunTransactionBlock({
619
- transactionBlock: await tx.build({ client: this.suiClient }),
620
- });
621
- if (result.effects.status.status === "success") {
622
- const actualGas = (0, gas_1.calculateActualGas)(result.effects.gasUsed);
623
- const optimizedBudget = (0, gas_1.calculateOptimizedBudget)(actualGas);
624
- return {
625
- success: true,
626
- gasUsed: optimizedBudget,
627
- };
628
- }
629
- return {
630
- success: false,
631
- error: result.effects.status.error || "Dry run failed",
632
- };
539
+ async dryRun(tx) {
540
+ return (0, execution_1.dryRunTransaction)(this.suiClient, tx);
633
541
  }
634
542
  /**
635
- * Execute transaction with gas optimization
543
+ * Execute a transaction with gas optimization (Node.js only)
636
544
  *
637
545
  * Flow:
638
546
  * 1. Dryrun with small fixed budget to get actual gas usage
@@ -640,285 +548,25 @@ class DefiDashSDK {
640
548
  * 3. Check user has enough balance
641
549
  * 4. Execute with optimized budget
642
550
  *
643
- * This ensures we never overpay for gas.
551
+ * @param tx - Built transaction to execute
552
+ * @returns Strategy result with transaction digest and gas used
553
+ *
554
+ * @throws {KeypairRequiredError} If keypair not provided
555
+ *
556
+ * @example
557
+ * ```typescript
558
+ * const tx = new Transaction();
559
+ * tx.setSender(address);
560
+ * await sdk.buildLeverageTransaction(tx, params);
561
+ * const result = await sdk.execute(tx);
562
+ * console.log(`TX: ${result.txDigest}`);
563
+ * ```
644
564
  */
645
565
  async execute(tx) {
646
566
  if (!this.keypair) {
647
567
  throw new errors_1.KeypairRequiredError();
648
568
  }
649
- // Step 1: Check user's available gas balance first
650
- const balance = await this.suiClient.getBalance({
651
- owner: this.userAddress,
652
- });
653
- const userBalance = BigInt(balance.totalBalance);
654
- // Step 2: Set dryrun budget (use available balance or default, whichever is lower)
655
- const dryrunBudget = userBalance < BigInt(gas_1.DRYRUN_GAS_BUDGET)
656
- ? userBalance
657
- : BigInt(gas_1.DRYRUN_GAS_BUDGET);
658
- if (dryrunBudget < 10000000n) {
659
- // Min 0.01 SUI for dryrun
660
- return {
661
- success: false,
662
- error: `Insufficient balance for gas. Have: ${Number(userBalance) / 1e9} SUI`,
663
- };
664
- }
665
- tx.setGasBudget(dryrunBudget);
666
- const dryRunResult = await this.suiClient.dryRunTransactionBlock({
667
- transactionBlock: await tx.build({ client: this.suiClient }),
668
- });
669
- if (dryRunResult.effects.status.status !== "success") {
670
- return {
671
- success: false,
672
- error: `Dry run failed: ${dryRunResult.effects.status.error}`,
673
- };
674
- }
675
- // Step 3: Calculate optimized gas budget (actual + 20% buffer)
676
- const actualGas = (0, gas_1.calculateActualGas)(dryRunResult.effects.gasUsed);
677
- const optimizedBudget = (0, gas_1.calculateOptimizedBudget)(actualGas);
678
- // Step 4: Check if user has enough balance for actual execution
679
- if (userBalance < optimizedBudget) {
680
- return {
681
- success: false,
682
- error: `Insufficient balance for gas. Need: ${Number(optimizedBudget) / 1e9} SUI, Have: ${Number(userBalance) / 1e9} SUI`,
683
- };
684
- }
685
- // Step 4: Execute with optimized gas budget
686
- tx.setGasBudget(optimizedBudget);
687
- const result = await this.suiClient.signAndExecuteTransaction({
688
- signer: this.keypair,
689
- transaction: tx,
690
- options: {
691
- showEffects: true,
692
- },
693
- });
694
- if (result.effects?.status.status === "success") {
695
- return {
696
- success: true,
697
- txDigest: result.digest,
698
- gasUsed: BigInt(result.effects.gasUsed.computationCost),
699
- };
700
- }
701
- return {
702
- success: false,
703
- txDigest: result.digest,
704
- error: result.effects?.status.error || "Execution failed",
705
- };
706
- }
707
- // ============================================================================
708
- // Scallop-Specific Methods (uses Scallop SDK builder for oracle updates)
709
- // ============================================================================
710
- /**
711
- * Execute Scallop leverage using native Scallop SDK builder
712
- *
713
- * Scallop requires oracle price updates via their SDK's updateAssetPricesQuick.
714
- * This method uses the Scallop SDK builder internally.
715
- */
716
- async executeScallopLeverage(params) {
717
- if (!this.keypair) {
718
- return { success: false, error: "Keypair required" };
719
- }
720
- try {
721
- // Resolve coin type and amounts
722
- const coinType = this.resolveCoinType(params.depositAsset);
723
- const reserve = (0, constants_1.getReserveByCoinType)(coinType);
724
- const decimals = reserve?.decimals || 9;
725
- const symbol = coinType.split("::").pop()?.toUpperCase() || "SUI";
726
- const isSui = coinType.endsWith("::sui::SUI");
727
- // Get coin name for Scallop (e.g., "sui", "usdc")
728
- const coinName = this.getScallopCoinName(coinType);
729
- // Calculate deposit amount
730
- let depositAmountStr;
731
- if (params.depositValueUsd) {
732
- const price = await (0, sdk_ts_1.getTokenPrice)(coinType);
733
- depositAmountStr = (params.depositValueUsd / price).toFixed(decimals);
734
- }
735
- else {
736
- depositAmountStr = params.depositAmount;
737
- }
738
- const depositAmountRaw = (0, utils_1.parseUnits)(depositAmountStr, decimals);
739
- const depositAmountHuman = parseFloat(depositAmountStr);
740
- // Calculate flash loan amount
741
- const depositPrice = await (0, sdk_ts_1.getTokenPrice)(coinType);
742
- const initialEquityUsd = depositAmountHuman * depositPrice;
743
- const flashLoanUsd = initialEquityUsd * (params.multiplier - 1);
744
- const flashLoanUsdc = BigInt(Math.ceil(flashLoanUsd * 1e6 * 1.02));
745
- const flashLoanFee = flash_loan_1.ScallopFlashLoanClient.calculateFee(flashLoanUsdc);
746
- const repaymentAmount = flashLoanUsdc + flashLoanFee;
747
- const borrowFeeBuffer = 1.003;
748
- const borrowAmount = BigInt(Math.ceil(Number(repaymentAmount) * borrowFeeBuffer));
749
- // Initialize Scallop SDK with secret key
750
- // Scallop SDK requires the original secret key string (not extracted from keypair)
751
- if (!this.options.secretKey) {
752
- return {
753
- success: false,
754
- error: "Scallop operations require secretKey in SDK options. Pass { secretKey: 'suiprivkey...' } to DefiDashSDK constructor.",
755
- };
756
- }
757
- const scallop = new sui_scallop_sdk_1.Scallop({
758
- secretKey: this.options.secretKey,
759
- networkType: "mainnet",
760
- });
761
- await scallop.init();
762
- const builder = await scallop.createScallopBuilder();
763
- const client = await scallop.createScallopClient();
764
- const tx = builder.createTxBlock();
765
- tx.setSender(this.userAddress);
766
- // Check for existing obligation
767
- const existingObligations = await client.getObligations();
768
- const hasExistingObligation = existingObligations.length > 0;
769
- let existingObligationId = null;
770
- let existingObligationKeyId = null;
771
- let isCurrentlyLocked = false;
772
- if (hasExistingObligation) {
773
- existingObligationId = existingObligations[0].id;
774
- existingObligationKeyId = existingObligations[0].keyId;
775
- isCurrentlyLocked = existingObligations[0].locked;
776
- }
777
- // Get swap quote
778
- const swapQuotes = await this.swapClient.quote({
779
- amountIn: flashLoanUsdc.toString(),
780
- coinTypeIn: types_1.COIN_TYPES.USDC,
781
- coinTypeOut: coinType,
782
- });
783
- if (swapQuotes.length === 0) {
784
- return { success: false, error: `No swap quotes for USDC → ${symbol}` };
785
- }
786
- const bestQuote = swapQuotes.sort((a, b) => Number(b.amountOut) - Number(a.amountOut))[0];
787
- // Build transaction using Scallop SDK
788
- // Step 1: Flash loan USDC
789
- const [loanCoin, receipt] = await tx.borrowFlashLoan(Number(flashLoanUsdc), "usdc");
790
- // Step 2: Swap USDC → deposit asset
791
- const swappedAsset = await this.swapClient.swap({
792
- quote: bestQuote,
793
- signer: this.userAddress,
794
- coinIn: loanCoin,
795
- tx: tx.txBlock,
796
- }, 100);
797
- // Step 3: Prepare deposit coin
798
- let depositCoin;
799
- if (isSui) {
800
- const [userDeposit] = tx.splitSUIFromGas([Number(depositAmountRaw)]);
801
- tx.mergeCoins(userDeposit, [swappedAsset]);
802
- depositCoin = userDeposit;
803
- }
804
- else {
805
- const userCoins = await this.suiClient.getCoins({
806
- owner: this.userAddress,
807
- coinType,
808
- });
809
- if (userCoins.data.length === 0) {
810
- return { success: false, error: `No ${symbol} coins in wallet` };
811
- }
812
- const primaryCoin = tx.txBlock.object(userCoins.data[0].coinObjectId);
813
- if (userCoins.data.length > 1) {
814
- const otherCoins = userCoins.data
815
- .slice(1)
816
- .map((c) => tx.txBlock.object(c.coinObjectId));
817
- tx.mergeCoins(primaryCoin, otherCoins);
818
- }
819
- const [userContribution] = tx.splitCoins(primaryCoin, [
820
- Number(depositAmountRaw),
821
- ]);
822
- tx.mergeCoins(userContribution, [swappedAsset]);
823
- depositCoin = userContribution;
824
- }
825
- // Step 4: Handle obligation
826
- let obligation;
827
- let obligationKey;
828
- let obligationHotPotato;
829
- let isNewObligation = false;
830
- if (hasExistingObligation && existingObligationId && existingObligationKeyId) {
831
- obligation = tx.txBlock.object(existingObligationId);
832
- obligationKey = tx.txBlock.object(existingObligationKeyId);
833
- if (isCurrentlyLocked) {
834
- tx.unstakeObligation(obligation, obligationKey);
835
- }
836
- tx.addCollateral(obligation, depositCoin, coinName);
837
- }
838
- else {
839
- [obligation, obligationKey, obligationHotPotato] = tx.openObligation();
840
- tx.addCollateral(obligation, depositCoin, coinName);
841
- isNewObligation = true;
842
- }
843
- // Step 5: Update oracles (critical for Scallop!)
844
- await tx.updateAssetPricesQuick([coinName, "usdc"]);
845
- // Step 6: Borrow USDC
846
- const borrowedUsdc = tx.borrow(obligation, obligationKey, Number(borrowAmount), "usdc");
847
- // Step 7: Repay flash loan
848
- await tx.repayFlashLoan(borrowedUsdc, receipt, "usdc");
849
- // Step 8: Finalize
850
- if (isNewObligation) {
851
- tx.returnObligation(obligation, obligationHotPotato);
852
- tx.stakeObligation(obligation, obligationKey);
853
- tx.transferObjects([obligationKey], this.userAddress);
854
- }
855
- else {
856
- tx.stakeObligation(obligation, obligationKey);
857
- }
858
- // Execute
859
- if (params.dryRun) {
860
- tx.txBlock.setGasBudget(gas_1.DRYRUN_GAS_BUDGET);
861
- const dryRunResult = await this.suiClient.dryRunTransactionBlock({
862
- transactionBlock: await tx.txBlock.build({ client: this.suiClient }),
863
- });
864
- if (dryRunResult.effects.status.status === "success") {
865
- const actualGas = (0, gas_1.calculateActualGas)(dryRunResult.effects.gasUsed);
866
- const optimizedBudget = (0, gas_1.calculateOptimizedBudget)(actualGas);
867
- return { success: true, gasUsed: optimizedBudget };
868
- }
869
- return {
870
- success: false,
871
- error: dryRunResult.effects.status.error || "Dry run failed",
872
- };
873
- }
874
- // For real execution, do dryrun first to optimize gas
875
- tx.txBlock.setGasBudget(gas_1.DRYRUN_GAS_BUDGET);
876
- const dryRunResult = await this.suiClient.dryRunTransactionBlock({
877
- transactionBlock: await tx.txBlock.build({ client: this.suiClient }),
878
- });
879
- if (dryRunResult.effects.status.status !== "success") {
880
- return {
881
- success: false,
882
- error: `Dry run failed: ${dryRunResult.effects.status.error}`,
883
- };
884
- }
885
- const actualGas = (0, gas_1.calculateActualGas)(dryRunResult.effects.gasUsed);
886
- const optimizedBudget = (0, gas_1.calculateOptimizedBudget)(actualGas);
887
- tx.txBlock.setGasBudget(optimizedBudget);
888
- const result = await builder.signAndSendTxBlock(tx);
889
- // Fetch transaction details to get actual gas used
890
- const txDetails = await this.suiClient.waitForTransaction({
891
- digest: result.digest,
892
- options: { showEffects: true },
893
- });
894
- const gasUsed = txDetails.effects?.gasUsed
895
- ? BigInt(txDetails.effects.gasUsed.computationCost)
896
- : actualGas;
897
- return {
898
- success: true,
899
- txDigest: result.digest,
900
- gasUsed,
901
- };
902
- }
903
- catch (error) {
904
- return {
905
- success: false,
906
- error: error.message || String(error),
907
- };
908
- }
909
- }
910
- /**
911
- * Get Scallop coin name from coin type
912
- */
913
- getScallopCoinName(coinType) {
914
- const normalized = (0, utils_1.normalizeCoinType)(coinType);
915
- const COIN_NAME_MAP = {
916
- "0x0000000000000000000000000000000000000000000000000000000000000002::sui::SUI": "sui",
917
- "0xdba34672e30cb065b1f93e3ab55318768fd6fef66c15942c9f7cb846e2f900e7::usdc::USDC": "usdc",
918
- "0x5d4b302506645c37ff133b98c4b50a5ae14841659738d6d733d59d0d217a93bf::coin::COIN": "wusdc",
919
- "0xc060006111016b8a020ad5b33834984a437aaa7d3c74c18e09a95d48aceab08c::coin::COIN": "wusdt",
920
- };
921
- return COIN_NAME_MAP[normalized] || normalized.split("::").pop()?.toLowerCase() || "sui";
569
+ return (0, execution_1.executeTransaction)(this.suiClient, this.keypair, this.userAddress, tx);
922
570
  }
923
571
  }
924
572
  exports.DefiDashSDK = DefiDashSDK;