@eulerxyz/euler-v2-sdk 0.1.2-beta → 0.2.0-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/README.md +24 -25
- package/dist/src/entities/Account.d.ts +48 -47
- package/dist/src/entities/Account.d.ts.map +1 -1
- package/dist/src/entities/Account.js +85 -64
- package/dist/src/entities/Account.js.map +1 -1
- package/dist/src/entities/ERC4626Vault.d.ts +6 -5
- package/dist/src/entities/ERC4626Vault.d.ts.map +1 -1
- package/dist/src/entities/ERC4626Vault.js +13 -6
- package/dist/src/entities/ERC4626Vault.js.map +1 -1
- package/dist/src/entities/EVault.d.ts +30 -15
- package/dist/src/entities/EVault.d.ts.map +1 -1
- package/dist/src/entities/EVault.js +66 -14
- package/dist/src/entities/EVault.js.map +1 -1
- package/dist/src/entities/EulerEarn.d.ts +3 -0
- package/dist/src/entities/EulerEarn.d.ts.map +1 -1
- package/dist/src/entities/EulerEarn.js +12 -3
- package/dist/src/entities/EulerEarn.js.map +1 -1
- package/dist/src/entities/EulerLabels.d.ts +74 -0
- package/dist/src/entities/EulerLabels.d.ts.map +1 -1
- package/dist/src/entities/Portfolio.d.ts +38 -17
- package/dist/src/entities/Portfolio.d.ts.map +1 -1
- package/dist/src/entities/Portfolio.js +71 -23
- package/dist/src/entities/Portfolio.js.map +1 -1
- package/dist/src/entities/Wallet.d.ts +1 -0
- package/dist/src/entities/Wallet.d.ts.map +1 -1
- package/dist/src/entities/Wallet.js +2 -2
- package/dist/src/entities/Wallet.js.map +1 -1
- package/dist/src/index.d.ts +5 -2
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +5 -2
- package/dist/src/index.js.map +1 -1
- package/dist/src/plugins/keyring/keyringPlugin.d.ts +1 -1
- package/dist/src/plugins/keyring/keyringPlugin.d.ts.map +1 -1
- package/dist/src/plugins/keyring/keyringPlugin.js +70 -12
- package/dist/src/plugins/keyring/keyringPlugin.js.map +1 -1
- package/dist/src/plugins/pyth/pythPlugin.d.ts.map +1 -1
- package/dist/src/plugins/pyth/pythPlugin.js +132 -11
- package/dist/src/plugins/pyth/pythPlugin.js.map +1 -1
- package/dist/src/plugins/types.d.ts +4 -7
- package/dist/src/plugins/types.d.ts.map +1 -1
- package/dist/src/plugins/types.js.map +1 -1
- package/dist/src/sdk/buildSDK.d.ts +11 -7
- package/dist/src/sdk/buildSDK.d.ts.map +1 -1
- package/dist/src/sdk/buildSDK.js +369 -116
- package/dist/src/sdk/buildSDK.js.map +1 -1
- package/dist/src/sdk/config.d.ts +74 -0
- package/dist/src/sdk/config.d.ts.map +1 -0
- package/dist/src/sdk/config.js +187 -0
- package/dist/src/sdk/config.js.map +1 -0
- package/dist/src/sdk/defaultConfig.d.ts +5 -2
- package/dist/src/sdk/defaultConfig.d.ts.map +1 -1
- package/dist/src/sdk/defaultConfig.js +21 -18
- package/dist/src/sdk/defaultConfig.js.map +1 -1
- package/dist/src/sdk/sdk.d.ts +6 -8
- package/dist/src/sdk/sdk.d.ts.map +1 -1
- package/dist/src/sdk/sdk.js +2 -6
- package/dist/src/sdk/sdk.js.map +1 -1
- package/dist/src/services/accountService/accountService.d.ts.map +1 -1
- package/dist/src/services/accountService/accountService.js +10 -7
- package/dist/src/services/accountService/accountService.js.map +1 -1
- package/dist/src/services/accountService/adapters/accountOnchainAdapter/accountInfoConverter.d.ts +2 -2
- package/dist/src/services/accountService/adapters/accountOnchainAdapter/accountInfoConverter.d.ts.map +1 -1
- package/dist/src/services/accountService/adapters/accountOnchainAdapter/accountInfoConverter.js +22 -17
- package/dist/src/services/accountService/adapters/accountOnchainAdapter/accountInfoConverter.js.map +1 -1
- package/dist/src/services/accountService/adapters/accountOnchainAdapter/accountOnchainAdapter.d.ts +1 -1
- package/dist/src/services/accountService/adapters/accountOnchainAdapter/accountOnchainAdapter.d.ts.map +1 -1
- package/dist/src/services/accountService/adapters/accountOnchainAdapter/accountOnchainAdapter.js +16 -17
- package/dist/src/services/accountService/adapters/accountOnchainAdapter/accountOnchainAdapter.js.map +1 -1
- package/dist/src/services/accountService/adapters/accountV3Adapter/accountV3Adapter.d.ts +7 -1
- package/dist/src/services/accountService/adapters/accountV3Adapter/accountV3Adapter.d.ts.map +1 -1
- package/dist/src/services/accountService/adapters/accountV3Adapter/accountV3Adapter.js +141 -54
- package/dist/src/services/accountService/adapters/accountV3Adapter/accountV3Adapter.js.map +1 -1
- package/dist/src/services/deploymentService/deploymentService.d.ts +1 -0
- package/dist/src/services/deploymentService/deploymentService.d.ts.map +1 -1
- package/dist/src/services/deploymentService/deploymentService.js.map +1 -1
- package/dist/src/services/eulerLabelsService/eulerLabelsService.d.ts +18 -1
- package/dist/src/services/eulerLabelsService/eulerLabelsService.d.ts.map +1 -1
- package/dist/src/services/eulerLabelsService/eulerLabelsService.js +373 -30
- package/dist/src/services/eulerLabelsService/eulerLabelsService.js.map +1 -1
- package/dist/src/services/executionService/encode.d.ts +30 -0
- package/dist/src/services/executionService/encode.d.ts.map +1 -0
- package/dist/src/services/executionService/encode.js +841 -0
- package/dist/src/services/executionService/encode.js.map +1 -0
- package/dist/src/services/executionService/execute.d.ts +65 -0
- package/dist/src/services/executionService/execute.d.ts.map +1 -0
- package/dist/src/services/executionService/execute.js +185 -0
- package/dist/src/services/executionService/execute.js.map +1 -0
- package/dist/src/services/executionService/executionService.d.ts +169 -37
- package/dist/src/services/executionService/executionService.d.ts.map +1 -1
- package/dist/src/services/executionService/executionService.js +510 -893
- package/dist/src/services/executionService/executionService.js.map +1 -1
- package/dist/src/services/executionService/executionServiceTypes.d.ts +93 -9
- package/dist/src/services/executionService/executionServiceTypes.d.ts.map +1 -1
- package/dist/src/services/executionService/executionServiceTypes.js +6 -0
- package/dist/src/services/executionService/executionServiceTypes.js.map +1 -1
- package/dist/src/services/executionService/index.d.ts +5 -2
- package/dist/src/services/executionService/index.d.ts.map +1 -1
- package/dist/src/services/executionService/index.js +3 -1
- package/dist/src/services/executionService/index.js.map +1 -1
- package/dist/src/services/{simulationService/simulationService.d.ts → executionService/simulate.d.ts} +26 -40
- package/dist/src/services/executionService/simulate.d.ts.map +1 -0
- package/dist/src/services/executionService/simulate.js +532 -0
- package/dist/src/services/executionService/simulate.js.map +1 -0
- 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/oracleAdapterService/oracleAdapterService.d.ts +5 -0
- package/dist/src/services/oracleAdapterService/oracleAdapterService.d.ts.map +1 -1
- package/dist/src/services/oracleAdapterService/oracleAdapterService.js +38 -11
- package/dist/src/services/oracleAdapterService/oracleAdapterService.js.map +1 -1
- package/dist/src/services/priceService/backendClient.d.ts +7 -13
- package/dist/src/services/priceService/backendClient.d.ts.map +1 -1
- package/dist/src/services/priceService/backendClient.js +7 -14
- package/dist/src/services/priceService/backendClient.js.map +1 -1
- package/dist/src/services/priceService/index.d.ts +2 -2
- package/dist/src/services/priceService/index.d.ts.map +1 -1
- package/dist/src/services/priceService/index.js +1 -1
- package/dist/src/services/priceService/index.js.map +1 -1
- package/dist/src/services/priceService/priceService.d.ts +19 -17
- package/dist/src/services/priceService/priceService.d.ts.map +1 -1
- package/dist/src/services/priceService/priceService.js +53 -76
- package/dist/src/services/priceService/priceService.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 +26 -13
- package/dist/src/services/rewardsService/adapters/rewardsV3Adapter/rewardsV3Adapter.js.map +1 -1
- package/dist/src/services/rewardsService/adapters/rewardsV3Adapter/rewardsV3AdapterTypes.d.ts +10 -10
- package/dist/src/services/rewardsService/adapters/rewardsV3Adapter/rewardsV3AdapterTypes.d.ts.map +1 -1
- package/dist/src/services/rewardsService/rewardsServiceTypes.d.ts +1 -1
- package/dist/src/services/rewardsService/rewardsServiceTypes.d.ts.map +1 -1
- package/dist/src/services/vaults/eVaultService/adapters/eVaultOnchainAdapter/eVaultOnchainAdapter.d.ts +1 -1
- package/dist/src/services/vaults/eVaultService/adapters/eVaultOnchainAdapter/eVaultOnchainAdapter.d.ts.map +1 -1
- package/dist/src/services/vaults/eVaultService/adapters/eVaultOnchainAdapter/eVaultOnchainAdapter.js +6 -13
- package/dist/src/services/vaults/eVaultService/adapters/eVaultOnchainAdapter/eVaultOnchainAdapter.js.map +1 -1
- package/dist/src/services/vaults/eVaultService/adapters/eVaultOnchainAdapter/vaultInfoConverter.d.ts +1 -1
- package/dist/src/services/vaults/eVaultService/adapters/eVaultOnchainAdapter/vaultInfoConverter.d.ts.map +1 -1
- package/dist/src/services/vaults/eVaultService/adapters/eVaultOnchainAdapter/vaultInfoConverter.js +69 -51
- package/dist/src/services/vaults/eVaultService/adapters/eVaultOnchainAdapter/vaultInfoConverter.js.map +1 -1
- package/dist/src/services/vaults/eVaultService/adapters/eVaultV3Adapter/eVaultV3Adapter.d.ts +6 -2
- package/dist/src/services/vaults/eVaultService/adapters/eVaultV3Adapter/eVaultV3Adapter.d.ts.map +1 -1
- package/dist/src/services/vaults/eVaultService/adapters/eVaultV3Adapter/eVaultV3Adapter.js +70 -21
- package/dist/src/services/vaults/eVaultService/adapters/eVaultV3Adapter/eVaultV3Adapter.js.map +1 -1
- package/dist/src/services/vaults/eVaultService/adapters/eVaultV3Adapter/eVaultV3AdapterConversions.d.ts +1 -1
- package/dist/src/services/vaults/eVaultService/adapters/eVaultV3Adapter/eVaultV3AdapterConversions.d.ts.map +1 -1
- package/dist/src/services/vaults/eVaultService/adapters/eVaultV3Adapter/eVaultV3AdapterConversions.js +106 -111
- package/dist/src/services/vaults/eVaultService/adapters/eVaultV3Adapter/eVaultV3AdapterConversions.js.map +1 -1
- package/dist/src/services/vaults/eVaultService/eVaultService.d.ts +4 -4
- package/dist/src/services/vaults/eVaultService/eVaultService.d.ts.map +1 -1
- package/dist/src/services/vaults/eVaultService/eVaultService.js +56 -57
- package/dist/src/services/vaults/eVaultService/eVaultService.js.map +1 -1
- 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/adapters/eulerEarnInfoConverter.d.ts +1 -1
- package/dist/src/services/vaults/eulerEarnService/adapters/eulerEarnInfoConverter.d.ts.map +1 -1
- package/dist/src/services/vaults/eulerEarnService/adapters/eulerEarnInfoConverter.js +22 -21
- package/dist/src/services/vaults/eulerEarnService/adapters/eulerEarnInfoConverter.js.map +1 -1
- package/dist/src/services/vaults/eulerEarnService/adapters/eulerEarnOnchainAdapter.d.ts.map +1 -1
- package/dist/src/services/vaults/eulerEarnService/adapters/eulerEarnOnchainAdapter.js +27 -32
- package/dist/src/services/vaults/eulerEarnService/adapters/eulerEarnOnchainAdapter.js.map +1 -1
- package/dist/src/services/vaults/eulerEarnService/adapters/eulerEarnV3Adapter.d.ts +1 -1
- package/dist/src/services/vaults/eulerEarnService/adapters/eulerEarnV3Adapter.d.ts.map +1 -1
- package/dist/src/services/vaults/eulerEarnService/adapters/eulerEarnV3Adapter.js +113 -72
- package/dist/src/services/vaults/eulerEarnService/adapters/eulerEarnV3Adapter.js.map +1 -1
- package/dist/src/services/vaults/eulerEarnService/eulerEarnService.d.ts +5 -5
- package/dist/src/services/vaults/eulerEarnService/eulerEarnService.d.ts.map +1 -1
- package/dist/src/services/vaults/eulerEarnService/eulerEarnService.js +30 -28
- package/dist/src/services/vaults/eulerEarnService/eulerEarnService.js.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/securitizeVaultService/adapters/securitizeVaultInfoConverter.d.ts +1 -1
- package/dist/src/services/vaults/securitizeVaultService/adapters/securitizeVaultInfoConverter.d.ts.map +1 -1
- package/dist/src/services/vaults/securitizeVaultService/adapters/securitizeVaultInfoConverter.js +10 -7
- package/dist/src/services/vaults/securitizeVaultService/adapters/securitizeVaultInfoConverter.js.map +1 -1
- package/dist/src/services/vaults/securitizeVaultService/adapters/securitizeVaultOnchainAdapter.d.ts.map +1 -1
- package/dist/src/services/vaults/securitizeVaultService/adapters/securitizeVaultOnchainAdapter.js +6 -8
- package/dist/src/services/vaults/securitizeVaultService/adapters/securitizeVaultOnchainAdapter.js.map +1 -1
- package/dist/src/services/vaults/securitizeVaultService/securitizeVaultService.d.ts +2 -2
- package/dist/src/services/vaults/securitizeVaultService/securitizeVaultService.d.ts.map +1 -1
- package/dist/src/services/vaults/securitizeVaultService/securitizeVaultService.js +13 -18
- package/dist/src/services/vaults/securitizeVaultService/securitizeVaultService.js.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/dist/src/services/vaults/vaultMetaService/vaultMetaService.d.ts +3 -3
- package/dist/src/services/vaults/vaultMetaService/vaultMetaService.d.ts.map +1 -1
- package/dist/src/services/vaults/vaultMetaService/vaultMetaService.js +31 -32
- package/dist/src/services/vaults/vaultMetaService/vaultMetaService.js.map +1 -1
- package/dist/src/services/walletService/adapters/walletOnchainAdapter.d.ts +5 -1
- package/dist/src/services/walletService/adapters/walletOnchainAdapter.d.ts.map +1 -1
- package/dist/src/services/walletService/adapters/walletOnchainAdapter.js +181 -40
- package/dist/src/services/walletService/adapters/walletOnchainAdapter.js.map +1 -1
- package/dist/src/services/walletService/walletService.d.ts +1 -1
- package/dist/src/services/walletService/walletService.d.ts.map +1 -1
- package/dist/src/services/walletService/walletService.js +4 -3
- package/dist/src/services/walletService/walletService.js.map +1 -1
- package/dist/src/utils/accountComputations.d.ts +42 -12
- package/dist/src/utils/accountComputations.d.ts.map +1 -1
- package/dist/src/utils/accountComputations.js +142 -40
- package/dist/src/utils/accountComputations.js.map +1 -1
- package/dist/src/utils/accountPositionClassification.d.ts +15 -0
- package/dist/src/utils/accountPositionClassification.d.ts.map +1 -0
- package/dist/src/utils/accountPositionClassification.js +27 -0
- package/dist/src/utils/accountPositionClassification.js.map +1 -0
- package/dist/src/utils/buildQuery.d.ts +1 -0
- package/dist/src/utils/buildQuery.d.ts.map +1 -1
- package/dist/src/utils/buildQuery.js +1 -1
- package/dist/src/utils/buildQuery.js.map +1 -1
- package/dist/src/utils/entityDiagnostics.d.ts +75 -12
- package/dist/src/utils/entityDiagnostics.d.ts.map +1 -1
- package/dist/src/utils/entityDiagnostics.js +85 -19
- package/dist/src/utils/entityDiagnostics.js.map +1 -1
- package/dist/src/utils/eulerLabels.d.ts +34 -0
- package/dist/src/utils/eulerLabels.d.ts.map +1 -0
- package/dist/src/utils/eulerLabels.js +156 -0
- package/dist/src/utils/eulerLabels.js.map +1 -0
- package/dist/src/utils/healthCheckSets.d.ts +14 -0
- package/dist/src/utils/healthCheckSets.d.ts.map +1 -0
- package/dist/src/utils/healthCheckSets.js +174 -0
- package/dist/src/utils/healthCheckSets.js.map +1 -0
- package/dist/src/utils/normalization.d.ts +10 -4
- package/dist/src/utils/normalization.d.ts.map +1 -1
- package/dist/src/utils/normalization.js +38 -11
- package/dist/src/utils/normalization.js.map +1 -1
- package/dist/src/utils/oracle.d.ts.map +1 -1
- package/dist/src/utils/oracle.js +12 -1
- package/dist/src/utils/oracle.js.map +1 -1
- package/dist/src/utils/parsing.d.ts +2 -2
- package/dist/src/utils/parsing.d.ts.map +1 -1
- package/dist/src/utils/parsing.js +12 -22
- package/dist/src/utils/parsing.js.map +1 -1
- package/package.json +2 -2
- package/dist/src/services/simulationService/index.d.ts +0 -3
- package/dist/src/services/simulationService/index.d.ts.map +0 -1
- package/dist/src/services/simulationService/index.js +0 -2
- package/dist/src/services/simulationService/index.js.map +0 -1
- package/dist/src/services/simulationService/simulationService.d.ts.map +0 -1
- package/dist/src/services/simulationService/simulationService.js +0 -533
- package/dist/src/services/simulationService/simulationService.js.map +0 -1
|
@@ -1,34 +1,137 @@
|
|
|
1
|
-
import { encodeFunctionData, getAddress, maxUint256,
|
|
1
|
+
import { decodeFunctionData, encodeFunctionData, erc20Abi, getAddress, maxUint256, maxUint160, } from "viem";
|
|
2
|
+
import { resolveBorrowCollateralPositions } from "../../utils/accountPositionClassification.js";
|
|
2
3
|
import { ethereumVaultConnectorAbi } from "./abis/ethereumVaultConnectorAbi.js";
|
|
3
4
|
import { eVaultAbi } from "./abis/eVaultAbi.js";
|
|
4
5
|
import { permit2PermitAbi } from "./abis/permit2PermitAbi.js";
|
|
5
6
|
import { swapperAbi } from "./abis/swapperAbi.js";
|
|
6
7
|
import { swapVerifierAbi } from "./abis/swapVerifierAbi.js";
|
|
7
|
-
import
|
|
8
|
+
import * as encodeHelpers from "./encode.js";
|
|
9
|
+
import { isEVCBatchOperation } from "./executionServiceTypes.js";
|
|
10
|
+
import { executeTransactionPlan, } from "./execute.js";
|
|
11
|
+
import { deriveStateOverrides, estimateGasForTransactionPlan, simulateTransactionPlan, } from "./simulate.js";
|
|
8
12
|
const TOKENS_REQUIRING_ZERO_APPROVAL_RESET = {
|
|
9
13
|
1: [getAddress("0xdAC17F958D2ee523a2206206994597C13D831ec7")],
|
|
10
14
|
};
|
|
11
15
|
function requiresZeroApprovalReset(chainId, token) {
|
|
12
16
|
return (TOKENS_REQUIRING_ZERO_APPROVAL_RESET[chainId]?.some((resetToken) => resetToken === getAddress(token)) ?? false);
|
|
13
17
|
}
|
|
14
|
-
|
|
18
|
+
function isSavingsCollateral(collateral) {
|
|
19
|
+
return collateral?.source === "savings";
|
|
20
|
+
}
|
|
21
|
+
function isWalletCollateral(collateral) {
|
|
22
|
+
return !!collateral && !isSavingsCollateral(collateral);
|
|
23
|
+
}
|
|
24
|
+
function cloneBatchEntries(entries) {
|
|
25
|
+
return entries.map((entry) => "type" in entry && entry.type === "operation"
|
|
26
|
+
? { type: "operation", name: entry.name, items: [...entry.items] }
|
|
27
|
+
: entry);
|
|
28
|
+
}
|
|
15
29
|
const WAD = 10n ** 18n;
|
|
16
30
|
// TODO explain how this service is coupled to the concrete abis of ERC4626, permit2 and EVK.
|
|
17
31
|
// this is a helper service, not a generic one.
|
|
18
32
|
export class ExecutionService {
|
|
19
33
|
deploymentService;
|
|
20
|
-
walletService;
|
|
21
34
|
plugins = [];
|
|
22
|
-
|
|
35
|
+
walletService;
|
|
36
|
+
providerService;
|
|
37
|
+
vaultMetaService;
|
|
38
|
+
priceService;
|
|
39
|
+
rewardsService;
|
|
40
|
+
intrinsicApyService;
|
|
41
|
+
eulerLabelsService;
|
|
42
|
+
processPlugins;
|
|
43
|
+
constructor(deploymentService, walletService, providerService, vaultMetaService, priceService, rewardsService, intrinsicApyService, eulerLabelsService) {
|
|
23
44
|
this.deploymentService = deploymentService;
|
|
24
45
|
this.walletService = walletService;
|
|
46
|
+
this.providerService = providerService;
|
|
47
|
+
this.vaultMetaService = vaultMetaService;
|
|
48
|
+
this.priceService = priceService;
|
|
49
|
+
this.rewardsService = rewardsService;
|
|
50
|
+
this.intrinsicApyService = intrinsicApyService;
|
|
51
|
+
this.eulerLabelsService = eulerLabelsService;
|
|
25
52
|
}
|
|
26
53
|
setWalletService(walletService) {
|
|
27
54
|
this.walletService = walletService;
|
|
28
55
|
}
|
|
56
|
+
setProviderService(providerService) {
|
|
57
|
+
this.providerService = providerService;
|
|
58
|
+
}
|
|
59
|
+
setVaultMetaService(vaultMetaService) {
|
|
60
|
+
this.vaultMetaService = vaultMetaService;
|
|
61
|
+
}
|
|
62
|
+
setPriceService(priceService) {
|
|
63
|
+
this.priceService = priceService;
|
|
64
|
+
}
|
|
65
|
+
setRewardsService(rewardsService) {
|
|
66
|
+
this.rewardsService = rewardsService;
|
|
67
|
+
}
|
|
68
|
+
setIntrinsicApyService(intrinsicApyService) {
|
|
69
|
+
this.intrinsicApyService = intrinsicApyService;
|
|
70
|
+
}
|
|
71
|
+
setEulerLabelsService(eulerLabelsService) {
|
|
72
|
+
this.eulerLabelsService = eulerLabelsService;
|
|
73
|
+
}
|
|
29
74
|
setPlugins(plugins) {
|
|
30
75
|
this.plugins = plugins;
|
|
31
76
|
}
|
|
77
|
+
setPluginProcessor(processPlugins) {
|
|
78
|
+
this.processPlugins = processPlugins;
|
|
79
|
+
}
|
|
80
|
+
/** Derive storage overrides needed to simulate the plan against the current account state. */
|
|
81
|
+
async deriveStateOverrides(chainId, account, transactionPlan, options) {
|
|
82
|
+
return deriveStateOverrides(this.getSimulationContext(), chainId, account, transactionPlan, options);
|
|
83
|
+
}
|
|
84
|
+
/** Simulate the full transaction plan, including approval resolution and plugin-aware batch execution. */
|
|
85
|
+
async simulateTransactionPlan(chainId, account, transactionPlan, options) {
|
|
86
|
+
const processedPlan = await this.processPlanPlugins(transactionPlan, account, chainId);
|
|
87
|
+
const owner = this.getAccountOwner(account);
|
|
88
|
+
return simulateTransactionPlan(this.getSimulationContext(), chainId, owner, processedPlan, options);
|
|
89
|
+
}
|
|
90
|
+
/** Estimate gas for the full transaction plan after applying the same simulation pipeline used for execution. */
|
|
91
|
+
async estimateGasForTransactionPlan(chainId, account, transactionPlan, options) {
|
|
92
|
+
const processedPlan = await this.processPlanPlugins(transactionPlan, account, chainId);
|
|
93
|
+
const owner = this.getAccountOwner(account);
|
|
94
|
+
return estimateGasForTransactionPlan(this.getSimulationContext(), chainId, owner, processedPlan, options);
|
|
95
|
+
}
|
|
96
|
+
/** Execute a transaction plan using caller-provided signing and send callbacks. */
|
|
97
|
+
async executeTransactionPlan(args) {
|
|
98
|
+
const { providerService } = this;
|
|
99
|
+
if (!providerService) {
|
|
100
|
+
throw new Error("ExecutionService.executeTransactionPlan requires a providerService. Pass it to the ExecutionService constructor or call setProviderService().");
|
|
101
|
+
}
|
|
102
|
+
const helperArgs = {
|
|
103
|
+
...args,
|
|
104
|
+
plan: await this.processPlanPlugins(args.plan, args.account, args.chainId),
|
|
105
|
+
executionService: this,
|
|
106
|
+
deploymentService: this.deploymentService,
|
|
107
|
+
providerService,
|
|
108
|
+
};
|
|
109
|
+
return executeTransactionPlan(helperArgs);
|
|
110
|
+
}
|
|
111
|
+
getSimulationContext() {
|
|
112
|
+
return {
|
|
113
|
+
deploymentService: this.deploymentService,
|
|
114
|
+
walletService: this.walletService,
|
|
115
|
+
providerService: this.providerService,
|
|
116
|
+
vaultMetaService: this.vaultMetaService,
|
|
117
|
+
priceService: this.priceService,
|
|
118
|
+
rewardsService: this.rewardsService,
|
|
119
|
+
intrinsicApyService: this.intrinsicApyService,
|
|
120
|
+
eulerLabelsService: this.eulerLabelsService,
|
|
121
|
+
describeBatch: (batch) => this.describeBatch(batch),
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
async processPlanPlugins(plan, account, chainId) {
|
|
125
|
+
return this.processPlugins
|
|
126
|
+
? this.processPlugins(plan, account, chainId)
|
|
127
|
+
: plan;
|
|
128
|
+
}
|
|
129
|
+
getAccountOwner(account) {
|
|
130
|
+
return typeof account === "string" ? account : account.owner;
|
|
131
|
+
}
|
|
132
|
+
getCoreAddresses(chainId) {
|
|
133
|
+
return this.deploymentService.getDeployment(chainId).addresses.coreAddrs;
|
|
134
|
+
}
|
|
32
135
|
/**
|
|
33
136
|
* Encodes an array of EVC batch items into a single calldata hex for `EVC.batch()`.
|
|
34
137
|
*
|
|
@@ -36,11 +139,7 @@ export class ExecutionService {
|
|
|
36
139
|
* @returns Encoded calldata hex for the EVC batch call
|
|
37
140
|
*/
|
|
38
141
|
encodeBatch(items) {
|
|
39
|
-
return
|
|
40
|
-
abi: ethereumVaultConnectorAbi,
|
|
41
|
-
functionName: "batch",
|
|
42
|
-
args: [items],
|
|
43
|
-
});
|
|
142
|
+
return encodeHelpers.encodeBatch(items);
|
|
44
143
|
}
|
|
45
144
|
/**
|
|
46
145
|
* Encodes EVC batch items for depositing underlying assets into a vault (mints shares to receiver).
|
|
@@ -55,33 +154,9 @@ export class ExecutionService {
|
|
|
55
154
|
* @param args.permit2 - Optional Permit2 message + signature; if set, prepends a permit2 permit call so transferFrom can be used
|
|
56
155
|
* @returns Array of EVC batch items (optional permit2, optional enableCollateral, deposit)
|
|
57
156
|
*/
|
|
58
|
-
encodeDeposit({ chainId,
|
|
59
|
-
const
|
|
60
|
-
|
|
61
|
-
const permit2Call = this.encodePermit2Call({
|
|
62
|
-
chainId,
|
|
63
|
-
owner,
|
|
64
|
-
message: permit2.message,
|
|
65
|
-
signature: permit2.signature,
|
|
66
|
-
});
|
|
67
|
-
items.push(permit2Call);
|
|
68
|
-
}
|
|
69
|
-
// Add enable collateral if flag is set
|
|
70
|
-
if (enableCollateral) {
|
|
71
|
-
items.push(this.encodeEnableCollateral(chainId, receiver, vault));
|
|
72
|
-
}
|
|
73
|
-
// Add deposit operation
|
|
74
|
-
items.push({
|
|
75
|
-
targetContract: vault,
|
|
76
|
-
onBehalfOfAccount: owner,
|
|
77
|
-
value: 0n,
|
|
78
|
-
data: encodeFunctionData({
|
|
79
|
-
abi: eVaultAbi,
|
|
80
|
-
functionName: "deposit",
|
|
81
|
-
args: [amount, receiver],
|
|
82
|
-
}),
|
|
83
|
-
});
|
|
84
|
-
return items;
|
|
157
|
+
encodeDeposit({ chainId, ...args }) {
|
|
158
|
+
const { evc, permit2 } = this.getCoreAddresses(chainId);
|
|
159
|
+
return encodeHelpers.encodeDeposit(evc, permit2, { chainId, ...args });
|
|
85
160
|
}
|
|
86
161
|
/**
|
|
87
162
|
* Encodes EVC batch items for minting vault shares by depositing underlying assets.
|
|
@@ -96,33 +171,9 @@ export class ExecutionService {
|
|
|
96
171
|
* @param args.permit2 - Optional Permit2 message + signature for transferFrom
|
|
97
172
|
* @returns Array of EVC batch items (optional permit2, optional enableCollateral, mint)
|
|
98
173
|
*/
|
|
99
|
-
encodeMint({ chainId,
|
|
100
|
-
const
|
|
101
|
-
|
|
102
|
-
const permit2Call = this.encodePermit2Call({
|
|
103
|
-
chainId,
|
|
104
|
-
owner,
|
|
105
|
-
message: permit2.message,
|
|
106
|
-
signature: permit2.signature,
|
|
107
|
-
});
|
|
108
|
-
items.push(permit2Call);
|
|
109
|
-
}
|
|
110
|
-
// Add enable collateral if flag is set
|
|
111
|
-
if (enableCollateral) {
|
|
112
|
-
items.push(this.encodeEnableCollateral(chainId, receiver, vault));
|
|
113
|
-
}
|
|
114
|
-
// Add mint operation
|
|
115
|
-
items.push({
|
|
116
|
-
targetContract: vault,
|
|
117
|
-
onBehalfOfAccount: owner,
|
|
118
|
-
value: 0n,
|
|
119
|
-
data: encodeFunctionData({
|
|
120
|
-
abi: eVaultAbi,
|
|
121
|
-
functionName: "mint",
|
|
122
|
-
args: [shares, receiver],
|
|
123
|
-
}),
|
|
124
|
-
});
|
|
125
|
-
return items;
|
|
174
|
+
encodeMint({ chainId, ...args }) {
|
|
175
|
+
const { evc, permit2 } = this.getCoreAddresses(chainId);
|
|
176
|
+
return encodeHelpers.encodeMint(evc, permit2, { chainId, ...args });
|
|
126
177
|
}
|
|
127
178
|
/**
|
|
128
179
|
* Encodes EVC batch items for withdrawing underlying assets from a vault (burns shares).
|
|
@@ -136,24 +187,9 @@ export class ExecutionService {
|
|
|
136
187
|
* @param args.disableCollateral - If true, appends disableCollateral( owner, vault ) via EVC before withdraw
|
|
137
188
|
* @returns Array of EVC batch items (optional disableCollateral, withdraw)
|
|
138
189
|
*/
|
|
139
|
-
encodeWithdraw({ chainId,
|
|
140
|
-
const
|
|
141
|
-
|
|
142
|
-
if (disableCollateral) {
|
|
143
|
-
items.push(this.encodeDisableCollateral(chainId, owner, vault));
|
|
144
|
-
}
|
|
145
|
-
// Add withdraw operation
|
|
146
|
-
items.push({
|
|
147
|
-
targetContract: vault,
|
|
148
|
-
onBehalfOfAccount: owner,
|
|
149
|
-
value: 0n,
|
|
150
|
-
data: encodeFunctionData({
|
|
151
|
-
abi: eVaultAbi,
|
|
152
|
-
functionName: "withdraw",
|
|
153
|
-
args: [assets, receiver, owner],
|
|
154
|
-
}),
|
|
155
|
-
});
|
|
156
|
-
return items;
|
|
190
|
+
encodeWithdraw({ chainId, ...args }) {
|
|
191
|
+
const { evc } = this.getCoreAddresses(chainId);
|
|
192
|
+
return encodeHelpers.encodeWithdraw(evc, { chainId, ...args });
|
|
157
193
|
}
|
|
158
194
|
/**
|
|
159
195
|
* Encodes EVC batch items for redeeming vault shares for underlying assets.
|
|
@@ -167,24 +203,9 @@ export class ExecutionService {
|
|
|
167
203
|
* @param args.disableCollateral - If true, prepends disableCollateral( owner, vault ) via EVC
|
|
168
204
|
* @returns Array of EVC batch items (optional disableCollateral, redeem)
|
|
169
205
|
*/
|
|
170
|
-
encodeRedeem({ chainId,
|
|
171
|
-
const
|
|
172
|
-
|
|
173
|
-
if (disableCollateral) {
|
|
174
|
-
items.push(this.encodeDisableCollateral(chainId, owner, vault));
|
|
175
|
-
}
|
|
176
|
-
// Add redeem operation
|
|
177
|
-
items.push({
|
|
178
|
-
targetContract: vault,
|
|
179
|
-
onBehalfOfAccount: owner,
|
|
180
|
-
value: 0n,
|
|
181
|
-
data: encodeFunctionData({
|
|
182
|
-
abi: eVaultAbi,
|
|
183
|
-
functionName: "redeem",
|
|
184
|
-
args: [shares, receiver, owner],
|
|
185
|
-
}),
|
|
186
|
-
});
|
|
187
|
-
return items;
|
|
206
|
+
encodeRedeem({ chainId, ...args }) {
|
|
207
|
+
const { evc } = this.getCoreAddresses(chainId);
|
|
208
|
+
return encodeHelpers.encodeRedeem(evc, { chainId, ...args });
|
|
188
209
|
}
|
|
189
210
|
/**
|
|
190
211
|
* Encodes EVC batch items for borrowing from a liability vault, optionally depositing collateral in the same batch.
|
|
@@ -205,42 +226,8 @@ export class ExecutionService {
|
|
|
205
226
|
* @returns Array of EVC batch items (optional deposit, optional disableController, optional enableController, borrow)
|
|
206
227
|
*/
|
|
207
228
|
encodeBorrow(args) {
|
|
208
|
-
const {
|
|
209
|
-
|
|
210
|
-
// Add collateral if provided
|
|
211
|
-
if (collateralVault &&
|
|
212
|
-
collateralAmount !== undefined &&
|
|
213
|
-
collateralAmount > 0n) {
|
|
214
|
-
const depositItems = this.encodeDeposit({
|
|
215
|
-
chainId,
|
|
216
|
-
vault: collateralVault,
|
|
217
|
-
amount: collateralAmount,
|
|
218
|
-
receiver: borrowAccount,
|
|
219
|
-
enableCollateral,
|
|
220
|
-
permit2: collateralPermit2,
|
|
221
|
-
owner: owner,
|
|
222
|
-
});
|
|
223
|
-
items.push(...depositItems);
|
|
224
|
-
}
|
|
225
|
-
// Add disable controller if there's a different controller enabled
|
|
226
|
-
if (currentController && currentController !== vault) {
|
|
227
|
-
items.push(this.encodeDisableController(currentController, borrowAccount));
|
|
228
|
-
}
|
|
229
|
-
if (enableController) {
|
|
230
|
-
items.push(this.encodeEnableController(chainId, borrowAccount, vault));
|
|
231
|
-
}
|
|
232
|
-
// Add borrow operation
|
|
233
|
-
items.push({
|
|
234
|
-
targetContract: vault,
|
|
235
|
-
onBehalfOfAccount: borrowAccount,
|
|
236
|
-
value: 0n,
|
|
237
|
-
data: encodeFunctionData({
|
|
238
|
-
abi: eVaultAbi,
|
|
239
|
-
functionName: "borrow",
|
|
240
|
-
args: [amount, receiver],
|
|
241
|
-
}),
|
|
242
|
-
});
|
|
243
|
-
return items;
|
|
229
|
+
const { evc, permit2 } = this.getCoreAddresses(args.chainId);
|
|
230
|
+
return encodeHelpers.encodeBorrow(evc, permit2, args);
|
|
244
231
|
}
|
|
245
232
|
/**
|
|
246
233
|
* Encodes EVC batch items for liquidating an undercollateralized account (repay debt, seize collateral).
|
|
@@ -257,28 +244,9 @@ export class ExecutionService {
|
|
|
257
244
|
* @param args.enableCollateral - If true, enables collateral vault for liquidator sub-account after liquidate (default true)
|
|
258
245
|
* @returns Array of EVC batch items (optional enableController, liquidate, optional enableCollateral)
|
|
259
246
|
*/
|
|
260
|
-
encodeLiquidation({ chainId,
|
|
261
|
-
const
|
|
262
|
-
|
|
263
|
-
if (enableController) {
|
|
264
|
-
items.push(this.encodeEnableController(chainId, liquidatorSubAccountAddress, vault));
|
|
265
|
-
}
|
|
266
|
-
// Perform the liquidation
|
|
267
|
-
items.push({
|
|
268
|
-
targetContract: vault,
|
|
269
|
-
onBehalfOfAccount: liquidatorSubAccountAddress,
|
|
270
|
-
value: 0n,
|
|
271
|
-
data: encodeFunctionData({
|
|
272
|
-
abi: eVaultAbi,
|
|
273
|
-
functionName: "liquidate",
|
|
274
|
-
args: [violator, collateral, repayAssets, minYieldBalance],
|
|
275
|
-
}),
|
|
276
|
-
});
|
|
277
|
-
// Optionally enable collateral for the seized collateral vault on the liquidator account
|
|
278
|
-
if (enableCollateral) {
|
|
279
|
-
items.push(this.encodeEnableCollateral(chainId, liquidatorSubAccountAddress, collateral));
|
|
280
|
-
}
|
|
281
|
-
return items;
|
|
247
|
+
encodeLiquidation({ chainId, ...args }) {
|
|
248
|
+
const { evc } = this.getCoreAddresses(chainId);
|
|
249
|
+
return encodeHelpers.encodeLiquidation(evc, { chainId, ...args });
|
|
282
250
|
}
|
|
283
251
|
/**
|
|
284
252
|
* Encodes EVC batch items for pulling debt from one sub-account to another on the same liability vault.
|
|
@@ -292,24 +260,9 @@ export class ExecutionService {
|
|
|
292
260
|
* @param args.enableController - If true, enables vault as controller for `to` via EVC before pullDebt (default true)
|
|
293
261
|
* @returns Array of EVC batch items (optional enableController, pullDebt)
|
|
294
262
|
*/
|
|
295
|
-
encodePullDebt({ chainId,
|
|
296
|
-
const
|
|
297
|
-
|
|
298
|
-
if (enableController) {
|
|
299
|
-
items.push(this.encodeEnableController(chainId, to, vault));
|
|
300
|
-
}
|
|
301
|
-
// Add pullDebt operation
|
|
302
|
-
items.push({
|
|
303
|
-
targetContract: vault,
|
|
304
|
-
onBehalfOfAccount: to,
|
|
305
|
-
value: 0n,
|
|
306
|
-
data: encodeFunctionData({
|
|
307
|
-
abi: eVaultAbi,
|
|
308
|
-
functionName: "pullDebt",
|
|
309
|
-
args: [amount, from],
|
|
310
|
-
}),
|
|
311
|
-
});
|
|
312
|
-
return items;
|
|
263
|
+
encodePullDebt({ chainId, ...args }) {
|
|
264
|
+
const { evc } = this.getCoreAddresses(chainId);
|
|
265
|
+
return encodeHelpers.encodePullDebt(evc, { chainId, ...args });
|
|
313
266
|
}
|
|
314
267
|
/**
|
|
315
268
|
* Encodes EVC batch items for a multiply/leverage operation when liability and long asset differ (swap required).
|
|
@@ -333,77 +286,8 @@ export class ExecutionService {
|
|
|
333
286
|
* @returns Array of EVC batch items
|
|
334
287
|
*/
|
|
335
288
|
encodeMultiplyWithSwap(args) {
|
|
336
|
-
const {
|
|
337
|
-
|
|
338
|
-
// 1. Add permit2 for collateral if provided
|
|
339
|
-
if (collateralPermit2) {
|
|
340
|
-
const permit2Call = this.encodePermit2Call({
|
|
341
|
-
chainId,
|
|
342
|
-
owner,
|
|
343
|
-
message: collateralPermit2.message,
|
|
344
|
-
signature: collateralPermit2.signature,
|
|
345
|
-
});
|
|
346
|
-
items.push(permit2Call);
|
|
347
|
-
}
|
|
348
|
-
// 2. Deposit initial collateral if amount > 0
|
|
349
|
-
if (collateralAmount > 0n) {
|
|
350
|
-
// Enable collateral for collateral vault
|
|
351
|
-
if (enableCollateral) {
|
|
352
|
-
items.push(this.encodeEnableCollateral(chainId, receiver, collateralVault));
|
|
353
|
-
}
|
|
354
|
-
// Deposit collateral
|
|
355
|
-
items.push({
|
|
356
|
-
targetContract: collateralVault,
|
|
357
|
-
onBehalfOfAccount: owner,
|
|
358
|
-
value: 0n,
|
|
359
|
-
data: encodeFunctionData({
|
|
360
|
-
abi: eVaultAbi,
|
|
361
|
-
functionName: "deposit",
|
|
362
|
-
args: [collateralAmount, receiver],
|
|
363
|
-
}),
|
|
364
|
-
});
|
|
365
|
-
}
|
|
366
|
-
// 3. Disable current controller if there's a different one enabled
|
|
367
|
-
if (currentController && currentController !== liabilityVault) {
|
|
368
|
-
items.push(this.encodeDisableController(currentController, receiver));
|
|
369
|
-
}
|
|
370
|
-
// 4. Enable controller for liability vault
|
|
371
|
-
if (enableController) {
|
|
372
|
-
items.push(this.encodeEnableController(chainId, receiver, liabilityVault));
|
|
373
|
-
}
|
|
374
|
-
// 5. Borrow from liability vault to swapper
|
|
375
|
-
items.push({
|
|
376
|
-
targetContract: liabilityVault,
|
|
377
|
-
onBehalfOfAccount: receiver,
|
|
378
|
-
value: 0n,
|
|
379
|
-
data: encodeFunctionData({
|
|
380
|
-
abi: eVaultAbi,
|
|
381
|
-
functionName: "borrow",
|
|
382
|
-
args: [liabilityAmount, swapQuote.swap.swapperAddress],
|
|
383
|
-
}),
|
|
384
|
-
});
|
|
385
|
-
// 6. Execute swap multicall
|
|
386
|
-
items.push({
|
|
387
|
-
targetContract: swapQuote.swap.swapperAddress,
|
|
388
|
-
onBehalfOfAccount: receiver,
|
|
389
|
-
value: 0n,
|
|
390
|
-
data: swapQuote.swap.swapperData,
|
|
391
|
-
});
|
|
392
|
-
// 7. Verify swap and skim to long vault
|
|
393
|
-
if (swapQuote.verify.type !== "skimMin") {
|
|
394
|
-
throw new Error("Invalid swap quote type for multiply - must be skimMin");
|
|
395
|
-
}
|
|
396
|
-
items.push({
|
|
397
|
-
targetContract: swapQuote.verify.verifierAddress,
|
|
398
|
-
onBehalfOfAccount: receiver,
|
|
399
|
-
value: 0n,
|
|
400
|
-
data: swapQuote.verify.verifierData,
|
|
401
|
-
});
|
|
402
|
-
// 8. Enable collateral on long vault
|
|
403
|
-
if (enableCollateralLong && collateralVault !== longVault) {
|
|
404
|
-
items.push(this.encodeEnableCollateral(chainId, receiver, longVault));
|
|
405
|
-
}
|
|
406
|
-
return items;
|
|
289
|
+
const { evc, permit2 } = this.getCoreAddresses(args.chainId);
|
|
290
|
+
return encodeHelpers.encodeMultiplyWithSwap(evc, permit2, args);
|
|
407
291
|
}
|
|
408
292
|
/**
|
|
409
293
|
* Encodes EVC batch items for a multiply/leverage operation when liability and long asset are the same (no swap).
|
|
@@ -426,71 +310,8 @@ export class ExecutionService {
|
|
|
426
310
|
* @returns Array of EVC batch items
|
|
427
311
|
*/
|
|
428
312
|
encodeMultiplySameAsset(args) {
|
|
429
|
-
const {
|
|
430
|
-
|
|
431
|
-
// 1. Add permit2 for collateral if provided
|
|
432
|
-
if (collateralPermit2) {
|
|
433
|
-
const permit2Call = this.encodePermit2Call({
|
|
434
|
-
chainId,
|
|
435
|
-
owner,
|
|
436
|
-
message: collateralPermit2.message,
|
|
437
|
-
signature: collateralPermit2.signature,
|
|
438
|
-
});
|
|
439
|
-
items.push(permit2Call);
|
|
440
|
-
}
|
|
441
|
-
// 2. Deposit initial collateral if amount > 0
|
|
442
|
-
if (collateralAmount > 0n) {
|
|
443
|
-
// Enable collateral for collateral vault
|
|
444
|
-
if (enableCollateral) {
|
|
445
|
-
items.push(this.encodeEnableCollateral(chainId, receiver, collateralVault));
|
|
446
|
-
}
|
|
447
|
-
// Deposit collateral
|
|
448
|
-
items.push({
|
|
449
|
-
targetContract: collateralVault,
|
|
450
|
-
onBehalfOfAccount: owner,
|
|
451
|
-
value: 0n,
|
|
452
|
-
data: encodeFunctionData({
|
|
453
|
-
abi: eVaultAbi,
|
|
454
|
-
functionName: "deposit",
|
|
455
|
-
args: [collateralAmount, receiver],
|
|
456
|
-
}),
|
|
457
|
-
});
|
|
458
|
-
}
|
|
459
|
-
// 3. Disable current controller if there's a different one enabled
|
|
460
|
-
if (currentController && currentController !== liabilityVault) {
|
|
461
|
-
items.push(this.encodeDisableController(currentController, receiver));
|
|
462
|
-
}
|
|
463
|
-
// 4. Enable controller for liability vault
|
|
464
|
-
if (enableController) {
|
|
465
|
-
items.push(this.encodeEnableController(chainId, receiver, liabilityVault));
|
|
466
|
-
}
|
|
467
|
-
// 5. Borrow from liability vault directly to long vault
|
|
468
|
-
items.push({
|
|
469
|
-
targetContract: liabilityVault,
|
|
470
|
-
onBehalfOfAccount: receiver,
|
|
471
|
-
value: 0n,
|
|
472
|
-
data: encodeFunctionData({
|
|
473
|
-
abi: eVaultAbi,
|
|
474
|
-
functionName: "borrow",
|
|
475
|
-
args: [liabilityAmount, longVault],
|
|
476
|
-
}),
|
|
477
|
-
});
|
|
478
|
-
// 6. Skim borrowed assets to position
|
|
479
|
-
items.push({
|
|
480
|
-
targetContract: longVault,
|
|
481
|
-
onBehalfOfAccount: receiver,
|
|
482
|
-
value: 0n,
|
|
483
|
-
data: encodeFunctionData({
|
|
484
|
-
abi: eVaultAbi,
|
|
485
|
-
functionName: "skim",
|
|
486
|
-
args: [liabilityAmount, receiver],
|
|
487
|
-
}),
|
|
488
|
-
});
|
|
489
|
-
// 7. Enable collateral on long vault
|
|
490
|
-
if (enableCollateralLong) {
|
|
491
|
-
items.push(this.encodeEnableCollateral(chainId, receiver, longVault));
|
|
492
|
-
}
|
|
493
|
-
return items;
|
|
313
|
+
const { evc, permit2 } = this.getCoreAddresses(args.chainId);
|
|
314
|
+
return encodeHelpers.encodeMultiplySameAsset(evc, permit2, args);
|
|
494
315
|
}
|
|
495
316
|
/**
|
|
496
317
|
* Encodes EVC batch items for repaying debt using assets from the sender's wallet (transferFrom to vault then repay).
|
|
@@ -507,41 +328,16 @@ export class ExecutionService {
|
|
|
507
328
|
* @returns Array of EVC batch items (optional permit2, repay, optional disableController)
|
|
508
329
|
*/
|
|
509
330
|
encodeRepayFromWallet(args) {
|
|
510
|
-
const {
|
|
511
|
-
|
|
512
|
-
if (permit2) {
|
|
513
|
-
const permit2Call = this.encodePermit2Call({
|
|
514
|
-
chainId,
|
|
515
|
-
owner: sender,
|
|
516
|
-
message: permit2.message,
|
|
517
|
-
signature: permit2.signature,
|
|
518
|
-
});
|
|
519
|
-
items.push(permit2Call);
|
|
520
|
-
}
|
|
521
|
-
// Repay operation
|
|
522
|
-
items.push({
|
|
523
|
-
targetContract: liabilityVault,
|
|
524
|
-
onBehalfOfAccount: sender,
|
|
525
|
-
value: 0n,
|
|
526
|
-
data: encodeFunctionData({
|
|
527
|
-
abi: eVaultAbi,
|
|
528
|
-
functionName: "repay",
|
|
529
|
-
args: [isMax ? maxUint256 : liabilityAmount, receiver],
|
|
530
|
-
}),
|
|
531
|
-
});
|
|
532
|
-
// Disable controller if needed (for max repay)
|
|
533
|
-
// Sender must be allowed to act on behalf of receiver (sender is subaccount of receiver or is an operator)
|
|
534
|
-
if (disableControllerOnMax && isMax) {
|
|
535
|
-
items.push(this.encodeDisableController(liabilityVault, receiver));
|
|
536
|
-
}
|
|
537
|
-
return items;
|
|
331
|
+
const { permit2 } = this.getCoreAddresses(args.chainId);
|
|
332
|
+
return encodeHelpers.encodeRepayFromWallet(permit2, args);
|
|
538
333
|
}
|
|
539
334
|
/**
|
|
540
335
|
* Encodes EVC batch items for repaying debt from a deposit (same-asset only).
|
|
541
|
-
* Path 1: same asset and same vault → repayWithShares.
|
|
336
|
+
* Path 1: same asset and same vault → repayWithShares.
|
|
337
|
+
* Path 2: same asset, different vault → withdraw to liability vault, skim, then repayWithShares.
|
|
542
338
|
*
|
|
543
339
|
* @param args - Repay-from-deposit encoding arguments
|
|
544
|
-
* @param args.chainId - Chain ID
|
|
340
|
+
* @param args.chainId - Chain ID used for EVC controller calls
|
|
545
341
|
* @param args.liabilityVault - Vault (liability) to repay debt to
|
|
546
342
|
* @param args.liabilityAsset - Underlying asset address of the liability vault
|
|
547
343
|
* @param args.liabilityAmount - Amount of liability to repay (maxUint256 with isMax for full repay)
|
|
@@ -554,31 +350,7 @@ export class ExecutionService {
|
|
|
554
350
|
* @returns Array of EVC batch items. Throws if fromAsset !== liabilityAsset.
|
|
555
351
|
*/
|
|
556
352
|
encodeRepayFromDeposit(args) {
|
|
557
|
-
|
|
558
|
-
// PATH 1: Same asset, same vault - use repayWithShares
|
|
559
|
-
if (fromAsset === liabilityAsset && fromVault === liabilityVault) {
|
|
560
|
-
return this.encodeRepayWithSharesSameAssetAndVault({
|
|
561
|
-
chainId,
|
|
562
|
-
vault: liabilityVault,
|
|
563
|
-
amount: liabilityAmount,
|
|
564
|
-
receiver,
|
|
565
|
-
from,
|
|
566
|
-
disableController: isMax && disableControllerOnMax,
|
|
567
|
-
});
|
|
568
|
-
}
|
|
569
|
-
// PATH 2: Same asset, different vault
|
|
570
|
-
if (fromAsset === liabilityAsset) {
|
|
571
|
-
return this.encodeRepayWithSharesSameAssetDifferentVault({
|
|
572
|
-
fromVault,
|
|
573
|
-
toVault: liabilityVault,
|
|
574
|
-
amount: liabilityAmount,
|
|
575
|
-
receiver,
|
|
576
|
-
from,
|
|
577
|
-
isMax,
|
|
578
|
-
disableControllerOnMax,
|
|
579
|
-
});
|
|
580
|
-
}
|
|
581
|
-
throw new Error("encodeRepayFromDeposit only supports same-asset paths");
|
|
353
|
+
return encodeHelpers.encodeRepayFromDeposit(args);
|
|
582
354
|
}
|
|
583
355
|
/**
|
|
584
356
|
* Encodes EVC batch items for repaying debt by swapping collateral (withdraw from vaultIn → swap → verify/repay debtMax).
|
|
@@ -593,50 +365,7 @@ export class ExecutionService {
|
|
|
593
365
|
* @returns Array of EVC batch items (withdraw, swap, verify/repay, optional disableController)
|
|
594
366
|
*/
|
|
595
367
|
encodeRepayWithSwap(args) {
|
|
596
|
-
|
|
597
|
-
const items = [];
|
|
598
|
-
// Determine withdraw amount (cap to available amount if provided)
|
|
599
|
-
const withdrawAmount = maxWithdraw &&
|
|
600
|
-
maxWithdraw < BigInt(swapQuote.amountInMax || swapQuote.amountIn)
|
|
601
|
-
? maxWithdraw
|
|
602
|
-
: BigInt(swapQuote.amountInMax || swapQuote.amountIn);
|
|
603
|
-
// 1. Withdraw collateral from vault to swapper
|
|
604
|
-
items.push({
|
|
605
|
-
targetContract: swapQuote.vaultIn,
|
|
606
|
-
onBehalfOfAccount: swapQuote.accountIn,
|
|
607
|
-
value: 0n,
|
|
608
|
-
data: encodeFunctionData({
|
|
609
|
-
abi: eVaultAbi,
|
|
610
|
-
functionName: "withdraw",
|
|
611
|
-
args: [
|
|
612
|
-
withdrawAmount,
|
|
613
|
-
swapQuote.swap.swapperAddress,
|
|
614
|
-
swapQuote.accountIn,
|
|
615
|
-
],
|
|
616
|
-
}),
|
|
617
|
-
});
|
|
618
|
-
// 2. Execute swap multicall
|
|
619
|
-
items.push({
|
|
620
|
-
targetContract: swapQuote.swap.swapperAddress,
|
|
621
|
-
onBehalfOfAccount: swapQuote.accountIn,
|
|
622
|
-
value: 0n,
|
|
623
|
-
data: swapQuote.swap.swapperData,
|
|
624
|
-
});
|
|
625
|
-
// 3. Verify swap and repay (verifyDebtMax handles the repay)
|
|
626
|
-
if (swapQuote.verify.type !== "debtMax") {
|
|
627
|
-
throw new Error("Invalid swap quote type for repay - must be debtMax");
|
|
628
|
-
}
|
|
629
|
-
items.push({
|
|
630
|
-
targetContract: swapQuote.verify.verifierAddress,
|
|
631
|
-
onBehalfOfAccount: swapQuote.verify.account,
|
|
632
|
-
value: 0n,
|
|
633
|
-
data: swapQuote.verify.verifierData,
|
|
634
|
-
});
|
|
635
|
-
// 4. Disable controller if needed (for max repay)
|
|
636
|
-
if (isMax && disableControllerOnMax) {
|
|
637
|
-
items.push(this.encodeDisableController(swapQuote.receiver, swapQuote.accountOut));
|
|
638
|
-
}
|
|
639
|
-
return items;
|
|
368
|
+
return encodeHelpers.encodeRepayWithSwap(args);
|
|
640
369
|
}
|
|
641
370
|
/**
|
|
642
371
|
* Encodes EVC batch items for depositing into a vault using tokens from the user's wallet, going through a swap.
|
|
@@ -651,42 +380,8 @@ export class ExecutionService {
|
|
|
651
380
|
* @returns Array of EVC batch items (transferFromSender, swap, verify, optional enableCollateral)
|
|
652
381
|
*/
|
|
653
382
|
encodeDepositWithSwapFromWallet(args) {
|
|
654
|
-
const {
|
|
655
|
-
|
|
656
|
-
// 1. Transfer tokens from sender's wallet to swapper via SwapVerifier.transferFromSender
|
|
657
|
-
items.push({
|
|
658
|
-
targetContract: swapQuote.verify.verifierAddress,
|
|
659
|
-
onBehalfOfAccount: sender,
|
|
660
|
-
value: 0n,
|
|
661
|
-
data: encodeFunctionData({
|
|
662
|
-
abi: swapVerifierAbi,
|
|
663
|
-
functionName: "transferFromSender",
|
|
664
|
-
args: [
|
|
665
|
-
swapQuote.tokenIn.address,
|
|
666
|
-
amount,
|
|
667
|
-
swapQuote.swap.swapperAddress,
|
|
668
|
-
],
|
|
669
|
-
}),
|
|
670
|
-
});
|
|
671
|
-
// 2. Execute swap multicall
|
|
672
|
-
items.push({
|
|
673
|
-
targetContract: swapQuote.swap.swapperAddress,
|
|
674
|
-
onBehalfOfAccount: sender,
|
|
675
|
-
value: 0n,
|
|
676
|
-
data: swapQuote.swap.swapperData,
|
|
677
|
-
});
|
|
678
|
-
// 3. Verify swap
|
|
679
|
-
items.push({
|
|
680
|
-
targetContract: swapQuote.verify.verifierAddress,
|
|
681
|
-
onBehalfOfAccount: swapQuote.accountOut || sender,
|
|
682
|
-
value: 0n,
|
|
683
|
-
data: swapQuote.verify.verifierData,
|
|
684
|
-
});
|
|
685
|
-
// 4. Enable collateral if needed
|
|
686
|
-
if (enableCollateral && swapQuote.receiver) {
|
|
687
|
-
items.push(this.encodeEnableCollateral(chainId, swapQuote.accountOut || sender, swapQuote.receiver));
|
|
688
|
-
}
|
|
689
|
-
return items;
|
|
383
|
+
const { evc } = this.getCoreAddresses(args.chainId);
|
|
384
|
+
return encodeHelpers.encodeDepositWithSwapFromWallet(evc, args);
|
|
690
385
|
}
|
|
691
386
|
/**
|
|
692
387
|
* Encodes EVC batch items for swapping a token from the sender's wallet into another token
|
|
@@ -702,38 +397,7 @@ export class ExecutionService {
|
|
|
702
397
|
* @returns Array of EVC batch items (transferFromSender, swap, verify)
|
|
703
398
|
*/
|
|
704
399
|
encodeSwapFromWallet(args) {
|
|
705
|
-
|
|
706
|
-
const items = [];
|
|
707
|
-
if (swapQuote.verify.type !== "transferMin") {
|
|
708
|
-
throw new Error("Invalid swap quote type for wallet swap - must be transferMin");
|
|
709
|
-
}
|
|
710
|
-
items.push({
|
|
711
|
-
targetContract: swapQuote.verify.verifierAddress,
|
|
712
|
-
onBehalfOfAccount: sender,
|
|
713
|
-
value: 0n,
|
|
714
|
-
data: encodeFunctionData({
|
|
715
|
-
abi: swapVerifierAbi,
|
|
716
|
-
functionName: "transferFromSender",
|
|
717
|
-
args: [
|
|
718
|
-
swapQuote.tokenIn.address,
|
|
719
|
-
amount,
|
|
720
|
-
swapQuote.swap.swapperAddress,
|
|
721
|
-
],
|
|
722
|
-
}),
|
|
723
|
-
});
|
|
724
|
-
items.push({
|
|
725
|
-
targetContract: swapQuote.swap.swapperAddress,
|
|
726
|
-
onBehalfOfAccount: sender,
|
|
727
|
-
value: 0n,
|
|
728
|
-
data: swapQuote.swap.swapperData,
|
|
729
|
-
});
|
|
730
|
-
items.push({
|
|
731
|
-
targetContract: swapQuote.verify.verifierAddress,
|
|
732
|
-
onBehalfOfAccount: sender,
|
|
733
|
-
value: 0n,
|
|
734
|
-
data: swapQuote.verify.verifierData,
|
|
735
|
-
});
|
|
736
|
-
return items;
|
|
400
|
+
return encodeHelpers.encodeSwapFromWallet(args);
|
|
737
401
|
}
|
|
738
402
|
/**
|
|
739
403
|
* Encodes EVC batch items for swapping collateral: withdraw from vaultIn → swap → verify/skim to receiver; optional enable/disable collateral.
|
|
@@ -748,50 +412,8 @@ export class ExecutionService {
|
|
|
748
412
|
* @returns Array of EVC batch items (withdraw, swap, verify/skim, optional disableCollateral, optional enableCollateral)
|
|
749
413
|
*/
|
|
750
414
|
encodeSwapCollateral(args) {
|
|
751
|
-
const {
|
|
752
|
-
|
|
753
|
-
// 1. Withdraw from source vault to swapper
|
|
754
|
-
const withdrawAmount = BigInt(swapQuote.amountInMax || swapQuote.amountIn);
|
|
755
|
-
items.push({
|
|
756
|
-
targetContract: swapQuote.vaultIn,
|
|
757
|
-
onBehalfOfAccount: swapQuote.accountIn,
|
|
758
|
-
value: 0n,
|
|
759
|
-
data: encodeFunctionData({
|
|
760
|
-
abi: eVaultAbi,
|
|
761
|
-
functionName: "withdraw",
|
|
762
|
-
args: [
|
|
763
|
-
withdrawAmount,
|
|
764
|
-
swapQuote.swap.swapperAddress,
|
|
765
|
-
swapQuote.accountIn,
|
|
766
|
-
],
|
|
767
|
-
}),
|
|
768
|
-
});
|
|
769
|
-
// 2. Execute swap multicall
|
|
770
|
-
items.push({
|
|
771
|
-
targetContract: swapQuote.swap.swapperAddress,
|
|
772
|
-
onBehalfOfAccount: swapQuote.accountIn,
|
|
773
|
-
value: 0n,
|
|
774
|
-
data: swapQuote.swap.swapperData,
|
|
775
|
-
});
|
|
776
|
-
// 3. Verify swap and skim
|
|
777
|
-
if (swapQuote.verify.type !== "skimMin") {
|
|
778
|
-
throw new Error("Invalid swap quote type for swap collateral - must be skimMin");
|
|
779
|
-
}
|
|
780
|
-
items.push({
|
|
781
|
-
targetContract: swapQuote.verify.verifierAddress,
|
|
782
|
-
onBehalfOfAccount: swapQuote.accountOut,
|
|
783
|
-
value: 0n,
|
|
784
|
-
data: swapQuote.verify.verifierData,
|
|
785
|
-
});
|
|
786
|
-
// 4. Disable collateral if needed (for max swap)
|
|
787
|
-
if (isMax && disableCollateralOnMax) {
|
|
788
|
-
items.push(this.encodeDisableCollateral(chainId, swapQuote.accountIn, swapQuote.vaultIn));
|
|
789
|
-
}
|
|
790
|
-
// 5. Enable collateral if needed
|
|
791
|
-
if (enableCollateral) {
|
|
792
|
-
items.push(this.encodeEnableCollateral(chainId, swapQuote.accountOut, swapQuote.receiver));
|
|
793
|
-
}
|
|
794
|
-
return items;
|
|
415
|
+
const { evc } = this.getCoreAddresses(args.chainId);
|
|
416
|
+
return encodeHelpers.encodeSwapCollateral(evc, args);
|
|
795
417
|
}
|
|
796
418
|
/**
|
|
797
419
|
* Encodes EVC batch items for swapping debt: enableController → borrow from vaultIn → swap → verify/repay (debtMax).
|
|
@@ -805,46 +427,51 @@ export class ExecutionService {
|
|
|
805
427
|
* @param args.isMax - If true, treats as full debt swap (can trigger disableControllerOnMax)
|
|
806
428
|
* @returns Array of EVC batch items (optional enableController, borrow, swap, verify/repay, optional disableController)
|
|
807
429
|
*/
|
|
808
|
-
encodeSwapDebt(
|
|
809
|
-
const
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
430
|
+
encodeSwapDebt(args) {
|
|
431
|
+
const { evc } = this.getCoreAddresses(args.chainId);
|
|
432
|
+
return encodeHelpers.encodeSwapDebt(evc, args);
|
|
433
|
+
}
|
|
434
|
+
/**
|
|
435
|
+
* Encodes EVC batch items for migrating a supplied/collateral position between two same-asset vaults.
|
|
436
|
+
* Partial migration uses withdraw(amount, toVault, account) then skim(amount, account).
|
|
437
|
+
* Max migration uses redeem(maxShares || maxUint256, toVault, account) then skim(amount, account).
|
|
438
|
+
*
|
|
439
|
+
* @param args - Same-asset collateral migration encoding arguments
|
|
440
|
+
* @param args.chainId - Chain ID (used for EVC enable/disable collateral)
|
|
441
|
+
* @param args.fromVault - Source vault holding the supplied shares
|
|
442
|
+
* @param args.toVault - Destination vault with the same underlying asset
|
|
443
|
+
* @param args.amount - Asset amount expected to arrive at the destination vault and be skimmed
|
|
444
|
+
* @param args.account - Sub-account that owns the source shares and receives destination shares
|
|
445
|
+
* @param args.isMax - If true, redeems shares instead of withdrawing assets
|
|
446
|
+
* @param args.maxShares - Optional exact share amount for max migration; defaults to maxUint256
|
|
447
|
+
* @param args.enableCollateralTo - If true, enables the destination vault as collateral after skim
|
|
448
|
+
* @param args.disableCollateralFrom - If true, disables the source vault as collateral after enabling the destination
|
|
449
|
+
* @returns Array of EVC batch items
|
|
450
|
+
*/
|
|
451
|
+
encodeMigrateSameAssetCollateral(args) {
|
|
452
|
+
const { evc } = this.getCoreAddresses(args.chainId);
|
|
453
|
+
return encodeHelpers.encodeMigrateSameAssetCollateral(evc, args);
|
|
454
|
+
}
|
|
455
|
+
/**
|
|
456
|
+
* Encodes EVC batch items for migrating a full debt position between two same-asset liability vaults.
|
|
457
|
+
* Flow: enable new controller → borrow with interest cushion to old vault → skim → repay old debt with shares
|
|
458
|
+
* → disable old controller → optionally sweep cushion to the new vault → optionally transfer remaining new-vault shares.
|
|
459
|
+
*
|
|
460
|
+
* @param args - Same-asset debt migration encoding arguments
|
|
461
|
+
* @param args.chainId - Chain ID (used for EVC enable controller)
|
|
462
|
+
* @param args.oldLiabilityVault - Existing debt vault to fully repay and disable
|
|
463
|
+
* @param args.newLiabilityVault - New same-asset debt vault to borrow from
|
|
464
|
+
* @param args.amount - Current debt amount before applying the 0.01% interest cushion
|
|
465
|
+
* @param args.account - Sub-account that owns the debt position
|
|
466
|
+
* @param args.enableController - If true, enables the new liability vault as controller first
|
|
467
|
+
* @param args.disableController - If true, disables the old liability vault after repayment
|
|
468
|
+
* @param args.sweepExcess - If true, redeems any old-vault cushion shares back to the new vault and skims them
|
|
469
|
+
* @param args.transferRemainingSharesTo - If set, transfers all new-vault shares from the sub-account to this address
|
|
470
|
+
* @returns Array of EVC batch items
|
|
471
|
+
*/
|
|
472
|
+
encodeMigrateSameAssetDebt(args) {
|
|
473
|
+
const { evc } = this.getCoreAddresses(args.chainId);
|
|
474
|
+
return encodeHelpers.encodeMigrateSameAssetDebt(evc, args);
|
|
848
475
|
}
|
|
849
476
|
/**
|
|
850
477
|
* Encodes EVC batch items for transferring vault shares between sub-accounts.
|
|
@@ -859,28 +486,9 @@ export class ExecutionService {
|
|
|
859
486
|
* @param args.disableCollateralFrom - If true, prepends disableCollateral( from, vault ) via EVC before transfer
|
|
860
487
|
* @returns Array of EVC batch items (optional disableCollateralFrom, transfer, optional enableCollateralTo)
|
|
861
488
|
*/
|
|
862
|
-
encodeTransfer({ chainId,
|
|
863
|
-
const
|
|
864
|
-
|
|
865
|
-
if (disableCollateralFrom) {
|
|
866
|
-
items.push(this.encodeDisableCollateral(chainId, from, vault));
|
|
867
|
-
}
|
|
868
|
-
// Add transfer operation
|
|
869
|
-
items.push({
|
|
870
|
-
targetContract: vault,
|
|
871
|
-
onBehalfOfAccount: from,
|
|
872
|
-
value: 0n,
|
|
873
|
-
data: encodeFunctionData({
|
|
874
|
-
abi: eVaultAbi,
|
|
875
|
-
functionName: "transfer",
|
|
876
|
-
args: [to, amount],
|
|
877
|
-
}),
|
|
878
|
-
});
|
|
879
|
-
// Add enable collateral to receiver if flag is set
|
|
880
|
-
if (enableCollateralTo) {
|
|
881
|
-
items.push(this.encodeEnableCollateral(chainId, to, vault));
|
|
882
|
-
}
|
|
883
|
-
return items;
|
|
489
|
+
encodeTransfer({ chainId, ...args }) {
|
|
490
|
+
const { evc } = this.getCoreAddresses(chainId);
|
|
491
|
+
return encodeHelpers.encodeTransfer(evc, { chainId, ...args });
|
|
884
492
|
}
|
|
885
493
|
/**
|
|
886
494
|
* Encodes a single EVC batch item that calls Permit2's `permit` with the given message and signature.
|
|
@@ -894,73 +502,23 @@ export class ExecutionService {
|
|
|
894
502
|
* @returns Single EVC batch item (targetContract = Permit2, permit call)
|
|
895
503
|
*/
|
|
896
504
|
encodePermit2Call(args) {
|
|
897
|
-
const {
|
|
898
|
-
|
|
899
|
-
const permit2 = deployment.addresses.coreAddrs.permit2;
|
|
900
|
-
return {
|
|
901
|
-
targetContract: permit2,
|
|
902
|
-
onBehalfOfAccount: owner,
|
|
903
|
-
value: 0n,
|
|
904
|
-
data: encodeFunctionData({
|
|
905
|
-
abi: permit2PermitAbi,
|
|
906
|
-
functionName: "permit",
|
|
907
|
-
args: [owner, message, signature],
|
|
908
|
-
}),
|
|
909
|
-
};
|
|
505
|
+
const { permit2 } = this.getCoreAddresses(args.chainId);
|
|
506
|
+
return encodeHelpers.encodePermit2Call(permit2, args);
|
|
910
507
|
}
|
|
911
508
|
encodeEnableCollateral(chainId, account, vault) {
|
|
912
|
-
const
|
|
913
|
-
|
|
914
|
-
return {
|
|
915
|
-
targetContract: evc,
|
|
916
|
-
onBehalfOfAccount: zeroAddress,
|
|
917
|
-
value: 0n,
|
|
918
|
-
data: encodeFunctionData({
|
|
919
|
-
abi: ethereumVaultConnectorAbi,
|
|
920
|
-
functionName: "enableCollateral",
|
|
921
|
-
args: [account, vault],
|
|
922
|
-
}),
|
|
923
|
-
};
|
|
509
|
+
const { evc } = this.getCoreAddresses(chainId);
|
|
510
|
+
return encodeHelpers.encodeEnableCollateral(evc, account, vault);
|
|
924
511
|
}
|
|
925
512
|
encodeDisableCollateral(chainId, account, vault) {
|
|
926
|
-
const
|
|
927
|
-
|
|
928
|
-
return {
|
|
929
|
-
targetContract: evc,
|
|
930
|
-
onBehalfOfAccount: zeroAddress,
|
|
931
|
-
value: 0n,
|
|
932
|
-
data: encodeFunctionData({
|
|
933
|
-
abi: ethereumVaultConnectorAbi,
|
|
934
|
-
functionName: "disableCollateral",
|
|
935
|
-
args: [account, vault],
|
|
936
|
-
}),
|
|
937
|
-
};
|
|
513
|
+
const { evc } = this.getCoreAddresses(chainId);
|
|
514
|
+
return encodeHelpers.encodeDisableCollateral(evc, account, vault);
|
|
938
515
|
}
|
|
939
516
|
encodeEnableController(chainId, account, vault) {
|
|
940
|
-
const
|
|
941
|
-
|
|
942
|
-
return {
|
|
943
|
-
targetContract: evc,
|
|
944
|
-
onBehalfOfAccount: zeroAddress,
|
|
945
|
-
value: 0n,
|
|
946
|
-
data: encodeFunctionData({
|
|
947
|
-
abi: ethereumVaultConnectorAbi,
|
|
948
|
-
functionName: "enableController",
|
|
949
|
-
args: [account, vault],
|
|
950
|
-
}),
|
|
951
|
-
};
|
|
517
|
+
const { evc } = this.getCoreAddresses(chainId);
|
|
518
|
+
return encodeHelpers.encodeEnableController(evc, account, vault);
|
|
952
519
|
}
|
|
953
520
|
encodeDisableController(vault, account) {
|
|
954
|
-
return
|
|
955
|
-
targetContract: vault,
|
|
956
|
-
onBehalfOfAccount: account,
|
|
957
|
-
value: 0n,
|
|
958
|
-
data: encodeFunctionData({
|
|
959
|
-
abi: eVaultAbi,
|
|
960
|
-
functionName: "disableController",
|
|
961
|
-
args: [],
|
|
962
|
-
}),
|
|
963
|
-
};
|
|
521
|
+
return encodeHelpers.encodeDisableController(vault, account);
|
|
964
522
|
}
|
|
965
523
|
/**
|
|
966
524
|
* Builds EIP-712 typed data for a Permit2 PermitSingle signature (token approval for a spender).
|
|
@@ -977,46 +535,10 @@ export class ExecutionService {
|
|
|
977
535
|
* @returns EIP-712 typed data (domain, types, primaryType, message) for signing
|
|
978
536
|
*/
|
|
979
537
|
getPermit2TypedData(args) {
|
|
980
|
-
const
|
|
981
|
-
|
|
982
|
-
const deployment = this.deploymentService.getDeployment(chainId);
|
|
983
|
-
const permit2 = deployment.addresses.coreAddrs.permit2;
|
|
984
|
-
const permitSingle = {
|
|
985
|
-
details: {
|
|
986
|
-
token,
|
|
987
|
-
amount: amount > maxUint160 ? maxUint160 : amount,
|
|
988
|
-
expiration: expiration ?? Number(maxUint48),
|
|
989
|
-
nonce,
|
|
990
|
-
},
|
|
991
|
-
spender,
|
|
992
|
-
sigDeadline: sigDeadline ?? nowInSeconds() + PERMIT2_SIG_WINDOW,
|
|
993
|
-
};
|
|
994
|
-
return {
|
|
995
|
-
domain: {
|
|
996
|
-
name: "Permit2",
|
|
997
|
-
chainId,
|
|
998
|
-
verifyingContract: permit2,
|
|
999
|
-
},
|
|
1000
|
-
types: PERMIT2_TYPES,
|
|
1001
|
-
primaryType: "PermitSingle",
|
|
1002
|
-
message: permitSingle,
|
|
1003
|
-
};
|
|
538
|
+
const { permit2 } = this.getCoreAddresses(args.chainId);
|
|
539
|
+
return encodeHelpers.getPermit2TypedData(permit2, args);
|
|
1004
540
|
}
|
|
1005
|
-
/**
|
|
1006
|
-
* Decodes EVC batch items into human-readable function names and named arguments.
|
|
1007
|
-
* Tries known ABIs (EVC, eVault, Permit2, swapper, swapVerifier) to decode each item's data.
|
|
1008
|
-
*
|
|
1009
|
-
* @param batch - Array of EVC batch items (targetContract, onBehalfOfAccount, value, data) to decode
|
|
1010
|
-
* @param extraAbis - Optional extra ABIs to try first when decoding unknown batch items.
|
|
1011
|
-
* @returns Array of decoded items with targetContract, onBehalfOfAccount, functionName, and args (record of param name to value). Throws if any item cannot be decoded.
|
|
1012
|
-
* @example
|
|
1013
|
-
* const batchItems = executionService.encodeDeposit({ ... });
|
|
1014
|
-
* const described = executionService.describeBatch(batchItems);
|
|
1015
|
-
* console.log(described[0].functionName); // "deposit"
|
|
1016
|
-
* console.log(described[0].args); // { amount: 1000n, receiver: "0x..." }
|
|
1017
|
-
*/
|
|
1018
541
|
describeBatch(batch, extraAbis) {
|
|
1019
|
-
const decodedBatchItems = [];
|
|
1020
542
|
const executionDecodeAbis = [
|
|
1021
543
|
...(extraAbis ?? []),
|
|
1022
544
|
ethereumVaultConnectorAbi,
|
|
@@ -1025,7 +547,7 @@ export class ExecutionService {
|
|
|
1025
547
|
swapperAbi,
|
|
1026
548
|
swapVerifierAbi,
|
|
1027
549
|
];
|
|
1028
|
-
|
|
550
|
+
const decodeBatchItem = (item) => {
|
|
1029
551
|
let decoded = false;
|
|
1030
552
|
for (const abi of executionDecodeAbis) {
|
|
1031
553
|
try {
|
|
@@ -1050,14 +572,13 @@ export class ExecutionService {
|
|
|
1050
572
|
}
|
|
1051
573
|
});
|
|
1052
574
|
}
|
|
1053
|
-
|
|
575
|
+
decoded = true;
|
|
576
|
+
return {
|
|
1054
577
|
targetContract: item.targetContract,
|
|
1055
578
|
onBehalfOfAccount: item.onBehalfOfAccount,
|
|
1056
579
|
functionName: decodedData.functionName,
|
|
1057
580
|
args: namedArgs,
|
|
1058
|
-
}
|
|
1059
|
-
decoded = true;
|
|
1060
|
-
break;
|
|
581
|
+
};
|
|
1061
582
|
}
|
|
1062
583
|
catch { }
|
|
1063
584
|
}
|
|
@@ -1069,29 +590,35 @@ export class ExecutionService {
|
|
|
1069
590
|
try {
|
|
1070
591
|
const result = plugin.decodeBatchItem(item);
|
|
1071
592
|
if (result) {
|
|
1072
|
-
decodedBatchItems.push(result);
|
|
1073
593
|
decoded = true;
|
|
1074
|
-
|
|
594
|
+
return result;
|
|
1075
595
|
}
|
|
1076
596
|
}
|
|
1077
597
|
catch { }
|
|
1078
598
|
}
|
|
1079
599
|
}
|
|
1080
600
|
if (!decoded) {
|
|
1081
|
-
|
|
601
|
+
return {
|
|
1082
602
|
targetContract: item.targetContract,
|
|
1083
603
|
onBehalfOfAccount: item.onBehalfOfAccount,
|
|
1084
604
|
functionName: "Unknown",
|
|
1085
605
|
args: {},
|
|
1086
|
-
}
|
|
606
|
+
};
|
|
1087
607
|
}
|
|
1088
|
-
|
|
1089
|
-
|
|
608
|
+
throw new Error("unreachable batch item decode state");
|
|
609
|
+
};
|
|
610
|
+
return batch.map((entry) => isEVCBatchOperation(entry)
|
|
611
|
+
? {
|
|
612
|
+
type: "operation",
|
|
613
|
+
name: entry.name,
|
|
614
|
+
items: entry.items.map(decodeBatchItem),
|
|
615
|
+
}
|
|
616
|
+
: decodeBatchItem(entry));
|
|
1090
617
|
}
|
|
1091
618
|
/**
|
|
1092
619
|
* Merges multiple transaction plans into a single plan.
|
|
1093
620
|
* Required approvals for the same (token, owner, spender) are summed.
|
|
1094
|
-
* Executable items are preserved in order; adjacent EVC
|
|
621
|
+
* Executable items are preserved in order; adjacent EVC batches are concatenated without flattening operation groupings.
|
|
1095
622
|
* Can be used to construct a transaction queue.
|
|
1096
623
|
*
|
|
1097
624
|
* @param plans - Array of transaction plans to merge
|
|
@@ -1117,19 +644,37 @@ export class ExecutionService {
|
|
|
1117
644
|
else if (item.type === "evcBatch") {
|
|
1118
645
|
const previous = executableItems[executableItems.length - 1];
|
|
1119
646
|
if (previous?.type === "evcBatch") {
|
|
1120
|
-
previous.items.push(...item.items);
|
|
647
|
+
previous.items.push(...cloneBatchEntries(item.items));
|
|
1121
648
|
}
|
|
1122
649
|
else {
|
|
1123
|
-
executableItems.push({
|
|
650
|
+
executableItems.push({
|
|
651
|
+
type: "evcBatch",
|
|
652
|
+
items: cloneBatchEntries(item.items),
|
|
653
|
+
});
|
|
1124
654
|
}
|
|
1125
655
|
}
|
|
1126
656
|
else {
|
|
1127
|
-
|
|
657
|
+
throw new Error("ExecutionService.mergePlans cannot merge contractCall plan items. Merge these plans manually to preserve call boundaries.");
|
|
1128
658
|
}
|
|
1129
659
|
}
|
|
1130
660
|
}
|
|
1131
661
|
return [...approvalByKey.values(), ...executableItems];
|
|
1132
662
|
}
|
|
663
|
+
/**
|
|
664
|
+
* Appends a raw batch item to the last EVC batch in the plan, or creates one.
|
|
665
|
+
* Mutates and returns the provided plan.
|
|
666
|
+
*/
|
|
667
|
+
addBatchItemToPlan(plan, item) {
|
|
668
|
+
for (let index = plan.length - 1; index >= 0; index--) {
|
|
669
|
+
const planItem = plan[index];
|
|
670
|
+
if (planItem?.type === "evcBatch") {
|
|
671
|
+
planItem.items.push(item);
|
|
672
|
+
return plan;
|
|
673
|
+
}
|
|
674
|
+
}
|
|
675
|
+
plan.push({ type: "evcBatch", items: [item] });
|
|
676
|
+
return plan;
|
|
677
|
+
}
|
|
1133
678
|
/**
|
|
1134
679
|
* Converts EVC batch items into a transaction plan.
|
|
1135
680
|
* Returns a plan with a single evcBatch containing the given items (no required approvals).
|
|
@@ -1138,127 +683,50 @@ export class ExecutionService {
|
|
|
1138
683
|
* @param items - EVC batch items to wrap in a plan
|
|
1139
684
|
* @returns Transaction plan containing one evcBatch with the items
|
|
1140
685
|
*/
|
|
1141
|
-
convertBatchItemsToPlan(items) {
|
|
686
|
+
convertBatchItemsToPlan(items, operationName) {
|
|
1142
687
|
if (items.length === 0)
|
|
1143
688
|
return [];
|
|
689
|
+
if (operationName) {
|
|
690
|
+
return [
|
|
691
|
+
{
|
|
692
|
+
type: "evcBatch",
|
|
693
|
+
items: [{ type: "operation", name: operationName, items }],
|
|
694
|
+
},
|
|
695
|
+
];
|
|
696
|
+
}
|
|
1144
697
|
return [{ type: "evcBatch", items }];
|
|
1145
698
|
}
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
*/
|
|
1149
|
-
encodeRepayWithSharesSameAssetAndVault({ chainId: _chainId, vault, amount, from, receiver, disableController, }) {
|
|
1150
|
-
const items = [];
|
|
1151
|
-
// Repay with shares
|
|
1152
|
-
items.push({
|
|
1153
|
-
targetContract: vault,
|
|
1154
|
-
onBehalfOfAccount: from,
|
|
1155
|
-
value: 0n,
|
|
1156
|
-
data: encodeFunctionData({
|
|
1157
|
-
abi: eVaultAbi,
|
|
1158
|
-
functionName: "repayWithShares",
|
|
1159
|
-
args: [amount, receiver],
|
|
1160
|
-
}),
|
|
1161
|
-
});
|
|
1162
|
-
// Disable controller if needed (for max repay)
|
|
1163
|
-
if (disableController) {
|
|
1164
|
-
items.push(this.encodeDisableController(vault, receiver));
|
|
1165
|
-
}
|
|
1166
|
-
return items;
|
|
699
|
+
encodeTransferFromMax(vault, from, to) {
|
|
700
|
+
return encodeHelpers.encodeTransferFromMax(vault, from, to);
|
|
1167
701
|
}
|
|
1168
702
|
/**
|
|
1169
|
-
*
|
|
703
|
+
* Appends post-full-repay cleanup calls owned by plan builders:
|
|
704
|
+
* disable each active collateral used by the repaid borrow, transfer those collateral shares to the owner,
|
|
705
|
+
* and, when a source deposit funded the repay, transfer any remaining source-vault shares to the owner.
|
|
1170
706
|
*/
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
const
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
if (
|
|
1183
|
-
|
|
1184
|
-
}
|
|
1185
|
-
// 1. Withdraw from collateral vault
|
|
1186
|
-
items.push({
|
|
1187
|
-
targetContract: fromVault,
|
|
1188
|
-
onBehalfOfAccount: from,
|
|
1189
|
-
value: 0n,
|
|
1190
|
-
data: encodeFunctionData({
|
|
1191
|
-
abi: eVaultAbi,
|
|
1192
|
-
functionName: "withdraw",
|
|
1193
|
-
args: [amountWithExtra, toVault, from],
|
|
1194
|
-
}),
|
|
1195
|
-
});
|
|
1196
|
-
// 2. Skim exact withdrawal amount to liability vault
|
|
1197
|
-
items.push({
|
|
1198
|
-
targetContract: toVault,
|
|
1199
|
-
onBehalfOfAccount: receiver,
|
|
1200
|
-
value: 0n,
|
|
1201
|
-
data: encodeFunctionData({
|
|
1202
|
-
abi: eVaultAbi,
|
|
1203
|
-
functionName: "skim",
|
|
1204
|
-
args: [amountWithExtra, receiver],
|
|
1205
|
-
}),
|
|
1206
|
-
});
|
|
1207
|
-
// 3. Repay with shares (max)
|
|
1208
|
-
items.push({
|
|
1209
|
-
targetContract: toVault,
|
|
1210
|
-
onBehalfOfAccount: receiver,
|
|
1211
|
-
value: 0n,
|
|
1212
|
-
data: encodeFunctionData({
|
|
1213
|
-
abi: eVaultAbi,
|
|
1214
|
-
functionName: "repayWithShares",
|
|
1215
|
-
// max is ok now, because skim deposited exact amount and it is the full debt,
|
|
1216
|
-
// so pre-existing balance will not be consumed
|
|
1217
|
-
args: [maxUint256, receiver],
|
|
1218
|
-
}),
|
|
1219
|
-
});
|
|
1220
|
-
// 4. Disable controller if needed
|
|
1221
|
-
if (disableControllerOnMax) {
|
|
1222
|
-
items.push(this.encodeDisableController(toVault, receiver));
|
|
707
|
+
appendMaxRepayCleanup(args) {
|
|
708
|
+
const { account, liabilityPosition, receiver, batchItems, sourceAccount, sourceVault, } = args;
|
|
709
|
+
const receiverSubAccount = typeof account.getSubAccount === "function"
|
|
710
|
+
? account.getSubAccount(receiver)
|
|
711
|
+
: undefined;
|
|
712
|
+
const activeCollaterals = receiverSubAccount
|
|
713
|
+
? resolveBorrowCollateralPositions(receiverSubAccount, liabilityPosition)
|
|
714
|
+
: [];
|
|
715
|
+
const transferredPositions = new Set();
|
|
716
|
+
for (const collateral of activeCollaterals) {
|
|
717
|
+
batchItems.push(this.encodeDisableCollateral(account.chainId, receiver, collateral.vaultAddress));
|
|
718
|
+
if (getAddress(receiver) !== getAddress(account.owner)) {
|
|
719
|
+
batchItems.push(this.encodeTransferFromMax(collateral.vaultAddress, receiver, account.owner));
|
|
1223
720
|
}
|
|
721
|
+
transferredPositions.add(`${getAddress(receiver)}:${getAddress(collateral.vaultAddress)}`);
|
|
1224
722
|
}
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
value: 0n,
|
|
1232
|
-
data: encodeFunctionData({
|
|
1233
|
-
abi: eVaultAbi,
|
|
1234
|
-
functionName: "withdraw",
|
|
1235
|
-
args: [amount, toVault, from],
|
|
1236
|
-
}),
|
|
1237
|
-
});
|
|
1238
|
-
// 2. Skim the received assets into the borrow sub-account.
|
|
1239
|
-
items.push({
|
|
1240
|
-
targetContract: toVault,
|
|
1241
|
-
onBehalfOfAccount: receiver,
|
|
1242
|
-
value: 0n,
|
|
1243
|
-
data: encodeFunctionData({
|
|
1244
|
-
abi: eVaultAbi,
|
|
1245
|
-
functionName: "skim",
|
|
1246
|
-
args: [amount, receiver],
|
|
1247
|
-
}),
|
|
1248
|
-
});
|
|
1249
|
-
// 3. Burn the skimmed shares to repay debt.
|
|
1250
|
-
items.push({
|
|
1251
|
-
targetContract: toVault,
|
|
1252
|
-
onBehalfOfAccount: receiver,
|
|
1253
|
-
value: 0n,
|
|
1254
|
-
data: encodeFunctionData({
|
|
1255
|
-
abi: eVaultAbi,
|
|
1256
|
-
functionName: "repayWithShares",
|
|
1257
|
-
args: [amount > 0n ? amount - 1n : 0n, receiver],
|
|
1258
|
-
}),
|
|
1259
|
-
});
|
|
723
|
+
if (sourceAccount && sourceVault) {
|
|
724
|
+
const sourcePositionKey = `${getAddress(sourceAccount)}:${getAddress(sourceVault)}`;
|
|
725
|
+
if (getAddress(sourceAccount) !== getAddress(account.owner) &&
|
|
726
|
+
!transferredPositions.has(sourcePositionKey)) {
|
|
727
|
+
batchItems.push(this.encodeTransferFromMax(sourceVault, sourceAccount, account.owner));
|
|
728
|
+
}
|
|
1260
729
|
}
|
|
1261
|
-
return items;
|
|
1262
730
|
}
|
|
1263
731
|
/**
|
|
1264
732
|
* Resolves RequiredApproval items in a transaction plan by filling in each item's `resolved` field.
|
|
@@ -1381,6 +849,9 @@ export class ExecutionService {
|
|
|
1381
849
|
*/
|
|
1382
850
|
async resolveRequiredApprovals(args) {
|
|
1383
851
|
const { plan, chainId, account, usePermit2 = true, unlimitedApproval = false, } = args;
|
|
852
|
+
if (!this.walletService) {
|
|
853
|
+
throw new Error("ExecutionService.resolveRequiredApprovals requires a walletService. Pass it to the ExecutionService constructor or call setWalletService().");
|
|
854
|
+
}
|
|
1384
855
|
// Filter transaction plan for only RequiredApproval items
|
|
1385
856
|
const requiredApprovals = plan.filter((item) => item.type === "requiredApproval");
|
|
1386
857
|
// Transform RequiredApprovals into AssetWithSpenders
|
|
@@ -1445,10 +916,7 @@ export class ExecutionService {
|
|
|
1445
916
|
enableCollateral: !isCollateralEnabled && enableCollateral,
|
|
1446
917
|
// Permit2 is handled separately in the plan
|
|
1447
918
|
});
|
|
1448
|
-
plan.push(
|
|
1449
|
-
type: "evcBatch",
|
|
1450
|
-
items: batchItems,
|
|
1451
|
-
});
|
|
919
|
+
plan.push(...this.convertBatchItemsToPlan(batchItems, "deposit"));
|
|
1452
920
|
return plan;
|
|
1453
921
|
}
|
|
1454
922
|
/**
|
|
@@ -1490,10 +958,7 @@ export class ExecutionService {
|
|
|
1490
958
|
enableCollateral: !isCollateralEnabled && enableCollateral,
|
|
1491
959
|
// Permit2 is handled separately in the plan
|
|
1492
960
|
});
|
|
1493
|
-
plan.push(
|
|
1494
|
-
type: "evcBatch",
|
|
1495
|
-
items: batchItems,
|
|
1496
|
-
});
|
|
961
|
+
plan.push(...this.convertBatchItemsToPlan(batchItems, "mint"));
|
|
1497
962
|
return plan;
|
|
1498
963
|
}
|
|
1499
964
|
/**
|
|
@@ -1522,10 +987,7 @@ export class ExecutionService {
|
|
|
1522
987
|
owner,
|
|
1523
988
|
disableCollateral: disableCollateral && (!position || position.isCollateral),
|
|
1524
989
|
});
|
|
1525
|
-
plan.push(
|
|
1526
|
-
type: "evcBatch",
|
|
1527
|
-
items: batchItems,
|
|
1528
|
-
});
|
|
990
|
+
plan.push(...this.convertBatchItemsToPlan(batchItems, "withdraw"));
|
|
1529
991
|
return plan;
|
|
1530
992
|
}
|
|
1531
993
|
/**
|
|
@@ -1555,10 +1017,7 @@ export class ExecutionService {
|
|
|
1555
1017
|
owner,
|
|
1556
1018
|
disableCollateral: disableCollateral && (!position || position.isCollateral),
|
|
1557
1019
|
});
|
|
1558
|
-
plan.push(
|
|
1559
|
-
type: "evcBatch",
|
|
1560
|
-
items: batchItems,
|
|
1561
|
-
});
|
|
1020
|
+
plan.push(...this.convertBatchItemsToPlan(batchItems, "redeem"));
|
|
1562
1021
|
return plan;
|
|
1563
1022
|
}
|
|
1564
1023
|
/**
|
|
@@ -1580,6 +1039,12 @@ export class ExecutionService {
|
|
|
1580
1039
|
planBorrow(args) {
|
|
1581
1040
|
const { vault, amount, receiver, borrowAccount, account, collateral } = args;
|
|
1582
1041
|
const plan = [];
|
|
1042
|
+
const savingsCollateral = isSavingsCollateral(collateral)
|
|
1043
|
+
? collateral
|
|
1044
|
+
: undefined;
|
|
1045
|
+
const walletCollateral = isWalletCollateral(collateral)
|
|
1046
|
+
? collateral
|
|
1047
|
+
: undefined;
|
|
1583
1048
|
const enableCollateral = collateral && collateral.amount > 0n
|
|
1584
1049
|
? !(account?.isCollateralEnabled(borrowAccount, collateral.vault) ??
|
|
1585
1050
|
false)
|
|
@@ -1588,15 +1053,15 @@ export class ExecutionService {
|
|
|
1588
1053
|
// Default: controller is not enabled when account/sub-account is not available
|
|
1589
1054
|
const currentController = account?.getCurrentController(borrowAccount);
|
|
1590
1055
|
const enableController = !(account?.isControllerEnabled(borrowAccount, vault) ?? false);
|
|
1591
|
-
if (
|
|
1056
|
+
if (walletCollateral && walletCollateral.amount > 0n) {
|
|
1592
1057
|
// Approval is needed from the account owner (who owns the wallet tokens)
|
|
1593
1058
|
// Add approval requirement (will be resolved later with Wallet data)
|
|
1594
1059
|
plan.push({
|
|
1595
1060
|
type: "requiredApproval",
|
|
1596
|
-
token:
|
|
1061
|
+
token: walletCollateral.asset,
|
|
1597
1062
|
owner: account.owner,
|
|
1598
|
-
spender:
|
|
1599
|
-
amount:
|
|
1063
|
+
spender: walletCollateral.vault,
|
|
1064
|
+
amount: walletCollateral.amount,
|
|
1600
1065
|
});
|
|
1601
1066
|
}
|
|
1602
1067
|
const batchItems = this.encodeBorrow({
|
|
@@ -1610,12 +1075,18 @@ export class ExecutionService {
|
|
|
1610
1075
|
currentController: currentController || undefined,
|
|
1611
1076
|
enableCollateral,
|
|
1612
1077
|
collateralVault: collateral?.vault,
|
|
1613
|
-
collateralAmount:
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1078
|
+
collateralAmount: walletCollateral?.amount,
|
|
1079
|
+
collateralShareSource: savingsCollateral
|
|
1080
|
+
? {
|
|
1081
|
+
from: savingsCollateral.from,
|
|
1082
|
+
shares: savingsCollateral.amount,
|
|
1083
|
+
disableCollateralFrom: savingsCollateral.disableCollateralFrom &&
|
|
1084
|
+
(account?.isCollateralEnabled(savingsCollateral.from, savingsCollateral.vault) ??
|
|
1085
|
+
false),
|
|
1086
|
+
}
|
|
1087
|
+
: undefined,
|
|
1618
1088
|
});
|
|
1089
|
+
plan.push(...this.convertBatchItemsToPlan(batchItems, "borrow"));
|
|
1619
1090
|
return plan;
|
|
1620
1091
|
}
|
|
1621
1092
|
/**
|
|
@@ -1659,10 +1130,7 @@ export class ExecutionService {
|
|
|
1659
1130
|
enableController,
|
|
1660
1131
|
enableCollateral,
|
|
1661
1132
|
});
|
|
1662
|
-
plan.push(
|
|
1663
|
-
type: "evcBatch",
|
|
1664
|
-
items: batchItems,
|
|
1665
|
-
});
|
|
1133
|
+
plan.push(...this.convertBatchItemsToPlan(batchItems, "liquidation"));
|
|
1666
1134
|
return plan;
|
|
1667
1135
|
}
|
|
1668
1136
|
/**
|
|
@@ -1674,10 +1142,11 @@ export class ExecutionService {
|
|
|
1674
1142
|
* @param args.liabilityAmount - Amount of liability asset to repay (use maxUint256 for "repay all")
|
|
1675
1143
|
* @param args.receiver - Sub-account address whose debt is being repaid
|
|
1676
1144
|
* @param args.account - Account entity; used for chainId, owner, and position (to resolve liability asset)
|
|
1145
|
+
* @param args.cleanupOnMax - When true and liabilityAmount is maxUint256, the batch disables active collaterals on the repaid sub-account and transfers their shares to the owner account (default false)
|
|
1677
1146
|
* @returns Array of transaction plan items (approval + EVC batch)
|
|
1678
1147
|
*/
|
|
1679
1148
|
planRepayFromWallet(args) {
|
|
1680
|
-
const { liabilityVault, liabilityAmount, receiver, account } = args;
|
|
1149
|
+
const { liabilityVault, liabilityAmount, receiver, account, cleanupOnMax = false, } = args;
|
|
1681
1150
|
const plan = [];
|
|
1682
1151
|
// Get position to determine asset
|
|
1683
1152
|
const position = account?.getPosition(receiver, liabilityVault);
|
|
@@ -1692,6 +1161,7 @@ export class ExecutionService {
|
|
|
1692
1161
|
spender: liabilityVault,
|
|
1693
1162
|
amount: liabilityAmount,
|
|
1694
1163
|
});
|
|
1164
|
+
const isMax = liabilityAmount === maxUint256;
|
|
1695
1165
|
// Build EVC batch items
|
|
1696
1166
|
const batchItems = this.encodeRepayFromWallet({
|
|
1697
1167
|
chainId: account.chainId,
|
|
@@ -1700,18 +1170,28 @@ export class ExecutionService {
|
|
|
1700
1170
|
liabilityAmount,
|
|
1701
1171
|
receiver,
|
|
1702
1172
|
disableControllerOnMax: true,
|
|
1703
|
-
isMax
|
|
1173
|
+
isMax,
|
|
1704
1174
|
// Permit2 is handled separately in the plan
|
|
1705
1175
|
});
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1176
|
+
if (cleanupOnMax && isMax) {
|
|
1177
|
+
this.appendMaxRepayCleanup({
|
|
1178
|
+
account,
|
|
1179
|
+
liabilityPosition: position,
|
|
1180
|
+
receiver,
|
|
1181
|
+
batchItems,
|
|
1182
|
+
});
|
|
1183
|
+
}
|
|
1184
|
+
plan.push(...this.convertBatchItemsToPlan(batchItems, "repayFromWallet"));
|
|
1710
1185
|
return plan;
|
|
1711
1186
|
}
|
|
1712
1187
|
/**
|
|
1713
1188
|
* Builds a transaction plan for repaying debt using assets from another vault deposit (same asset only).
|
|
1714
|
-
* Use `maxUint256` for `liabilityAmount` to
|
|
1189
|
+
* Use `maxUint256` for `liabilityAmount` to perform a full repay.
|
|
1190
|
+
* Full repay can opt into cleanup. For different-vault full repays, cleanup only redeems
|
|
1191
|
+
* liability-vault shares left from the repay cushion when the account snapshot shows no pre-existing liability-vault deposit;
|
|
1192
|
+
* otherwise those shares are preserved in the liability vault instead of being migrated to the source vault.
|
|
1193
|
+
* Cleanup also disables active collaterals on the repaid sub-account, transfers those collateral shares to the owner
|
|
1194
|
+
* account, and transfers any remaining source-vault shares from the source sub-account to the owner account.
|
|
1715
1195
|
*
|
|
1716
1196
|
* @param args - Repay-from-deposit plan arguments
|
|
1717
1197
|
* @param args.liabilityVault - Address of the liability vault (debt is repaid to this vault)
|
|
@@ -1720,10 +1200,11 @@ export class ExecutionService {
|
|
|
1720
1200
|
* @param args.fromVault - Vault to withdraw assets from (must be same underlying asset as liability for this plan)
|
|
1721
1201
|
* @param args.fromAccount - Sub-account that holds the deposit in `fromVault`
|
|
1722
1202
|
* @param args.account - Account entity; used for chainId, owner, and positions (to resolve assets and eligibility)
|
|
1723
|
-
* @
|
|
1203
|
+
* @param args.cleanupOnMax - Whether max repay should append repay-cushion, collateral, and source-share cleanup (default false)
|
|
1204
|
+
* @returns Array of transaction plan items (EVC batch only). Throws if asset differs between fromVault and liabilityVault; use planRepayWithSwap for cross-asset.
|
|
1724
1205
|
*/
|
|
1725
1206
|
planRepayFromDeposit(args) {
|
|
1726
|
-
const { liabilityVault, liabilityAmount, receiver, fromVault, fromAccount, account, } = args;
|
|
1207
|
+
const { liabilityVault, liabilityAmount, receiver, fromVault, fromAccount, account, cleanupOnMax = false, } = args;
|
|
1727
1208
|
const plan = [];
|
|
1728
1209
|
// Get positions
|
|
1729
1210
|
const liabilityPosition = account?.getPosition(receiver, liabilityVault);
|
|
@@ -1735,7 +1216,7 @@ export class ExecutionService {
|
|
|
1735
1216
|
}
|
|
1736
1217
|
const liabilityAsset = liabilityPosition.asset;
|
|
1737
1218
|
const fromAsset = fromPosition.asset;
|
|
1738
|
-
//
|
|
1219
|
+
// Cross-asset repay requires a swap path; this planner only builds same-asset batches.
|
|
1739
1220
|
if (fromAsset !== liabilityAsset) {
|
|
1740
1221
|
// This path requires a swap, which is handled by planRepayWithSwap
|
|
1741
1222
|
throw new Error("planRepayFromDeposit only supports same-asset paths. Use planRepayWithSwap for different assets.");
|
|
@@ -1744,6 +1225,7 @@ export class ExecutionService {
|
|
|
1744
1225
|
const amount = isMax && fromVault !== liabilityVault
|
|
1745
1226
|
? liabilityPosition.borrowed
|
|
1746
1227
|
: liabilityAmount;
|
|
1228
|
+
const hasPreExistingLiabilityDeposit = (liabilityPosition.assets ?? 0n) > 0n;
|
|
1747
1229
|
// Build EVC batch items
|
|
1748
1230
|
const batchItems = this.encodeRepayFromDeposit({
|
|
1749
1231
|
chainId: account.chainId,
|
|
@@ -1758,10 +1240,41 @@ export class ExecutionService {
|
|
|
1758
1240
|
isMax,
|
|
1759
1241
|
// Permit2 is handled separately in the plan
|
|
1760
1242
|
});
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
|
|
1243
|
+
if (cleanupOnMax && isMax) {
|
|
1244
|
+
if (fromVault !== liabilityVault && !hasPreExistingLiabilityDeposit) {
|
|
1245
|
+
// Sweep only the repay cushion. If liability shares existed before this batch,
|
|
1246
|
+
// redeem(max) would also migrate that unrelated deposit into the source vault.
|
|
1247
|
+
batchItems.push({
|
|
1248
|
+
targetContract: liabilityVault,
|
|
1249
|
+
onBehalfOfAccount: receiver,
|
|
1250
|
+
value: 0n,
|
|
1251
|
+
data: encodeFunctionData({
|
|
1252
|
+
abi: eVaultAbi,
|
|
1253
|
+
functionName: "redeem",
|
|
1254
|
+
args: [maxUint256, fromVault, receiver],
|
|
1255
|
+
}),
|
|
1256
|
+
});
|
|
1257
|
+
batchItems.push({
|
|
1258
|
+
targetContract: fromVault,
|
|
1259
|
+
onBehalfOfAccount: fromAccount,
|
|
1260
|
+
value: 0n,
|
|
1261
|
+
data: encodeFunctionData({
|
|
1262
|
+
abi: eVaultAbi,
|
|
1263
|
+
functionName: "skim",
|
|
1264
|
+
args: [maxUint256, fromAccount],
|
|
1265
|
+
}),
|
|
1266
|
+
});
|
|
1267
|
+
}
|
|
1268
|
+
this.appendMaxRepayCleanup({
|
|
1269
|
+
account,
|
|
1270
|
+
liabilityPosition,
|
|
1271
|
+
receiver,
|
|
1272
|
+
batchItems,
|
|
1273
|
+
sourceAccount: fromAccount,
|
|
1274
|
+
sourceVault: fromVault,
|
|
1275
|
+
});
|
|
1276
|
+
}
|
|
1277
|
+
plan.push(...this.convertBatchItemsToPlan(batchItems, "repayFromDeposit"));
|
|
1765
1278
|
return plan;
|
|
1766
1279
|
}
|
|
1767
1280
|
/**
|
|
@@ -1771,10 +1284,11 @@ export class ExecutionService {
|
|
|
1771
1284
|
* @param args - Repay-with-swap plan arguments
|
|
1772
1285
|
* @param args.swapQuote - Quote from swap service (e.g. fetchRepayQuotes); defines vaultIn, accountIn, accountOut, receiver, swap and verify steps
|
|
1773
1286
|
* @param args.account - Account entity; used for chainId and positions (to compute isMax and maxWithdraw)
|
|
1287
|
+
* @param args.cleanupOnMax - When true and the quote repays the full debt, the batch disables active collaterals on the repaid sub-account, transfers their shares to the owner account, and transfers remaining source-vault shares to the owner account (default false)
|
|
1774
1288
|
* @returns Array of transaction plan items (EVC batch: withdraw, swap, verify/repay). Throws if positions not found or liability is zero.
|
|
1775
1289
|
*/
|
|
1776
1290
|
planRepayWithSwap(args) {
|
|
1777
|
-
const { swapQuote, account } = args;
|
|
1291
|
+
const { swapQuote, account, cleanupOnMax = false } = args;
|
|
1778
1292
|
const plan = [];
|
|
1779
1293
|
const liabilityPosition = account?.getPosition(swapQuote.accountOut, swapQuote.receiver);
|
|
1780
1294
|
const fromPosition = account?.getPosition(swapQuote.accountIn, swapQuote.vaultIn);
|
|
@@ -1793,10 +1307,17 @@ export class ExecutionService {
|
|
|
1793
1307
|
isMax,
|
|
1794
1308
|
disableControllerOnMax: true,
|
|
1795
1309
|
});
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1310
|
+
if (cleanupOnMax && isMax) {
|
|
1311
|
+
this.appendMaxRepayCleanup({
|
|
1312
|
+
account,
|
|
1313
|
+
liabilityPosition,
|
|
1314
|
+
receiver: swapQuote.accountOut,
|
|
1315
|
+
batchItems,
|
|
1316
|
+
sourceAccount: swapQuote.accountIn,
|
|
1317
|
+
sourceVault: swapQuote.vaultIn,
|
|
1318
|
+
});
|
|
1319
|
+
}
|
|
1320
|
+
plan.push(...this.convertBatchItemsToPlan(batchItems, "repayWithSwap"));
|
|
1800
1321
|
return plan;
|
|
1801
1322
|
}
|
|
1802
1323
|
/**
|
|
@@ -1838,10 +1359,7 @@ export class ExecutionService {
|
|
|
1838
1359
|
sender: account.owner,
|
|
1839
1360
|
enableCollateral: shouldEnableCollateral,
|
|
1840
1361
|
});
|
|
1841
|
-
plan.push(
|
|
1842
|
-
type: "evcBatch",
|
|
1843
|
-
items: batchItems,
|
|
1844
|
-
});
|
|
1362
|
+
plan.push(...this.convertBatchItemsToPlan(batchItems, "depositWithSwapFromWallet"));
|
|
1845
1363
|
return plan;
|
|
1846
1364
|
}
|
|
1847
1365
|
/**
|
|
@@ -1871,10 +1389,7 @@ export class ExecutionService {
|
|
|
1871
1389
|
amount,
|
|
1872
1390
|
sender: account.owner,
|
|
1873
1391
|
});
|
|
1874
|
-
plan.push(
|
|
1875
|
-
type: "evcBatch",
|
|
1876
|
-
items: batchItems,
|
|
1877
|
-
});
|
|
1392
|
+
plan.push(...this.convertBatchItemsToPlan(batchItems, "swapFromWallet"));
|
|
1878
1393
|
return plan;
|
|
1879
1394
|
}
|
|
1880
1395
|
/**
|
|
@@ -1906,10 +1421,7 @@ export class ExecutionService {
|
|
|
1906
1421
|
disableCollateralOnMax: true,
|
|
1907
1422
|
isMax,
|
|
1908
1423
|
});
|
|
1909
|
-
plan.push(
|
|
1910
|
-
type: "evcBatch",
|
|
1911
|
-
items: batchItems,
|
|
1912
|
-
});
|
|
1424
|
+
plan.push(...this.convertBatchItemsToPlan(batchItems, "swapCollateral"));
|
|
1913
1425
|
return plan;
|
|
1914
1426
|
}
|
|
1915
1427
|
/**
|
|
@@ -1937,10 +1449,103 @@ export class ExecutionService {
|
|
|
1937
1449
|
disableControllerOnMax: true,
|
|
1938
1450
|
isMax,
|
|
1939
1451
|
});
|
|
1940
|
-
plan.push(
|
|
1941
|
-
|
|
1942
|
-
|
|
1452
|
+
plan.push(...this.convertBatchItemsToPlan(batchItems, "swapDebt"));
|
|
1453
|
+
return plan;
|
|
1454
|
+
}
|
|
1455
|
+
/**
|
|
1456
|
+
* Builds a transaction plan for migrating a supplied/collateral position between two same-asset vaults.
|
|
1457
|
+
* This is the no-swap path for moving shares from one vault to another vault with the same underlying asset.
|
|
1458
|
+
*
|
|
1459
|
+
* @param args - Same-asset collateral migration plan arguments
|
|
1460
|
+
* @param args.fromVault - Source vault holding the supplied shares
|
|
1461
|
+
* @param args.toVault - Destination vault with the same underlying asset
|
|
1462
|
+
* @param args.amount - Asset amount to withdraw/redeem and skim into the destination vault
|
|
1463
|
+
* @param args.positionAccount - Sub-account that owns the source shares and receives destination shares
|
|
1464
|
+
* @param args.fromAsset - Optional source underlying asset; defaults to the account position asset
|
|
1465
|
+
* @param args.toAsset - Destination underlying asset, used to verify this is a same-asset migration
|
|
1466
|
+
* @param args.isMax - If true, redeems shares instead of withdrawing assets
|
|
1467
|
+
* @param args.maxShares - Optional exact share amount for max migration
|
|
1468
|
+
* @param args.enableCollateralTo - Optional override for enabling destination collateral
|
|
1469
|
+
* @param args.disableCollateralFrom - Optional override for disabling source collateral
|
|
1470
|
+
* @returns Array of transaction plan items (EVC batch; no token approvals)
|
|
1471
|
+
*/
|
|
1472
|
+
planMigrateSameAssetCollateral(args) {
|
|
1473
|
+
const { account, fromVault, toVault, amount, positionAccount, fromAsset, toAsset, isMax = false, maxShares, enableCollateralTo, disableCollateralFrom, } = args;
|
|
1474
|
+
const plan = [];
|
|
1475
|
+
const sourcePosition = account?.getPosition(positionAccount, fromVault);
|
|
1476
|
+
const resolvedFromAsset = fromAsset ?? sourcePosition?.asset;
|
|
1477
|
+
if (!resolvedFromAsset) {
|
|
1478
|
+
throw new Error(`Position not found. From vault: ${fromVault}, Account: ${positionAccount}. Source asset is required when position is not available.`);
|
|
1479
|
+
}
|
|
1480
|
+
if (getAddress(resolvedFromAsset) !== getAddress(toAsset)) {
|
|
1481
|
+
throw new Error("planMigrateSameAssetCollateral only supports same-asset vault migrations. Use planSwapCollateral for cross-asset migrations.");
|
|
1482
|
+
}
|
|
1483
|
+
const shouldEnableCollateralTo = enableCollateralTo ??
|
|
1484
|
+
!account.isCollateralEnabled(positionAccount, toVault);
|
|
1485
|
+
const shouldDisableCollateralFrom = disableCollateralFrom ??
|
|
1486
|
+
(isMax && account.isCollateralEnabled(positionAccount, fromVault));
|
|
1487
|
+
const batchItems = this.encodeMigrateSameAssetCollateral({
|
|
1488
|
+
chainId: account.chainId,
|
|
1489
|
+
fromVault,
|
|
1490
|
+
toVault,
|
|
1491
|
+
amount,
|
|
1492
|
+
account: positionAccount,
|
|
1493
|
+
isMax,
|
|
1494
|
+
maxShares: maxShares ?? (isMax ? sourcePosition?.shares : undefined),
|
|
1495
|
+
enableCollateralTo: shouldEnableCollateralTo,
|
|
1496
|
+
disableCollateralFrom: shouldDisableCollateralFrom,
|
|
1943
1497
|
});
|
|
1498
|
+
plan.push(...this.convertBatchItemsToPlan(batchItems, "migrateSameAssetCollateral"));
|
|
1499
|
+
return plan;
|
|
1500
|
+
}
|
|
1501
|
+
/**
|
|
1502
|
+
* Builds a transaction plan for migrating a full same-asset debt position from one liability vault to another.
|
|
1503
|
+
* This is the no-swap path for debt vault migration and repays the old vault with shares after borrowing
|
|
1504
|
+
* slightly more from the new vault to cover interest accrual.
|
|
1505
|
+
*
|
|
1506
|
+
* @param args - Same-asset debt migration plan arguments
|
|
1507
|
+
* @param args.oldLiabilityVault - Existing debt vault to fully repay and disable
|
|
1508
|
+
* @param args.newLiabilityVault - New same-asset debt vault to borrow from
|
|
1509
|
+
* @param args.liabilityAccount - Sub-account that owns the debt position
|
|
1510
|
+
* @param args.liabilityAmount - Current debt amount; defaults to the old-vault borrowed amount in account data
|
|
1511
|
+
* @param args.oldLiabilityAsset - Optional old liability asset; defaults to the old-vault account position asset
|
|
1512
|
+
* @param args.newLiabilityAsset - New liability underlying asset, used to verify this is a same-asset migration
|
|
1513
|
+
* @param args.sweepExcess - Whether to redeem and skim the migration cushion back into the new vault (default true)
|
|
1514
|
+
* @param args.transferRemainingSharesToOwner - Whether to transfer new-vault shares to the owner when liabilityAccount differs from owner (default true)
|
|
1515
|
+
* @returns Array of transaction plan items (EVC batch; no token approvals)
|
|
1516
|
+
*/
|
|
1517
|
+
planMigrateSameAssetDebt(args) {
|
|
1518
|
+
const { account, oldLiabilityVault, newLiabilityVault, liabilityAccount, liabilityAmount, oldLiabilityAsset, newLiabilityAsset, sweepExcess = true, transferRemainingSharesToOwner = true, } = args;
|
|
1519
|
+
const plan = [];
|
|
1520
|
+
const oldPosition = account?.getPosition(liabilityAccount, oldLiabilityVault);
|
|
1521
|
+
const resolvedOldAsset = oldLiabilityAsset ?? oldPosition?.asset;
|
|
1522
|
+
if (!resolvedOldAsset) {
|
|
1523
|
+
throw new Error(`Position not found. Old liability vault: ${oldLiabilityVault}, Account: ${liabilityAccount}. Old liability asset is required when position is not available.`);
|
|
1524
|
+
}
|
|
1525
|
+
if (getAddress(resolvedOldAsset) !== getAddress(newLiabilityAsset)) {
|
|
1526
|
+
throw new Error("planMigrateSameAssetDebt only supports same-asset debt migrations. Use planSwapDebt for cross-asset migrations.");
|
|
1527
|
+
}
|
|
1528
|
+
const amount = liabilityAmount ?? oldPosition?.borrowed;
|
|
1529
|
+
if (!amount || amount <= 0n) {
|
|
1530
|
+
throw new Error(`Debt position not found or liability is 0. Old liability vault: ${oldLiabilityVault}, Account: ${liabilityAccount}`);
|
|
1531
|
+
}
|
|
1532
|
+
const enableController = !account.isControllerEnabled(liabilityAccount, newLiabilityVault);
|
|
1533
|
+
const transferRemainingSharesTo = transferRemainingSharesToOwner &&
|
|
1534
|
+
getAddress(liabilityAccount) !== getAddress(account.owner)
|
|
1535
|
+
? account.owner
|
|
1536
|
+
: undefined;
|
|
1537
|
+
const batchItems = this.encodeMigrateSameAssetDebt({
|
|
1538
|
+
chainId: account.chainId,
|
|
1539
|
+
oldLiabilityVault,
|
|
1540
|
+
newLiabilityVault,
|
|
1541
|
+
amount,
|
|
1542
|
+
account: liabilityAccount,
|
|
1543
|
+
enableController,
|
|
1544
|
+
disableController: true,
|
|
1545
|
+
sweepExcess,
|
|
1546
|
+
transferRemainingSharesTo,
|
|
1547
|
+
});
|
|
1548
|
+
plan.push(...this.convertBatchItemsToPlan(batchItems, "migrateSameAssetDebt"));
|
|
1944
1549
|
return plan;
|
|
1945
1550
|
}
|
|
1946
1551
|
/**
|
|
@@ -1971,10 +1576,7 @@ export class ExecutionService {
|
|
|
1971
1576
|
disableCollateralFrom: disableCollateralFrom &&
|
|
1972
1577
|
(account?.isCollateralEnabled(from, vault) ?? false),
|
|
1973
1578
|
});
|
|
1974
|
-
plan.push(
|
|
1975
|
-
type: "evcBatch",
|
|
1976
|
-
items: batchItems,
|
|
1977
|
-
});
|
|
1579
|
+
plan.push(...this.convertBatchItemsToPlan(batchItems, "transfer"));
|
|
1978
1580
|
return plan;
|
|
1979
1581
|
}
|
|
1980
1582
|
/**
|
|
@@ -2001,10 +1603,7 @@ export class ExecutionService {
|
|
|
2001
1603
|
to,
|
|
2002
1604
|
enableController,
|
|
2003
1605
|
});
|
|
2004
|
-
plan.push(
|
|
2005
|
-
type: "evcBatch",
|
|
2006
|
-
items: batchItems,
|
|
2007
|
-
});
|
|
1606
|
+
plan.push(...this.convertBatchItemsToPlan(batchItems, "pullDebt"));
|
|
2008
1607
|
return plan;
|
|
2009
1608
|
}
|
|
2010
1609
|
/**
|
|
@@ -2020,10 +1619,10 @@ export class ExecutionService {
|
|
|
2020
1619
|
* @returns Array of transaction plan items (optional approval + EVC batch). Throws if swapQuote.accountIn !== swapQuote.accountOut.
|
|
2021
1620
|
*/
|
|
2022
1621
|
planMultiplyWithSwap(args) {
|
|
2023
|
-
const { collateralVault, collateralAmount, collateralAsset, account, swapQuote, } = args;
|
|
1622
|
+
const { collateralVault, collateralAmount, collateralAsset, collateralShareSource, account, swapQuote, } = args;
|
|
2024
1623
|
const plan = [];
|
|
2025
1624
|
// 1. Check if collateral approval is needed (only if depositing collateral)
|
|
2026
|
-
if (collateralAmount > 0n) {
|
|
1625
|
+
if (!collateralShareSource && collateralAmount > 0n) {
|
|
2027
1626
|
// Add approval requirement (will be resolved later with Wallet data)
|
|
2028
1627
|
plan.push({
|
|
2029
1628
|
type: "requiredApproval",
|
|
@@ -2041,8 +1640,19 @@ export class ExecutionService {
|
|
|
2041
1640
|
const longVault = swapQuote.receiver;
|
|
2042
1641
|
const liabilityAmount = BigInt(swapQuote.amountIn);
|
|
2043
1642
|
// 2. Determine if collateral needs to be enabled
|
|
2044
|
-
const
|
|
1643
|
+
const hasCollateralInput = collateralShareSource
|
|
1644
|
+
? collateralShareSource.shares > 0n
|
|
1645
|
+
: collateralAmount > 0n;
|
|
1646
|
+
const enableCollateral = hasCollateralInput &&
|
|
2045
1647
|
!(account?.isCollateralEnabled(receiver, collateralVault) ?? false);
|
|
1648
|
+
const resolvedCollateralShareSource = collateralShareSource
|
|
1649
|
+
? {
|
|
1650
|
+
...collateralShareSource,
|
|
1651
|
+
disableCollateralFrom: collateralShareSource.disableCollateralFrom &&
|
|
1652
|
+
(account?.isCollateralEnabled(collateralShareSource.from, collateralVault) ??
|
|
1653
|
+
false),
|
|
1654
|
+
}
|
|
1655
|
+
: undefined;
|
|
2046
1656
|
// 3. Determine if controller needs to be enabled
|
|
2047
1657
|
const enableController = !(account?.isControllerEnabled(receiver, liabilityVault) ?? false);
|
|
2048
1658
|
// 4. Get current controller (may need to disable if different)
|
|
@@ -2060,13 +1670,11 @@ export class ExecutionService {
|
|
|
2060
1670
|
enableCollateral,
|
|
2061
1671
|
currentController: currentController || undefined,
|
|
2062
1672
|
enableController,
|
|
1673
|
+
collateralShareSource: resolvedCollateralShareSource,
|
|
2063
1674
|
swapQuote,
|
|
2064
1675
|
// Permit2 is handled separately in the plan
|
|
2065
1676
|
});
|
|
2066
|
-
plan.push(
|
|
2067
|
-
type: "evcBatch",
|
|
2068
|
-
items: batchItems,
|
|
2069
|
-
});
|
|
1677
|
+
plan.push(...this.convertBatchItemsToPlan(batchItems, "multiplyWithSwap"));
|
|
2070
1678
|
return plan;
|
|
2071
1679
|
}
|
|
2072
1680
|
/**
|
|
@@ -2085,10 +1693,10 @@ export class ExecutionService {
|
|
|
2085
1693
|
* @returns Array of transaction plan items (optional approval + EVC batch)
|
|
2086
1694
|
*/
|
|
2087
1695
|
planMultiplySameAsset(args) {
|
|
2088
|
-
const { collateralVault, collateralAmount, collateralAsset, liabilityVault, liabilityAmount, longVault, receiver, account, } = args;
|
|
1696
|
+
const { collateralVault, collateralAmount, collateralAsset, collateralShareSource, liabilityVault, liabilityAmount, longVault, receiver, account, } = args;
|
|
2089
1697
|
const plan = [];
|
|
2090
1698
|
// 1. Check if collateral approval is needed (only if depositing collateral)
|
|
2091
|
-
if (collateralAmount > 0n) {
|
|
1699
|
+
if (!collateralShareSource && collateralAmount > 0n) {
|
|
2092
1700
|
// Add approval requirement (will be resolved later with Wallet data)
|
|
2093
1701
|
plan.push({
|
|
2094
1702
|
type: "requiredApproval",
|
|
@@ -2099,8 +1707,19 @@ export class ExecutionService {
|
|
|
2099
1707
|
});
|
|
2100
1708
|
}
|
|
2101
1709
|
// 2. Determine if collateral needs to be enabled
|
|
2102
|
-
const
|
|
1710
|
+
const hasCollateralInput = collateralShareSource
|
|
1711
|
+
? collateralShareSource.shares > 0n
|
|
1712
|
+
: collateralAmount > 0n;
|
|
1713
|
+
const enableCollateral = hasCollateralInput &&
|
|
2103
1714
|
!(account?.isCollateralEnabled(receiver, collateralVault) ?? false);
|
|
1715
|
+
const resolvedCollateralShareSource = collateralShareSource
|
|
1716
|
+
? {
|
|
1717
|
+
...collateralShareSource,
|
|
1718
|
+
disableCollateralFrom: collateralShareSource.disableCollateralFrom &&
|
|
1719
|
+
(account?.isCollateralEnabled(collateralShareSource.from, collateralVault) ??
|
|
1720
|
+
false),
|
|
1721
|
+
}
|
|
1722
|
+
: undefined;
|
|
2104
1723
|
// 3. Determine if controller needs to be enabled
|
|
2105
1724
|
const enableController = !(account?.isControllerEnabled(receiver, liabilityVault) ?? false);
|
|
2106
1725
|
// 4. Get current controller (may need to disable if different)
|
|
@@ -2118,12 +1737,10 @@ export class ExecutionService {
|
|
|
2118
1737
|
enableCollateral,
|
|
2119
1738
|
currentController: currentController || undefined,
|
|
2120
1739
|
enableController,
|
|
1740
|
+
collateralShareSource: resolvedCollateralShareSource,
|
|
2121
1741
|
// Permit2 is handled separately in the plan
|
|
2122
1742
|
});
|
|
2123
|
-
plan.push(
|
|
2124
|
-
type: "evcBatch",
|
|
2125
|
-
items: batchItems,
|
|
2126
|
-
});
|
|
1743
|
+
plan.push(...this.convertBatchItemsToPlan(batchItems, "multiplySameAsset"));
|
|
2127
1744
|
return plan;
|
|
2128
1745
|
}
|
|
2129
1746
|
}
|