@augustdigital/sdk 8.0.0 → 8.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/lib/abis/SwapRouter.d.ts +1042 -0
  2. package/lib/abis/SwapRouter.js +739 -0
  3. package/lib/abis/index.d.ts +1 -0
  4. package/lib/abis/index.js +1 -0
  5. package/lib/adapters/evm/index.d.ts +4 -0
  6. package/lib/adapters/evm/index.js +12 -0
  7. package/lib/adapters/stellar/constants.d.ts +1 -1
  8. package/lib/adapters/stellar/constants.js +1 -1
  9. package/lib/adapters/stellar/getters.d.ts +1 -1
  10. package/lib/adapters/stellar/getters.js +9 -5
  11. package/lib/adapters/stellar/index.d.ts +1 -1
  12. package/lib/adapters/stellar/soroban.js +27 -5
  13. package/lib/adapters/stellar/types.d.ts +1 -0
  14. package/lib/adapters/sui/getters.js +3 -2
  15. package/lib/core/analytics/method-taxonomy.js +3 -0
  16. package/lib/core/analytics/sentry.js +37 -0
  17. package/lib/core/analytics/version.d.ts +1 -1
  18. package/lib/core/analytics/version.js +1 -1
  19. package/lib/core/base.class.js +1 -1
  20. package/lib/core/constants/swap-router.d.ts +8 -0
  21. package/lib/core/constants/swap-router.js +18 -0
  22. package/lib/core/fetcher.d.ts +1 -1
  23. package/lib/core/fetcher.js +4 -4
  24. package/lib/core/helpers/core.d.ts +1 -1
  25. package/lib/core/helpers/core.js +1 -1
  26. package/lib/core/helpers/swap-router.d.ts +4 -0
  27. package/lib/core/helpers/swap-router.js +22 -0
  28. package/lib/core/helpers/web3.js +10 -10
  29. package/lib/core/index.d.ts +2 -0
  30. package/lib/core/index.js +2 -0
  31. package/lib/core/logger/index.d.ts +12 -0
  32. package/lib/core/logger/index.js +13 -1
  33. package/lib/index.d.ts +1 -0
  34. package/lib/index.js +1 -0
  35. package/lib/modules/vaults/fetcher.js +4 -1
  36. package/lib/modules/vaults/getters.d.ts +2 -2
  37. package/lib/modules/vaults/getters.js +4 -1
  38. package/lib/modules/vaults/utils.d.ts +1 -1
  39. package/lib/modules/vaults/utils.js +3 -2
  40. package/lib/modules/vaults/write.actions.d.ts +9 -2
  41. package/lib/modules/vaults/write.actions.js +263 -2
  42. package/lib/services/swap-quotes/index.d.ts +25 -0
  43. package/lib/services/swap-quotes/index.js +51 -0
  44. package/lib/services/swap-quotes/paraswap.d.ts +26 -0
  45. package/lib/services/swap-quotes/paraswap.js +116 -0
  46. package/lib/types/vaults.d.ts +29 -0
  47. package/lib/types/vaults.js +6 -1
  48. package/package.json +4 -11
@@ -31,7 +31,10 @@ async function fetchVaultWithFallback(vaultAddress, fetchFn, options = {}) {
31
31
  return { success: true, data, strategy: 'extended-retry' };
32
32
  }
33
33
  catch (error) {
34
- console.warn(`Vault ${vaultAddress} failed with extended retry strategy:`, error);
34
+ core_1.Logger.log.warn('fetchVaultWithFallback:extended_retry_failed', {
35
+ vault: vaultAddress,
36
+ error,
37
+ });
35
38
  }
36
39
  return {
37
40
  success: false,
@@ -1,5 +1,5 @@
1
- import { IAddress, IHistoricalTimeseriesResponse, INormalizedNumber, ISubgraphWithdrawProccessed, IVault, IVaultAllocations, IVaultAnnualizedApy, IVaultAvailableRedemption, IVaultLoan, IVaultPosition, IVaultRedemptionHistoryItem, IVaultSummary, IVaultWithdrawals, IVaultPendingRedemptions, IActiveStakingPosition, IVaultHistoricalParams, IVaultUserLifetimePnl, IVaultBorrowerHealthFactor, IVaultPnl, VaultAddress } from '../../types';
2
- import { IVaultBaseOptions } from './types';
1
+ import { type IAddress, type IHistoricalTimeseriesResponse, type INormalizedNumber, type ISubgraphWithdrawProccessed, type IVault, type IVaultAllocations, type IVaultAnnualizedApy, type IVaultAvailableRedemption, type IVaultLoan, type IVaultPosition, type IVaultRedemptionHistoryItem, type IVaultSummary, type IVaultWithdrawals, type IVaultPendingRedemptions, type IActiveStakingPosition, type IVaultHistoricalParams, type IVaultUserLifetimePnl, type IVaultBorrowerHealthFactor, type IVaultPnl, type VaultAddress } from '../../types';
2
+ import type { IVaultBaseOptions } from './types';
3
3
  export declare function getVault({ vault, loans, allocations, options, loadSubaccounts, loadSnapshots, }: {
4
4
  vault: IAddress;
5
5
  loans?: boolean;
@@ -909,9 +909,12 @@ async function getVaultPositions({ vault, wallet, solanaWallet, stellarWallet, o
909
909
  if (stellarWallet && (0, utils_3.isStellarAddress)(stellarWallet)) {
910
910
  const stellarNetwork = v.stellar_vault_metadata?.network_name ?? 'mainnet';
911
911
  const position = await StellarGetters.getStellarUserPosition(v.address, stellarWallet, stellarNetwork);
912
- if (position) {
912
+ if (position && !position.decimalsFromFallback) {
913
913
  balance = (0, core_1.toNormalizedBn)(BigInt(position.shares), position.decimals);
914
914
  }
915
+ else if (position) {
916
+ core_1.Logger.log.warn('getVaultPositions', 'Stellar decimals() unresolved — refusing to scale balance with fallback decimals (showing zero)', { vault: v.address, wallet: stellarWallet });
917
+ }
915
918
  else {
916
919
  core_1.Logger.log.warn('getVaultPositions', 'Stellar position query failed — showing zero balance', { vault: v.address, wallet: stellarWallet });
917
920
  }
@@ -1,4 +1,4 @@
1
- import { IAddress, IContractRunner, INormalizedNumber, IPoolFunctions, ITokenizedVault, IVault } from '../../types';
1
+ import type { IAddress, IContractRunner, INormalizedNumber, IPoolFunctions, ITokenizedVault, IVault } from '../../types';
2
2
  import { ethers } from 'ethers';
3
3
  import type { WalletClient } from 'viem';
4
4
  export declare function walletClientToSigner(walletClient: WalletClient): Promise<ethers.JsonRpcSigner>;
@@ -427,12 +427,13 @@ async function buildFormattedVault(provider, tokenizedVault, contractCalls) {
427
427
  }
428
428
  depositAssets = [...depositAssets, ...extraAssets];
429
429
  totalSupply = contractCalls.totalSupply;
430
- ((maxSupply = (0, core_1.toNormalizedBn)(1000000000000)),
430
+ (maxSupply =
431
+ (0, core_1.toNormalizedBn)(1000000000000)),
431
432
  (receipt = {
432
433
  symbol: tokenizedVault.receipt_token_symbol,
433
434
  address: contractCalls.lpTokenAddress,
434
435
  decimals: contractCalls.decimals,
435
- }));
436
+ });
436
437
  break;
437
438
  }
438
439
  default: {
@@ -1,5 +1,6 @@
1
- import { Signer, Wallet, TransactionResponse } from 'ethers';
2
- import { IAddress } from '../../types';
1
+ import { type Signer, type Wallet, type TransactionResponse } from 'ethers';
2
+ import type { IAddress } from '../../types';
3
+ import type { ISwapAndDepositOptions, ISwapRouterDirectDepositOptions, ISwapRouterNativeDepositOptions } from '../../types';
3
4
  export type IContractWriteOptions = {
4
5
  target: IAddress;
5
6
  wallet: IAddress;
@@ -10,6 +11,8 @@ export type IContractWriteOptions = {
10
11
  poolName?: string;
11
12
  isInstantRedeem?: boolean;
12
13
  isDepositWithPermit?: boolean;
14
+ receiver?: IAddress;
15
+ slippageBps?: number;
13
16
  };
14
17
  export type INativeDepositOptions = {
15
18
  wrapperAddress: IAddress;
@@ -31,6 +34,7 @@ export declare function resolveSpender(args: {
31
34
  isMultiAssetVault: boolean;
32
35
  isAdapterDeposit: boolean;
33
36
  adapterWrapperAddress?: IAddress;
37
+ swapRouterAddress?: IAddress;
34
38
  }): IAddress;
35
39
  export declare function validateAmountPrecision(amount: string | bigint | number): void;
36
40
  export declare function isNonceParsing(error: unknown): boolean;
@@ -71,3 +75,6 @@ export type IRwaRedeemOptions = {
71
75
  wait?: boolean;
72
76
  };
73
77
  export declare function rwaRedeemAsset(signer: Signer | Wallet, options: IRwaRedeemOptions): Promise<string>;
78
+ export declare function swapAndDeposit(signer: Signer | Wallet, options: ISwapAndDepositOptions): Promise<string>;
79
+ export declare function depositViaSwapRouter(signer: Signer | Wallet, options: ISwapRouterDirectDepositOptions): Promise<string>;
80
+ export declare function depositNativeViaSwapRouter(signer: Signer | Wallet, options: ISwapRouterNativeDepositOptions): Promise<string>;
@@ -15,9 +15,13 @@ exports.vaultRequestRedeem = vaultRequestRedeem;
15
15
  exports.vaultRedeem = vaultRedeem;
16
16
  exports.depositNative = depositNative;
17
17
  exports.rwaRedeemAsset = rwaRedeemAsset;
18
+ exports.swapAndDeposit = swapAndDeposit;
19
+ exports.depositViaSwapRouter = depositViaSwapRouter;
20
+ exports.depositNativeViaSwapRouter = depositNativeViaSwapRouter;
18
21
  const ethers_1 = require("ethers");
19
22
  const abis_1 = require("../../abis");
20
23
  const core_1 = require("../../core");
24
+ const swap_quotes_1 = require("../../services/swap-quotes");
21
25
  const adapter_helpers_1 = require("./adapter.helpers");
22
26
  const utils_1 = require("./utils");
23
27
  function safeBigInt(value, context = 'safeBigInt') {
@@ -50,6 +54,8 @@ async function resolveDepositTokenDecimals(args) {
50
54
  return readErc20Decimals(actualDepositAsset);
51
55
  }
52
56
  function resolveSpender(args) {
57
+ if (args.swapRouterAddress)
58
+ return args.swapRouterAddress;
53
59
  if (args.isMultiAssetVault)
54
60
  return args.target;
55
61
  if (args.isAdapterDeposit && args.adapterWrapperAddress)
@@ -202,11 +208,16 @@ async function approveCore(signer, options) {
202
208
  if (isNativeToken)
203
209
  return { kind: 'native' };
204
210
  const isAdapterDeposit = actualDepositAsset.toLowerCase() !== underlyingAsset.toLowerCase();
211
+ const resolvedChainId = options.chainId ?? tokenizedVault?.chain;
212
+ const swapRouterAddress = resolvedChainId !== undefined && (0, core_1.vaultUsesSwapRouter)(target)
213
+ ? (0, core_1.getSwapRouterAddress)(resolvedChainId)
214
+ : undefined;
205
215
  const spenderAddress = resolveSpender({
206
216
  target,
207
217
  isMultiAssetVault,
208
218
  isAdapterDeposit,
209
219
  adapterWrapperAddress: adapterConfig?.wrapperAddress,
220
+ swapRouterAddress,
210
221
  });
211
222
  const depositTokenDecimals = await resolveDepositTokenDecimals({
212
223
  actualDepositAsset,
@@ -318,7 +329,23 @@ async function vaultDeposit(signer, options) {
318
329
  actualDepositAsset === '0x0000000000000000000000000000000000000000';
319
330
  const isAdapterDeposit = actualDepositAsset.toLowerCase() !== underlyingAsset.toLowerCase();
320
331
  const isMultiAssetVault = vaultVersion === 'evm-2';
321
- if (isAdapterDeposit && !isMultiAssetVault && !adapterConfig) {
332
+ const resolvedChainId = chainId ?? tokenizedVault?.chain;
333
+ const wantsSwapRouter = (0, core_1.vaultUsesSwapRouter)(target);
334
+ const swapRouterAddress = wantsSwapRouter && resolvedChainId !== undefined
335
+ ? (0, core_1.getSwapRouterAddress)(resolvedChainId)
336
+ : undefined;
337
+ if (wantsSwapRouter && !swapRouterAddress) {
338
+ throw new core_1.AugustValidationError('INVALID_CHAIN', resolvedChainId === undefined
339
+ ? `vaultDeposit: vault ${target} requires SwapRouter routing but chainId could not be resolved — pass options.chainId or ensure tokenized-vault metadata is loaded`
340
+ : `vaultDeposit: vault ${target} is registered on SwapRouter but no SwapRouter is deployed for chainId ${resolvedChainId}`, { context: { vault: target, chainId: resolvedChainId } });
341
+ }
342
+ if (wantsSwapRouter && options?.isDepositWithPermit) {
343
+ throw new core_1.AugustValidationError('INVALID_INPUT', `vaultDeposit: isDepositWithPermit is not supported on SwapRouter-routed vaults (${target}). Call vaultDeposit without isDepositWithPermit, or use the legacy vault.deposit path directly.`, { context: { vault: target } });
344
+ }
345
+ if (isAdapterDeposit &&
346
+ !isMultiAssetVault &&
347
+ !adapterConfig &&
348
+ !swapRouterAddress) {
322
349
  throw new core_1.AugustValidationError('INVALID_INPUT', `vaultDeposit: depositAsset ${actualDepositAsset} differs from vault underlying ${underlyingAsset} but no adapter is configured for vault ${target}`);
323
350
  }
324
351
  const depositTokenDecimals = await resolveDepositTokenDecimals({
@@ -337,6 +364,23 @@ async function vaultDeposit(signer, options) {
337
364
  },
338
365
  });
339
366
  const normalizedAmt = (0, core_1.toNormalizedBn)(amount, depositTokenDecimals);
367
+ if (swapRouterAddress && resolvedChainId !== undefined) {
368
+ return dispatchViaSwapRouter({
369
+ signer,
370
+ routerAddress: swapRouterAddress,
371
+ chainId: resolvedChainId,
372
+ target,
373
+ wallet,
374
+ receiver: options.receiver,
375
+ actualDepositAsset,
376
+ underlyingAsset,
377
+ isNativeToken,
378
+ depositTokenDecimals,
379
+ normalizedAmt,
380
+ slippageBps: options.slippageBps,
381
+ wait,
382
+ });
383
+ }
340
384
  if (!isNativeToken) {
341
385
  const spenderAddress = resolveSpender({
342
386
  target,
@@ -408,7 +452,9 @@ async function vaultDeposit(signer, options) {
408
452
  userAddress: wallet,
409
453
  });
410
454
  depositTx = await nativeDepositConfig.contract
411
- .connect(signer)[nativeDepositConfig.functionName](...nativeDepositConfig.args, nativeDepositConfig.value ? { value: nativeDepositConfig.value } : {});
455
+ .connect(signer)[nativeDepositConfig.functionName](...nativeDepositConfig.args, nativeDepositConfig.value
456
+ ? { value: nativeDepositConfig.value }
457
+ : {});
412
458
  }
413
459
  }
414
460
  else {
@@ -666,4 +712,219 @@ async function rwaRedeemAsset(signer, options) {
666
712
  throw new core_1.AugustSDKError('UNKNOWN', `RWA redeem failed: ${e instanceof Error ? e.message : 'Unknown error'}`, { cause: e, context: { target, asset, amount, minOut } });
667
713
  }
668
714
  }
715
+ async function dispatchViaSwapRouter(args) {
716
+ const amountRaw = BigInt(args.normalizedAmt.raw);
717
+ const sharesReceiver = args.receiver ?? args.wallet;
718
+ if (args.isNativeToken) {
719
+ const wrappedNative = core_1.SWAP_ROUTER_WRAPPED_NATIVE[args.chainId];
720
+ if (!wrappedNative ||
721
+ args.underlyingAsset.toLowerCase() !== wrappedNative.toLowerCase()) {
722
+ throw new core_1.AugustValidationError('INVALID_INPUT', `vaultDeposit (SwapRouter): native deposit is only supported when the vault's reference asset is the chain's wrapped-native token. Vault ${args.target} underlying ${args.underlyingAsset} is not. Wrap to ${wrappedNative ?? 'WETH'} first and call again with depositAsset = the wrapped token.`, {
723
+ context: {
724
+ vault: args.target,
725
+ underlying: args.underlyingAsset,
726
+ chainId: args.chainId,
727
+ wrappedNative,
728
+ },
729
+ });
730
+ }
731
+ return depositNativeViaSwapRouter(args.signer, {
732
+ chainId: args.chainId,
733
+ vault: args.target,
734
+ receiver: sharesReceiver,
735
+ amount: amountRaw,
736
+ wait: args.wait,
737
+ });
738
+ }
739
+ const isUnderlying = args.actualDepositAsset.toLowerCase() ===
740
+ args.underlyingAsset.toLowerCase();
741
+ if (isUnderlying) {
742
+ return depositViaSwapRouter(args.signer, {
743
+ chainId: args.chainId,
744
+ vault: args.target,
745
+ receiver: sharesReceiver,
746
+ asset: args.actualDepositAsset,
747
+ amount: amountRaw,
748
+ wait: args.wait,
749
+ });
750
+ }
751
+ const underlyingErc20 = (0, core_1.createContract)({
752
+ address: args.underlyingAsset,
753
+ provider: args.signer,
754
+ abi: abis_1.ABI_ERC20,
755
+ });
756
+ const underlyingDecimals = Number(await underlyingErc20.decimals());
757
+ const quote = await (0, swap_quotes_1.fetchSwapQuote)({
758
+ chainId: args.chainId,
759
+ srcToken: args.actualDepositAsset,
760
+ srcDecimals: args.depositTokenDecimals,
761
+ destToken: args.underlyingAsset,
762
+ destDecimals: underlyingDecimals,
763
+ amount: amountRaw,
764
+ receiver: args.routerAddress,
765
+ slippageBps: args.slippageBps,
766
+ });
767
+ return swapAndDeposit(args.signer, {
768
+ chainId: args.chainId,
769
+ vault: args.target,
770
+ receiver: sharesReceiver,
771
+ swaps: [
772
+ {
773
+ tokenIn: args.actualDepositAsset,
774
+ tokenOut: args.underlyingAsset,
775
+ amountIn: amountRaw,
776
+ minAmountOut: quote.minAmountOut,
777
+ router: quote.router,
778
+ payload: quote.payload,
779
+ },
780
+ ],
781
+ wait: args.wait,
782
+ });
783
+ }
784
+ function resolveSwapRouterOrThrow(chainId) {
785
+ const router = (0, core_1.getSwapRouterAddress)(chainId);
786
+ if (!router) {
787
+ throw new core_1.AugustValidationError('INVALID_CHAIN', `SwapRouter: no deployment registered for chainId ${chainId}`, { context: { chainId } });
788
+ }
789
+ return router;
790
+ }
791
+ async function ensureAllowance(signer, token, owner, spender, amount) {
792
+ const tokenContract = (0, core_1.createContract)({
793
+ address: token,
794
+ provider: signer,
795
+ abi: abis_1.ABI_ERC20,
796
+ });
797
+ const current = safeBigInt(await tokenContract.allowance(owner, spender), 'swapRouter:allowance');
798
+ if (current >= amount)
799
+ return;
800
+ const { hash } = await safeSendTx(() => tokenContract.connect(signer).approve(spender, amount), signer, true);
801
+ core_1.Logger.log.info('swapRouter:approve:tx_hash', hash);
802
+ }
803
+ function ensureSwapsValid(swaps) {
804
+ if (swaps.length === 0) {
805
+ throw new core_1.AugustValidationError('INVALID_INPUT', 'swapAndDeposit: at least one swap leg is required');
806
+ }
807
+ if (swaps.length > core_1.SWAP_ROUTER_MAX_SWAPS) {
808
+ throw new core_1.AugustValidationError('INVALID_INPUT', `swapAndDeposit: too many swaps (${swaps.length} > ${core_1.SWAP_ROUTER_MAX_SWAPS})`, { context: { count: swaps.length, max: core_1.SWAP_ROUTER_MAX_SWAPS } });
809
+ }
810
+ for (let i = 0; i < swaps.length; i += 1) {
811
+ validateSwapParams(swaps[i], i);
812
+ }
813
+ }
814
+ function validateSwapParams(swap, index) {
815
+ const where = `swapAndDeposit: swaps[${index}]`;
816
+ if (!(0, core_1.checkAddress)(swap.tokenIn, console, 'contract')) {
817
+ throw new core_1.AugustValidationError('INVALID_ADDRESS', `${where}.tokenIn is not a valid address`);
818
+ }
819
+ if (!(0, core_1.checkAddress)(swap.tokenOut, console, 'contract')) {
820
+ throw new core_1.AugustValidationError('INVALID_ADDRESS', `${where}.tokenOut is not a valid address`);
821
+ }
822
+ if (!(0, core_1.checkAddress)(swap.router, console, 'contract')) {
823
+ throw new core_1.AugustValidationError('INVALID_ADDRESS', `${where}.router is not a valid address`);
824
+ }
825
+ if (swap.tokenIn.toLowerCase() === swap.tokenOut.toLowerCase()) {
826
+ throw new core_1.AugustValidationError('INVALID_INPUT', `${where}: tokenIn and tokenOut are identical — no swap needed`);
827
+ }
828
+ if (swap.amountIn <= 0n) {
829
+ throw new core_1.AugustValidationError('INVALID_INPUT', `${where}.amountIn must be greater than zero`);
830
+ }
831
+ if (swap.minAmountOut <= 0n) {
832
+ throw new core_1.AugustValidationError('INVALID_INPUT', `${where}.minAmountOut must be greater than zero — slippage protection cannot be disabled`);
833
+ }
834
+ if (!/^0x[0-9a-fA-F]+$/.test(swap.payload) || swap.payload.length < 10) {
835
+ throw new core_1.AugustValidationError('INVALID_INPUT', `${where}.payload must be ABI-encoded calldata (got "${swap.payload.slice(0, 12)}…")`);
836
+ }
837
+ }
838
+ function totalInputPerToken(swaps) {
839
+ const totals = new Map();
840
+ for (const swap of swaps) {
841
+ const key = swap.tokenIn.toLowerCase();
842
+ totals.set(key, (totals.get(key) ?? 0n) + swap.amountIn);
843
+ }
844
+ return totals;
845
+ }
846
+ async function resolveSignerEOA(signer, callerContext) {
847
+ const getAddress = signer.getAddress;
848
+ if (typeof getAddress !== 'function') {
849
+ throw new core_1.AugustValidationError('INVALID_INPUT', `${callerContext}: signer must implement getAddress(); got ${typeof getAddress}`);
850
+ }
851
+ const eoa = await getAddress.call(signer);
852
+ if (!eoa || !(0, core_1.checkAddress)(eoa, console, 'wallet')) {
853
+ throw new core_1.AugustValidationError('INVALID_ADDRESS', `${callerContext}: signer.getAddress() returned an invalid address: ${String(eoa)}`);
854
+ }
855
+ return eoa;
856
+ }
857
+ async function swapAndDeposit(signer, options) {
858
+ const { chainId, vault, receiver, swaps, originCode, wait } = options;
859
+ const goodVault = (0, core_1.checkAddress)(vault, console, 'contract');
860
+ const goodReceiver = (0, core_1.checkAddress)(receiver, console, 'wallet');
861
+ if (!goodVault || !goodReceiver) {
862
+ throw new core_1.AugustValidationError('INVALID_ADDRESS', `swapAndDeposit: invalid ${!goodVault ? 'vault' : 'receiver'} address`);
863
+ }
864
+ ensureSwapsValid(swaps);
865
+ const routerAddress = resolveSwapRouterOrThrow(chainId);
866
+ const eoa = await resolveSignerEOA(signer, 'swapAndDeposit');
867
+ for (const [tokenIn, totalIn] of totalInputPerToken(swaps)) {
868
+ await ensureAllowance(signer, tokenIn, eoa, routerAddress, totalIn);
869
+ }
870
+ const routerContract = (0, core_1.createContract)({
871
+ address: routerAddress,
872
+ provider: signer,
873
+ abi: abis_1.ABI_SWAP_ROUTER,
874
+ });
875
+ const { hash } = await safeSendTx(() => routerContract
876
+ .connect(signer)
877
+ .swapAndDeposit((0, core_1.resolveOriginCode)(originCode), vault, receiver, swaps), signer, wait);
878
+ core_1.Logger.log.info('swapAndDeposit:tx_hash', hash);
879
+ return hash;
880
+ }
881
+ async function depositViaSwapRouter(signer, options) {
882
+ const { chainId, vault, receiver, asset, amount, originCode, wait } = options;
883
+ const goodVault = (0, core_1.checkAddress)(vault, console, 'contract');
884
+ const goodReceiver = (0, core_1.checkAddress)(receiver, console, 'wallet');
885
+ const goodAsset = (0, core_1.checkAddress)(asset, console, 'contract');
886
+ if (!goodVault || !goodReceiver || !goodAsset) {
887
+ throw new core_1.AugustValidationError('INVALID_ADDRESS', 'depositViaSwapRouter: invalid address');
888
+ }
889
+ if (amount === 0n) {
890
+ throw new core_1.AugustValidationError('INVALID_INPUT', 'depositViaSwapRouter: amount must be greater than zero');
891
+ }
892
+ const routerAddress = resolveSwapRouterOrThrow(chainId);
893
+ const eoa = await resolveSignerEOA(signer, 'depositViaSwapRouter');
894
+ await ensureAllowance(signer, asset, eoa, routerAddress, amount);
895
+ const routerContract = (0, core_1.createContract)({
896
+ address: routerAddress,
897
+ provider: signer,
898
+ abi: abis_1.ABI_SWAP_ROUTER,
899
+ });
900
+ const { hash } = await safeSendTx(() => routerContract
901
+ .connect(signer)
902
+ .deposit((0, core_1.resolveOriginCode)(originCode), amount, vault, asset, receiver), signer, wait);
903
+ core_1.Logger.log.info('depositViaSwapRouter:tx_hash', hash);
904
+ return hash;
905
+ }
906
+ async function depositNativeViaSwapRouter(signer, options) {
907
+ const { chainId, vault, receiver, amount, originCode, wait } = options;
908
+ const goodVault = (0, core_1.checkAddress)(vault, console, 'contract');
909
+ const goodReceiver = (0, core_1.checkAddress)(receiver, console, 'wallet');
910
+ if (!goodVault || !goodReceiver) {
911
+ throw new core_1.AugustValidationError('INVALID_ADDRESS', 'depositNativeViaSwapRouter: invalid address');
912
+ }
913
+ if (amount === 0n) {
914
+ throw new core_1.AugustValidationError('INVALID_INPUT', 'depositNativeViaSwapRouter: amount must be greater than zero');
915
+ }
916
+ const routerAddress = resolveSwapRouterOrThrow(chainId);
917
+ const routerContract = (0, core_1.createContract)({
918
+ address: routerAddress,
919
+ provider: signer,
920
+ abi: abis_1.ABI_SWAP_ROUTER,
921
+ });
922
+ const { hash } = await safeSendTx(() => routerContract
923
+ .connect(signer)
924
+ .depositNativeToken((0, core_1.resolveOriginCode)(originCode), vault, receiver, {
925
+ value: amount,
926
+ }), signer, wait);
927
+ core_1.Logger.log.info('depositNativeViaSwapRouter:tx_hash', hash);
928
+ return hash;
929
+ }
669
930
  //# sourceMappingURL=write.actions.js.map
@@ -0,0 +1,25 @@
1
+ import type { IAddress } from '../../types';
2
+ export type ISwapQuoteProvider = 'paraswap';
3
+ export interface ISwapQuoteRequest {
4
+ chainId: number;
5
+ srcToken: IAddress;
6
+ srcDecimals: number;
7
+ destToken: IAddress;
8
+ destDecimals: number;
9
+ amount: bigint;
10
+ receiver: IAddress;
11
+ slippageBps?: number;
12
+ partner?: string;
13
+ partnerAddress?: IAddress;
14
+ fetchImpl?: typeof fetch;
15
+ signal?: AbortSignal;
16
+ }
17
+ export type ISwapQuoteResult = {
18
+ provider: 'paraswap';
19
+ router: IAddress;
20
+ payload: `0x${string}`;
21
+ expectedAmountOut: bigint;
22
+ minAmountOut: bigint;
23
+ fetchedAt: number;
24
+ };
25
+ export declare function fetchSwapQuote(request: ISwapQuoteRequest): Promise<ISwapQuoteResult>;
@@ -0,0 +1,51 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.fetchSwapQuote = fetchSwapQuote;
4
+ const errors_1 = require("../../core/errors");
5
+ const paraswap_1 = require("./paraswap");
6
+ const DEFAULT_SLIPPAGE_BPS = 100;
7
+ const BPS_DENOMINATOR = 10000n;
8
+ async function fetchSwapQuote(request) {
9
+ validateRequest(request);
10
+ const slippageBps = request.slippageBps ?? DEFAULT_SLIPPAGE_BPS;
11
+ const fetchImpl = request.fetchImpl ?? globalThis.fetch;
12
+ const { router, payload, expectedAmountOut, fetchedAt } = await (0, paraswap_1.fetchParaswapQuote)({
13
+ chainId: request.chainId,
14
+ srcToken: request.srcToken,
15
+ srcDecimals: request.srcDecimals,
16
+ destToken: request.destToken,
17
+ destDecimals: request.destDecimals,
18
+ amount: request.amount,
19
+ receiver: request.receiver,
20
+ slippageBps,
21
+ partner: request.partner ?? paraswap_1.PARASWAP_DEFAULTS.partner,
22
+ partnerAddress: request.partnerAddress ?? paraswap_1.PARASWAP_DEFAULTS.partnerAddress,
23
+ fetchImpl,
24
+ signal: request.signal,
25
+ });
26
+ const minAmountOut = applySlippage(expectedAmountOut, slippageBps);
27
+ return {
28
+ provider: 'paraswap',
29
+ router,
30
+ payload,
31
+ expectedAmountOut,
32
+ minAmountOut,
33
+ fetchedAt,
34
+ };
35
+ }
36
+ function validateRequest(req) {
37
+ if (req.slippageBps !== undefined &&
38
+ (req.slippageBps < 0 || req.slippageBps >= 10000)) {
39
+ throw new errors_1.AugustValidationError('INVALID_INPUT', `fetchSwapQuote: slippageBps must be in [0, 10000), got ${req.slippageBps}. 10000 bps = 100% slippage and disables protection entirely; use a tighter bound.`);
40
+ }
41
+ if (req.amount === 0n) {
42
+ throw new errors_1.AugustValidationError('INVALID_INPUT', 'fetchSwapQuote: amount must be greater than zero');
43
+ }
44
+ if (req.srcToken.toLowerCase() === req.destToken.toLowerCase()) {
45
+ throw new errors_1.AugustValidationError('INVALID_INPUT', 'fetchSwapQuote: srcToken and destToken are identical — no swap needed');
46
+ }
47
+ }
48
+ function applySlippage(amount, slippageBps) {
49
+ return (amount * (BPS_DENOMINATOR - BigInt(slippageBps))) / BPS_DENOMINATOR;
50
+ }
51
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,26 @@
1
+ import type { IAddress } from '../../types';
2
+ export interface IParaswapQuoteInput {
3
+ chainId: number;
4
+ srcToken: IAddress;
5
+ srcDecimals: number;
6
+ destToken: IAddress;
7
+ destDecimals: number;
8
+ amount: bigint;
9
+ receiver: IAddress;
10
+ slippageBps: number;
11
+ partner: string;
12
+ partnerAddress: IAddress;
13
+ fetchImpl: typeof fetch;
14
+ signal?: AbortSignal;
15
+ }
16
+ export interface IParaswapQuoteOutput {
17
+ router: IAddress;
18
+ payload: `0x${string}`;
19
+ expectedAmountOut: bigint;
20
+ fetchedAt: number;
21
+ }
22
+ export declare function fetchParaswapQuote(input: IParaswapQuoteInput): Promise<IParaswapQuoteOutput>;
23
+ export declare const PARASWAP_DEFAULTS: {
24
+ readonly partner: "august";
25
+ readonly partnerAddress: `0x${string}`;
26
+ };
@@ -0,0 +1,116 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PARASWAP_DEFAULTS = void 0;
4
+ exports.fetchParaswapQuote = fetchParaswapQuote;
5
+ const errors_1 = require("../../core/errors");
6
+ const web3_1 = require("../../core/helpers/web3");
7
+ const PARASWAP_PRICES_URL = 'https://api.paraswap.io/prices';
8
+ const PARASWAP_TRANSACTIONS_BASE_URL = 'https://api.paraswap.io/transactions';
9
+ const DEFAULT_PARTNER = 'august';
10
+ const DEFAULT_PARTNER_ADDRESS = '0xb60ee0FA5B6bA917255A03e744967E0Bda531dD0';
11
+ const PARASWAP_VERSION = '6.2';
12
+ const BPS_DENOMINATOR = 10000n;
13
+ async function fetchParaswapQuote(input) {
14
+ const priceRoute = await getPriceRoute(input);
15
+ const destAmountRaw = priceRoute.destAmount;
16
+ if (typeof destAmountRaw !== 'string' || !/^\d+$/.test(destAmountRaw)) {
17
+ throw new errors_1.AugustServerError(200, `fetchSwapQuote: Paraswap /prices returned non-numeric destAmount: ${String(destAmountRaw)}`, { context: { destAmount: destAmountRaw } });
18
+ }
19
+ const expectedAmountOut = BigInt(destAmountRaw);
20
+ const { router, payload } = await getTransactionData(input, priceRoute);
21
+ return { router, payload, expectedAmountOut, fetchedAt: Date.now() };
22
+ }
23
+ async function getPriceRoute(input) {
24
+ const params = new URLSearchParams({
25
+ network: String(input.chainId),
26
+ srcToken: input.srcToken,
27
+ srcDecimals: String(input.srcDecimals),
28
+ destToken: input.destToken,
29
+ destDecimals: String(input.destDecimals),
30
+ amount: input.amount.toString(),
31
+ partner: input.partner,
32
+ partnerAddress: input.partnerAddress,
33
+ version: PARASWAP_VERSION,
34
+ });
35
+ const url = `${PARASWAP_PRICES_URL}?${params.toString()}`;
36
+ let response;
37
+ try {
38
+ response = await input.fetchImpl(url, {
39
+ method: 'GET',
40
+ headers: { 'Content-Type': 'application/json' },
41
+ signal: input.signal,
42
+ });
43
+ }
44
+ catch (cause) {
45
+ throw new errors_1.AugustNetworkError('fetchSwapQuote: Paraswap /prices fetch failed', { cause, context: { url } });
46
+ }
47
+ if (!response.ok) {
48
+ throw new errors_1.AugustServerError(response.status, `fetchSwapQuote: Paraswap /prices returned HTTP ${response.status}`, { context: { url } });
49
+ }
50
+ const body = (await response.json());
51
+ if (body.error) {
52
+ throw new errors_1.AugustServerError(response.status, `fetchSwapQuote: Paraswap /prices error: ${body.error}`, { context: { providerError: body.error } });
53
+ }
54
+ if (!body.priceRoute) {
55
+ throw new errors_1.AugustServerError(response.status, 'fetchSwapQuote: Paraswap /prices returned no priceRoute', { context: { body } });
56
+ }
57
+ return body.priceRoute;
58
+ }
59
+ async function getTransactionData(input, priceRoute) {
60
+ const url = `${PARASWAP_TRANSACTIONS_BASE_URL}/${input.chainId}/?ignoreChecks=true&ignoreGasEstimate=true&onlyParams=false`;
61
+ const expectedDestAmount = BigInt(priceRoute.destAmount);
62
+ const minDestAmount = (expectedDestAmount * (BPS_DENOMINATOR - BigInt(input.slippageBps))) /
63
+ BPS_DENOMINATOR;
64
+ const requestBody = {
65
+ userAddress: input.receiver,
66
+ srcToken: input.srcToken,
67
+ destToken: input.destToken,
68
+ srcDecimals: input.srcDecimals,
69
+ destDecimals: input.destDecimals,
70
+ srcAmount: input.amount.toString(),
71
+ destAmount: minDestAmount.toString(),
72
+ priceRoute,
73
+ partner: input.partner,
74
+ partnerAddress: input.partnerAddress,
75
+ };
76
+ let response;
77
+ try {
78
+ response = await input.fetchImpl(url, {
79
+ method: 'POST',
80
+ headers: { 'Content-Type': 'application/json' },
81
+ body: JSON.stringify(requestBody),
82
+ signal: input.signal,
83
+ });
84
+ }
85
+ catch (cause) {
86
+ throw new errors_1.AugustNetworkError('fetchSwapQuote: Paraswap /transactions fetch failed', { cause, context: { url } });
87
+ }
88
+ if (!response.ok) {
89
+ throw new errors_1.AugustServerError(response.status, `fetchSwapQuote: Paraswap /transactions returned HTTP ${response.status}`, { context: { url } });
90
+ }
91
+ const body = (await response.json());
92
+ if (body.error) {
93
+ throw new errors_1.AugustServerError(response.status, `fetchSwapQuote: Paraswap /transactions error: ${body.error}`, { context: { providerError: body.error } });
94
+ }
95
+ if (!body.to || !body.data) {
96
+ throw new errors_1.AugustServerError(response.status, 'fetchSwapQuote: Paraswap /transactions returned no to/data', { context: { body } });
97
+ }
98
+ if (!(0, web3_1.checkAddress)(body.to, console, 'contract')) {
99
+ throw new errors_1.AugustServerError(response.status, `fetchSwapQuote: Paraswap /transactions returned an invalid router address: ${body.to}`, { context: { to: body.to } });
100
+ }
101
+ if (!/^0x[0-9a-fA-F]+$/.test(body.data) || body.data.length % 2 !== 0) {
102
+ throw new errors_1.AugustServerError(response.status, `fetchSwapQuote: Paraswap /transactions returned malformed calldata (${body.data.length} chars)`, { context: { dataPrefix: body.data.slice(0, 16) } });
103
+ }
104
+ if (body.data.length < 10) {
105
+ throw new errors_1.AugustValidationError('INVALID_INPUT', 'fetchSwapQuote: Paraswap /transactions returned calldata shorter than a 4-byte selector');
106
+ }
107
+ return {
108
+ router: body.to,
109
+ payload: body.data,
110
+ };
111
+ }
112
+ exports.PARASWAP_DEFAULTS = {
113
+ partner: DEFAULT_PARTNER,
114
+ partnerAddress: DEFAULT_PARTNER_ADDRESS,
115
+ };
116
+ //# sourceMappingURL=paraswap.js.map
@@ -332,3 +332,32 @@ export interface IVaultMetadataItem {
332
332
  address: string;
333
333
  }
334
334
  export type IVaultMetadata = Record<string, IVaultMetadataItem>;
335
+ export declare enum SwapRouterVaultType {
336
+ ERC4626 = 1,
337
+ TokenizedVaultV2 = 2
338
+ }
339
+ export interface ISwapParams {
340
+ tokenIn: IAddress;
341
+ tokenOut: IAddress;
342
+ amountIn: bigint;
343
+ minAmountOut: bigint;
344
+ router: IAddress;
345
+ payload: `0x${string}`;
346
+ }
347
+ export interface ISwapRouterBaseOptions {
348
+ chainId: number;
349
+ vault: IAddress;
350
+ receiver: IAddress;
351
+ originCode?: `0x${string}`;
352
+ wait?: boolean;
353
+ }
354
+ export interface ISwapAndDepositOptions extends ISwapRouterBaseOptions {
355
+ swaps: ISwapParams[];
356
+ }
357
+ export interface ISwapRouterDirectDepositOptions extends ISwapRouterBaseOptions {
358
+ asset: IAddress;
359
+ amount: bigint;
360
+ }
361
+ export interface ISwapRouterNativeDepositOptions extends ISwapRouterBaseOptions {
362
+ amount: bigint;
363
+ }