@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.
Files changed (60) hide show
  1. package/dist/src/entities/Account.d.ts +2 -2
  2. package/dist/src/entities/Account.d.ts.map +1 -1
  3. package/dist/src/entities/Account.js +2 -2
  4. package/dist/src/entities/Account.js.map +1 -1
  5. package/dist/src/sdk/defaultConfig.d.ts +1 -1
  6. package/dist/src/sdk/defaultConfig.d.ts.map +1 -1
  7. package/dist/src/sdk/defaultConfig.js +1 -1
  8. package/dist/src/sdk/defaultConfig.js.map +1 -1
  9. package/dist/src/services/accountService/accountServiceConfig.d.ts +1 -1
  10. package/dist/src/services/accountService/accountServiceConfig.d.ts.map +1 -1
  11. package/dist/src/services/executionService/encode.d.ts +15 -11
  12. package/dist/src/services/executionService/encode.d.ts.map +1 -1
  13. package/dist/src/services/executionService/encode.js +242 -23
  14. package/dist/src/services/executionService/encode.js.map +1 -1
  15. package/dist/src/services/executionService/executionService.d.ts +35 -3
  16. package/dist/src/services/executionService/executionService.d.ts.map +1 -1
  17. package/dist/src/services/executionService/executionService.js +306 -18
  18. package/dist/src/services/executionService/executionService.js.map +1 -1
  19. package/dist/src/services/executionService/executionServiceTypes.d.ts +109 -1
  20. package/dist/src/services/executionService/executionServiceTypes.d.ts.map +1 -1
  21. package/dist/src/services/executionService/executionServiceTypes.js.map +1 -1
  22. package/dist/src/services/executionService/index.d.ts +1 -1
  23. package/dist/src/services/executionService/index.d.ts.map +1 -1
  24. package/dist/src/services/executionService/index.js.map +1 -1
  25. package/dist/src/services/intrinsicApyService/adapters/intrinsicApyV3Adapter/intrinsicApyV3AdapterTypes.d.ts +1 -1
  26. package/dist/src/services/intrinsicApyService/adapters/intrinsicApyV3Adapter/intrinsicApyV3AdapterTypes.d.ts.map +1 -1
  27. package/dist/src/services/priceService/priceService.d.ts +2 -1
  28. package/dist/src/services/priceService/priceService.d.ts.map +1 -1
  29. package/dist/src/services/priceService/priceService.js +8 -25
  30. package/dist/src/services/priceService/priceService.js.map +1 -1
  31. package/dist/src/services/rewardsService/adapters/rewardsDirectAdapter/rewardsDirectAdapter.d.ts +4 -1
  32. package/dist/src/services/rewardsService/adapters/rewardsDirectAdapter/rewardsDirectAdapter.d.ts.map +1 -1
  33. package/dist/src/services/rewardsService/adapters/rewardsDirectAdapter/rewardsDirectAdapter.js +20 -4
  34. package/dist/src/services/rewardsService/adapters/rewardsDirectAdapter/rewardsDirectAdapter.js.map +1 -1
  35. package/dist/src/services/rewardsService/adapters/rewardsV3Adapter/rewardsV3Adapter.d.ts.map +1 -1
  36. package/dist/src/services/rewardsService/adapters/rewardsV3Adapter/rewardsV3Adapter.js +5 -2
  37. package/dist/src/services/rewardsService/adapters/rewardsV3Adapter/rewardsV3Adapter.js.map +1 -1
  38. package/dist/src/services/rewardsService/adapters/rewardsV3Adapter/rewardsV3AdapterTypes.d.ts +2 -0
  39. package/dist/src/services/rewardsService/adapters/rewardsV3Adapter/rewardsV3AdapterTypes.d.ts.map +1 -1
  40. package/dist/src/services/rewardsService/rewardsService.d.ts +6 -1
  41. package/dist/src/services/rewardsService/rewardsService.d.ts.map +1 -1
  42. package/dist/src/services/rewardsService/rewardsService.js +128 -3
  43. package/dist/src/services/rewardsService/rewardsService.js.map +1 -1
  44. package/dist/src/services/rewardsService/rewardsServiceTypes.d.ts +5 -3
  45. package/dist/src/services/rewardsService/rewardsServiceTypes.d.ts.map +1 -1
  46. package/dist/src/services/swapService/swapService.d.ts +4 -6
  47. package/dist/src/services/swapService/swapService.d.ts.map +1 -1
  48. package/dist/src/services/swapService/swapService.js +90 -99
  49. package/dist/src/services/swapService/swapService.js.map +1 -1
  50. package/dist/src/services/swapService/swapVerification.d.ts +28 -0
  51. package/dist/src/services/swapService/swapVerification.d.ts.map +1 -0
  52. package/dist/src/services/swapService/swapVerification.js +138 -0
  53. package/dist/src/services/swapService/swapVerification.js.map +1 -0
  54. package/dist/src/services/vaults/eVaultService/eVaultServiceConfig.d.ts +1 -1
  55. package/dist/src/services/vaults/eVaultService/eVaultServiceConfig.d.ts.map +1 -1
  56. package/dist/src/services/vaults/eulerEarnService/eulerEarnServiceConfig.d.ts +1 -1
  57. package/dist/src/services/vaults/eulerEarnService/eulerEarnServiceConfig.d.ts.map +1 -1
  58. package/dist/src/services/vaults/vaultMetaService/adapters/VaultTypeV3Adapter.d.ts +1 -1
  59. package/dist/src/services/vaults/vaultMetaService/adapters/VaultTypeV3Adapter.d.ts.map +1 -1
  60. 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 maxUint48 if omitted)
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
- return [...approvalByKey.values(), ...executableItems];
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, approval/permit amounts use maxUint256/maxUint160 (default 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 = true, } = args;
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, unlimitedApproval ? maxUint256 : amount));
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, unlimitedApproval ? maxUint256 : amount, assetForPermit2);
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: liabilityAmount,
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 = BigInt(swapQuote.amountIn);
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"));