@sodax/sdk 1.0.1-beta-rc3 → 1.0.2-beta

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/dist/index.mjs CHANGED
@@ -6905,6 +6905,11 @@ var ConfigService = class {
6905
6905
  getMoneyMarketTokens() {
6906
6906
  return this.sodaxConfig.supportedMoneyMarketTokens;
6907
6907
  }
6908
+ getMoneyMarketToken(chainId, token) {
6909
+ return this.sodaxConfig.supportedMoneyMarketTokens[chainId].find(
6910
+ (t) => t.address.toLowerCase() === token.toLowerCase()
6911
+ );
6912
+ }
6908
6913
  getMoneyMarketReserveAssets() {
6909
6914
  return this.sodaxConfig.supportedMoneyMarketReserveAssets;
6910
6915
  }
@@ -6924,7 +6929,10 @@ var ConfigService = class {
6924
6929
  return this.supportedSodaVaultAssetsSet.has(vault.toLowerCase());
6925
6930
  }
6926
6931
  isValidVault(vault) {
6927
- return this.isValidSodaVaultAsset(vault);
6932
+ if (typeof vault === "string") {
6933
+ return this.isValidSodaVaultAsset(vault);
6934
+ }
6935
+ return this.isValidSodaVaultAsset(vault.address);
6928
6936
  }
6929
6937
  isValidChainHubAsset(chainId, hubAsset) {
6930
6938
  return this.chainIdToHubAssetsMap.get(chainId)?.has(hubAsset.toLowerCase()) ?? false;
@@ -12899,7 +12907,8 @@ var SwapService = class {
12899
12907
  intentParams: params,
12900
12908
  spokeProvider,
12901
12909
  fee = this.config.partnerFee,
12902
- raw
12910
+ raw,
12911
+ skipSimulation = false
12903
12912
  }) {
12904
12913
  invariant6(
12905
12914
  this.configService.isValidOriginalAssetAddress(params.srcChain, params.inputToken),
@@ -12968,7 +12977,8 @@ var SwapService = class {
12968
12977
  },
12969
12978
  spokeProvider,
12970
12979
  this.hubProvider,
12971
- raw
12980
+ raw,
12981
+ skipSimulation
12972
12982
  );
12973
12983
  return {
12974
12984
  ok: true,
@@ -12988,6 +12998,179 @@ var SwapService = class {
12988
12998
  };
12989
12999
  }
12990
13000
  }
13001
+ /**
13002
+ * Creates a limit order intent (no deadline, must be cancelled manually by user).
13003
+ * Similar to swap but enforces deadline=0n (no deadline).
13004
+ * Limit orders remain active until manually cancelled by the user.
13005
+ *
13006
+ * @param {Prettify<LimitOrderParams<S> & OptionalTimeout>} params - Object containing:
13007
+ * - intentParams: The parameters for creating the limit order (deadline is automatically set to 0n, deadline field should be omitted).
13008
+ * - spokeProvider: The spoke provider instance.
13009
+ * - fee: (Optional) Partner fee configuration.
13010
+ * - timeout: (Optional) Timeout in milliseconds for the transaction (default: 60 seconds).
13011
+ * - skipSimulation: (Optional) Whether to skip transaction simulation (default: false).
13012
+ * @returns {Promise<Result<[SolverExecutionResponse, Intent, IntentDeliveryInfo], IntentError<IntentErrorCode>>>} A promise resolving to a Result containing a tuple of SolverExecutionResponse, Intent, and intent delivery info, or an IntentError if the operation fails.
13013
+ *
13014
+ * @example
13015
+ * const payload = {
13016
+ * "inputToken": "0x2170Ed0880ac9A755fd29B2688956BD959F933F8", // BSC ETH token address
13017
+ * "outputToken": "0x2f2a2543B76A4166549F7aaB2e75Bef0aefC5B0f", // ARB WBTC token address
13018
+ * "inputAmount": 1000000000000000n, // The amount of input tokens
13019
+ * "minOutputAmount": 900000000000000n, // min amount you are expecting to receive
13020
+ * // deadline is omitted - will be automatically set to 0n
13021
+ * "allowPartialFill": false, // Whether the intent can be partially filled
13022
+ * "srcChain": "0x38.bsc", // Chain ID where input tokens originate
13023
+ * "dstChain": "0xa4b1.arbitrum", // Chain ID where output tokens should be delivered
13024
+ * "srcAddress": "0x..", // Source address (original address on spoke chain)
13025
+ * "dstAddress": "0x...", // Destination address (original address on spoke chain)
13026
+ * "solver": "0x..", // Optional specific solver address (address(0) = any solver)
13027
+ * "data": "0x..", // Additional arbitrary data
13028
+ * } satisfies CreateLimitOrderParams;
13029
+ *
13030
+ * const createLimitOrderResult = await swapService.createLimitOrder({
13031
+ * intentParams: payload,
13032
+ * spokeProvider,
13033
+ * fee, // optional
13034
+ * timeout, // optional
13035
+ * });
13036
+ *
13037
+ * if (createLimitOrderResult.ok) {
13038
+ * const [solverExecutionResponse, intent, intentDeliveryInfo] = createLimitOrderResult.value;
13039
+ * console.log('Intent execution response:', solverExecutionResponse);
13040
+ * console.log('Intent:', intent);
13041
+ * console.log('Intent delivery info:', intentDeliveryInfo);
13042
+ * // Limit order is now active and will remain until cancelled manually
13043
+ * } else {
13044
+ * // handle error
13045
+ * }
13046
+ */
13047
+ async createLimitOrder({
13048
+ intentParams: params,
13049
+ spokeProvider,
13050
+ fee = this.config.partnerFee,
13051
+ timeout = DEFAULT_RELAY_TX_TIMEOUT,
13052
+ skipSimulation = false
13053
+ }) {
13054
+ const limitOrderParams = {
13055
+ ...params,
13056
+ deadline: 0n
13057
+ };
13058
+ return this.createAndSubmitIntent({
13059
+ intentParams: limitOrderParams,
13060
+ spokeProvider,
13061
+ fee,
13062
+ timeout,
13063
+ skipSimulation
13064
+ });
13065
+ }
13066
+ /**
13067
+ * Creates a limit order intent (no deadline, must be cancelled manually by user).
13068
+ * Similar to createIntent but enforces deadline=0n (no deadline) and uses LimitOrderParams.
13069
+ * Limit orders remain active until manually cancelled by the user.
13070
+ * NOTE: This method does not submit the intent to the Solver API
13071
+ *
13072
+ * @param {Prettify<LimitOrderParams<S> & OptionalRaw<R>>} params - Object containing:
13073
+ * - intentParams: The parameters for creating the limit order (deadline is automatically set to 0n, deadline field should be omitted).
13074
+ * - spokeProvider: The spoke provider instance.
13075
+ * - fee: (Optional) Partner fee configuration.
13076
+ * - raw: (Optional) Whether to return the raw transaction data instead of executing it
13077
+ * - skipSimulation: (Optional) Whether to skip transaction simulation (default: false).
13078
+ * @returns {Promise<Result<[TxReturnType<S, R>, Intent & FeeAmount, Hex], IntentError<'CREATION_FAILED'>>>} The encoded contract call or raw transaction data, Intent and intent data as hex
13079
+ *
13080
+ * @example
13081
+ * const payload = {
13082
+ * "inputToken": "0x2170Ed0880ac9A755fd29B2688956BD959F933F8", // BSC ETH token address
13083
+ * "outputToken": "0x2f2a2543B76A4166549F7aaB2e75Bef0aefC5B0f", // ARB WBTC token address
13084
+ * "inputAmount": 1000000000000000n, // The amount of input tokens
13085
+ * "minOutputAmount": 900000000000000n, // min amount you are expecting to receive
13086
+ * // deadline is omitted - will be automatically set to 0n
13087
+ * "allowPartialFill": false, // Whether the intent can be partially filled
13088
+ * "srcChain": "0x38.bsc", // Chain ID where input tokens originate
13089
+ * "dstChain": "0xa4b1.arbitrum", // Chain ID where output tokens should be delivered
13090
+ * "srcAddress": "0x..", // Source address (original address on spoke chain)
13091
+ * "dstAddress": "0x...", // Destination address (original address on spoke chain)
13092
+ * "solver": "0x..", // Optional specific solver address (address(0) = any solver)
13093
+ * "data": "0x..", // Additional arbitrary data
13094
+ * } satisfies CreateLimitOrderParams;
13095
+ *
13096
+ * const createLimitOrderIntentResult = await swapService.createLimitOrderIntent({
13097
+ * intentParams: payload,
13098
+ * spokeProvider,
13099
+ * fee, // optional
13100
+ * raw, // optional
13101
+ * });
13102
+ *
13103
+ * if (createLimitOrderIntentResult.ok) {
13104
+ * const [txResult, intent, intentData] = createLimitOrderIntentResult.value;
13105
+ * console.log('Transaction result:', txResult);
13106
+ * console.log('Intent:', intent);
13107
+ * console.log('Intent data:', intentData);
13108
+ * } else {
13109
+ * // handle error
13110
+ * }
13111
+ */
13112
+ async createLimitOrderIntent({
13113
+ intentParams: params,
13114
+ spokeProvider,
13115
+ fee = this.config.partnerFee,
13116
+ raw,
13117
+ skipSimulation = false
13118
+ }) {
13119
+ const limitOrderParams = {
13120
+ ...params,
13121
+ deadline: 0n
13122
+ };
13123
+ return this.createIntent({
13124
+ intentParams: limitOrderParams,
13125
+ spokeProvider,
13126
+ fee,
13127
+ raw,
13128
+ skipSimulation
13129
+ });
13130
+ }
13131
+ /**
13132
+ * Syntactic sugar for cancelAndSubmitIntent: cancels a limit order intent and submits it to the Relayer API.
13133
+ * Similar to swap function that wraps createAndSubmitIntent.
13134
+ *
13135
+ * @param params - Object containing:
13136
+ * @param params.intent - The limit order intent to cancel.
13137
+ * @param params.spokeProvider - The spoke provider instance.
13138
+ * @param params.timeout - (Optional) Timeout in milliseconds for the transaction (default: 60 seconds).
13139
+ * @returns
13140
+ * A promise resolving to a Result containing a tuple of cancel transaction hash and destination transaction hash,
13141
+ * or an IntentError if the operation fails.
13142
+ *
13143
+ * @example
13144
+ * // Get intent first (or use intent from createLimitOrder response)
13145
+ * const intent: Intent = await swapService.getIntent(txHash);
13146
+ *
13147
+ * // Cancel the limit order
13148
+ * const result = await swapService.cancelLimitOrder({
13149
+ * intent,
13150
+ * spokeProvider,
13151
+ * timeout, // optional
13152
+ * });
13153
+ *
13154
+ * if (result.ok) {
13155
+ * const [cancelTxHash, dstTxHash] = result.value;
13156
+ * console.log('Cancel transaction hash:', cancelTxHash);
13157
+ * console.log('Destination transaction hash:', dstTxHash);
13158
+ * } else {
13159
+ * // handle error
13160
+ * console.error('[cancelLimitOrder] error:', result.error);
13161
+ * }
13162
+ */
13163
+ async cancelLimitOrder({
13164
+ intent,
13165
+ spokeProvider,
13166
+ timeout = DEFAULT_RELAY_TX_TIMEOUT
13167
+ }) {
13168
+ return this.cancelAndSubmitIntent({
13169
+ intent,
13170
+ spokeProvider,
13171
+ timeout
13172
+ });
13173
+ }
12991
13174
  /**
12992
13175
  * Cancels an intent
12993
13176
  * @param {Intent} intent - The intent to cancel
@@ -13029,7 +13212,97 @@ var SwapService = class {
13029
13212
  } catch (error) {
13030
13213
  return {
13031
13214
  ok: false,
13032
- error
13215
+ error: {
13216
+ code: "CANCEL_FAILED",
13217
+ data: {
13218
+ payload: intent,
13219
+ error
13220
+ }
13221
+ }
13222
+ };
13223
+ }
13224
+ }
13225
+ /**
13226
+ * Cancels an intent on the spoke chain, submits the cancel intent to the relayer API,
13227
+ * and waits until the intent cancel is executed (on the destination/hub chain).
13228
+ * Follows a similar workflow to createAndSubmitIntent, but for cancelling.
13229
+ *
13230
+ * @param params - The parameters for canceling and submitting the intent.
13231
+ * @param params.intent - The intent to be canceled.
13232
+ * @param params.spokeProvider - The provider for the spoke chain.
13233
+ * @param params.timeout - Optional timeout in milliseconds (default: 60 seconds).
13234
+ * @returns
13235
+ * A Result containing the SolverExecutionResponse (cancel tx), intent, and relay info,
13236
+ * or an IntentError on failure.
13237
+ */
13238
+ async cancelAndSubmitIntent({
13239
+ intent,
13240
+ spokeProvider,
13241
+ timeout = DEFAULT_RELAY_TX_TIMEOUT
13242
+ }) {
13243
+ try {
13244
+ const cancelResult = await this.cancelIntent(intent, spokeProvider, false);
13245
+ if (!cancelResult.ok) {
13246
+ return cancelResult;
13247
+ }
13248
+ const cancelTxHash = cancelResult.value;
13249
+ const verifyTxHashResult = await SpokeService.verifyTxHash(cancelTxHash, spokeProvider);
13250
+ if (!verifyTxHashResult.ok) {
13251
+ return {
13252
+ ok: false,
13253
+ error: {
13254
+ code: "CANCEL_FAILED",
13255
+ data: {
13256
+ payload: intent,
13257
+ error: verifyTxHashResult.error
13258
+ }
13259
+ }
13260
+ };
13261
+ }
13262
+ let dstIntentTxHash;
13263
+ if (spokeProvider.chainConfig.chain.id !== this.hubProvider.chainConfig.chain.id) {
13264
+ const intentRelayChainId = intent.srcChain.toString();
13265
+ const submitPayload = {
13266
+ action: "submit",
13267
+ params: {
13268
+ chain_id: intentRelayChainId,
13269
+ tx_hash: cancelTxHash
13270
+ }
13271
+ };
13272
+ const submitResult = await this.submitIntent(submitPayload);
13273
+ if (!submitResult.ok) {
13274
+ return submitResult;
13275
+ }
13276
+ const packet = await waitUntilIntentExecuted({
13277
+ intentRelayChainId,
13278
+ spokeTxHash: cancelTxHash,
13279
+ timeout,
13280
+ apiUrl: this.config.relayerApiEndpoint
13281
+ });
13282
+ if (!packet.ok) {
13283
+ return {
13284
+ ok: false,
13285
+ error: packet.error
13286
+ };
13287
+ }
13288
+ dstIntentTxHash = packet.value.dst_tx_hash;
13289
+ } else {
13290
+ dstIntentTxHash = cancelTxHash;
13291
+ }
13292
+ return {
13293
+ ok: true,
13294
+ value: [cancelTxHash, dstIntentTxHash]
13295
+ };
13296
+ } catch (error) {
13297
+ return {
13298
+ ok: false,
13299
+ error: {
13300
+ code: "CANCEL_FAILED",
13301
+ data: {
13302
+ payload: intent,
13303
+ error
13304
+ }
13305
+ }
13033
13306
  };
13034
13307
  }
13035
13308
  }
@@ -13346,7 +13619,7 @@ var SonicSpokeService = class _SonicSpokeService {
13346
13619
  const aTokenAddress = (await dataService.getReserveData(vaultAddress)).aTokenAddress;
13347
13620
  return {
13348
13621
  aTokenAddress,
13349
- aTokenAmount: amount,
13622
+ aTokenAmount: EvmVaultTokenService.translateIncomingDecimals(assetConfig.decimal, amount),
13350
13623
  token
13351
13624
  };
13352
13625
  }
@@ -13359,12 +13632,15 @@ var SonicSpokeService = class _SonicSpokeService {
13359
13632
  * @param configService - The config service
13360
13633
  * @returns BorrowInfo containing variable debt token address and vault address
13361
13634
  */
13362
- static async getBorrowInfo(token, amount, chainId, dataService, configService) {
13635
+ static async getBorrowInfo(token, amount, chainId, dataService, configService, moneyMarketConfig) {
13363
13636
  const assetConfig = configService.getHubAssetInfo(chainId, token);
13364
13637
  if (!assetConfig) {
13365
13638
  throw new Error("[SonicSpokeService.getBorrowInfo] Hub asset not found");
13366
13639
  }
13367
- const vaultAddress = assetConfig.vault;
13640
+ let vaultAddress = assetConfig.vault;
13641
+ if (moneyMarketConfig.bnUSDVault.toLowerCase() === vaultAddress.toLowerCase()) {
13642
+ vaultAddress = moneyMarketConfig.bnUSD;
13643
+ }
13368
13644
  const reserveData = await dataService.getReserveData(vaultAddress);
13369
13645
  const variableDebtTokenAddress = reserveData.variableDebtTokenAddress;
13370
13646
  return {
@@ -13576,10 +13852,18 @@ var MoneyMarketService = class _MoneyMarketService {
13576
13852
  try {
13577
13853
  invariant6(params.amount > 0n, "Amount must be greater than 0");
13578
13854
  invariant6(params.token.length > 0, "Token is required");
13579
- invariant6(
13580
- this.configService.isMoneyMarketSupportedToken(spokeProvider.chainConfig.chain.id, params.token),
13581
- `Unsupported spoke chain (${spokeProvider.chainConfig.chain.id}) token: ${params.token}`
13582
- );
13855
+ if (params.action === "withdraw" || params.action === "borrow") {
13856
+ const toChainId = params.toChainId ?? spokeProvider.chainConfig.chain.id;
13857
+ invariant6(
13858
+ this.configService.isMoneyMarketSupportedToken(toChainId, params.token),
13859
+ `Unsupported spoke chain (${toChainId}) token: ${params.token}`
13860
+ );
13861
+ } else {
13862
+ invariant6(
13863
+ this.configService.isMoneyMarketSupportedToken(spokeProvider.chainConfig.chain.id, params.token),
13864
+ `Unsupported spoke chain (${spokeProvider.chainConfig.chain.id}) token: ${params.token}`
13865
+ );
13866
+ }
13583
13867
  const walletAddress = await spokeProvider.walletProvider.getWalletAddress();
13584
13868
  if (spokeProvider instanceof StellarSpokeProvider && (params.action === "supply" || params.action === "repay")) {
13585
13869
  return {
@@ -13617,7 +13901,8 @@ var MoneyMarketService = class _MoneyMarketService {
13617
13901
  params.amount,
13618
13902
  params.toChainId ?? spokeProvider.chainConfig.chain.id,
13619
13903
  this.data,
13620
- this.configService
13904
+ this.configService,
13905
+ this.config
13621
13906
  );
13622
13907
  return await SonicSpokeService.isBorrowApproved(
13623
13908
  walletAddress,
@@ -13681,10 +13966,18 @@ var MoneyMarketService = class _MoneyMarketService {
13681
13966
  try {
13682
13967
  invariant6(params.amount > 0n, "Amount must be greater than 0");
13683
13968
  invariant6(params.token.length > 0, "Token is required");
13684
- invariant6(
13685
- this.configService.isMoneyMarketSupportedToken(spokeProvider.chainConfig.chain.id, params.token),
13686
- `Unsupported spoke chain (${spokeProvider.chainConfig.chain.id}) token: ${params.token}`
13687
- );
13969
+ if (params.action === "withdraw" || params.action === "borrow") {
13970
+ const toChainId = params.toChainId ?? spokeProvider.chainConfig.chain.id;
13971
+ invariant6(
13972
+ this.configService.isMoneyMarketSupportedToken(toChainId, params.token),
13973
+ `Unsupported spoke chain (${toChainId}) token: ${params.token}`
13974
+ );
13975
+ } else {
13976
+ invariant6(
13977
+ this.configService.isMoneyMarketSupportedToken(spokeProvider.chainConfig.chain.id, params.token),
13978
+ `Unsupported spoke chain (${spokeProvider.chainConfig.chain.id}) token: ${params.token}`
13979
+ );
13980
+ }
13688
13981
  const walletAddress = await spokeProvider.walletProvider.getWalletAddress();
13689
13982
  if (spokeProvider instanceof StellarSpokeProvider) {
13690
13983
  invariant6(
@@ -13746,7 +14039,8 @@ var MoneyMarketService = class _MoneyMarketService {
13746
14039
  params.amount,
13747
14040
  params?.toChainId ?? spokeProvider.chainConfig.chain.id,
13748
14041
  this.data,
13749
- this.configService
14042
+ this.configService,
14043
+ this.config
13750
14044
  );
13751
14045
  const result = await SonicSpokeService.approveBorrow(
13752
14046
  walletAddress,
@@ -13835,7 +14129,7 @@ var MoneyMarketService = class _MoneyMarketService {
13835
14129
  };
13836
14130
  }
13837
14131
  let intentTxHash = null;
13838
- if (spokeProvider.chainConfig.chain.id !== SONIC_MAINNET_CHAIN_ID) {
14132
+ if (spokeProvider.chainConfig.chain.id !== this.hubProvider.chainConfig.chain.id) {
13839
14133
  const packetResult = await relayTxAndWaitPacket(
13840
14134
  txResult.value,
13841
14135
  spokeProvider instanceof SolanaSpokeProvider ? txResult.data : void 0,
@@ -14000,10 +14294,8 @@ var MoneyMarketService = class _MoneyMarketService {
14000
14294
  }
14001
14295
  };
14002
14296
  }
14003
- const fromChainId = spokeProvider.chainConfig.chain.id;
14004
- const toChainId = params.toChainId ?? fromChainId;
14005
14297
  let intentTxHash = null;
14006
- if (toChainId !== SONIC_MAINNET_CHAIN_ID) {
14298
+ if (spokeProvider.chainConfig.chain.id !== this.hubProvider.chainConfig.chain.id || params.toChainId && params.toAddress && params.toChainId !== this.hubProvider.chainConfig.chain.id) {
14007
14299
  const packetResult = await relayTxAndWaitPacket(
14008
14300
  txResult.value,
14009
14301
  spokeProvider instanceof SolanaSpokeProvider ? txResult.data : void 0,
@@ -14079,13 +14371,11 @@ var MoneyMarketService = class _MoneyMarketService {
14079
14371
  const fromAddress = await spokeProvider.walletProvider.getWalletAddress();
14080
14372
  const toChainId = params.toChainId ?? fromChainId;
14081
14373
  const toAddress = params.toAddress ?? fromAddress;
14082
- invariant6(
14083
- this.configService.isMoneyMarketSupportedToken(toChainId, params.token),
14084
- `Unsupported spoke chain (${toChainId}) token: ${params.token}`
14085
- );
14374
+ const dstToken = this.configService.getMoneyMarketToken(toChainId, params.token);
14375
+ invariant6(dstToken, `Money market token not found for spoke chain (${toChainId}) token: ${params.token}`);
14086
14376
  const encodedToAddress = encodeAddress(toChainId, toAddress);
14087
14377
  const fromHubWallet = await deriveUserWalletAddress(this.hubProvider, fromChainId, fromAddress);
14088
- const data = this.buildBorrowData(fromHubWallet, encodedToAddress, params.token, params.amount, toChainId);
14378
+ const data = this.buildBorrowData(fromHubWallet, encodedToAddress, dstToken.address, params.amount, toChainId);
14089
14379
  let txResult;
14090
14380
  if (fromChainId === this.hubProvider.chainConfig.chain.id && isSonicSpokeProviderType(spokeProvider)) {
14091
14381
  txResult = await SonicSpokeService.callWallet(data, spokeProvider, raw);
@@ -14148,10 +14438,8 @@ var MoneyMarketService = class _MoneyMarketService {
14148
14438
  }
14149
14439
  };
14150
14440
  }
14151
- const fromChainId = spokeProvider.chainConfig.chain.id;
14152
- const toChainId = params.toChainId ?? fromChainId;
14153
14441
  let intentTxHash = null;
14154
- if (toChainId !== SONIC_MAINNET_CHAIN_ID) {
14442
+ if (spokeProvider.chainConfig.chain.id !== this.hubProvider.chainConfig.chain.id || params.toChainId && params.toAddress && params.toChainId !== this.hubProvider.chainConfig.chain.id && params.toAddress !== this.hubProvider.chainConfig.addresses.walletRouter) {
14155
14443
  const packetResult = await relayTxAndWaitPacket(
14156
14444
  txResult.value,
14157
14445
  spokeProvider instanceof SolanaSpokeProvider ? txResult.data : void 0,
@@ -14312,7 +14600,7 @@ var MoneyMarketService = class _MoneyMarketService {
14312
14600
  };
14313
14601
  }
14314
14602
  let intentTxHash = null;
14315
- if (spokeProvider.chainConfig.chain.id !== SONIC_MAINNET_CHAIN_ID) {
14603
+ if (spokeProvider.chainConfig.chain.id !== this.hubProvider.chainConfig.chain.id) {
14316
14604
  const packetResult = await relayTxAndWaitPacket(
14317
14605
  txResult.value,
14318
14606
  spokeProvider instanceof SolanaSpokeProvider ? txResult.data : void 0,
@@ -14431,8 +14719,10 @@ var MoneyMarketService = class _MoneyMarketService {
14431
14719
  const fromHubAsset = this.configService.getHubAssetInfo(fromChainId, fromToken);
14432
14720
  invariant6(fromHubAsset, `hub asset not found for source chain token (token): ${fromToken}`);
14433
14721
  const lendingPool = this.config.lendingPool;
14434
- calls.push(Erc20Service.encodeApprove(fromHubAsset.asset, fromHubAsset.vault, amount));
14435
- calls.push(EvmVaultTokenService.encodeDeposit(fromHubAsset.vault, fromHubAsset.asset, amount));
14722
+ if (!this.configService.isValidVault(fromHubAsset.asset)) {
14723
+ calls.push(Erc20Service.encodeApprove(fromHubAsset.asset, fromHubAsset.vault, amount));
14724
+ calls.push(EvmVaultTokenService.encodeDeposit(fromHubAsset.vault, fromHubAsset.asset, amount));
14725
+ }
14436
14726
  const translatedAmount = EvmVaultTokenService.translateIncomingDecimals(fromHubAsset.decimal, amount);
14437
14727
  calls.push(Erc20Service.encodeApprove(fromHubAsset.vault, lendingPool, translatedAmount));
14438
14728
  calls.push(
@@ -14454,29 +14744,44 @@ var MoneyMarketService = class _MoneyMarketService {
14454
14744
  */
14455
14745
  buildBorrowData(fromHubAddress, toAddress, toToken, amount, toChainId) {
14456
14746
  const toHubAsset = this.configService.getHubAssetInfo(toChainId, toToken);
14747
+ const dstToken = this.configService.getMoneyMarketToken(toChainId, toToken);
14457
14748
  invariant6(toHubAsset, `hub asset not found for target chain token (toToken): ${toToken}`);
14749
+ invariant6(dstToken, `Money market token not found for spoke chain (${toChainId}) token: ${toToken}`);
14458
14750
  const assetAddress = toHubAsset.asset;
14459
14751
  const vaultAddress = toHubAsset.vault;
14460
14752
  const bnUSDVault = this.config.bnUSDVault;
14461
14753
  const bnUSD = this.config.bnUSD;
14462
- const feeAmount = calculateFeeAmount(amount, this.config.partnerFee);
14754
+ const translatedInAmount = EvmVaultTokenService.translateIncomingDecimals(toHubAsset.decimal, amount);
14755
+ const feeAmount = calculateFeeAmount(translatedInAmount, this.config.partnerFee);
14463
14756
  const calls = [];
14464
- if (bnUSDVault && bnUSD && bnUSDVault.toLowerCase() === vaultAddress.toLowerCase()) {
14757
+ if (bnUSDVault.toLowerCase() === vaultAddress.toLowerCase()) {
14465
14758
  calls.push(
14466
14759
  _MoneyMarketService.encodeBorrow(
14467
- { asset: bnUSD, amount, interestRateMode: 2n, referralCode: 0, onBehalfOf: fromHubAddress },
14760
+ {
14761
+ asset: bnUSD,
14762
+ amount: translatedInAmount,
14763
+ interestRateMode: 2n,
14764
+ referralCode: 0,
14765
+ onBehalfOf: fromHubAddress
14766
+ },
14468
14767
  this.config.lendingPool
14469
14768
  )
14470
14769
  );
14471
- calls.push(Erc20Service.encodeApprove(bnUSD, bnUSDVault, amount));
14472
- calls.push(EvmVaultTokenService.encodeDeposit(bnUSDVault, bnUSD, amount));
14770
+ calls.push(Erc20Service.encodeApprove(bnUSD, bnUSDVault, translatedInAmount));
14771
+ calls.push(EvmVaultTokenService.encodeDeposit(bnUSDVault, bnUSD, translatedInAmount));
14473
14772
  if (this.config.partnerFee && feeAmount) {
14474
14773
  calls.push(Erc20Service.encodeTransfer(bnUSDVault, this.config.partnerFee.address, feeAmount));
14475
14774
  }
14476
14775
  } else {
14477
14776
  calls.push(
14478
14777
  _MoneyMarketService.encodeBorrow(
14479
- { asset: vaultAddress, amount, interestRateMode: 2n, referralCode: 0, onBehalfOf: fromHubAddress },
14778
+ {
14779
+ asset: vaultAddress,
14780
+ amount: translatedInAmount,
14781
+ interestRateMode: 2n,
14782
+ referralCode: 0,
14783
+ onBehalfOf: fromHubAddress
14784
+ },
14480
14785
  this.config.lendingPool
14481
14786
  )
14482
14787
  );
@@ -14484,8 +14789,21 @@ var MoneyMarketService = class _MoneyMarketService {
14484
14789
  calls.push(Erc20Service.encodeTransfer(vaultAddress, this.config.partnerFee.address, feeAmount));
14485
14790
  }
14486
14791
  }
14487
- calls.push(EvmVaultTokenService.encodeWithdraw(vaultAddress, assetAddress, amount - feeAmount));
14488
- const translatedAmountOut = EvmVaultTokenService.translateOutgoingDecimals(toHubAsset.decimal, amount - feeAmount);
14792
+ if (toToken.toLowerCase() !== vaultAddress.toLowerCase()) {
14793
+ calls.push(EvmVaultTokenService.encodeWithdraw(vaultAddress, assetAddress, translatedInAmount - feeAmount));
14794
+ }
14795
+ let translatedAmountOut;
14796
+ if (this.configService.isValidVault(toToken)) {
14797
+ translatedAmountOut = EvmVaultTokenService.translateOutgoingDecimals(
14798
+ toHubAsset.decimal,
14799
+ translatedInAmount - feeAmount
14800
+ );
14801
+ } else {
14802
+ translatedAmountOut = EvmVaultTokenService.translateOutgoingDecimals(
14803
+ dstToken.decimals,
14804
+ translatedInAmount - feeAmount
14805
+ );
14806
+ }
14489
14807
  if (toChainId === this.hubProvider.chainConfig.chain.id) {
14490
14808
  if (assetAddress.toLowerCase() === this.configService.spokeChainConfig[toChainId].addresses.wrappedSonic.toLowerCase()) {
14491
14809
  const withdrawToCall = {
@@ -14525,17 +14843,27 @@ var MoneyMarketService = class _MoneyMarketService {
14525
14843
  buildWithdrawData(fromHubAddress, toAddress, toToken, amount, toChainId) {
14526
14844
  const calls = [];
14527
14845
  const toHubAsset = this.configService.getHubAssetInfo(toChainId, toToken);
14846
+ const dstToken = this.configService.getMoneyMarketToken(toChainId, toToken);
14528
14847
  invariant6(toHubAsset, `hub asset not found for target chain token (toToken): ${toToken}`);
14848
+ invariant6(dstToken, `Money market token not found for spoke chain (${toChainId}) token: ${toToken}`);
14529
14849
  const assetAddress = toHubAsset.asset;
14530
14850
  const vaultAddress = toHubAsset.vault;
14851
+ const translatedInAmount = EvmVaultTokenService.translateIncomingDecimals(toHubAsset.decimal, amount);
14531
14852
  calls.push(
14532
14853
  _MoneyMarketService.encodeWithdraw(
14533
- { asset: vaultAddress, amount, to: fromHubAddress },
14854
+ { asset: vaultAddress, amount: translatedInAmount, to: fromHubAddress },
14534
14855
  this.config.lendingPool
14535
14856
  )
14536
14857
  );
14537
- calls.push(EvmVaultTokenService.encodeWithdraw(vaultAddress, assetAddress, amount));
14538
- const translatedAmountOut = EvmVaultTokenService.translateOutgoingDecimals(toHubAsset.decimal, amount);
14858
+ if (!this.configService.isValidVault(toToken)) {
14859
+ calls.push(EvmVaultTokenService.encodeWithdraw(vaultAddress, assetAddress, translatedInAmount));
14860
+ }
14861
+ let translatedAmountOut;
14862
+ if (this.configService.isValidVault(toToken)) {
14863
+ translatedAmountOut = EvmVaultTokenService.translateOutgoingDecimals(toHubAsset.decimal, translatedInAmount);
14864
+ } else {
14865
+ translatedAmountOut = EvmVaultTokenService.translateOutgoingDecimals(dstToken.decimals, translatedInAmount);
14866
+ }
14539
14867
  if (toChainId === this.hubProvider.chainConfig.chain.id) {
14540
14868
  if (assetAddress.toLowerCase() === this.configService.spokeChainConfig[toChainId].addresses.wrappedSonic.toLowerCase()) {
14541
14869
  const withdrawToCall = {
@@ -14579,18 +14907,23 @@ var MoneyMarketService = class _MoneyMarketService {
14579
14907
  const vaultAddress = fromHubAsset.vault;
14580
14908
  const bnUSDVault = this.config.bnUSDVault;
14581
14909
  const bnUSD = this.config.bnUSD;
14582
- calls.push(Erc20Service.encodeApprove(assetAddress, vaultAddress, amount));
14583
- calls.push(EvmVaultTokenService.encodeDeposit(vaultAddress, assetAddress, amount));
14584
- const translatedAmount = EvmVaultTokenService.translateIncomingDecimals(fromHubAsset.decimal, amount);
14910
+ const translatedAmountIn = EvmVaultTokenService.translateIncomingDecimals(fromHubAsset.decimal, amount);
14585
14911
  let repayToken = vaultAddress;
14586
- if (bnUSDVault && bnUSD && bnUSDVault.toLowerCase() === vaultAddress.toLowerCase()) {
14912
+ if (bnUSDVault.toLowerCase() === vaultAddress.toLowerCase()) {
14587
14913
  repayToken = bnUSD;
14588
- calls.push(EvmVaultTokenService.encodeWithdraw(bnUSDVault, bnUSD, translatedAmount));
14914
+ if (assetAddress.toLowerCase() !== bnUSDVault.toLowerCase()) {
14915
+ calls.push(Erc20Service.encodeApprove(assetAddress, vaultAddress, translatedAmountIn));
14916
+ calls.push(EvmVaultTokenService.encodeDeposit(vaultAddress, assetAddress, translatedAmountIn));
14917
+ }
14918
+ calls.push(EvmVaultTokenService.encodeWithdraw(bnUSDVault, bnUSD, translatedAmountIn));
14919
+ } else {
14920
+ calls.push(Erc20Service.encodeApprove(assetAddress, vaultAddress, amount));
14921
+ calls.push(EvmVaultTokenService.encodeDeposit(vaultAddress, assetAddress, amount));
14589
14922
  }
14590
- calls.push(Erc20Service.encodeApprove(repayToken, this.config.lendingPool, translatedAmount));
14923
+ calls.push(Erc20Service.encodeApprove(repayToken, this.config.lendingPool, translatedAmountIn));
14591
14924
  calls.push(
14592
14925
  _MoneyMarketService.encodeRepay(
14593
- { asset: repayToken, amount: translatedAmount, interestRateMode: 2n, onBehalfOf: toHubAddress },
14926
+ { asset: repayToken, amount: translatedAmountIn, interestRateMode: 2n, onBehalfOf: toHubAddress },
14594
14927
  this.config.lendingPool
14595
14928
  )
14596
14929
  );
@@ -15610,6 +15943,29 @@ var BackendApiService = class {
15610
15943
  const endpoint = `/solver/orderbook?${queryString}`;
15611
15944
  return this.makeRequest(endpoint, { method: "GET" });
15612
15945
  }
15946
+ /**
15947
+ * Get all intents created by a specific user address with optional filters.
15948
+ *
15949
+ * @param params - Options to filter the user intents.
15950
+ * @param params.userAddress - The user's wallet address on the hub chain (required).
15951
+ * @param params.startDate - Optional. Start timestamp in milliseconds (number, required if filtering by date).
15952
+ * @param params.endDate - Optional. End timestamp in milliseconds (number, required if filtering by date).
15953
+ * @param params.limit - Optional. Max number of results (string).
15954
+ * @param params.offset - Optional. Pagination offset (string).
15955
+ *
15956
+ * @returns {Promise<UserIntentsResponse>} Promise resolving to an array of intent responses for the user.
15957
+ */
15958
+ async getUserIntents(params) {
15959
+ const { userAddress, startDate, endDate, limit, offset } = params;
15960
+ const queryParams = new URLSearchParams();
15961
+ if (startDate) queryParams.append("startDate", new Date(startDate).toISOString());
15962
+ if (endDate) queryParams.append("endDate", new Date(endDate).toISOString());
15963
+ if (limit) queryParams.append("limit", limit);
15964
+ if (offset) queryParams.append("offset", offset);
15965
+ const queryString = queryParams.toString();
15966
+ const endpoint = queryString.length > 0 ? `/intent/user/${userAddress}?${queryString}` : `/intent/user/${userAddress}`;
15967
+ return this.makeRequest(endpoint, { method: "GET" });
15968
+ }
15613
15969
  // Money Market endpoints
15614
15970
  /**
15615
15971
  * Get money market position for a specific user
@@ -17086,7 +17442,13 @@ var StakingService = class {
17086
17442
  spokeProvider,
17087
17443
  this.hubProvider
17088
17444
  );
17089
- const data = this.buildUnstakeData(hubWallet, params);
17445
+ const xSoda = this.hubProvider.chainConfig.addresses.xSoda;
17446
+ const underlyingSodaAmount = await StakingLogic.convertXSodaSharesToSoda(
17447
+ xSoda,
17448
+ params.amount,
17449
+ this.hubProvider.publicClient
17450
+ );
17451
+ const data = this.buildUnstakeData(hubWallet, params, xSoda, underlyingSodaAmount);
17090
17452
  let txResult;
17091
17453
  if (isHub) {
17092
17454
  txResult = await SpokeService.deposit(
@@ -17129,13 +17491,12 @@ var StakingService = class {
17129
17491
  * @param params - The unstake parameters
17130
17492
  * @returns The encoded contract call data
17131
17493
  */
17132
- buildUnstakeData(hubWallet, params) {
17494
+ buildUnstakeData(hubWallet, params, xSoda, underlyingSodaAmount) {
17133
17495
  const hubConfig = getHubChainConfig();
17134
17496
  const stakedSoda = hubConfig.addresses.stakedSoda;
17135
- const xSoda = hubConfig.addresses.xSoda;
17136
17497
  const calls = [];
17137
17498
  calls.push(StakingLogic.encodeXSodaRedeem(xSoda, params.amount, hubWallet, hubWallet));
17138
- calls.push(StakingLogic.encodeUnstake(stakedSoda, hubWallet, params.amount));
17499
+ calls.push(StakingLogic.encodeUnstake(stakedSoda, hubWallet, underlyingSodaAmount));
17139
17500
  return encodeContractCalls(calls);
17140
17501
  }
17141
17502
  /**