@augustdigital/sdk 9.7.1 → 9.9.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/README.md +57 -0
- package/lib/adapters/evm/index.d.ts +23 -5
- package/lib/adapters/evm/index.js +25 -4
- package/lib/core/analytics/method-taxonomy.js +2 -0
- package/lib/core/analytics/version.d.ts +1 -1
- package/lib/core/analytics/version.js +1 -1
- package/lib/core/attribution.d.ts +37 -5
- package/lib/core/attribution.js +39 -3
- package/lib/core/base.class.d.ts +6 -0
- package/lib/core/constants/swap-router.d.ts +22 -5
- package/lib/core/constants/swap-router.js +27 -6
- package/lib/core/helpers/swap-router.d.ts +66 -5
- package/lib/core/helpers/swap-router.js +158 -7
- package/lib/main.d.ts +21 -3
- package/lib/main.js +20 -3
- package/lib/modules/vaults/getters.d.ts +287 -14
- package/lib/modules/vaults/getters.js +452 -45
- package/lib/modules/vaults/main.d.ts +18 -1
- package/lib/modules/vaults/main.js +23 -0
- package/lib/modules/vaults/write.actions.d.ts +119 -29
- package/lib/modules/vaults/write.actions.js +384 -77
- package/lib/sdk.d.ts +11674 -11107
- package/lib/services/layerzero/deposits.d.ts +6 -0
- package/lib/services/layerzero/deposits.js +8 -0
- package/lib/services/subgraph/schema.d.ts +5 -2
- package/lib/services/subgraph/schema.js +22 -10
- package/lib/services/subgraph/vaults.d.ts +23 -1
- package/lib/services/subgraph/vaults.js +65 -0
- package/lib/types/subgraph.d.ts +10 -0
- package/lib/types/vaults.d.ts +38 -6
- package/package.json +1 -1
|
@@ -8,6 +8,7 @@ exports.isNonceParsing = isNonceParsing;
|
|
|
8
8
|
exports.safeWaitForTx = safeWaitForTx;
|
|
9
9
|
exports.safeSendTx = safeSendTx;
|
|
10
10
|
exports.tryRecoverTxHash = tryRecoverTxHash;
|
|
11
|
+
exports.getDepositRoute = getDepositRoute;
|
|
11
12
|
exports.vaultApprove = vaultApprove;
|
|
12
13
|
exports.approve = approve;
|
|
13
14
|
exports.vaultDeposit = vaultDeposit;
|
|
@@ -24,6 +25,7 @@ exports.swapRouterDeposit = swapRouterDeposit;
|
|
|
24
25
|
const ethers_1 = require("ethers");
|
|
25
26
|
const abis_1 = require("../../abis");
|
|
26
27
|
const core_1 = require("../../core");
|
|
28
|
+
const types_1 = require("../../types");
|
|
27
29
|
const swap_quotes_1 = require("../../services/swap-quotes");
|
|
28
30
|
const adapter_helpers_1 = require("./adapter.helpers");
|
|
29
31
|
const utils_1 = require("./utils");
|
|
@@ -428,6 +430,191 @@ function throwIfInsufficientFunds(isInsufficient, operation, error, context) {
|
|
|
428
430
|
return;
|
|
429
431
|
throw new core_1.AugustValidationError('ACCOUNT_NOT_FUNDED', `${operation} failed: insufficient native balance to cover gas/network fees`, { cause: error, context });
|
|
430
432
|
}
|
|
433
|
+
/**
|
|
434
|
+
* Shared catch path for the SwapRouter write methods, with the same recovery
|
|
435
|
+
* and classification as `vaultDeposit`: recover a nonce-parse hash, pass typed
|
|
436
|
+
* SDK errors through, log (demoting user rejections and unfunded accounts),
|
|
437
|
+
* map insufficient funds to `ACCOUNT_NOT_FUNDED`, and wrap the rest.
|
|
438
|
+
* @internal
|
|
439
|
+
*/
|
|
440
|
+
async function handleSwapRouterWriteError(e, tx, signer, wait, operation, label, context) {
|
|
441
|
+
const recovered = await tryRecoverTxHash(e, signer, wait);
|
|
442
|
+
if (recovered) {
|
|
443
|
+
core_1.Logger.log.warn(`${operation}:nonce-fallback`, { hash: recovered });
|
|
444
|
+
return recovered;
|
|
445
|
+
}
|
|
446
|
+
if (e instanceof core_1.AugustSDKError)
|
|
447
|
+
throw e;
|
|
448
|
+
const ctx = { ...context, ...localTxBroadcastContext(tx, e) };
|
|
449
|
+
const insufficientFunds = (0, core_1.isInsufficientFundsError)(e);
|
|
450
|
+
(0, core_1.logChainError)(operation, e, (0, core_1.isUserRejectionError)(e) || insufficientFunds, ctx);
|
|
451
|
+
throwIfInsufficientFunds(insufficientFunds, label, e, ctx);
|
|
452
|
+
throw new core_1.AugustSDKError('UNKNOWN', `${label} failed: ${e instanceof Error ? e.message : 'Unknown error'}`, { cause: e, context: ctx });
|
|
453
|
+
}
|
|
454
|
+
/**
|
|
455
|
+
* Whether a router-registered vault takes `asset` as-is: its reference asset,
|
|
456
|
+
* or, for a Tokenized Vault V2 (backend `evm-2` and router `vaultType`), an
|
|
457
|
+
* asset on the vault's assets whitelist. Shared by the deposit-route resolver
|
|
458
|
+
* and the `swapRouterDeposit` dispatch so neither swaps an asset the vault
|
|
459
|
+
* accepts.
|
|
460
|
+
* @internal
|
|
461
|
+
*/
|
|
462
|
+
async function isAcceptedDirectly(signer, target, asset, isMultiAssetVault, vaultInfo) {
|
|
463
|
+
const lower = asset.toLowerCase();
|
|
464
|
+
return (lower === vaultInfo.referenceAsset.toLowerCase() ||
|
|
465
|
+
(isMultiAssetVault &&
|
|
466
|
+
vaultInfo.vaultType === types_1.SwapRouterVaultType.TokenizedVaultV2 &&
|
|
467
|
+
(await (0, core_1.getWhitelistedAssets)(signer, await (0, core_1.createContract)({
|
|
468
|
+
address: target,
|
|
469
|
+
provider: signer,
|
|
470
|
+
abi: abis_1.ABI_TOKENIZED_VAULT_V2,
|
|
471
|
+
}).assetsWhitelistAddress())).some((a) => a.toLowerCase() === lower)));
|
|
472
|
+
}
|
|
473
|
+
/** @internal */
|
|
474
|
+
async function resolveDepositRoute(signer, args) {
|
|
475
|
+
const { target, chainId, actualDepositAsset, isMultiAssetVault } = args;
|
|
476
|
+
const asset = actualDepositAsset.toLowerCase();
|
|
477
|
+
const isNativeToken = actualDepositAsset === ethers_1.ZeroAddress;
|
|
478
|
+
const isAdapterDeposit = asset !== args.underlyingAsset.toLowerCase();
|
|
479
|
+
const wrapper = (0, core_1.getVaultAdapterConfig)(target)?.wrapperAddress;
|
|
480
|
+
const native = (reason) => ({
|
|
481
|
+
via: 'native',
|
|
482
|
+
spender: isNativeToken
|
|
483
|
+
? null
|
|
484
|
+
: resolveSpender({
|
|
485
|
+
target,
|
|
486
|
+
isMultiAssetVault,
|
|
487
|
+
isAdapterDeposit,
|
|
488
|
+
adapterWrapperAddress: wrapper,
|
|
489
|
+
}),
|
|
490
|
+
reason,
|
|
491
|
+
});
|
|
492
|
+
const originCode = (0, core_1.getOriginCode)();
|
|
493
|
+
if (!originCode)
|
|
494
|
+
return native('no-origin-code');
|
|
495
|
+
const router = chainId ? (0, core_1.getSwapRouterAddress)(chainId) : undefined;
|
|
496
|
+
if (!chainId || !router)
|
|
497
|
+
return native('no-router');
|
|
498
|
+
if (!core_1.ORIGIN_ATTRIBUTION_CHAINS.includes(chainId)) {
|
|
499
|
+
return native('chain-not-supported');
|
|
500
|
+
}
|
|
501
|
+
if (args.isDepositWithPermit)
|
|
502
|
+
return native('permit');
|
|
503
|
+
if (isNativeToken)
|
|
504
|
+
return native('native-token');
|
|
505
|
+
if (isAdapterDeposit && !isMultiAssetVault && wrapper) {
|
|
506
|
+
return native('adapter');
|
|
507
|
+
}
|
|
508
|
+
const vaultInfo = await (0, core_1.readSwapRouterVaultInfo)(signer, chainId, target);
|
|
509
|
+
if (!vaultInfo || vaultInfo.referenceAsset === ethers_1.ZeroAddress) {
|
|
510
|
+
return native('vault-not-registered');
|
|
511
|
+
}
|
|
512
|
+
if (!(await isAcceptedDirectly(signer, target, actualDepositAsset, isMultiAssetVault, vaultInfo))) {
|
|
513
|
+
return native('asset-not-accepted');
|
|
514
|
+
}
|
|
515
|
+
if (!(await (0, core_1.readSwapRouterTokenWhitelisted)(signer, chainId, actualDepositAsset))) {
|
|
516
|
+
return native('router-token-not-whitelisted');
|
|
517
|
+
}
|
|
518
|
+
if (!(await (0, core_1.readOriginInfo)(chainId, originCode, () => signer)).registered) {
|
|
519
|
+
if ((0, core_1.isStrictOrigin)()) {
|
|
520
|
+
throw new core_1.AugustValidationError('INVALID_INPUT', `attribution.originCode is not registered on the SwapRouter for chain ${chainId} and attribution.strictOrigin is set. Register it with addOrigin, or unset strictOrigin to fall back to a native deposit.`, { context: { chainId, target } });
|
|
521
|
+
}
|
|
522
|
+
return native('origin-not-registered');
|
|
523
|
+
}
|
|
524
|
+
return { via: 'router', spender: router };
|
|
525
|
+
}
|
|
526
|
+
/**
|
|
527
|
+
* Resolve whether a deposit can go through the SwapRouter carrying the
|
|
528
|
+
* instance origin code (`router`) or takes the vault's native path
|
|
529
|
+
* (`native`), and which address to approve. Read-only. `vaultDeposit` and
|
|
530
|
+
* `approve` follow this route, so integrators that manage approvals
|
|
531
|
+
* themselves must approve `route.spender`, not the vault.
|
|
532
|
+
*
|
|
533
|
+
* The route is `router` only when an origin code is configured, the chain is
|
|
534
|
+
* Ethereum mainnet ({@link ORIGIN_ATTRIBUTION_CHAINS}) and has a SwapRouter,
|
|
535
|
+
* the vault is registered on it, the vault accepts the asset directly (its
|
|
536
|
+
* reference asset, or a Tokenized Vault V2 whitelisted asset — deposited
|
|
537
|
+
* as-is, never swapped), the router whitelists the asset, the deposit is not a
|
|
538
|
+
* permit, native-token or adapter deposit, and the code is registered.
|
|
539
|
+
* Otherwise it is `native` with a `reason`.
|
|
540
|
+
*
|
|
541
|
+
* @param signer - ethers `Signer` / `Wallet` used for the reads.
|
|
542
|
+
* @param options - {@link IGetDepositRouteOptions}; `depositAsset` defaults
|
|
543
|
+
* to the vault's underlying.
|
|
544
|
+
* @returns {@link IDepositRoute}.
|
|
545
|
+
* @throws AugustValidationError on an invalid `target`, or an unregistered
|
|
546
|
+
* code under `attribution.strictOrigin`.
|
|
547
|
+
* @throws AugustSDKError when a backend, vault or router read fails.
|
|
548
|
+
* @worstCaseRpcCalls 7 — the backend vault row, `asset()`, the router's
|
|
549
|
+
* `vaultInfo`, the vault's `assetsWhitelistAddress()` and
|
|
550
|
+
* `getWhitelistedAssets()` (Tokenized Vault V2 non-reference asset only),
|
|
551
|
+
* the router's `whitelistedTokens(asset)`, and the router's `origins`. The
|
|
552
|
+
* router reads and `getWhitelistedAssets()` are cached for 5 minutes. No
|
|
553
|
+
* router read without a code or off Ethereum mainnet.
|
|
554
|
+
* @example
|
|
555
|
+
* ```ts
|
|
556
|
+
* const route = await augustSdk.evm.getDepositRoute({ target: vault, depositAsset: usdt });
|
|
557
|
+
* if (route.spender) await approveToken(usdt, route.spender, amount);
|
|
558
|
+
* ```
|
|
559
|
+
*/
|
|
560
|
+
async function getDepositRoute(signer, options) {
|
|
561
|
+
const { target, depositAsset } = options;
|
|
562
|
+
if (!(0, core_1.checkAddress)(target, console)) {
|
|
563
|
+
throw new core_1.AugustValidationError('INVALID_ADDRESS', 'getDepositRoute: invalid target address');
|
|
564
|
+
}
|
|
565
|
+
try {
|
|
566
|
+
const tokenizedVault = (await (0, core_1.fetchTokenizedVault)(target))?.[0];
|
|
567
|
+
const isMultiAssetVault = (0, core_1.getVaultVersionV2)(tokenizedVault) === 'evm-2';
|
|
568
|
+
const underlyingAsset = (await (0, core_1.createContract)({
|
|
569
|
+
address: target,
|
|
570
|
+
provider: signer,
|
|
571
|
+
abi: isMultiAssetVault ? abis_1.ABI_TOKENIZED_VAULT_V2 : abis_1.ABI_LENDING_POOLS,
|
|
572
|
+
}).asset());
|
|
573
|
+
return await resolveDepositRoute(signer, {
|
|
574
|
+
target,
|
|
575
|
+
chainId: tokenizedVault?.chain ?? options.chainId,
|
|
576
|
+
actualDepositAsset: depositAsset || underlyingAsset,
|
|
577
|
+
underlyingAsset,
|
|
578
|
+
isMultiAssetVault,
|
|
579
|
+
isDepositWithPermit: options.isDepositWithPermit,
|
|
580
|
+
});
|
|
581
|
+
}
|
|
582
|
+
catch (e) {
|
|
583
|
+
if (e instanceof core_1.AugustSDKError)
|
|
584
|
+
throw e;
|
|
585
|
+
throw new core_1.AugustSDKError('UNKNOWN', `getDepositRoute failed: ${e instanceof Error ? e.message : 'Unknown error'}`, { cause: e, context: { target, chainId: options.chainId } });
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
/**
|
|
589
|
+
* Report whether a deposit carried the instance origin code: the bounded
|
|
590
|
+
* `sdk.attribution.origin` tag (`applied` | `skipped` | `none`), the code only
|
|
591
|
+
* as a span attribute, and — when a configured code was not applied — a
|
|
592
|
+
* warning with the resolver's reason, which the logger also forwards to
|
|
593
|
+
* Sentry as a breadcrumb.
|
|
594
|
+
* @internal
|
|
595
|
+
*/
|
|
596
|
+
function trackOriginAttribution(route, context, operation = 'vaultDeposit') {
|
|
597
|
+
const status = route.via === 'router'
|
|
598
|
+
? 'applied'
|
|
599
|
+
: route.reason === 'no-origin-code'
|
|
600
|
+
? 'none'
|
|
601
|
+
: 'skipped';
|
|
602
|
+
if (status === 'skipped') {
|
|
603
|
+
core_1.Logger.log.warn(`${operation}:attribution-skipped`, {
|
|
604
|
+
reason: route.reason,
|
|
605
|
+
...context,
|
|
606
|
+
});
|
|
607
|
+
}
|
|
608
|
+
if (!(0, core_1.isAnalyticsEnabled)())
|
|
609
|
+
return;
|
|
610
|
+
const sentry = (0, core_1.getSentrySDK)();
|
|
611
|
+
sentry?.setTag('sdk.attribution.origin', status);
|
|
612
|
+
if (status === 'applied') {
|
|
613
|
+
sentry
|
|
614
|
+
?.getActiveSpan()
|
|
615
|
+
?.setAttribute('sdk.attribution.origin_code', (0, core_1.resolveOriginCode)(undefined, context.chainId));
|
|
616
|
+
}
|
|
617
|
+
}
|
|
431
618
|
async function approveCore(signer, options) {
|
|
432
619
|
const { wallet, target, wait, amount, depositAsset } = options;
|
|
433
620
|
const [goodWallet, goodPool] = [
|
|
@@ -444,7 +631,6 @@ async function approveCore(signer, options) {
|
|
|
444
631
|
try {
|
|
445
632
|
const tokenizedVault = (await (0, core_1.fetchTokenizedVault)(target))?.[0];
|
|
446
633
|
const vaultVersion = (0, core_1.getVaultVersionV2)(tokenizedVault);
|
|
447
|
-
const adapterConfig = (0, core_1.getVaultAdapterConfig)(target);
|
|
448
634
|
const isMultiAssetVault = vaultVersion === 'evm-2';
|
|
449
635
|
const poolContract = isMultiAssetVault
|
|
450
636
|
? (0, core_1.createContract)({
|
|
@@ -483,13 +669,14 @@ async function approveCore(signer, options) {
|
|
|
483
669
|
// Native tokens travel as msg.value — no ERC-20 allowance to grant.
|
|
484
670
|
if (isNativeToken)
|
|
485
671
|
return { kind: 'native' };
|
|
486
|
-
const
|
|
487
|
-
const spenderAddress = resolveSpender({
|
|
672
|
+
const spenderAddress = (await resolveDepositRoute(signer, {
|
|
488
673
|
target,
|
|
674
|
+
chainId: tokenizedVault?.chain ?? options.chainId,
|
|
675
|
+
actualDepositAsset,
|
|
676
|
+
underlyingAsset,
|
|
489
677
|
isMultiAssetVault,
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
});
|
|
678
|
+
isDepositWithPermit: options.isDepositWithPermit,
|
|
679
|
+
})).spender;
|
|
493
680
|
const depositTokenDecimals = await resolveDepositTokenDecimals({
|
|
494
681
|
actualDepositAsset,
|
|
495
682
|
underlyingAsset,
|
|
@@ -547,14 +734,18 @@ async function approveCore(signer, options) {
|
|
|
547
734
|
* Approve a vault (or the appropriate adapter wrapper) to spend a token
|
|
548
735
|
* ahead of a separate deposit call. Spender routing mirrors
|
|
549
736
|
* {@link vaultDeposit} (multi-asset → vault, adapter → wrapper, standard →
|
|
550
|
-
* vault
|
|
551
|
-
* `
|
|
737
|
+
* vault, SwapRouter when {@link getDepositRoute} routes there). Returns
|
|
738
|
+
* `undefined` when the existing allowance already covers `amount` **or**
|
|
739
|
+
* when the deposit asset is native.
|
|
552
740
|
*
|
|
553
741
|
* @returns Transaction hash when an approval was sent, `undefined` when
|
|
554
742
|
* the existing allowance already covers `amount` or the deposit asset is
|
|
555
743
|
* native (no ERC-20 allowance applies). Use {@link approve} for a
|
|
556
744
|
* discriminated `ApproveResult` if you need to tell those two cases apart.
|
|
557
745
|
* @throws AugustValidationError on invalid wallet/target/amount.
|
|
746
|
+
* @throws AugustValidationError when `attribution.strictOrigin` is set and the
|
|
747
|
+
* configured origin code is not registered on the SwapRouter (the spender
|
|
748
|
+
* follows {@link getDepositRoute}).
|
|
558
749
|
*
|
|
559
750
|
* @example
|
|
560
751
|
* ```ts
|
|
@@ -600,6 +791,9 @@ async function vaultApprove(signer, options) {
|
|
|
600
791
|
* ```
|
|
601
792
|
*
|
|
602
793
|
* @throws AugustValidationError on invalid wallet/target/amount.
|
|
794
|
+
* @throws AugustValidationError when `attribution.strictOrigin` is set and the
|
|
795
|
+
* configured origin code is not registered on the SwapRouter (the spender
|
|
796
|
+
* follows {@link getDepositRoute}).
|
|
603
797
|
* @throws AugustSDKError when the approval submission fails.
|
|
604
798
|
*/
|
|
605
799
|
async function approve(signer, options) {
|
|
@@ -611,6 +805,11 @@ async function approve(signer, options) {
|
|
|
611
805
|
* Paraswap adapter, native-token wrapper, depositWithPermit) based on the
|
|
612
806
|
* vault version and `depositAsset`.
|
|
613
807
|
*
|
|
808
|
+
* With `attribution.originCode` configured, a deposit the SwapRouter can take
|
|
809
|
+
* directly goes through `SwapRouter.deposit` carrying that code, and the
|
|
810
|
+
* router is approved instead of the vault — see {@link getDepositRoute} for
|
|
811
|
+
* the rules and the fallback reasons. Without a code nothing changes.
|
|
812
|
+
*
|
|
614
813
|
* Amounts are encoded against the **deposit token's** decimals, not the
|
|
615
814
|
* vault's share decimals. The SDK reads the appropriate decimals via the
|
|
616
815
|
* vault metadata and the asset's ERC-20.
|
|
@@ -626,6 +825,8 @@ async function approve(signer, options) {
|
|
|
626
825
|
* @returns Deposit transaction hash.
|
|
627
826
|
* @throws AugustValidationError on invalid wallet/target/amount or missing
|
|
628
827
|
* adapter config when `depositAsset` differs from the vault underlying.
|
|
828
|
+
* @throws AugustValidationError when `attribution.strictOrigin` is set and the
|
|
829
|
+
* configured origin code is not registered on the SwapRouter.
|
|
629
830
|
* @throws AugustSDKError when the deposit submission or on-chain call fails.
|
|
630
831
|
*
|
|
631
832
|
* @example
|
|
@@ -708,13 +909,23 @@ async function vaultDeposit(signer, options) {
|
|
|
708
909
|
actualDepositAsset === '0x0000000000000000000000000000000000000000';
|
|
709
910
|
const isAdapterDeposit = actualDepositAsset.toLowerCase() !== underlyingAsset.toLowerCase();
|
|
710
911
|
const isMultiAssetVault = vaultVersion === 'evm-2';
|
|
711
|
-
// vaultDeposit
|
|
712
|
-
//
|
|
713
|
-
//
|
|
714
|
-
//
|
|
912
|
+
// vaultDeposit never swaps. Any-token swap deposits are the explicit,
|
|
913
|
+
// opt-in job of {@link swapRouterDeposit}; keeping them out of here is what
|
|
914
|
+
// stops a natively-accepted asset from being silently swapped. The only
|
|
915
|
+
// SwapRouter use is a direct deposit carrying a configured origin code.
|
|
715
916
|
if (isAdapterDeposit && !isMultiAssetVault && !adapterConfig) {
|
|
716
917
|
throw new core_1.AugustValidationError('INVALID_INPUT', `vaultDeposit: depositAsset ${actualDepositAsset} differs from vault underlying ${underlyingAsset} but no adapter is configured for vault ${target}. For an any-token deposit into a SwapRouter-eligible vault, use swapRouterDeposit instead.`);
|
|
717
918
|
}
|
|
919
|
+
const routeChainId = tokenizedVault?.chain ?? chainId;
|
|
920
|
+
const route = await resolveDepositRoute(signer, {
|
|
921
|
+
target,
|
|
922
|
+
chainId: routeChainId,
|
|
923
|
+
actualDepositAsset,
|
|
924
|
+
underlyingAsset,
|
|
925
|
+
isMultiAssetVault,
|
|
926
|
+
isDepositWithPermit: options?.isDepositWithPermit,
|
|
927
|
+
});
|
|
928
|
+
trackOriginAttribution(route, { chainId: routeChainId, target });
|
|
718
929
|
const depositTokenDecimals = await resolveDepositTokenDecimals({
|
|
719
930
|
actualDepositAsset,
|
|
720
931
|
underlyingAsset,
|
|
@@ -725,12 +936,7 @@ async function vaultDeposit(signer, options) {
|
|
|
725
936
|
});
|
|
726
937
|
const normalizedAmt = (0, core_1.toNormalizedBn)(amount, depositTokenDecimals);
|
|
727
938
|
if (!isNativeToken) {
|
|
728
|
-
const spenderAddress =
|
|
729
|
-
target,
|
|
730
|
-
isMultiAssetVault,
|
|
731
|
-
isAdapterDeposit,
|
|
732
|
-
adapterWrapperAddress: adapterConfig?.wrapperAddress,
|
|
733
|
-
});
|
|
939
|
+
const spenderAddress = route.spender;
|
|
734
940
|
const depositTokenContract = (0, core_1.createContract)({
|
|
735
941
|
address: actualDepositAsset,
|
|
736
942
|
provider: signer,
|
|
@@ -746,7 +952,16 @@ async function vaultDeposit(signer, options) {
|
|
|
746
952
|
}
|
|
747
953
|
}
|
|
748
954
|
// Route to appropriate deposit method
|
|
749
|
-
if (
|
|
955
|
+
if (route.via === 'router') {
|
|
956
|
+
depositTx = await (0, core_1.createContract)({
|
|
957
|
+
address: route.spender,
|
|
958
|
+
provider: signer,
|
|
959
|
+
abi: abis_1.ABI_SWAP_ROUTER,
|
|
960
|
+
})
|
|
961
|
+
.connect(signer)
|
|
962
|
+
.deposit((0, core_1.resolveOriginCode)(undefined, routeChainId), normalizedAmt.raw, target, actualDepositAsset, wallet);
|
|
963
|
+
}
|
|
964
|
+
else if (isMultiAssetVault) {
|
|
750
965
|
if (options?.isDepositWithPermit) {
|
|
751
966
|
// depositWithPermit flow
|
|
752
967
|
// build structure hash of permit off chain
|
|
@@ -1428,7 +1643,13 @@ async function dispatchViaSwapRouter(args) {
|
|
|
1428
1643
|
}
|
|
1429
1644
|
const isUnderlying = args.actualDepositAsset.toLowerCase() ===
|
|
1430
1645
|
args.underlyingAsset.toLowerCase();
|
|
1431
|
-
|
|
1646
|
+
const vaultInfo = !isUnderlying && args.isMultiAssetVault
|
|
1647
|
+
? await (0, core_1.readSwapRouterVaultInfo)(args.signer, args.chainId, args.target)
|
|
1648
|
+
: undefined;
|
|
1649
|
+
if (isUnderlying ||
|
|
1650
|
+
(vaultInfo &&
|
|
1651
|
+
(await isAcceptedDirectly(args.signer, args.target, args.actualDepositAsset, true, vaultInfo)) &&
|
|
1652
|
+
(await (0, core_1.readSwapRouterTokenWhitelisted)(args.signer, args.chainId, args.actualDepositAsset)))) {
|
|
1432
1653
|
return depositViaSwapRouter(args.signer, {
|
|
1433
1654
|
chainId: args.chainId,
|
|
1434
1655
|
vault: args.target,
|
|
@@ -1506,6 +1727,31 @@ async function dispatchViaSwapRouter(args) {
|
|
|
1506
1727
|
wait: args.wait,
|
|
1507
1728
|
});
|
|
1508
1729
|
}
|
|
1730
|
+
/**
|
|
1731
|
+
* Resolve the origin code a SwapRouter write method sends and check its
|
|
1732
|
+
* registration before any approval or transaction, so an unregistered code
|
|
1733
|
+
* never costs the user a reverted deposit. A code passed to the call must be
|
|
1734
|
+
* registered or the call throws. An unregistered instance code falls back to
|
|
1735
|
+
* the zero sentinel with the same `attribution-skipped` signal as
|
|
1736
|
+
* `vaultDeposit`, or throws under `attribution.strictOrigin`. The zero
|
|
1737
|
+
* sentinel is sent without a read.
|
|
1738
|
+
* @internal
|
|
1739
|
+
*/
|
|
1740
|
+
async function resolveRouterOriginCode(signer, operation, chainId, vault, provided) {
|
|
1741
|
+
const code = (0, core_1.resolveOriginCode)(provided, chainId);
|
|
1742
|
+
if (code === core_1.ORIGIN_CODES.default ||
|
|
1743
|
+
(await (0, core_1.readOriginInfo)(chainId, code, () => signer)).registered) {
|
|
1744
|
+
return code;
|
|
1745
|
+
}
|
|
1746
|
+
if (provided !== undefined) {
|
|
1747
|
+
throw new core_1.AugustValidationError('INVALID_INPUT', `${operation}: originCode is not registered on the SwapRouter for chain ${chainId}. Register it with addOrigin (check it with getOriginInfo), or pass a registered code.`, { context: { chainId, vault } });
|
|
1748
|
+
}
|
|
1749
|
+
if ((0, core_1.isStrictOrigin)()) {
|
|
1750
|
+
throw new core_1.AugustValidationError('INVALID_INPUT', `${operation}: attribution.originCode is not registered on the SwapRouter for chain ${chainId} and attribution.strictOrigin is set. Register it with addOrigin, or unset strictOrigin to deposit without an origin code.`, { context: { chainId, vault } });
|
|
1751
|
+
}
|
|
1752
|
+
trackOriginAttribution({ via: 'native', spender: null, reason: 'origin-not-registered' }, { chainId, target: vault }, operation);
|
|
1753
|
+
return core_1.ORIGIN_CODES.default;
|
|
1754
|
+
}
|
|
1509
1755
|
/** @internal */
|
|
1510
1756
|
function resolveSwapRouterOrThrow(chainId) {
|
|
1511
1757
|
const router = (0, core_1.getSwapRouterAddress)(chainId);
|
|
@@ -1599,7 +1845,9 @@ async function resolveSignerEOA(signer, callerContext) {
|
|
|
1599
1845
|
* @returns The transaction hash of the `swapAndDeposit` call.
|
|
1600
1846
|
*
|
|
1601
1847
|
* @throws {@link AugustValidationError} for unsupported chains, invalid
|
|
1602
|
-
* addresses, empty/oversized swap arrays
|
|
1848
|
+
* addresses, empty/oversized swap arrays, or an origin code not registered on
|
|
1849
|
+
* the router (a per-call code, or the instance code under
|
|
1850
|
+
* `attribution.strictOrigin`), before any approval.
|
|
1603
1851
|
* @throws {@link AugustSDKError} on unrecoverable contract or RPC failure.
|
|
1604
1852
|
*
|
|
1605
1853
|
* @example
|
|
@@ -1637,20 +1885,29 @@ async function swapAndDeposit(signer, options) {
|
|
|
1637
1885
|
}
|
|
1638
1886
|
ensureSwapsValid(swaps);
|
|
1639
1887
|
const routerAddress = resolveSwapRouterOrThrow(chainId);
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
await
|
|
1888
|
+
let tx;
|
|
1889
|
+
try {
|
|
1890
|
+
const origin = await resolveRouterOriginCode(signer, 'swapAndDeposit', chainId, vault, originCode);
|
|
1891
|
+
const eoa = await resolveSignerEOA(signer, 'swapAndDeposit');
|
|
1892
|
+
for (const [tokenIn, totalIn] of totalInputPerToken(swaps)) {
|
|
1893
|
+
await ensureAllowance(signer, tokenIn, eoa, routerAddress, totalIn);
|
|
1894
|
+
}
|
|
1895
|
+
const routerContract = (0, core_1.createContract)({
|
|
1896
|
+
address: routerAddress,
|
|
1897
|
+
provider: signer,
|
|
1898
|
+
abi: abis_1.ABI_SWAP_ROUTER,
|
|
1899
|
+
});
|
|
1900
|
+
tx = (await routerContract
|
|
1901
|
+
.connect(signer)
|
|
1902
|
+
.swapAndDeposit(origin, vault, receiver, swaps));
|
|
1903
|
+
if (wait)
|
|
1904
|
+
await safeWaitForTx(tx);
|
|
1905
|
+
core_1.Logger.log.info('swapAndDeposit:tx_hash', tx.hash);
|
|
1906
|
+
return tx.hash;
|
|
1907
|
+
}
|
|
1908
|
+
catch (e) {
|
|
1909
|
+
return handleSwapRouterWriteError(e, tx, signer, wait, 'swapAndDeposit', 'Swap and deposit', { chainId, vault });
|
|
1643
1910
|
}
|
|
1644
|
-
const routerContract = (0, core_1.createContract)({
|
|
1645
|
-
address: routerAddress,
|
|
1646
|
-
provider: signer,
|
|
1647
|
-
abi: abis_1.ABI_SWAP_ROUTER,
|
|
1648
|
-
});
|
|
1649
|
-
const { hash } = await safeSendTx(() => routerContract
|
|
1650
|
-
.connect(signer)
|
|
1651
|
-
.swapAndDeposit((0, core_1.resolveOriginCode)(originCode), vault, receiver, swaps), signer, wait);
|
|
1652
|
-
core_1.Logger.log.info('swapAndDeposit:tx_hash', hash);
|
|
1653
|
-
return hash;
|
|
1654
1911
|
}
|
|
1655
1912
|
/**
|
|
1656
1913
|
* Deposit a vault's reference asset directly through the SwapRouter — no
|
|
@@ -1662,7 +1919,11 @@ async function swapAndDeposit(signer, options) {
|
|
|
1662
1919
|
* @returns The transaction hash of the `deposit` call.
|
|
1663
1920
|
*
|
|
1664
1921
|
* @throws {@link AugustValidationError} for unsupported chains, invalid
|
|
1665
|
-
* addresses, or
|
|
1922
|
+
* addresses, zero amount, or an origin code not registered on the router (a
|
|
1923
|
+
* per-call code, or the instance code under `attribution.strictOrigin`),
|
|
1924
|
+
* before any approval; with code `ACCOUNT_NOT_FUNDED` when the account cannot
|
|
1925
|
+
* cover gas.
|
|
1926
|
+
* @throws {@link AugustSDKError} on unrecoverable contract or RPC failure.
|
|
1666
1927
|
*/
|
|
1667
1928
|
async function depositViaSwapRouter(signer, options) {
|
|
1668
1929
|
const { chainId, vault, receiver, asset, amount, originCode, wait } = options;
|
|
@@ -1676,18 +1937,27 @@ async function depositViaSwapRouter(signer, options) {
|
|
|
1676
1937
|
throw new core_1.AugustValidationError('INVALID_INPUT', 'depositViaSwapRouter: amount must be greater than zero');
|
|
1677
1938
|
}
|
|
1678
1939
|
const routerAddress = resolveSwapRouterOrThrow(chainId);
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1940
|
+
let tx;
|
|
1941
|
+
try {
|
|
1942
|
+
const origin = await resolveRouterOriginCode(signer, 'depositViaSwapRouter', chainId, vault, originCode);
|
|
1943
|
+
const eoa = await resolveSignerEOA(signer, 'depositViaSwapRouter');
|
|
1944
|
+
await ensureAllowance(signer, asset, eoa, routerAddress, amount);
|
|
1945
|
+
const routerContract = (0, core_1.createContract)({
|
|
1946
|
+
address: routerAddress,
|
|
1947
|
+
provider: signer,
|
|
1948
|
+
abi: abis_1.ABI_SWAP_ROUTER,
|
|
1949
|
+
});
|
|
1950
|
+
tx = (await routerContract
|
|
1951
|
+
.connect(signer)
|
|
1952
|
+
.deposit(origin, amount, vault, asset, receiver));
|
|
1953
|
+
if (wait)
|
|
1954
|
+
await safeWaitForTx(tx);
|
|
1955
|
+
core_1.Logger.log.info('depositViaSwapRouter:tx_hash', tx.hash);
|
|
1956
|
+
return tx.hash;
|
|
1957
|
+
}
|
|
1958
|
+
catch (e) {
|
|
1959
|
+
return handleSwapRouterWriteError(e, tx, signer, wait, 'depositViaSwapRouter', 'SwapRouter deposit', { chainId, vault });
|
|
1960
|
+
}
|
|
1691
1961
|
}
|
|
1692
1962
|
/**
|
|
1693
1963
|
* Deposit native ETH (or chain-native equivalent) into a vault via the
|
|
@@ -1710,7 +1980,11 @@ async function depositViaSwapRouter(signer, options) {
|
|
|
1710
1980
|
* @returns The transaction hash of the `depositNativeToken` call.
|
|
1711
1981
|
*
|
|
1712
1982
|
* @throws {@link AugustValidationError} for unsupported chains, invalid
|
|
1713
|
-
* addresses, or
|
|
1983
|
+
* addresses, zero amount, or an origin code not registered on the router (a
|
|
1984
|
+
* per-call code, or the instance code under `attribution.strictOrigin`),
|
|
1985
|
+
* before any approval; with code `ACCOUNT_NOT_FUNDED` when the account cannot
|
|
1986
|
+
* cover gas.
|
|
1987
|
+
* @throws {@link AugustSDKError} on unrecoverable contract or RPC failure.
|
|
1714
1988
|
*/
|
|
1715
1989
|
async function depositNativeViaSwapRouter(signer, options) {
|
|
1716
1990
|
const { chainId, vault, receiver, amount, originCode, wait } = options;
|
|
@@ -1723,18 +1997,27 @@ async function depositNativeViaSwapRouter(signer, options) {
|
|
|
1723
1997
|
throw new core_1.AugustValidationError('INVALID_INPUT', 'depositNativeViaSwapRouter: amount must be greater than zero');
|
|
1724
1998
|
}
|
|
1725
1999
|
const routerAddress = resolveSwapRouterOrThrow(chainId);
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
|
|
2000
|
+
let tx;
|
|
2001
|
+
try {
|
|
2002
|
+
const origin = await resolveRouterOriginCode(signer, 'depositNativeViaSwapRouter', chainId, vault, originCode);
|
|
2003
|
+
const routerContract = (0, core_1.createContract)({
|
|
2004
|
+
address: routerAddress,
|
|
2005
|
+
provider: signer,
|
|
2006
|
+
abi: abis_1.ABI_SWAP_ROUTER,
|
|
2007
|
+
});
|
|
2008
|
+
tx = (await routerContract
|
|
2009
|
+
.connect(signer)
|
|
2010
|
+
.depositNativeToken(origin, vault, receiver, {
|
|
2011
|
+
value: amount,
|
|
2012
|
+
}));
|
|
2013
|
+
if (wait)
|
|
2014
|
+
await safeWaitForTx(tx);
|
|
2015
|
+
core_1.Logger.log.info('depositNativeViaSwapRouter:tx_hash', tx.hash);
|
|
2016
|
+
return tx.hash;
|
|
2017
|
+
}
|
|
2018
|
+
catch (e) {
|
|
2019
|
+
return handleSwapRouterWriteError(e, tx, signer, wait, 'depositNativeViaSwapRouter', 'SwapRouter native deposit', { chainId, vault });
|
|
2020
|
+
}
|
|
1738
2021
|
}
|
|
1739
2022
|
/**
|
|
1740
2023
|
* Whether a vault can take a native-ETH (chain-native token) SwapRouter
|
|
@@ -1810,21 +2093,22 @@ async function isNativeSwapRouterDepositSupported(chainId, vault, options) {
|
|
|
1810
2093
|
}
|
|
1811
2094
|
/**
|
|
1812
2095
|
* Deposit into an August vault through the on-chain `SwapRouter`, selecting the
|
|
1813
|
-
* correct router path from the deposit asset.
|
|
1814
|
-
* counterpart to the SwapRouter branch inside {@link vaultDeposit}.
|
|
2096
|
+
* correct router path from the deposit asset.
|
|
1815
2097
|
*
|
|
1816
|
-
*
|
|
1817
|
-
*
|
|
1818
|
-
* SwapRouter because the caller asked it to. Making the intent explicit is the
|
|
2098
|
+
* {@link vaultDeposit} never swaps; this function always routes through the
|
|
2099
|
+
* SwapRouter, because the caller asked it to. Keeping swaps opt-in is the
|
|
1819
2100
|
* point: a native-deposit vault (e.g. a multi-asset Tokenized Vault V2 whose
|
|
1820
2101
|
* non-reference assets are accepted directly) is never accidentally swapped —
|
|
1821
|
-
* the regression that implicit, allowlist-driven routing
|
|
1822
|
-
* `vaultDeposit` for native / adapter
|
|
2102
|
+
* the regression that implicit, allowlist-driven routing inside `vaultDeposit`
|
|
2103
|
+
* caused before it was removed. Use `vaultDeposit` for native / adapter
|
|
2104
|
+
* deposits and this for SwapRouter deposits.
|
|
1823
2105
|
*
|
|
1824
2106
|
* The vault's reference asset and its decimals are read on-chain (never trusted
|
|
1825
2107
|
* from the caller — a wrong reference asset would mis-route the swap). The path
|
|
1826
2108
|
* is then chosen from `depositAsset`:
|
|
1827
|
-
* - equals the reference asset
|
|
2109
|
+
* - equals the reference asset, or is an asset a Tokenized Vault V2 accepts
|
|
2110
|
+
* as-is that the router also whitelists (e.g. USDT into Sentora USD) →
|
|
2111
|
+
* direct router deposit, no swap and no swap fee
|
|
1828
2112
|
* ({@link depositViaSwapRouter});
|
|
1829
2113
|
* - the zero address → native-token deposit ({@link depositNativeViaSwapRouter}),
|
|
1830
2114
|
* valid only when the reference asset is the chain's wrapped-native token —
|
|
@@ -1835,23 +2119,36 @@ async function isNativeSwapRouterDepositSupported(chainId, vault, options) {
|
|
|
1835
2119
|
* the chain's whitelisted aggregator, fail-closed on router/selector drift)
|
|
1836
2120
|
* bundled into {@link swapAndDeposit}.
|
|
1837
2121
|
*
|
|
1838
|
-
*
|
|
1839
|
-
*
|
|
1840
|
-
*
|
|
2122
|
+
* The origin code — the per-call `originCode`, else the SDK instance's
|
|
2123
|
+
* `attribution.originCode` on Ethereum mainnet, else the all-zero sentinel
|
|
2124
|
+
* ("no origin fee") — is forwarded to whichever of those three entry points
|
|
2125
|
+
* runs, so a partner's origin fee accrues on every path.
|
|
1841
2126
|
*
|
|
1842
2127
|
* Side effects: reads tokenized-vault metadata, the vault's reference asset and
|
|
1843
|
-
* decimals,
|
|
1844
|
-
* `
|
|
2128
|
+
* decimals, for a Tokenized Vault V2 non-reference asset the router's
|
|
2129
|
+
* `vaultInfo` and `whitelistedTokens` and the vault's assets whitelist, the
|
|
2130
|
+
* origin code's registration, and (on the swap path) one Paraswap quote;
|
|
2131
|
+
* sends one ERC-20 `approve` to the SwapRouter when allowance is short, then
|
|
2132
|
+
* the deposit tx.
|
|
1845
2133
|
*
|
|
1846
2134
|
* @param signer - ethers `Signer` or `Wallet` that signs the approval + deposit.
|
|
1847
2135
|
* @param options - {@link ISwapRouterDepositOptions}.
|
|
1848
2136
|
* @returns The transaction hash of the router deposit call.
|
|
1849
2137
|
* @throws {@link AugustValidationError} for an unsupported chain (no SwapRouter
|
|
1850
2138
|
* deployment), an invalid vault or deposit-asset address, a missing or zero
|
|
1851
|
-
* amount, a native deposit into a non-wrapped-native vault,
|
|
1852
|
-
* the aggregator quote and the on-chain router whitelist
|
|
1853
|
-
*
|
|
1854
|
-
*
|
|
2139
|
+
* amount, a native deposit into a non-wrapped-native vault, drift between
|
|
2140
|
+
* the aggregator quote and the on-chain router whitelist, or an origin code
|
|
2141
|
+
* not registered on the router (a per-call code, or the instance code under
|
|
2142
|
+
* `attribution.strictOrigin`), before any approval; with code
|
|
2143
|
+
* `ACCOUNT_NOT_FUNDED` when the account cannot cover gas.
|
|
2144
|
+
* @throws {@link AugustSDKError} on unrecoverable contract or RPC failure.
|
|
2145
|
+
* @worstCaseRpcCalls 10 on the swap path into a Tokenized Vault V2 —
|
|
2146
|
+
* tokenized-vault metadata, reference asset + decimals, deposit-token
|
|
2147
|
+
* decimals, the router's `vaultInfo` and `whitelistedTokens`, the vault's
|
|
2148
|
+
* `assetsWhitelistAddress()` and `getWhitelistedAssets()`, the quote, the
|
|
2149
|
+
* origin code's `origins` (none for the zero sentinel), and the allowance
|
|
2150
|
+
* read. The router reads and `getWhitelistedAssets()` are cached for 5
|
|
2151
|
+
* minutes.
|
|
1855
2152
|
* @example
|
|
1856
2153
|
* ```ts
|
|
1857
2154
|
* // USDT deposited into a USDC-reference vault → swapped to USDC en route.
|
|
@@ -1865,6 +2162,15 @@ async function isNativeSwapRouterDepositSupported(chainId, vault, options) {
|
|
|
1865
2162
|
* ```
|
|
1866
2163
|
*/
|
|
1867
2164
|
async function swapRouterDeposit(signer, options) {
|
|
2165
|
+
try {
|
|
2166
|
+
return await swapRouterDepositCore(signer, options);
|
|
2167
|
+
}
|
|
2168
|
+
catch (e) {
|
|
2169
|
+
return handleSwapRouterWriteError(e, undefined, signer, options.wait, 'swapRouterDeposit', 'Swap router deposit', { chainId: options.chainId, vault: options.vault });
|
|
2170
|
+
}
|
|
2171
|
+
}
|
|
2172
|
+
/** @internal */
|
|
2173
|
+
async function swapRouterDepositCore(signer, options) {
|
|
1868
2174
|
const { chainId, vault, depositAsset, amount, receiver, slippageBps, originCode, wait, } = options;
|
|
1869
2175
|
if (!(0, core_1.checkAddress)(vault, console, 'contract')) {
|
|
1870
2176
|
throw new core_1.AugustValidationError('INVALID_ADDRESS', `swapRouterDeposit: invalid vault address "${vault}"`);
|
|
@@ -1941,6 +2247,7 @@ async function swapRouterDeposit(signer, options) {
|
|
|
1941
2247
|
actualDepositAsset: depositAsset,
|
|
1942
2248
|
underlyingAsset,
|
|
1943
2249
|
isNativeToken,
|
|
2250
|
+
isMultiAssetVault,
|
|
1944
2251
|
depositTokenDecimals,
|
|
1945
2252
|
normalizedAmt,
|
|
1946
2253
|
slippageBps,
|