@augustdigital/sdk 7.0.1 → 8.2.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.
- package/lib/abis/SwapRouter.d.ts +1042 -0
- package/lib/abis/SwapRouter.js +739 -0
- package/lib/abis/index.d.ts +1 -0
- package/lib/abis/index.js +1 -0
- package/lib/adapters/evm/index.d.ts +4 -0
- package/lib/adapters/evm/index.js +12 -0
- package/lib/adapters/stellar/types.d.ts +0 -1
- package/lib/core/analytics/method-taxonomy.js +3 -0
- package/lib/core/analytics/version.d.ts +1 -1
- package/lib/core/analytics/version.js +1 -1
- package/lib/core/base.class.d.ts +0 -1
- package/lib/core/constants/swap-router.d.ts +8 -0
- package/lib/core/constants/swap-router.js +18 -0
- package/lib/core/helpers/swap-router.d.ts +4 -0
- package/lib/core/helpers/swap-router.js +22 -0
- package/lib/core/index.d.ts +2 -0
- package/lib/core/index.js +2 -0
- package/lib/index.d.ts +1 -0
- package/lib/index.js +1 -0
- package/lib/main.d.ts +2 -1
- package/lib/main.js +1 -1
- package/lib/modules/vaults/fetcher.js +2 -2
- package/lib/modules/vaults/getters.d.ts +5 -14
- package/lib/modules/vaults/getters.js +54 -13
- package/lib/modules/vaults/main.d.ts +1 -1
- package/lib/modules/vaults/main.js +3 -1
- package/lib/modules/vaults/write.actions.d.ts +7 -0
- package/lib/modules/vaults/write.actions.js +260 -1
- package/lib/services/coingecko/fetcher.js +15 -5
- package/lib/services/debank/fetcher.js +6 -3
- package/lib/services/debank/utils.js +7 -6
- package/lib/services/octavfi/fetcher.js +10 -5
- package/lib/services/subgraph/vaults.js +6 -6
- package/lib/services/swap-quotes/index.d.ts +25 -0
- package/lib/services/swap-quotes/index.js +51 -0
- package/lib/services/swap-quotes/paraswap.d.ts +26 -0
- package/lib/services/swap-quotes/paraswap.js +116 -0
- package/lib/types/vaults.d.ts +40 -0
- package/lib/types/vaults.js +6 -1
- package/lib/types/web3.d.ts +0 -1
- package/package.json +1 -1
|
@@ -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
|
-
|
|
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,
|
|
@@ -666,4 +710,219 @@ async function rwaRedeemAsset(signer, options) {
|
|
|
666
710
|
throw new core_1.AugustSDKError('UNKNOWN', `RWA redeem failed: ${e instanceof Error ? e.message : 'Unknown error'}`, { cause: e, context: { target, asset, amount, minOut } });
|
|
667
711
|
}
|
|
668
712
|
}
|
|
713
|
+
async function dispatchViaSwapRouter(args) {
|
|
714
|
+
const amountRaw = BigInt(args.normalizedAmt.raw);
|
|
715
|
+
const sharesReceiver = args.receiver ?? args.wallet;
|
|
716
|
+
if (args.isNativeToken) {
|
|
717
|
+
const wrappedNative = core_1.SWAP_ROUTER_WRAPPED_NATIVE[args.chainId];
|
|
718
|
+
if (!wrappedNative ||
|
|
719
|
+
args.underlyingAsset.toLowerCase() !== wrappedNative.toLowerCase()) {
|
|
720
|
+
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.`, {
|
|
721
|
+
context: {
|
|
722
|
+
vault: args.target,
|
|
723
|
+
underlying: args.underlyingAsset,
|
|
724
|
+
chainId: args.chainId,
|
|
725
|
+
wrappedNative,
|
|
726
|
+
},
|
|
727
|
+
});
|
|
728
|
+
}
|
|
729
|
+
return depositNativeViaSwapRouter(args.signer, {
|
|
730
|
+
chainId: args.chainId,
|
|
731
|
+
vault: args.target,
|
|
732
|
+
receiver: sharesReceiver,
|
|
733
|
+
amount: amountRaw,
|
|
734
|
+
wait: args.wait,
|
|
735
|
+
});
|
|
736
|
+
}
|
|
737
|
+
const isUnderlying = args.actualDepositAsset.toLowerCase() ===
|
|
738
|
+
args.underlyingAsset.toLowerCase();
|
|
739
|
+
if (isUnderlying) {
|
|
740
|
+
return depositViaSwapRouter(args.signer, {
|
|
741
|
+
chainId: args.chainId,
|
|
742
|
+
vault: args.target,
|
|
743
|
+
receiver: sharesReceiver,
|
|
744
|
+
asset: args.actualDepositAsset,
|
|
745
|
+
amount: amountRaw,
|
|
746
|
+
wait: args.wait,
|
|
747
|
+
});
|
|
748
|
+
}
|
|
749
|
+
const underlyingErc20 = (0, core_1.createContract)({
|
|
750
|
+
address: args.underlyingAsset,
|
|
751
|
+
provider: args.signer,
|
|
752
|
+
abi: abis_1.ABI_ERC20,
|
|
753
|
+
});
|
|
754
|
+
const underlyingDecimals = Number(await underlyingErc20.decimals());
|
|
755
|
+
const quote = await (0, swap_quotes_1.fetchSwapQuote)({
|
|
756
|
+
chainId: args.chainId,
|
|
757
|
+
srcToken: args.actualDepositAsset,
|
|
758
|
+
srcDecimals: args.depositTokenDecimals,
|
|
759
|
+
destToken: args.underlyingAsset,
|
|
760
|
+
destDecimals: underlyingDecimals,
|
|
761
|
+
amount: amountRaw,
|
|
762
|
+
receiver: args.routerAddress,
|
|
763
|
+
slippageBps: args.slippageBps,
|
|
764
|
+
});
|
|
765
|
+
return swapAndDeposit(args.signer, {
|
|
766
|
+
chainId: args.chainId,
|
|
767
|
+
vault: args.target,
|
|
768
|
+
receiver: sharesReceiver,
|
|
769
|
+
swaps: [
|
|
770
|
+
{
|
|
771
|
+
tokenIn: args.actualDepositAsset,
|
|
772
|
+
tokenOut: args.underlyingAsset,
|
|
773
|
+
amountIn: amountRaw,
|
|
774
|
+
minAmountOut: quote.minAmountOut,
|
|
775
|
+
router: quote.router,
|
|
776
|
+
payload: quote.payload,
|
|
777
|
+
},
|
|
778
|
+
],
|
|
779
|
+
wait: args.wait,
|
|
780
|
+
});
|
|
781
|
+
}
|
|
782
|
+
function resolveSwapRouterOrThrow(chainId) {
|
|
783
|
+
const router = (0, core_1.getSwapRouterAddress)(chainId);
|
|
784
|
+
if (!router) {
|
|
785
|
+
throw new core_1.AugustValidationError('INVALID_CHAIN', `SwapRouter: no deployment registered for chainId ${chainId}`, { context: { chainId } });
|
|
786
|
+
}
|
|
787
|
+
return router;
|
|
788
|
+
}
|
|
789
|
+
async function ensureAllowance(signer, token, owner, spender, amount) {
|
|
790
|
+
const tokenContract = (0, core_1.createContract)({
|
|
791
|
+
address: token,
|
|
792
|
+
provider: signer,
|
|
793
|
+
abi: abis_1.ABI_ERC20,
|
|
794
|
+
});
|
|
795
|
+
const current = safeBigInt(await tokenContract.allowance(owner, spender), 'swapRouter:allowance');
|
|
796
|
+
if (current >= amount)
|
|
797
|
+
return;
|
|
798
|
+
const { hash } = await safeSendTx(() => tokenContract.connect(signer).approve(spender, amount), signer, true);
|
|
799
|
+
core_1.Logger.log.info('swapRouter:approve:tx_hash', hash);
|
|
800
|
+
}
|
|
801
|
+
function ensureSwapsValid(swaps) {
|
|
802
|
+
if (swaps.length === 0) {
|
|
803
|
+
throw new core_1.AugustValidationError('INVALID_INPUT', 'swapAndDeposit: at least one swap leg is required');
|
|
804
|
+
}
|
|
805
|
+
if (swaps.length > core_1.SWAP_ROUTER_MAX_SWAPS) {
|
|
806
|
+
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 } });
|
|
807
|
+
}
|
|
808
|
+
for (let i = 0; i < swaps.length; i += 1) {
|
|
809
|
+
validateSwapParams(swaps[i], i);
|
|
810
|
+
}
|
|
811
|
+
}
|
|
812
|
+
function validateSwapParams(swap, index) {
|
|
813
|
+
const where = `swapAndDeposit: swaps[${index}]`;
|
|
814
|
+
if (!(0, core_1.checkAddress)(swap.tokenIn, console, 'contract')) {
|
|
815
|
+
throw new core_1.AugustValidationError('INVALID_ADDRESS', `${where}.tokenIn is not a valid address`);
|
|
816
|
+
}
|
|
817
|
+
if (!(0, core_1.checkAddress)(swap.tokenOut, console, 'contract')) {
|
|
818
|
+
throw new core_1.AugustValidationError('INVALID_ADDRESS', `${where}.tokenOut is not a valid address`);
|
|
819
|
+
}
|
|
820
|
+
if (!(0, core_1.checkAddress)(swap.router, console, 'contract')) {
|
|
821
|
+
throw new core_1.AugustValidationError('INVALID_ADDRESS', `${where}.router is not a valid address`);
|
|
822
|
+
}
|
|
823
|
+
if (swap.tokenIn.toLowerCase() === swap.tokenOut.toLowerCase()) {
|
|
824
|
+
throw new core_1.AugustValidationError('INVALID_INPUT', `${where}: tokenIn and tokenOut are identical — no swap needed`);
|
|
825
|
+
}
|
|
826
|
+
if (swap.amountIn <= 0n) {
|
|
827
|
+
throw new core_1.AugustValidationError('INVALID_INPUT', `${where}.amountIn must be greater than zero`);
|
|
828
|
+
}
|
|
829
|
+
if (swap.minAmountOut <= 0n) {
|
|
830
|
+
throw new core_1.AugustValidationError('INVALID_INPUT', `${where}.minAmountOut must be greater than zero — slippage protection cannot be disabled`);
|
|
831
|
+
}
|
|
832
|
+
if (!/^0x[0-9a-fA-F]+$/.test(swap.payload) || swap.payload.length < 10) {
|
|
833
|
+
throw new core_1.AugustValidationError('INVALID_INPUT', `${where}.payload must be ABI-encoded calldata (got "${swap.payload.slice(0, 12)}…")`);
|
|
834
|
+
}
|
|
835
|
+
}
|
|
836
|
+
function totalInputPerToken(swaps) {
|
|
837
|
+
const totals = new Map();
|
|
838
|
+
for (const swap of swaps) {
|
|
839
|
+
const key = swap.tokenIn.toLowerCase();
|
|
840
|
+
totals.set(key, (totals.get(key) ?? 0n) + swap.amountIn);
|
|
841
|
+
}
|
|
842
|
+
return totals;
|
|
843
|
+
}
|
|
844
|
+
async function resolveSignerEOA(signer, callerContext) {
|
|
845
|
+
const getAddress = signer.getAddress;
|
|
846
|
+
if (typeof getAddress !== 'function') {
|
|
847
|
+
throw new core_1.AugustValidationError('INVALID_INPUT', `${callerContext}: signer must implement getAddress(); got ${typeof getAddress}`);
|
|
848
|
+
}
|
|
849
|
+
const eoa = await getAddress.call(signer);
|
|
850
|
+
if (!eoa || !(0, core_1.checkAddress)(eoa, console, 'wallet')) {
|
|
851
|
+
throw new core_1.AugustValidationError('INVALID_ADDRESS', `${callerContext}: signer.getAddress() returned an invalid address: ${String(eoa)}`);
|
|
852
|
+
}
|
|
853
|
+
return eoa;
|
|
854
|
+
}
|
|
855
|
+
async function swapAndDeposit(signer, options) {
|
|
856
|
+
const { chainId, vault, receiver, swaps, originCode, wait } = options;
|
|
857
|
+
const goodVault = (0, core_1.checkAddress)(vault, console, 'contract');
|
|
858
|
+
const goodReceiver = (0, core_1.checkAddress)(receiver, console, 'wallet');
|
|
859
|
+
if (!goodVault || !goodReceiver) {
|
|
860
|
+
throw new core_1.AugustValidationError('INVALID_ADDRESS', `swapAndDeposit: invalid ${!goodVault ? 'vault' : 'receiver'} address`);
|
|
861
|
+
}
|
|
862
|
+
ensureSwapsValid(swaps);
|
|
863
|
+
const routerAddress = resolveSwapRouterOrThrow(chainId);
|
|
864
|
+
const eoa = await resolveSignerEOA(signer, 'swapAndDeposit');
|
|
865
|
+
for (const [tokenIn, totalIn] of totalInputPerToken(swaps)) {
|
|
866
|
+
await ensureAllowance(signer, tokenIn, eoa, routerAddress, totalIn);
|
|
867
|
+
}
|
|
868
|
+
const routerContract = (0, core_1.createContract)({
|
|
869
|
+
address: routerAddress,
|
|
870
|
+
provider: signer,
|
|
871
|
+
abi: abis_1.ABI_SWAP_ROUTER,
|
|
872
|
+
});
|
|
873
|
+
const { hash } = await safeSendTx(() => routerContract
|
|
874
|
+
.connect(signer)
|
|
875
|
+
.swapAndDeposit((0, core_1.resolveOriginCode)(originCode), vault, receiver, swaps), signer, wait);
|
|
876
|
+
core_1.Logger.log.info('swapAndDeposit:tx_hash', hash);
|
|
877
|
+
return hash;
|
|
878
|
+
}
|
|
879
|
+
async function depositViaSwapRouter(signer, options) {
|
|
880
|
+
const { chainId, vault, receiver, asset, amount, originCode, wait } = options;
|
|
881
|
+
const goodVault = (0, core_1.checkAddress)(vault, console, 'contract');
|
|
882
|
+
const goodReceiver = (0, core_1.checkAddress)(receiver, console, 'wallet');
|
|
883
|
+
const goodAsset = (0, core_1.checkAddress)(asset, console, 'contract');
|
|
884
|
+
if (!goodVault || !goodReceiver || !goodAsset) {
|
|
885
|
+
throw new core_1.AugustValidationError('INVALID_ADDRESS', 'depositViaSwapRouter: invalid address');
|
|
886
|
+
}
|
|
887
|
+
if (amount === 0n) {
|
|
888
|
+
throw new core_1.AugustValidationError('INVALID_INPUT', 'depositViaSwapRouter: amount must be greater than zero');
|
|
889
|
+
}
|
|
890
|
+
const routerAddress = resolveSwapRouterOrThrow(chainId);
|
|
891
|
+
const eoa = await resolveSignerEOA(signer, 'depositViaSwapRouter');
|
|
892
|
+
await ensureAllowance(signer, asset, eoa, routerAddress, amount);
|
|
893
|
+
const routerContract = (0, core_1.createContract)({
|
|
894
|
+
address: routerAddress,
|
|
895
|
+
provider: signer,
|
|
896
|
+
abi: abis_1.ABI_SWAP_ROUTER,
|
|
897
|
+
});
|
|
898
|
+
const { hash } = await safeSendTx(() => routerContract
|
|
899
|
+
.connect(signer)
|
|
900
|
+
.deposit((0, core_1.resolveOriginCode)(originCode), amount, vault, asset, receiver), signer, wait);
|
|
901
|
+
core_1.Logger.log.info('depositViaSwapRouter:tx_hash', hash);
|
|
902
|
+
return hash;
|
|
903
|
+
}
|
|
904
|
+
async function depositNativeViaSwapRouter(signer, options) {
|
|
905
|
+
const { chainId, vault, receiver, amount, originCode, wait } = options;
|
|
906
|
+
const goodVault = (0, core_1.checkAddress)(vault, console, 'contract');
|
|
907
|
+
const goodReceiver = (0, core_1.checkAddress)(receiver, console, 'wallet');
|
|
908
|
+
if (!goodVault || !goodReceiver) {
|
|
909
|
+
throw new core_1.AugustValidationError('INVALID_ADDRESS', 'depositNativeViaSwapRouter: invalid address');
|
|
910
|
+
}
|
|
911
|
+
if (amount === 0n) {
|
|
912
|
+
throw new core_1.AugustValidationError('INVALID_INPUT', 'depositNativeViaSwapRouter: amount must be greater than zero');
|
|
913
|
+
}
|
|
914
|
+
const routerAddress = resolveSwapRouterOrThrow(chainId);
|
|
915
|
+
const routerContract = (0, core_1.createContract)({
|
|
916
|
+
address: routerAddress,
|
|
917
|
+
provider: signer,
|
|
918
|
+
abi: abis_1.ABI_SWAP_ROUTER,
|
|
919
|
+
});
|
|
920
|
+
const { hash } = await safeSendTx(() => routerContract
|
|
921
|
+
.connect(signer)
|
|
922
|
+
.depositNativeToken((0, core_1.resolveOriginCode)(originCode), vault, receiver, {
|
|
923
|
+
value: amount,
|
|
924
|
+
}), signer, wait);
|
|
925
|
+
core_1.Logger.log.info('depositNativeViaSwapRouter:tx_hash', hash);
|
|
926
|
+
return hash;
|
|
927
|
+
}
|
|
669
928
|
//# sourceMappingURL=write.actions.js.map
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.fetchTokenPricesFromCoinGecko = fetchTokenPricesFromCoinGecko;
|
|
4
|
+
const logger_1 = require("../../core/logger");
|
|
4
5
|
const utils_1 = require("./utils");
|
|
5
6
|
async function fetchTokenPricesFromCoinGecko(symbol, coinGeckoKey) {
|
|
6
7
|
const coinId = utils_1.COINGECKO_COIN_ID_MAP[symbol.toLowerCase()];
|
|
@@ -19,17 +20,26 @@ async function fetchTokenPricesFromCoinGecko(symbol, coinGeckoKey) {
|
|
|
19
20
|
},
|
|
20
21
|
});
|
|
21
22
|
if (!response.ok) {
|
|
22
|
-
|
|
23
|
-
|
|
23
|
+
const err = new Error(`CoinGecko API error: ${response.status} ${response.statusText}`);
|
|
24
|
+
logger_1.Logger.log.error('fetchTokenPricesFromCoinGecko', err, {
|
|
25
|
+
status: response.status,
|
|
26
|
+
statusText: response.statusText,
|
|
27
|
+
coinId,
|
|
28
|
+
symbol,
|
|
29
|
+
});
|
|
30
|
+
throw err;
|
|
24
31
|
}
|
|
25
32
|
const data = (await response.json());
|
|
26
|
-
if (data
|
|
27
|
-
return data.prices[data.length - 1][1];
|
|
33
|
+
if (data?.prices?.length) {
|
|
34
|
+
return data.prices[data.prices.length - 1][1];
|
|
28
35
|
}
|
|
29
36
|
return null;
|
|
30
37
|
}
|
|
31
38
|
catch (error) {
|
|
32
|
-
|
|
39
|
+
logger_1.Logger.log.error('fetchTokenPricesFromCoinGecko', error, {
|
|
40
|
+
coinId,
|
|
41
|
+
symbol,
|
|
42
|
+
});
|
|
33
43
|
return null;
|
|
34
44
|
}
|
|
35
45
|
}
|
|
@@ -10,18 +10,21 @@ async function fetchVaultDebankResponse(vaultAddress, headers) {
|
|
|
10
10
|
const data = (await response.json());
|
|
11
11
|
return data;
|
|
12
12
|
}
|
|
13
|
-
|
|
13
|
+
core_1.Logger.log.error('fetchVaultDebankResponse', new Error(`HTTP ${response.status} ${response.statusText}`), { status: response.status, statusText: response.statusText });
|
|
14
14
|
return false;
|
|
15
15
|
}
|
|
16
16
|
catch (e) {
|
|
17
|
-
|
|
17
|
+
core_1.Logger.log.error('fetchVaultDebankResponse', e);
|
|
18
18
|
return false;
|
|
19
19
|
}
|
|
20
20
|
}
|
|
21
21
|
async function fetchDebankResponse(address, headers) {
|
|
22
22
|
const debankResponse = await (0, core_1.fetchAugustWithKey)(undefined, core_1.WEBSERVER_ENDPOINTS.subaccount.debank(address), { override: true, headers: headers });
|
|
23
23
|
if (debankResponse.status !== 200) {
|
|
24
|
-
|
|
24
|
+
core_1.Logger.log.error('fetchDebankResponse', new Error(`HTTP ${debankResponse.status} ${debankResponse.statusText}`), {
|
|
25
|
+
status: debankResponse.status,
|
|
26
|
+
statusText: debankResponse.statusText,
|
|
27
|
+
});
|
|
25
28
|
return false;
|
|
26
29
|
}
|
|
27
30
|
else if (debankResponse.status === 200) {
|
|
@@ -3,12 +3,13 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.parseVaultLevelDebank = parseVaultLevelDebank;
|
|
4
4
|
exports.getVaultExposure = getVaultExposure;
|
|
5
5
|
exports.parseLoanLevelDebank = parseLoanLevelDebank;
|
|
6
|
-
const core_1 = require("../../core
|
|
6
|
+
const core_1 = require("../../core");
|
|
7
|
+
const core_2 = require("../../core/helpers/core");
|
|
7
8
|
function addToTokenExposure(token, tokenExposure, exposureType, protocol, exposurePerCategory, netValue, borrower) {
|
|
8
9
|
const usdAmount = Number(token?.price || 0) * Number(token?.amount);
|
|
9
10
|
if (exposureType === 'wallet'
|
|
10
|
-
? !(0,
|
|
11
|
-
: !(0,
|
|
11
|
+
? !(0, core_2.filterOutBySize)(usdAmount)
|
|
12
|
+
: !(0, core_2.filterOutBySize)(usdAmount))
|
|
12
13
|
return;
|
|
13
14
|
if (exposureType === 'borrow') {
|
|
14
15
|
netValue.value -= usdAmount;
|
|
@@ -73,7 +74,7 @@ function parseVaultLevelDebank(debankRes, protocolExposure, tokenExposure, borro
|
|
|
73
74
|
});
|
|
74
75
|
const foundExistingProtocolExposure = protocolExposure.find((exp) => exp.id === pos.id);
|
|
75
76
|
if (!foundExistingProtocolExposure &&
|
|
76
|
-
(0,
|
|
77
|
+
(0, core_2.filterOutBySize)(protoReturnObj.netUsdValue)) {
|
|
77
78
|
protocolExposure.push(protoReturnObj);
|
|
78
79
|
}
|
|
79
80
|
else if (foundExistingProtocolExposure) {
|
|
@@ -126,7 +127,7 @@ function parseVaultLevelDebank(debankRes, protocolExposure, tokenExposure, borro
|
|
|
126
127
|
});
|
|
127
128
|
const foundExistingProtocolExposure = protocolExposure.find((exp) => exp.id === pos.id);
|
|
128
129
|
if (!foundExistingProtocolExposure &&
|
|
129
|
-
(0,
|
|
130
|
+
(0, core_2.filterOutBySize)(protoReturnObj.netUsdValue)) {
|
|
130
131
|
protocolExposure.push(protoReturnObj);
|
|
131
132
|
}
|
|
132
133
|
else if (foundExistingProtocolExposure) {
|
|
@@ -272,7 +273,7 @@ function parseLoanLevelDebank(debankRes) {
|
|
|
272
273
|
exposure = uniqueExposure;
|
|
273
274
|
}
|
|
274
275
|
catch (err) {
|
|
275
|
-
|
|
276
|
+
core_1.Logger.log.error('getPoolLoansData.strategies', err);
|
|
276
277
|
}
|
|
277
278
|
return { exposure, positions };
|
|
278
279
|
}
|
|
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.fetchOctavfiPortfolios = fetchOctavfiPortfolios;
|
|
4
4
|
const ethers_1 = require("ethers");
|
|
5
5
|
const utils_1 = require("../../adapters/solana/utils");
|
|
6
|
+
const core_1 = require("../../core");
|
|
6
7
|
const BASE_URL = 'https://api.octav.fi';
|
|
7
8
|
const OCTAVFI_API_KEY = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJodHRwczovL2hhc3VyYS5pby9qd3QvY2xhaW1zIjp7IngtaGFzdXJhLWRlZmF1bHQtcm9sZSI6InVzZXIiLCJ4LWhhc3VyYS1hbGxvd2VkLXJvbGVzIjpbInVzZXIiXSwieC1oYXN1cmEtdXNlci1pZCI6ImF1Z3VzdDEyMjM0In19.zaMUtrtdC82uaDh6XSZrsneEcKO3PFOE6FyX3G-MR6c';
|
|
8
9
|
function filterEvmAndSolanaAddresses(addresses) {
|
|
@@ -15,7 +16,7 @@ function filterEvmAndSolanaAddresses(addresses) {
|
|
|
15
16
|
if (utils_1.SolanaUtils.isSolanaAddress(address)) {
|
|
16
17
|
return true;
|
|
17
18
|
}
|
|
18
|
-
|
|
19
|
+
core_1.Logger.log.info('filterEvmAndSolanaAddresses.excluded', { address });
|
|
19
20
|
return false;
|
|
20
21
|
});
|
|
21
22
|
}
|
|
@@ -30,16 +31,20 @@ async function fetchSinglePortfolio(address) {
|
|
|
30
31
|
});
|
|
31
32
|
if (!response.ok) {
|
|
32
33
|
const errorText = await response.text();
|
|
33
|
-
|
|
34
|
+
core_1.Logger.log.error('fetchSinglePortfolio', new Error(`HTTP ${response.status} ${response.statusText}: ${errorText}`), {
|
|
35
|
+
address,
|
|
36
|
+
status: response.status,
|
|
37
|
+
statusText: response.statusText,
|
|
38
|
+
});
|
|
34
39
|
return null;
|
|
35
40
|
}
|
|
36
41
|
const data = await response.json();
|
|
37
42
|
if (!data || typeof data !== 'object') {
|
|
38
|
-
|
|
43
|
+
core_1.Logger.log.error('fetchSinglePortfolio.unexpected-type', new Error(`unexpected response type: ${typeof data}`), { address });
|
|
39
44
|
return null;
|
|
40
45
|
}
|
|
41
46
|
if (data.error) {
|
|
42
|
-
|
|
47
|
+
core_1.Logger.log.error('fetchSinglePortfolio.api-error', new Error(String(data.error)), { address });
|
|
43
48
|
return null;
|
|
44
49
|
}
|
|
45
50
|
let portfolio = data;
|
|
@@ -57,7 +62,7 @@ async function fetchSinglePortfolio(address) {
|
|
|
57
62
|
return portfolio;
|
|
58
63
|
}
|
|
59
64
|
catch (error) {
|
|
60
|
-
|
|
65
|
+
core_1.Logger.log.error('fetchSinglePortfolio', error, { address });
|
|
61
66
|
return null;
|
|
62
67
|
}
|
|
63
68
|
}
|
|
@@ -297,7 +297,7 @@ async function getSubgraphWithdrawProccessed(pool, provider, slackWebookUrl = sl
|
|
|
297
297
|
const requests = [];
|
|
298
298
|
if (!goldskyUrl) {
|
|
299
299
|
const chainId = await (0, core_1.getChainId)(provider);
|
|
300
|
-
|
|
300
|
+
core_1.Logger.log.error('getSubgraphWithdrawProccessed.missing-subgraph-url', new Error('goldsky url is undefined'), { chainId, vaultSymbol, pool });
|
|
301
301
|
slack_1.SLACK.error({
|
|
302
302
|
title: 'Missing Subgraph',
|
|
303
303
|
error: '#getSubgraphWithdrawProccessed: goldsky url is undefined',
|
|
@@ -326,7 +326,7 @@ async function getSubgraphWithdrawProccessed(pool, provider, slackWebookUrl = sl
|
|
|
326
326
|
}
|
|
327
327
|
}`, GOLDSKY_API_KEY);
|
|
328
328
|
if (result.status !== 200) {
|
|
329
|
-
|
|
329
|
+
core_1.Logger.log.error('getSubgraphWithdrawProccessed', new Error(`HTTP ${result.status} ${result.statusText}`), { status: result.status, statusText: result.statusText, pool });
|
|
330
330
|
return [];
|
|
331
331
|
}
|
|
332
332
|
const json = (await result.json());
|
|
@@ -334,7 +334,7 @@ async function getSubgraphWithdrawProccessed(pool, provider, slackWebookUrl = sl
|
|
|
334
334
|
return requests;
|
|
335
335
|
}
|
|
336
336
|
catch (e) {
|
|
337
|
-
|
|
337
|
+
core_1.Logger.log.error('getSubgraphWithdrawProccessed', e, { pool });
|
|
338
338
|
return [];
|
|
339
339
|
}
|
|
340
340
|
}
|
|
@@ -638,7 +638,7 @@ async function getSubgraphVaultHistory(provider, pool, slackWebookUrl = slack_1.
|
|
|
638
638
|
}
|
|
639
639
|
}`, GOLDSKY_API_KEY);
|
|
640
640
|
if (result.status !== 200) {
|
|
641
|
-
|
|
641
|
+
core_1.Logger.log.error('getSubgraphVaultHistory', new Error(`HTTP ${result.status} ${result.statusText}`), { status: result.status, statusText: result.statusText });
|
|
642
642
|
return requests;
|
|
643
643
|
}
|
|
644
644
|
const json = (await result.json());
|
|
@@ -648,7 +648,7 @@ async function getSubgraphVaultHistory(provider, pool, slackWebookUrl = slack_1.
|
|
|
648
648
|
return formattedRequests;
|
|
649
649
|
}
|
|
650
650
|
catch (e) {
|
|
651
|
-
|
|
651
|
+
core_1.Logger.log.error('getSubgraphVaultHistory', e, { pool });
|
|
652
652
|
return [];
|
|
653
653
|
}
|
|
654
654
|
}
|
|
@@ -740,7 +740,7 @@ async function getSubgraphUserTransfers(user, provider, pool, slackWebookUrl = s
|
|
|
740
740
|
return userTransfers;
|
|
741
741
|
}
|
|
742
742
|
catch (e) {
|
|
743
|
-
|
|
743
|
+
core_1.Logger.log.error('getSubgraphUserTransfers', e, { pool });
|
|
744
744
|
return [];
|
|
745
745
|
}
|
|
746
746
|
}
|
|
@@ -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
|
+
};
|