@eulerxyz/euler-v2-sdk 0.2.0-beta → 0.2.1-beta
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/src/entities/Account.d.ts +2 -2
- package/dist/src/entities/Account.d.ts.map +1 -1
- package/dist/src/entities/Account.js +2 -2
- package/dist/src/entities/Account.js.map +1 -1
- package/dist/src/sdk/defaultConfig.d.ts +1 -1
- package/dist/src/sdk/defaultConfig.d.ts.map +1 -1
- package/dist/src/sdk/defaultConfig.js +1 -1
- package/dist/src/sdk/defaultConfig.js.map +1 -1
- package/dist/src/services/accountService/accountServiceConfig.d.ts +1 -1
- package/dist/src/services/accountService/accountServiceConfig.d.ts.map +1 -1
- package/dist/src/services/executionService/encode.d.ts +15 -11
- package/dist/src/services/executionService/encode.d.ts.map +1 -1
- package/dist/src/services/executionService/encode.js +242 -23
- package/dist/src/services/executionService/encode.js.map +1 -1
- package/dist/src/services/executionService/executionService.d.ts +35 -3
- package/dist/src/services/executionService/executionService.d.ts.map +1 -1
- package/dist/src/services/executionService/executionService.js +306 -18
- package/dist/src/services/executionService/executionService.js.map +1 -1
- package/dist/src/services/executionService/executionServiceTypes.d.ts +109 -1
- package/dist/src/services/executionService/executionServiceTypes.d.ts.map +1 -1
- package/dist/src/services/executionService/executionServiceTypes.js.map +1 -1
- package/dist/src/services/executionService/index.d.ts +1 -1
- package/dist/src/services/executionService/index.d.ts.map +1 -1
- package/dist/src/services/executionService/index.js.map +1 -1
- package/dist/src/services/intrinsicApyService/adapters/intrinsicApyV3Adapter/intrinsicApyV3AdapterTypes.d.ts +1 -1
- package/dist/src/services/intrinsicApyService/adapters/intrinsicApyV3Adapter/intrinsicApyV3AdapterTypes.d.ts.map +1 -1
- package/dist/src/services/priceService/priceService.d.ts +2 -1
- package/dist/src/services/priceService/priceService.d.ts.map +1 -1
- package/dist/src/services/priceService/priceService.js +8 -25
- package/dist/src/services/priceService/priceService.js.map +1 -1
- package/dist/src/services/rewardsService/adapters/rewardsDirectAdapter/rewardsDirectAdapter.d.ts +4 -1
- package/dist/src/services/rewardsService/adapters/rewardsDirectAdapter/rewardsDirectAdapter.d.ts.map +1 -1
- package/dist/src/services/rewardsService/adapters/rewardsDirectAdapter/rewardsDirectAdapter.js +20 -4
- package/dist/src/services/rewardsService/adapters/rewardsDirectAdapter/rewardsDirectAdapter.js.map +1 -1
- package/dist/src/services/rewardsService/adapters/rewardsV3Adapter/rewardsV3Adapter.d.ts.map +1 -1
- package/dist/src/services/rewardsService/adapters/rewardsV3Adapter/rewardsV3Adapter.js +5 -2
- package/dist/src/services/rewardsService/adapters/rewardsV3Adapter/rewardsV3Adapter.js.map +1 -1
- package/dist/src/services/rewardsService/adapters/rewardsV3Adapter/rewardsV3AdapterTypes.d.ts +2 -0
- package/dist/src/services/rewardsService/adapters/rewardsV3Adapter/rewardsV3AdapterTypes.d.ts.map +1 -1
- package/dist/src/services/rewardsService/rewardsService.d.ts +6 -1
- package/dist/src/services/rewardsService/rewardsService.d.ts.map +1 -1
- package/dist/src/services/rewardsService/rewardsService.js +128 -3
- package/dist/src/services/rewardsService/rewardsService.js.map +1 -1
- package/dist/src/services/rewardsService/rewardsServiceTypes.d.ts +5 -3
- package/dist/src/services/rewardsService/rewardsServiceTypes.d.ts.map +1 -1
- package/dist/src/services/swapService/swapService.d.ts +4 -6
- package/dist/src/services/swapService/swapService.d.ts.map +1 -1
- package/dist/src/services/swapService/swapService.js +90 -99
- package/dist/src/services/swapService/swapService.js.map +1 -1
- package/dist/src/services/swapService/swapVerification.d.ts +28 -0
- package/dist/src/services/swapService/swapVerification.d.ts.map +1 -0
- package/dist/src/services/swapService/swapVerification.js +138 -0
- package/dist/src/services/swapService/swapVerification.js.map +1 -0
- package/dist/src/services/vaults/eVaultService/eVaultServiceConfig.d.ts +1 -1
- package/dist/src/services/vaults/eVaultService/eVaultServiceConfig.d.ts.map +1 -1
- package/dist/src/services/vaults/eulerEarnService/eulerEarnServiceConfig.d.ts +1 -1
- package/dist/src/services/vaults/eulerEarnService/eulerEarnServiceConfig.d.ts.map +1 -1
- package/dist/src/services/vaults/vaultMetaService/adapters/VaultTypeV3Adapter.d.ts +1 -1
- package/dist/src/services/vaults/vaultMetaService/adapters/VaultTypeV3Adapter.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -9,6 +9,8 @@ import * as encodeHelpers from "./encode.js";
|
|
|
9
9
|
import { isEVCBatchOperation } from "./executionServiceTypes.js";
|
|
10
10
|
import { executeTransactionPlan, } from "./execute.js";
|
|
11
11
|
import { deriveStateOverrides, estimateGasForTransactionPlan, simulateTransactionPlan, } from "./simulate.js";
|
|
12
|
+
import { adjustForInterest, getSwapInputAmount, } from "../swapService/swapVerification.js";
|
|
13
|
+
import { SwapperMode } from "../swapService/swapServiceTypes.js";
|
|
12
14
|
const TOKENS_REQUIRING_ZERO_APPROVAL_RESET = {
|
|
13
15
|
1: [getAddress("0xdAC17F958D2ee523a2206206994597C13D831ec7")],
|
|
14
16
|
};
|
|
@@ -26,6 +28,118 @@ function cloneBatchEntries(entries) {
|
|
|
26
28
|
? { type: "operation", name: entry.name, items: [...entry.items] }
|
|
27
29
|
: entry);
|
|
28
30
|
}
|
|
31
|
+
function hasSuppliedPosition(position) {
|
|
32
|
+
return position.assets > 0n || position.shares > 0n;
|
|
33
|
+
}
|
|
34
|
+
function getStateTransition(item) {
|
|
35
|
+
try {
|
|
36
|
+
const decoded = decodeFunctionData({
|
|
37
|
+
abi: ethereumVaultConnectorAbi,
|
|
38
|
+
data: item.data,
|
|
39
|
+
});
|
|
40
|
+
if (decoded.functionName === "enableCollateral" ||
|
|
41
|
+
decoded.functionName === "disableCollateral" ||
|
|
42
|
+
decoded.functionName === "enableController") {
|
|
43
|
+
const [account, vault] = decoded.args;
|
|
44
|
+
return {
|
|
45
|
+
kind: decoded.functionName === "enableController"
|
|
46
|
+
? "controller"
|
|
47
|
+
: "collateral",
|
|
48
|
+
action: decoded.functionName.startsWith("enable")
|
|
49
|
+
? "enable"
|
|
50
|
+
: "disable",
|
|
51
|
+
account,
|
|
52
|
+
vault,
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
catch { }
|
|
57
|
+
try {
|
|
58
|
+
const decoded = decodeFunctionData({
|
|
59
|
+
abi: eVaultAbi,
|
|
60
|
+
data: item.data,
|
|
61
|
+
});
|
|
62
|
+
if (decoded.functionName === "disableController") {
|
|
63
|
+
return {
|
|
64
|
+
kind: "controller",
|
|
65
|
+
action: "disable",
|
|
66
|
+
account: item.onBehalfOfAccount,
|
|
67
|
+
vault: item.targetContract,
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
catch { }
|
|
72
|
+
return undefined;
|
|
73
|
+
}
|
|
74
|
+
function stateTransitionKey(transition) {
|
|
75
|
+
return `${transition.kind}:${getAddress(transition.account)}:${getAddress(transition.vault)}`;
|
|
76
|
+
}
|
|
77
|
+
function normalizeEVCStateTransitions(entries) {
|
|
78
|
+
const entryRefs = entries.map((entry) => isEVCBatchOperation(entry)
|
|
79
|
+
? entry.items.map((item) => ({
|
|
80
|
+
item,
|
|
81
|
+
remove: false,
|
|
82
|
+
transition: getStateTransition(item),
|
|
83
|
+
}))
|
|
84
|
+
: [
|
|
85
|
+
{
|
|
86
|
+
item: entry,
|
|
87
|
+
remove: false,
|
|
88
|
+
transition: getStateTransition(entry),
|
|
89
|
+
},
|
|
90
|
+
]);
|
|
91
|
+
const refs = entryRefs.flat();
|
|
92
|
+
const collateralStacks = new Map();
|
|
93
|
+
const controllerLast = new Map();
|
|
94
|
+
for (const ref of refs) {
|
|
95
|
+
const transition = ref.transition;
|
|
96
|
+
if (!transition)
|
|
97
|
+
continue;
|
|
98
|
+
const key = stateTransitionKey(transition);
|
|
99
|
+
if (transition.kind === "collateral") {
|
|
100
|
+
const stack = collateralStacks.get(key) ?? [];
|
|
101
|
+
const previous = stack[stack.length - 1];
|
|
102
|
+
if (previous?.action === transition.action) {
|
|
103
|
+
ref.remove = true;
|
|
104
|
+
}
|
|
105
|
+
else if (previous) {
|
|
106
|
+
previous.ref.remove = true;
|
|
107
|
+
ref.remove = true;
|
|
108
|
+
stack.pop();
|
|
109
|
+
}
|
|
110
|
+
else {
|
|
111
|
+
stack.push({ action: transition.action, ref });
|
|
112
|
+
}
|
|
113
|
+
collateralStacks.set(key, stack);
|
|
114
|
+
continue;
|
|
115
|
+
}
|
|
116
|
+
const previous = controllerLast.get(key);
|
|
117
|
+
if (previous?.action === transition.action) {
|
|
118
|
+
ref.remove = true;
|
|
119
|
+
}
|
|
120
|
+
else {
|
|
121
|
+
controllerLast.set(key, { action: transition.action });
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
const result = [];
|
|
125
|
+
entries.forEach((entry, index) => {
|
|
126
|
+
const refsForEntry = entryRefs[index] ?? [];
|
|
127
|
+
if (isEVCBatchOperation(entry)) {
|
|
128
|
+
const items = refsForEntry
|
|
129
|
+
.filter((ref) => !ref.remove)
|
|
130
|
+
.map((ref) => ref.item);
|
|
131
|
+
if (items.length > 0) {
|
|
132
|
+
result.push({ type: "operation", name: entry.name, items });
|
|
133
|
+
}
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
const ref = refsForEntry[0];
|
|
137
|
+
if (ref && !ref.remove) {
|
|
138
|
+
result.push(ref.item);
|
|
139
|
+
}
|
|
140
|
+
});
|
|
141
|
+
return result;
|
|
142
|
+
}
|
|
29
143
|
const WAD = 10n ** 18n;
|
|
30
144
|
// TODO explain how this service is coupled to the concrete abis of ERC4626, permit2 and EVK.
|
|
31
145
|
// this is a helper service, not a generic one.
|
|
@@ -399,6 +513,19 @@ export class ExecutionService {
|
|
|
399
513
|
encodeSwapFromWallet(args) {
|
|
400
514
|
return encodeHelpers.encodeSwapFromWallet(args);
|
|
401
515
|
}
|
|
516
|
+
encodeSwapAndBorrowFromWallet(args) {
|
|
517
|
+
const { evc } = this.getCoreAddresses(args.chainId);
|
|
518
|
+
return encodeHelpers.encodeSwapAndBorrowFromWallet(evc, args);
|
|
519
|
+
}
|
|
520
|
+
encodeSwapAndRepayFromWallet(args) {
|
|
521
|
+
return encodeHelpers.encodeSwapAndRepayFromWallet(args);
|
|
522
|
+
}
|
|
523
|
+
encodeWithdrawAndSwap(args) {
|
|
524
|
+
return encodeHelpers.encodeWithdrawAndSwap(args);
|
|
525
|
+
}
|
|
526
|
+
encodeRedeemAndSwap(args) {
|
|
527
|
+
return encodeHelpers.encodeRedeemAndSwap(args);
|
|
528
|
+
}
|
|
402
529
|
/**
|
|
403
530
|
* Encodes EVC batch items for swapping collateral: withdraw from vaultIn → swap → verify/skim to receiver; optional enable/disable collateral.
|
|
404
531
|
* Swap quote should come from swapService.fetchDepositQuote() or match the same structure (verify type skimMin).
|
|
@@ -531,7 +658,7 @@ export class ExecutionService {
|
|
|
531
658
|
* @param args.spender - Address that will be allowed to transfer the token (e.g. vault or Permit2)
|
|
532
659
|
* @param args.nonce - Unique nonce for this permit (e.g. from Permit2 nonce(owner, token, spender))
|
|
533
660
|
* @param args.sigDeadline - Signature deadline (defaults to now + 1 hour if omitted)
|
|
534
|
-
* @param args.expiration - Permit expiration (defaults to
|
|
661
|
+
* @param args.expiration - Permit expiration (defaults to now + 1 hour if omitted)
|
|
535
662
|
* @returns EIP-712 typed data (domain, types, primaryType, message) for signing
|
|
536
663
|
*/
|
|
537
664
|
getPermit2TypedData(args) {
|
|
@@ -658,7 +785,13 @@ export class ExecutionService {
|
|
|
658
785
|
}
|
|
659
786
|
}
|
|
660
787
|
}
|
|
661
|
-
|
|
788
|
+
const optimizedExecutableItems = executableItems.flatMap((item) => {
|
|
789
|
+
if (item.type !== "evcBatch")
|
|
790
|
+
return [item];
|
|
791
|
+
const items = normalizeEVCStateTransitions(item.items);
|
|
792
|
+
return items.length > 0 ? [{ type: "evcBatch", items }] : [];
|
|
793
|
+
});
|
|
794
|
+
return [...approvalByKey.values(), ...optimizedExecutableItems];
|
|
662
795
|
}
|
|
663
796
|
/**
|
|
664
797
|
* Appends a raw batch item to the last EVC batch in the plan, or creates one.
|
|
@@ -738,11 +871,11 @@ export class ExecutionService {
|
|
|
738
871
|
* @param args.chainId - Chain ID (used to resolve Permit2 address when usePermit2 is true)
|
|
739
872
|
* @param args.wallet - Wallet entity with token balances and allowances (assetForVault, assetForPermit2, etc.)
|
|
740
873
|
* @param args.usePermit2 - If true, prefer Permit2 path (approve Permit2 + sign PermitSingle) when allowance is insufficient (default true)
|
|
741
|
-
* @param args.unlimitedApproval - If true,
|
|
874
|
+
* @param args.unlimitedApproval - If true, direct approvals and Permit2 signed amounts use maxUint256/maxUint160 (default false). Token approvals to Permit2 use maxUint256.
|
|
742
875
|
* @returns The same plan array with requiredApproval[].resolved populated (approve and/or permit2 data to sign)
|
|
743
876
|
*/
|
|
744
877
|
resolveRequiredApprovalsWithWallet(args) {
|
|
745
|
-
const { plan, wallet, chainId, usePermit2 = true, unlimitedApproval =
|
|
878
|
+
const { plan, wallet, chainId, usePermit2 = true, unlimitedApproval = false, } = args;
|
|
746
879
|
const deployment = this.deploymentService.getDeployment(chainId);
|
|
747
880
|
const permit2 = deployment.addresses.coreAddrs.permit2;
|
|
748
881
|
for (const item of plan) {
|
|
@@ -783,7 +916,7 @@ export class ExecutionService {
|
|
|
783
916
|
if (!walletAsset || !allowances) {
|
|
784
917
|
if (usePermit2) {
|
|
785
918
|
// Need approval to permit2 and permit2 signature
|
|
786
|
-
resolvedItems.push(makeApprove(permit2,
|
|
919
|
+
resolvedItems.push(makeApprove(permit2, maxUint256));
|
|
787
920
|
resolvedItems.push(makePermit2(spender, unlimitedApproval ? maxUint160 : amount));
|
|
788
921
|
}
|
|
789
922
|
else {
|
|
@@ -810,7 +943,7 @@ export class ExecutionService {
|
|
|
810
943
|
}
|
|
811
944
|
// If assetForPermit2 is insufficient, we need both approval and permit2 signature
|
|
812
945
|
if (!hasSufficientPermit2Allowance) {
|
|
813
|
-
addApproveWithOptionalReset(permit2,
|
|
946
|
+
addApproveWithOptionalReset(permit2, maxUint256, assetForPermit2);
|
|
814
947
|
resolvedItems.push(makePermit2(spender, unlimitedApproval ? maxUint160 : amount));
|
|
815
948
|
}
|
|
816
949
|
else {
|
|
@@ -880,6 +1013,55 @@ export class ExecutionService {
|
|
|
880
1013
|
});
|
|
881
1014
|
}
|
|
882
1015
|
// ========== Transaction plan functions ==========
|
|
1016
|
+
/**
|
|
1017
|
+
* Builds a cleanup plan matching Lite's stale collateral/controller policy.
|
|
1018
|
+
*
|
|
1019
|
+
* Cleanup is derived from the provided account snapshot:
|
|
1020
|
+
* - no enabled controllers: disable all enabled collaterals
|
|
1021
|
+
* - enabled controllers but no active borrows: disable all collaterals, then controllers
|
|
1022
|
+
* - active borrows: disable only enabled collaterals with no supplied position
|
|
1023
|
+
*
|
|
1024
|
+
* If the sub-account snapshot is unavailable, no cleanup is planned.
|
|
1025
|
+
*/
|
|
1026
|
+
planCleanup(args) {
|
|
1027
|
+
const { account, subAccount } = args;
|
|
1028
|
+
if (typeof account.getSubAccount !== "function")
|
|
1029
|
+
return [];
|
|
1030
|
+
const subAccountSnapshot = account.getSubAccount(subAccount);
|
|
1031
|
+
if (!subAccountSnapshot)
|
|
1032
|
+
return [];
|
|
1033
|
+
const collaterals = subAccountSnapshot.enabledCollaterals ?? [];
|
|
1034
|
+
const controllers = subAccountSnapshot.enabledControllers ?? [];
|
|
1035
|
+
if (collaterals.length === 0 && controllers.length === 0)
|
|
1036
|
+
return [];
|
|
1037
|
+
const items = [];
|
|
1038
|
+
const disableAllCollaterals = () => {
|
|
1039
|
+
for (const collateral of collaterals) {
|
|
1040
|
+
items.push(this.encodeDisableCollateral(account.chainId, subAccount, collateral));
|
|
1041
|
+
}
|
|
1042
|
+
};
|
|
1043
|
+
if (controllers.length === 0) {
|
|
1044
|
+
disableAllCollaterals();
|
|
1045
|
+
return this.convertBatchItemsToPlan(items, "cleanup");
|
|
1046
|
+
}
|
|
1047
|
+
const hasActiveBorrow = subAccountSnapshot.positions.some((position) => position.borrowed > 0n);
|
|
1048
|
+
if (!hasActiveBorrow) {
|
|
1049
|
+
disableAllCollaterals();
|
|
1050
|
+
for (const controller of controllers) {
|
|
1051
|
+
items.push(this.encodeDisableController(controller, subAccount));
|
|
1052
|
+
}
|
|
1053
|
+
return this.convertBatchItemsToPlan(items, "cleanup");
|
|
1054
|
+
}
|
|
1055
|
+
const depositedVaults = new Set(subAccountSnapshot.positions
|
|
1056
|
+
.filter(hasSuppliedPosition)
|
|
1057
|
+
.map((position) => getAddress(position.vaultAddress)));
|
|
1058
|
+
for (const collateral of collaterals) {
|
|
1059
|
+
if (depositedVaults.has(getAddress(collateral)))
|
|
1060
|
+
continue;
|
|
1061
|
+
items.push(this.encodeDisableCollateral(account.chainId, subAccount, collateral));
|
|
1062
|
+
}
|
|
1063
|
+
return this.convertBatchItemsToPlan(items, "cleanup");
|
|
1064
|
+
}
|
|
883
1065
|
/**
|
|
884
1066
|
* Builds a transaction plan for depositing assets into a vault.
|
|
885
1067
|
* Use `maxUint256` for `amount` to deposit all available assets from the wallet.
|
|
@@ -894,7 +1076,7 @@ export class ExecutionService {
|
|
|
894
1076
|
* @returns Array of transaction plan items (required approvals + EVC batch)
|
|
895
1077
|
*/
|
|
896
1078
|
planDeposit(args) {
|
|
897
|
-
const { vault, amount, receiver, account, asset, enableCollateral } = args;
|
|
1079
|
+
const { vault, amount, receiver, account, asset, enableCollateral, wrappedNativeInfo, } = args;
|
|
898
1080
|
const plan = [];
|
|
899
1081
|
// Default: collateral is not enabled when account/position is not available
|
|
900
1082
|
const isCollateralEnabled = account?.isCollateralEnabled(receiver, vault) ?? false;
|
|
@@ -914,6 +1096,7 @@ export class ExecutionService {
|
|
|
914
1096
|
receiver,
|
|
915
1097
|
owner: account.owner,
|
|
916
1098
|
enableCollateral: !isCollateralEnabled && enableCollateral,
|
|
1099
|
+
wrappedNativeInfo,
|
|
917
1100
|
// Permit2 is handled separately in the plan
|
|
918
1101
|
});
|
|
919
1102
|
plan.push(...this.convertBatchItemsToPlan(batchItems, "deposit"));
|
|
@@ -933,7 +1116,7 @@ export class ExecutionService {
|
|
|
933
1116
|
* @returns Array of transaction plan items (required approvals + EVC batch)
|
|
934
1117
|
*/
|
|
935
1118
|
planMint(args) {
|
|
936
|
-
const { vault, shares, receiver, account, asset, enableCollateral, sharesToAssetsExchangeRateWad, } = args;
|
|
1119
|
+
const { vault, shares, receiver, account, asset, enableCollateral, sharesToAssetsExchangeRateWad, wrappedNativeInfo, } = args;
|
|
937
1120
|
const plan = [];
|
|
938
1121
|
// Default: collateral is not enabled when account/position is not available
|
|
939
1122
|
const isCollateralEnabled = account?.isCollateralEnabled(receiver, vault) ?? false;
|
|
@@ -956,6 +1139,7 @@ export class ExecutionService {
|
|
|
956
1139
|
receiver,
|
|
957
1140
|
owner: account.owner,
|
|
958
1141
|
enableCollateral: !isCollateralEnabled && enableCollateral,
|
|
1142
|
+
wrappedNativeInfo,
|
|
959
1143
|
// Permit2 is handled separately in the plan
|
|
960
1144
|
});
|
|
961
1145
|
plan.push(...this.convertBatchItemsToPlan(batchItems, "mint"));
|
|
@@ -1076,6 +1260,7 @@ export class ExecutionService {
|
|
|
1076
1260
|
enableCollateral,
|
|
1077
1261
|
collateralVault: collateral?.vault,
|
|
1078
1262
|
collateralAmount: walletCollateral?.amount,
|
|
1263
|
+
collateralWrappedNativeInfo: walletCollateral?.wrappedNativeInfo,
|
|
1079
1264
|
collateralShareSource: savingsCollateral
|
|
1080
1265
|
? {
|
|
1081
1266
|
from: savingsCollateral.from,
|
|
@@ -1153,15 +1338,16 @@ export class ExecutionService {
|
|
|
1153
1338
|
if (!position) {
|
|
1154
1339
|
throw new Error(`Position not found. Liability vault: ${liabilityVault}, Account: ${receiver}`);
|
|
1155
1340
|
}
|
|
1341
|
+
const isMax = liabilityAmount === maxUint256;
|
|
1342
|
+
const approvalAmount = adjustForInterest(isMax ? position.borrowed : liabilityAmount);
|
|
1156
1343
|
// Add approval requirement (will be resolved later with Wallet data)
|
|
1157
1344
|
plan.push({
|
|
1158
1345
|
type: "requiredApproval",
|
|
1159
1346
|
token: position.asset,
|
|
1160
1347
|
owner: account.owner,
|
|
1161
1348
|
spender: liabilityVault,
|
|
1162
|
-
amount:
|
|
1349
|
+
amount: approvalAmount,
|
|
1163
1350
|
});
|
|
1164
|
-
const isMax = liabilityAmount === maxUint256;
|
|
1165
1351
|
// Build EVC batch items
|
|
1166
1352
|
const batchItems = this.encodeRepayFromWallet({
|
|
1167
1353
|
chainId: account.chainId,
|
|
@@ -1288,7 +1474,7 @@ export class ExecutionService {
|
|
|
1288
1474
|
* @returns Array of transaction plan items (EVC batch: withdraw, swap, verify/repay). Throws if positions not found or liability is zero.
|
|
1289
1475
|
*/
|
|
1290
1476
|
planRepayWithSwap(args) {
|
|
1291
|
-
const { swapQuote, account, cleanupOnMax = false } = args;
|
|
1477
|
+
const { swapQuote, account, cleanupOnMax = false, swapperMode } = args;
|
|
1292
1478
|
const plan = [];
|
|
1293
1479
|
const liabilityPosition = account?.getPosition(swapQuote.accountOut, swapQuote.receiver);
|
|
1294
1480
|
const fromPosition = account?.getPosition(swapQuote.accountIn, swapQuote.vaultIn);
|
|
@@ -1306,6 +1492,7 @@ export class ExecutionService {
|
|
|
1306
1492
|
maxWithdraw,
|
|
1307
1493
|
isMax,
|
|
1308
1494
|
disableControllerOnMax: true,
|
|
1495
|
+
swapperMode,
|
|
1309
1496
|
});
|
|
1310
1497
|
if (cleanupOnMax && isMax) {
|
|
1311
1498
|
this.appendMaxRepayCleanup({
|
|
@@ -1334,7 +1521,7 @@ export class ExecutionService {
|
|
|
1334
1521
|
* @returns Array of transaction plan items (approval to SwapVerifier + EVC batch)
|
|
1335
1522
|
*/
|
|
1336
1523
|
planDepositWithSwapFromWallet(args) {
|
|
1337
|
-
const { swapQuote, amount, tokenIn, account, enableCollateral } = args;
|
|
1524
|
+
const { swapQuote, amount, tokenIn, account, enableCollateral, wrappedNativeInfo, } = args;
|
|
1338
1525
|
const plan = [];
|
|
1339
1526
|
// Approval goes to the transferFromSender contract (which uses permit2 transferFrom internally)
|
|
1340
1527
|
plan.push({
|
|
@@ -1358,6 +1545,7 @@ export class ExecutionService {
|
|
|
1358
1545
|
amount,
|
|
1359
1546
|
sender: account.owner,
|
|
1360
1547
|
enableCollateral: shouldEnableCollateral,
|
|
1548
|
+
wrappedNativeInfo,
|
|
1361
1549
|
});
|
|
1362
1550
|
plan.push(...this.convertBatchItemsToPlan(batchItems, "depositWithSwapFromWallet"));
|
|
1363
1551
|
return plan;
|
|
@@ -1374,7 +1562,7 @@ export class ExecutionService {
|
|
|
1374
1562
|
* @returns Array of transaction plan items (approval to SwapVerifier + EVC batch)
|
|
1375
1563
|
*/
|
|
1376
1564
|
planSwapFromWallet(args) {
|
|
1377
|
-
const { swapQuote, amount, tokenIn, account } = args;
|
|
1565
|
+
const { swapQuote, amount, tokenIn, account, wrappedNativeInfo } = args;
|
|
1378
1566
|
const plan = [];
|
|
1379
1567
|
plan.push({
|
|
1380
1568
|
type: "requiredApproval",
|
|
@@ -1388,10 +1576,102 @@ export class ExecutionService {
|
|
|
1388
1576
|
swapQuote,
|
|
1389
1577
|
amount,
|
|
1390
1578
|
sender: account.owner,
|
|
1579
|
+
wrappedNativeInfo,
|
|
1391
1580
|
});
|
|
1392
1581
|
plan.push(...this.convertBatchItemsToPlan(batchItems, "swapFromWallet"));
|
|
1393
1582
|
return plan;
|
|
1394
1583
|
}
|
|
1584
|
+
planSwapAndBorrowFromWallet(args) {
|
|
1585
|
+
const { swapQuote, amount, tokenIn, account, borrowVault, borrowAmount, borrowAccount = swapQuote.accountOut, receiver = account.owner, collateralVault = swapQuote.receiver, wrappedNativeInfo, } = args;
|
|
1586
|
+
const plan = [];
|
|
1587
|
+
plan.push({
|
|
1588
|
+
type: "requiredApproval",
|
|
1589
|
+
token: tokenIn,
|
|
1590
|
+
owner: account.owner,
|
|
1591
|
+
spender: swapQuote.verify.verifierAddress,
|
|
1592
|
+
amount,
|
|
1593
|
+
});
|
|
1594
|
+
const enableController = !(account?.isControllerEnabled(borrowAccount, borrowVault) ?? false);
|
|
1595
|
+
const enableCollateral = !(account?.isCollateralEnabled(borrowAccount, collateralVault) ?? false);
|
|
1596
|
+
const currentController = account?.getCurrentController(borrowAccount);
|
|
1597
|
+
const batchItems = this.encodeSwapAndBorrowFromWallet({
|
|
1598
|
+
chainId: account.chainId,
|
|
1599
|
+
swapQuote,
|
|
1600
|
+
amount,
|
|
1601
|
+
sender: account.owner,
|
|
1602
|
+
borrowAccount,
|
|
1603
|
+
collateralVault,
|
|
1604
|
+
borrowVault,
|
|
1605
|
+
borrowAmount,
|
|
1606
|
+
receiver,
|
|
1607
|
+
currentController: currentController || undefined,
|
|
1608
|
+
enableController,
|
|
1609
|
+
enableCollateral,
|
|
1610
|
+
wrappedNativeInfo,
|
|
1611
|
+
});
|
|
1612
|
+
plan.push(...this.convertBatchItemsToPlan(batchItems, "swapAndBorrowFromWallet"));
|
|
1613
|
+
return plan;
|
|
1614
|
+
}
|
|
1615
|
+
planSwapAndRepayFromWallet(args) {
|
|
1616
|
+
const { swapQuote, amount, tokenIn, account, liabilityVault = swapQuote.receiver, repayAccount = swapQuote.accountOut, isMax, cleanupOnMax = false, wrappedNativeInfo, } = args;
|
|
1617
|
+
const plan = [];
|
|
1618
|
+
plan.push({
|
|
1619
|
+
type: "requiredApproval",
|
|
1620
|
+
token: tokenIn,
|
|
1621
|
+
owner: account.owner,
|
|
1622
|
+
spender: swapQuote.verify.verifierAddress,
|
|
1623
|
+
amount,
|
|
1624
|
+
});
|
|
1625
|
+
const liabilityPosition = account?.getPosition(repayAccount, liabilityVault);
|
|
1626
|
+
const resolvedIsMax = isMax ??
|
|
1627
|
+
(liabilityPosition !== undefined &&
|
|
1628
|
+
liabilityPosition.borrowed <= BigInt(swapQuote.amountOutMin || 0));
|
|
1629
|
+
const batchItems = this.encodeSwapAndRepayFromWallet({
|
|
1630
|
+
chainId: account.chainId,
|
|
1631
|
+
swapQuote,
|
|
1632
|
+
amount,
|
|
1633
|
+
sender: account.owner,
|
|
1634
|
+
liabilityVault,
|
|
1635
|
+
repayAccount,
|
|
1636
|
+
isMax: resolvedIsMax,
|
|
1637
|
+
disableControllerOnMax: true,
|
|
1638
|
+
wrappedNativeInfo,
|
|
1639
|
+
});
|
|
1640
|
+
if (cleanupOnMax && resolvedIsMax && liabilityPosition) {
|
|
1641
|
+
this.appendMaxRepayCleanup({
|
|
1642
|
+
account,
|
|
1643
|
+
liabilityPosition,
|
|
1644
|
+
receiver: repayAccount,
|
|
1645
|
+
batchItems,
|
|
1646
|
+
});
|
|
1647
|
+
}
|
|
1648
|
+
plan.push(...this.convertBatchItemsToPlan(batchItems, "swapAndRepayFromWallet"));
|
|
1649
|
+
return plan;
|
|
1650
|
+
}
|
|
1651
|
+
planWithdrawAndSwap(args) {
|
|
1652
|
+
const { account, vault, assets, owner, swapQuote } = args;
|
|
1653
|
+
const batchItems = this.encodeWithdrawAndSwap({
|
|
1654
|
+
chainId: account.chainId,
|
|
1655
|
+
vault,
|
|
1656
|
+
assets,
|
|
1657
|
+
owner,
|
|
1658
|
+
sender: account.owner,
|
|
1659
|
+
swapQuote,
|
|
1660
|
+
});
|
|
1661
|
+
return this.convertBatchItemsToPlan(batchItems, "withdrawAndSwap");
|
|
1662
|
+
}
|
|
1663
|
+
planRedeemAndSwap(args) {
|
|
1664
|
+
const { account, vault, shares, owner, swapQuote } = args;
|
|
1665
|
+
const batchItems = this.encodeRedeemAndSwap({
|
|
1666
|
+
chainId: account.chainId,
|
|
1667
|
+
vault,
|
|
1668
|
+
shares,
|
|
1669
|
+
owner,
|
|
1670
|
+
sender: account.owner,
|
|
1671
|
+
swapQuote,
|
|
1672
|
+
});
|
|
1673
|
+
return this.convertBatchItemsToPlan(batchItems, "redeemAndSwap");
|
|
1674
|
+
}
|
|
1395
1675
|
/**
|
|
1396
1676
|
* Builds a transaction plan for swapping collateral from one vault to another (withdraw → swap → deposit/skim).
|
|
1397
1677
|
*
|
|
@@ -1401,7 +1681,7 @@ export class ExecutionService {
|
|
|
1401
1681
|
* @returns Array of transaction plan items (EVC batch: withdraw, swap, verify/skim, optional enable/disable collateral)
|
|
1402
1682
|
*/
|
|
1403
1683
|
planSwapCollateral(args) {
|
|
1404
|
-
const { swapQuote, account } = args;
|
|
1684
|
+
const { swapQuote, account, swapperMode } = args;
|
|
1405
1685
|
const plan = [];
|
|
1406
1686
|
// Check if source collateral needs to be disabled (when all is swapped)
|
|
1407
1687
|
// Default: when position is not available, assume amounts are zero, so we don't disable collateral
|
|
@@ -1420,6 +1700,7 @@ export class ExecutionService {
|
|
|
1420
1700
|
enableCollateral,
|
|
1421
1701
|
disableCollateralOnMax: true,
|
|
1422
1702
|
isMax,
|
|
1703
|
+
swapperMode,
|
|
1423
1704
|
});
|
|
1424
1705
|
plan.push(...this.convertBatchItemsToPlan(batchItems, "swapCollateral"));
|
|
1425
1706
|
return plan;
|
|
@@ -1433,7 +1714,7 @@ export class ExecutionService {
|
|
|
1433
1714
|
* @returns Array of transaction plan items (EVC batch: enableController, borrow, swap, verify/repay, optional disableController)
|
|
1434
1715
|
*/
|
|
1435
1716
|
planSwapDebt(args) {
|
|
1436
|
-
const { swapQuote, account } = args;
|
|
1717
|
+
const { swapQuote, account, swapperMode } = args;
|
|
1437
1718
|
const plan = [];
|
|
1438
1719
|
const sourcePosition = account?.getPosition(swapQuote.accountIn, swapQuote.vaultIn);
|
|
1439
1720
|
const isMax = sourcePosition
|
|
@@ -1448,6 +1729,7 @@ export class ExecutionService {
|
|
|
1448
1729
|
enableController,
|
|
1449
1730
|
disableControllerOnMax: true,
|
|
1450
1731
|
isMax,
|
|
1732
|
+
swapperMode,
|
|
1451
1733
|
});
|
|
1452
1734
|
plan.push(...this.convertBatchItemsToPlan(batchItems, "swapDebt"));
|
|
1453
1735
|
return plan;
|
|
@@ -1619,7 +1901,7 @@ export class ExecutionService {
|
|
|
1619
1901
|
* @returns Array of transaction plan items (optional approval + EVC batch). Throws if swapQuote.accountIn !== swapQuote.accountOut.
|
|
1620
1902
|
*/
|
|
1621
1903
|
planMultiplyWithSwap(args) {
|
|
1622
|
-
const { collateralVault, collateralAmount, collateralAsset, collateralShareSource, account, swapQuote, } = args;
|
|
1904
|
+
const { collateralVault, collateralAmount, collateralAsset, collateralShareSource, collateralWrappedNativeInfo, account, swapQuote, swapperMode, } = args;
|
|
1623
1905
|
const plan = [];
|
|
1624
1906
|
// 1. Check if collateral approval is needed (only if depositing collateral)
|
|
1625
1907
|
if (!collateralShareSource && collateralAmount > 0n) {
|
|
@@ -1638,13 +1920,14 @@ export class ExecutionService {
|
|
|
1638
1920
|
const receiver = swapQuote.accountIn;
|
|
1639
1921
|
const liabilityVault = swapQuote.vaultIn;
|
|
1640
1922
|
const longVault = swapQuote.receiver;
|
|
1641
|
-
const liabilityAmount =
|
|
1923
|
+
const liabilityAmount = getSwapInputAmount(swapQuote, swapperMode ?? SwapperMode.EXACT_IN);
|
|
1642
1924
|
// 2. Determine if collateral needs to be enabled
|
|
1643
1925
|
const hasCollateralInput = collateralShareSource
|
|
1644
1926
|
? collateralShareSource.shares > 0n
|
|
1645
1927
|
: collateralAmount > 0n;
|
|
1646
1928
|
const enableCollateral = hasCollateralInput &&
|
|
1647
1929
|
!(account?.isCollateralEnabled(receiver, collateralVault) ?? false);
|
|
1930
|
+
const enableCollateralLong = !(account?.isCollateralEnabled(receiver, longVault) ?? false);
|
|
1648
1931
|
const resolvedCollateralShareSource = collateralShareSource
|
|
1649
1932
|
? {
|
|
1650
1933
|
...collateralShareSource,
|
|
@@ -1671,7 +1954,9 @@ export class ExecutionService {
|
|
|
1671
1954
|
currentController: currentController || undefined,
|
|
1672
1955
|
enableController,
|
|
1673
1956
|
collateralShareSource: resolvedCollateralShareSource,
|
|
1957
|
+
collateralWrappedNativeInfo,
|
|
1674
1958
|
swapQuote,
|
|
1959
|
+
enableCollateralLong,
|
|
1675
1960
|
// Permit2 is handled separately in the plan
|
|
1676
1961
|
});
|
|
1677
1962
|
plan.push(...this.convertBatchItemsToPlan(batchItems, "multiplyWithSwap"));
|
|
@@ -1693,7 +1978,7 @@ export class ExecutionService {
|
|
|
1693
1978
|
* @returns Array of transaction plan items (optional approval + EVC batch)
|
|
1694
1979
|
*/
|
|
1695
1980
|
planMultiplySameAsset(args) {
|
|
1696
|
-
const { collateralVault, collateralAmount, collateralAsset, collateralShareSource, liabilityVault, liabilityAmount, longVault, receiver, account, } = args;
|
|
1981
|
+
const { collateralVault, collateralAmount, collateralAsset, collateralShareSource, collateralWrappedNativeInfo, liabilityVault, liabilityAmount, longVault, receiver, account, } = args;
|
|
1697
1982
|
const plan = [];
|
|
1698
1983
|
// 1. Check if collateral approval is needed (only if depositing collateral)
|
|
1699
1984
|
if (!collateralShareSource && collateralAmount > 0n) {
|
|
@@ -1712,6 +1997,7 @@ export class ExecutionService {
|
|
|
1712
1997
|
: collateralAmount > 0n;
|
|
1713
1998
|
const enableCollateral = hasCollateralInput &&
|
|
1714
1999
|
!(account?.isCollateralEnabled(receiver, collateralVault) ?? false);
|
|
2000
|
+
const enableCollateralLong = !(account?.isCollateralEnabled(receiver, longVault) ?? false);
|
|
1715
2001
|
const resolvedCollateralShareSource = collateralShareSource
|
|
1716
2002
|
? {
|
|
1717
2003
|
...collateralShareSource,
|
|
@@ -1738,6 +2024,8 @@ export class ExecutionService {
|
|
|
1738
2024
|
currentController: currentController || undefined,
|
|
1739
2025
|
enableController,
|
|
1740
2026
|
collateralShareSource: resolvedCollateralShareSource,
|
|
2027
|
+
collateralWrappedNativeInfo,
|
|
2028
|
+
enableCollateralLong,
|
|
1741
2029
|
// Permit2 is handled separately in the plan
|
|
1742
2030
|
});
|
|
1743
2031
|
plan.push(...this.convertBatchItemsToPlan(batchItems, "multiplySameAsset"));
|