@morpho-org/consumer-sdk 0.1.8 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,7 +1,10 @@
1
1
  import type { Action } from "@morpho-org/bundler-sdk-viem";
2
- import type { Permit2Action, PermitAction, PermitArgs } from "../../types";
2
+ import { type Address } from "viem";
3
+ import { type Permit2Action, type PermitAction, type PermitArgs } from "../../types";
3
4
  interface GetRequirementsActionParams {
4
5
  chainId: number;
6
+ asset: Address;
7
+ assets: bigint;
5
8
  requirementSignature: {
6
9
  args: PermitArgs;
7
10
  action: PermitAction | Permit2Action;
@@ -10,5 +13,5 @@ interface GetRequirementsActionParams {
10
13
  /**
11
14
  * Get the actions required to transfer the asset based on the requirement signature.
12
15
  */
13
- export declare const getRequirementsAction: ({ chainId, requirementSignature, }: GetRequirementsActionParams) => Action[];
16
+ export declare const getRequirementsAction: ({ chainId, asset, assets, requirementSignature, }: GetRequirementsActionParams) => Action[];
14
17
  export {};
@@ -2,10 +2,18 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.getRequirementsAction = void 0;
4
4
  const blue_sdk_1 = require("@morpho-org/blue-sdk");
5
+ const viem_1 = require("viem");
6
+ const types_1 = require("../../types");
5
7
  /**
6
8
  * Get the actions required to transfer the asset based on the requirement signature.
7
9
  */
8
- const getRequirementsAction = ({ chainId, requirementSignature, }) => {
10
+ const getRequirementsAction = ({ chainId, asset, assets, requirementSignature, }) => {
11
+ if (!(0, viem_1.isAddressEqual)(requirementSignature.args.asset, asset)) {
12
+ throw new types_1.DepositAssetMismatchError(asset, requirementSignature.args.asset);
13
+ }
14
+ if (requirementSignature.args.amount !== assets) {
15
+ throw new types_1.DepositAmountMismatchError(assets, requirementSignature.args.amount);
16
+ }
9
17
  const { bundler3: { generalAdapter1 }, } = (0, blue_sdk_1.getChainAddresses)(chainId);
10
18
  if (requirementSignature.action.type === "permit2") {
11
19
  if (!("expiration" in requirementSignature.args)) {
@@ -31,12 +39,7 @@ const getRequirementsAction = ({ chainId, requirementSignature, }) => {
31
39
  },
32
40
  {
33
41
  type: "transferFrom2",
34
- args: [
35
- requirementSignature.args.asset,
36
- requirementSignature.args.amount,
37
- generalAdapter1,
38
- false,
39
- ],
42
+ args: [asset, assets, generalAdapter1, false],
40
43
  },
41
44
  ];
42
45
  }
@@ -54,12 +57,7 @@ const getRequirementsAction = ({ chainId, requirementSignature, }) => {
54
57
  },
55
58
  {
56
59
  type: "erc20TransferFrom",
57
- args: [
58
- requirementSignature.args.asset,
59
- requirementSignature.args.amount,
60
- generalAdapter1,
61
- false,
62
- ],
60
+ args: [asset, assets, generalAdapter1, false],
63
61
  },
64
62
  ];
65
63
  };
@@ -45,7 +45,12 @@ const vaultV2Deposit = ({ vault: { chainId, address: vaultAddress, asset }, args
45
45
  }
46
46
  const actions = [];
47
47
  if (requirementSignature) {
48
- actions.push(...(0, getRequirementsAction_1.getRequirementsAction)({ chainId, requirementSignature }));
48
+ actions.push(...(0, getRequirementsAction_1.getRequirementsAction)({
49
+ chainId,
50
+ asset,
51
+ assets,
52
+ requirementSignature,
53
+ }));
49
54
  }
50
55
  else {
51
56
  const { bundler3: { generalAdapter1 }, } = (0, blue_sdk_1.getChainAddresses)(chainId);
@@ -0,0 +1,48 @@
1
+ import { type Address } from "viem";
2
+ import { type Deallocation, type Metadata, type Transaction, type VaultV2ForceRedeemAction } from "../../types";
3
+ export interface VaultV2ForceRedeemParams {
4
+ vault: {
5
+ address: Address;
6
+ };
7
+ args: {
8
+ deallocations: readonly Deallocation[];
9
+ redeem: {
10
+ shares: bigint;
11
+ recipient: Address;
12
+ };
13
+ onBehalf: Address;
14
+ };
15
+ metadata?: Metadata;
16
+ }
17
+ /**
18
+ * Prepares a force redeem transaction for the VaultV2 contract, using VaultV2's native `multicall`.
19
+ *
20
+ * This function encodes one or more `forceDeallocate` calls followed by a single `redeem`,
21
+ * executed atomically via VaultV2's `multicall`. This allows a user to free liquidity from
22
+ * adapters other than the liquidity adapter and redeem all their shares in one transaction.
23
+
24
+ *
25
+ * This is the share-based counterpart to `vaultV2ForceWithdraw`, useful when the user wants
26
+ * to redeem a maximum amount of shares rather than specifying an exact asset amount.
27
+ *
28
+ * The total assets passed to `forceDeallocate` calls must be greater than or equal to the
29
+ * asset-equivalent of the redeemed shares. The caller should apply a buffer on the deallocated
30
+ * amounts to account for share-price drift between submission and execution.
31
+ *
32
+ * A penalty is taken from `onBehalf` for each deallocation to discourage allocation manipulations.
33
+ * The penalty is applied as a share burn where assets are returned to the vault, so the share price
34
+ * remains stable (except for rounding).
35
+ *
36
+ * @param {Object} params - The vault related parameters.
37
+ * @param {Object} params.vault - The vault related parameters.
38
+ * @param {Address} params.vault.address - The vault contract address.
39
+ * @param {Object} params.args - The force redeem related parameters.
40
+ * @param {readonly Deallocation[]} params.args.deallocations - The list of deallocations to perform.
41
+ * @param {Object} params.args.redeem - The redeem parameters applied after deallocations.
42
+ * @param {bigint} params.args.redeem.shares - The amount of shares to redeem.
43
+ * @param {Address} params.args.redeem.recipient - The recipient of the redeemed assets.
44
+ * @param {Address} params.args.onBehalf - The address from which the penalty is taken (share owner).
45
+ * @param {Metadata} [params.metadata] - Optional analytics metadata to append.
46
+ * @returns {Readonly<Transaction<VaultV2ForceRedeemAction>>} The prepared multicall transaction.
47
+ */
48
+ export declare const vaultV2ForceRedeem: ({ vault: { address: vaultAddress }, args: { deallocations, redeem, onBehalf }, metadata, }: VaultV2ForceRedeemParams) => Readonly<Transaction<VaultV2ForceRedeemAction>>;
@@ -0,0 +1,85 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.vaultV2ForceRedeem = void 0;
4
+ const blue_sdk_viem_1 = require("@morpho-org/blue-sdk-viem");
5
+ const morpho_ts_1 = require("@morpho-org/morpho-ts");
6
+ const viem_1 = require("viem");
7
+ const helpers_1 = require("../../helpers");
8
+ const encodeDeallocation_1 = require("../../helpers/encodeDeallocation");
9
+ const types_1 = require("../../types");
10
+ /**
11
+ * Prepares a force redeem transaction for the VaultV2 contract, using VaultV2's native `multicall`.
12
+ *
13
+ * This function encodes one or more `forceDeallocate` calls followed by a single `redeem`,
14
+ * executed atomically via VaultV2's `multicall`. This allows a user to free liquidity from
15
+ * adapters other than the liquidity adapter and redeem all their shares in one transaction.
16
+
17
+ *
18
+ * This is the share-based counterpart to `vaultV2ForceWithdraw`, useful when the user wants
19
+ * to redeem a maximum amount of shares rather than specifying an exact asset amount.
20
+ *
21
+ * The total assets passed to `forceDeallocate` calls must be greater than or equal to the
22
+ * asset-equivalent of the redeemed shares. The caller should apply a buffer on the deallocated
23
+ * amounts to account for share-price drift between submission and execution.
24
+ *
25
+ * A penalty is taken from `onBehalf` for each deallocation to discourage allocation manipulations.
26
+ * The penalty is applied as a share burn where assets are returned to the vault, so the share price
27
+ * remains stable (except for rounding).
28
+ *
29
+ * @param {Object} params - The vault related parameters.
30
+ * @param {Object} params.vault - The vault related parameters.
31
+ * @param {Address} params.vault.address - The vault contract address.
32
+ * @param {Object} params.args - The force redeem related parameters.
33
+ * @param {readonly Deallocation[]} params.args.deallocations - The list of deallocations to perform.
34
+ * @param {Object} params.args.redeem - The redeem parameters applied after deallocations.
35
+ * @param {bigint} params.args.redeem.shares - The amount of shares to redeem.
36
+ * @param {Address} params.args.redeem.recipient - The recipient of the redeemed assets.
37
+ * @param {Address} params.args.onBehalf - The address from which the penalty is taken (share owner).
38
+ * @param {Metadata} [params.metadata] - Optional analytics metadata to append.
39
+ * @returns {Readonly<Transaction<VaultV2ForceRedeemAction>>} The prepared multicall transaction.
40
+ */
41
+ const vaultV2ForceRedeem = ({ vault: { address: vaultAddress }, args: { deallocations, redeem, onBehalf }, metadata, }) => {
42
+ if (deallocations.length === 0) {
43
+ throw new types_1.EmptyDeallocationsError(vaultAddress);
44
+ }
45
+ if (redeem.shares === 0n) {
46
+ throw new types_1.ZeroSharesAmountError(vaultAddress);
47
+ }
48
+ const calls = [];
49
+ for (const deallocation of deallocations) {
50
+ calls.push((0, encodeDeallocation_1.encodeForceDeallocateCall)(deallocation, onBehalf));
51
+ }
52
+ calls.push((0, viem_1.encodeFunctionData)({
53
+ abi: blue_sdk_viem_1.vaultV2Abi,
54
+ functionName: "redeem",
55
+ args: [redeem.shares, redeem.recipient, onBehalf],
56
+ }));
57
+ let tx = {
58
+ to: vaultAddress,
59
+ data: (0, viem_1.encodeFunctionData)({
60
+ abi: blue_sdk_viem_1.vaultV2Abi,
61
+ functionName: "multicall",
62
+ args: [calls],
63
+ }),
64
+ value: 0n,
65
+ };
66
+ if (metadata) {
67
+ tx = (0, helpers_1.addTransactionMetadata)(tx, metadata);
68
+ }
69
+ return (0, morpho_ts_1.deepFreeze)({
70
+ ...tx,
71
+ action: {
72
+ type: "vaultV2ForceRedeem",
73
+ args: {
74
+ vault: vaultAddress,
75
+ deallocations: deallocations.map((d) => ({ ...d })),
76
+ redeem: {
77
+ shares: redeem.shares,
78
+ recipient: redeem.recipient,
79
+ },
80
+ onBehalf,
81
+ },
82
+ },
83
+ });
84
+ };
85
+ exports.vaultV2ForceRedeem = vaultV2ForceRedeem;
@@ -0,0 +1,40 @@
1
+ import { type Address } from "viem";
2
+ import { type Deallocation, type Metadata, type Transaction, type VaultV2ForceWithdrawAction } from "../../types";
3
+ export interface VaultV2ForceWithdrawParams {
4
+ vault: {
5
+ address: Address;
6
+ };
7
+ args: {
8
+ deallocations: readonly Deallocation[];
9
+ withdraw: {
10
+ assets: bigint;
11
+ recipient: Address;
12
+ };
13
+ onBehalf: Address;
14
+ };
15
+ metadata?: Metadata;
16
+ }
17
+ /**
18
+ * Prepares a force withdraw transaction for the VaultV2 contract, using VaultV2's native `multicall`.
19
+ *
20
+ * This function encodes one or more `forceDeallocate` calls followed by a single `withdraw`,
21
+ * executed atomically via VaultV2's `multicall`. This allows a user to free liquidity from
22
+ * adapters other than the liquidity adapter and withdraw the resulting assets in one transaction.
23
+ *
24
+ * A penalty is taken from `onBehalf` for each deallocation to discourage allocation manipulations.
25
+ * The penalty is applied as a share burn where assets are returned to the vault, so the share price
26
+ * remains stable (except for rounding).
27
+ *
28
+ * @param {Object} params - The vault related parameters.
29
+ * @param {Object} params.vault - The vault related parameters.
30
+ * @param {Address} params.vault.address - The vault contract address.
31
+ * @param {Object} params.args - The force withdraw related parameters.
32
+ * @param {readonly Deallocation[]} params.args.deallocations - The list of deallocations to perform.
33
+ * @param {Object} params.args.withdraw - The withdraw parameters applied after deallocations.
34
+ * @param {bigint} params.args.withdraw.assets - The amount of assets to withdraw.
35
+ * @param {Address} params.args.withdraw.recipient - The recipient of the withdrawn assets.
36
+ * @param {Address} params.args.onBehalf - The address from which the penalty is taken (share owner).
37
+ * @param {Metadata} [params.metadata] - Optional analytics metadata to append.
38
+ * @returns {Readonly<Transaction<VaultV2ForceWithdrawAction>>} The prepared multicall transaction.
39
+ */
40
+ export declare const vaultV2ForceWithdraw: ({ vault: { address: vaultAddress }, args: { deallocations, withdraw, onBehalf }, metadata, }: VaultV2ForceWithdrawParams) => Readonly<Transaction<VaultV2ForceWithdrawAction>>;
@@ -0,0 +1,81 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.vaultV2ForceWithdraw = void 0;
4
+ const blue_sdk_viem_1 = require("@morpho-org/blue-sdk-viem");
5
+ const morpho_ts_1 = require("@morpho-org/morpho-ts");
6
+ const viem_1 = require("viem");
7
+ const helpers_1 = require("../../helpers");
8
+ const encodeDeallocation_1 = require("../../helpers/encodeDeallocation");
9
+ const types_1 = require("../../types");
10
+ /**
11
+ * Prepares a force withdraw transaction for the VaultV2 contract, using VaultV2's native `multicall`.
12
+ *
13
+ * This function encodes one or more `forceDeallocate` calls followed by a single `withdraw`,
14
+ * executed atomically via VaultV2's `multicall`. This allows a user to free liquidity from
15
+ * adapters other than the liquidity adapter and withdraw the resulting assets in one transaction.
16
+ *
17
+ * A penalty is taken from `onBehalf` for each deallocation to discourage allocation manipulations.
18
+ * The penalty is applied as a share burn where assets are returned to the vault, so the share price
19
+ * remains stable (except for rounding).
20
+ *
21
+ * @param {Object} params - The vault related parameters.
22
+ * @param {Object} params.vault - The vault related parameters.
23
+ * @param {Address} params.vault.address - The vault contract address.
24
+ * @param {Object} params.args - The force withdraw related parameters.
25
+ * @param {readonly Deallocation[]} params.args.deallocations - The list of deallocations to perform.
26
+ * @param {Object} params.args.withdraw - The withdraw parameters applied after deallocations.
27
+ * @param {bigint} params.args.withdraw.assets - The amount of assets to withdraw.
28
+ * @param {Address} params.args.withdraw.recipient - The recipient of the withdrawn assets.
29
+ * @param {Address} params.args.onBehalf - The address from which the penalty is taken (share owner).
30
+ * @param {Metadata} [params.metadata] - Optional analytics metadata to append.
31
+ * @returns {Readonly<Transaction<VaultV2ForceWithdrawAction>>} The prepared multicall transaction.
32
+ */
33
+ const vaultV2ForceWithdraw = ({ vault: { address: vaultAddress }, args: { deallocations, withdraw, onBehalf }, metadata, }) => {
34
+ if (deallocations.length === 0) {
35
+ throw new types_1.EmptyDeallocationsError(vaultAddress);
36
+ }
37
+ if (withdraw.assets === 0n) {
38
+ throw new types_1.ZeroAssetAmountError(vaultAddress);
39
+ }
40
+ const totalDeallocated = deallocations.reduce((sum, d) => sum + d.assets, 0n);
41
+ if (withdraw.assets < totalDeallocated) {
42
+ throw new types_1.DeallocationsExceedWithdrawError(vaultAddress, withdraw.assets, totalDeallocated);
43
+ }
44
+ const calls = [];
45
+ for (const deallocation of deallocations) {
46
+ calls.push((0, encodeDeallocation_1.encodeForceDeallocateCall)(deallocation, onBehalf));
47
+ }
48
+ calls.push((0, viem_1.encodeFunctionData)({
49
+ abi: blue_sdk_viem_1.vaultV2Abi,
50
+ functionName: "withdraw",
51
+ args: [withdraw.assets, withdraw.recipient, onBehalf],
52
+ }));
53
+ let tx = {
54
+ to: vaultAddress,
55
+ data: (0, viem_1.encodeFunctionData)({
56
+ abi: blue_sdk_viem_1.vaultV2Abi,
57
+ functionName: "multicall",
58
+ args: [calls],
59
+ }),
60
+ value: 0n,
61
+ };
62
+ if (metadata) {
63
+ tx = (0, helpers_1.addTransactionMetadata)(tx, metadata);
64
+ }
65
+ return (0, morpho_ts_1.deepFreeze)({
66
+ ...tx,
67
+ action: {
68
+ type: "vaultV2ForceWithdraw",
69
+ args: {
70
+ vault: vaultAddress,
71
+ deallocations: deallocations.map((d) => ({ ...d })),
72
+ withdraw: {
73
+ assets: withdraw.assets,
74
+ recipient: withdraw.recipient,
75
+ },
76
+ onBehalf,
77
+ },
78
+ },
79
+ });
80
+ };
81
+ exports.vaultV2ForceWithdraw = vaultV2ForceWithdraw;
@@ -1,3 +1,5 @@
1
1
  export * from "./deposit";
2
+ export * from "./forceRedeem";
3
+ export * from "./forceWithdraw";
2
4
  export * from "./redeem";
3
5
  export * from "./withdraw";
@@ -15,5 +15,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
17
  __exportStar(require("./deposit"), exports);
18
+ __exportStar(require("./forceRedeem"), exports);
19
+ __exportStar(require("./forceWithdraw"), exports);
18
20
  __exportStar(require("./redeem"), exports);
19
21
  __exportStar(require("./withdraw"), exports);
@@ -6,6 +6,8 @@ import { MorphoClient } from "./morphoClient";
6
6
  * Adds `morpho` namespace to viem clients with vaultV2 actions.
7
7
  *
8
8
  * @param metadata - (Optional) Metadata object that will be passed to all morpho actions. If provided, this metadata can be used for analytics, logging, or to carry additional information with each action.
9
+ * @param supportSignature - (Optional) Whether to support off-chain signature requirements. If true, the SDK will try to use permit or permit2 if the token supports it.
10
+ * @param supportDeployless - (Optional) Whether to support deployless mode. If true, the SDK will use the deployless mode to fetch data.
9
11
  * @returns Extension function that adds morpho namespace to viem clients
10
12
  *
11
13
  * @example
@@ -26,8 +28,9 @@ import { MorphoClient } from "./morphoClient";
26
28
  * ```
27
29
  */
28
30
  export declare function morphoViemExtension(_options?: {
29
- metadata?: Metadata;
30
- supportSignature?: boolean;
31
+ readonly metadata?: Metadata;
32
+ readonly supportSignature?: boolean;
33
+ readonly supportDeployless?: boolean;
31
34
  }): <TClient extends Client>(client: TClient) => {
32
35
  morpho: MorphoClient;
33
36
  };
@@ -7,6 +7,8 @@ const morphoClient_1 = require("./morphoClient");
7
7
  * Adds `morpho` namespace to viem clients with vaultV2 actions.
8
8
  *
9
9
  * @param metadata - (Optional) Metadata object that will be passed to all morpho actions. If provided, this metadata can be used for analytics, logging, or to carry additional information with each action.
10
+ * @param supportSignature - (Optional) Whether to support off-chain signature requirements. If true, the SDK will try to use permit or permit2 if the token supports it.
11
+ * @param supportDeployless - (Optional) Whether to support deployless mode. If true, the SDK will use the deployless mode to fetch data.
10
12
  * @returns Extension function that adds morpho namespace to viem clients
11
13
  *
12
14
  * @example
@@ -1,15 +1,17 @@
1
1
  import { fetchAccrualVaultV2 } from "@morpho-org/blue-sdk-viem";
2
2
  import type { Address } from "viem";
3
- import { type ERC20ApprovalAction, type MorphoClientType, type Requirement, type RequirementSignature, type Transaction, type VaultV2DepositAction, type VaultV2RedeemAction, type VaultV2WithdrawAction } from "../../types";
3
+ import { type Deallocation, type ERC20ApprovalAction, type MorphoClientType, type Requirement, type RequirementSignature, type Transaction, type VaultV2DepositAction, type VaultV2ForceRedeemAction, type VaultV2ForceWithdrawAction, type VaultV2RedeemAction, type VaultV2WithdrawAction } from "../../types";
4
+ import type { FetchParameters } from "../../types/data";
4
5
  export interface VaultV2Actions {
5
6
  /**
6
7
  * Fetches the latest vault data.
7
8
  *
8
9
  * This function fetches the latest vault data from the blockchain.
10
+ * @param {FetchParameters} [parameters] - The parameters for the fetch operation.
9
11
  *
10
12
  * @returns {Promise<Awaited<ReturnType<typeof fetchAccrualVaultV2>>>} The latest vault data.
11
13
  */
12
- getData: () => Promise<Awaited<ReturnType<typeof fetchAccrualVaultV2>>>;
14
+ getData: (parameters?: FetchParameters) => Promise<Awaited<ReturnType<typeof fetchAccrualVaultV2>>>;
13
15
  /**
14
16
  * Prepares a deposit transaction for the VaultV2 contract.
15
17
  *
@@ -21,7 +23,7 @@ export interface VaultV2Actions {
21
23
  * @param {Object} params - The deposit parameters.
22
24
  * @param {bigint} params.assets - The amount of assets to deposit.
23
25
  * @param {Address} [params.userAddress] - Optional user address initiating the deposit. Default is the client's user address is used.
24
- * @param {bigint} [params.slippageTolerance=DEFAULT_SLIPPAGE_TOLERANCE] - Optional slippage tolerance value. Default is 0.03%.
26
+ * @param {bigint} [params.slippageTolerance=DEFAULT_SLIPPAGE_TOLERANCE] - Optional slippage tolerance value. Default is 0.03%. Slippage tolerance must be less than 10%.
25
27
  * @returns {Object} The result object.
26
28
  * @returns {Readonly<Transaction<VaultV2DepositAction>>} returns.tx The prepared deposit transaction.
27
29
  * @returns {Promise<Readonly<Transaction<ERC20ApprovalAction>[]>>} returns.getRequirements The function for retrieving all required approval transactions.
@@ -43,7 +45,7 @@ export interface VaultV2Actions {
43
45
  *
44
46
  * @param {Object} params - The withdraw parameters.
45
47
  * @param {bigint} params.assets - The amount of assets to withdraw.
46
- * @param {Address} [params.userAddress] - Optional user address initiating the withdraw.
48
+ * @param {Address} params.userAddress - User address initiating the withdraw.
47
49
  * @returns {Object} The result object.
48
50
  * @returns {Readonly<Transaction<VaultV2WithdrawAction>>} returns.tx The prepared withdraw transaction.
49
51
  */
@@ -60,7 +62,7 @@ export interface VaultV2Actions {
60
62
  *
61
63
  * @param {Object} params - The redeem parameters.
62
64
  * @param {bigint} params.shares - The amount of shares to redeem.
63
- * @param {Address} [params.userAddress] - Optional user address initiating the redeem.
65
+ * @param {Address} params.userAddress - User address initiating the redeem.
64
66
  * @returns {Object} The result object.
65
67
  * @returns {Readonly<Transaction<VaultV2RedeemAction>>} returns.tx The prepared redeem transaction.
66
68
  */
@@ -70,13 +72,68 @@ export interface VaultV2Actions {
70
72
  }) => {
71
73
  buildTx: () => Readonly<Transaction<VaultV2RedeemAction>>;
72
74
  };
75
+ /**
76
+ * Prepares a force withdraw transaction for the VaultV2 contract using the vault's native multicall.
77
+ *
78
+ * This function encodes one or more on-chain forceDeallocate calls followed by a single withdraw,
79
+ * executed atomically via VaultV2's multicall. This allows a user to free liquidity from multiple
80
+ * illiquid markets and withdraw the resulting assets in one transaction.
81
+ *
82
+ * @param {Object} params - The force withdraw parameters.
83
+ * @param {readonly Deallocation[]} params.deallocations - The typed list of deallocations to perform.
84
+ * @param {Object} params.withdraw - The withdraw parameters applied after deallocations.
85
+ * @param {bigint} params.withdraw.assets - The amount of assets to withdraw.
86
+ * @param {Address} params.userAddress - User address (penalty source and withdraw recipient).
87
+ * @returns {Object} The result object.
88
+ * @returns {Readonly<Transaction<VaultV2ForceWithdrawAction>>} returns.buildTx The prepared multicall transaction.
89
+ */
90
+ forceWithdraw: (params: {
91
+ deallocations: readonly Deallocation[];
92
+ withdraw: {
93
+ assets: bigint;
94
+ };
95
+ userAddress: Address;
96
+ }) => {
97
+ buildTx: () => Readonly<Transaction<VaultV2ForceWithdrawAction>>;
98
+ };
99
+ /**
100
+ * Prepares a force redeem transaction for the VaultV2 contract using the vault's native multicall.
101
+ *
102
+ * This function encodes one or more on-chain forceDeallocate calls followed by a single redeem,
103
+ * executed atomically via VaultV2's multicall. This allows a user to free liquidity from multiple
104
+ * illiquid markets and redeem all their shares in one transaction.
105
+ *
106
+ * This is the share-based counterpart to forceWithdraw, useful for maximum withdrawal scenarios
107
+ * where specifying an exact asset amount is impractical.
108
+ *
109
+ * The total assets passed to forceDeallocate calls must be greater than or equal to the
110
+ * asset-equivalent of the redeemed shares. The caller should apply a buffer on the deallocated
111
+ * amounts to account for share-price drift between submission and execution.
112
+ *
113
+ * @param {Object} params - The force redeem parameters.
114
+ * @param {readonly Deallocation[]} params.deallocations - The typed list of deallocations to perform.
115
+ * @param {Object} params.redeem - The redeem parameters applied after deallocations.
116
+ * @param {bigint} params.redeem.shares - The amount of shares to redeem.
117
+ * @param {Address} params.userAddress - User address (penalty source and redeem recipient).
118
+ * @returns {Object} The result object.
119
+ * @returns {Readonly<Transaction<VaultV2ForceRedeemAction>>} returns.buildTx The prepared multicall transaction.
120
+ */
121
+ forceRedeem: (params: {
122
+ deallocations: readonly Deallocation[];
123
+ redeem: {
124
+ shares: bigint;
125
+ };
126
+ userAddress: Address;
127
+ }) => {
128
+ buildTx: () => Readonly<Transaction<VaultV2ForceRedeemAction>>;
129
+ };
73
130
  }
74
131
  export declare class MorphoVaultV2 implements VaultV2Actions {
75
132
  private readonly client;
76
133
  private readonly vault;
77
134
  private readonly chainId;
78
135
  constructor(client: MorphoClientType, vault: Address, chainId: number);
79
- getData(): Promise<import("@morpho-org/blue-sdk").AccrualVaultV2>;
136
+ getData(parameters?: FetchParameters): Promise<import("@morpho-org/blue-sdk").AccrualVaultV2>;
80
137
  deposit({ assets, userAddress, slippageTolerance, }: {
81
138
  assets: bigint;
82
139
  userAddress: Address;
@@ -99,4 +156,22 @@ export declare class MorphoVaultV2 implements VaultV2Actions {
99
156
  }): {
100
157
  buildTx: () => Readonly<Transaction<VaultV2RedeemAction>>;
101
158
  };
159
+ forceWithdraw({ deallocations, withdraw, userAddress, }: {
160
+ deallocations: readonly Deallocation[];
161
+ withdraw: {
162
+ assets: bigint;
163
+ };
164
+ userAddress: Address;
165
+ }): {
166
+ buildTx: () => Readonly<Transaction<VaultV2ForceWithdrawAction>>;
167
+ };
168
+ forceRedeem({ deallocations, redeem, userAddress, }: {
169
+ deallocations: readonly Deallocation[];
170
+ redeem: {
171
+ shares: bigint;
172
+ };
173
+ userAddress: Address;
174
+ }): {
175
+ buildTx: () => Readonly<Transaction<VaultV2ForceRedeemAction>>;
176
+ };
102
177
  }
@@ -4,6 +4,7 @@ exports.MorphoVaultV2 = void 0;
4
4
  const blue_sdk_1 = require("@morpho-org/blue-sdk");
5
5
  const blue_sdk_viem_1 = require("@morpho-org/blue-sdk-viem");
6
6
  const actions_1 = require("../../actions");
7
+ const constant_1 = require("../../helpers/constant");
7
8
  const types_1 = require("../../types");
8
9
  class MorphoVaultV2 {
9
10
  client;
@@ -14,8 +15,9 @@ class MorphoVaultV2 {
14
15
  this.vault = vault;
15
16
  this.chainId = chainId;
16
17
  }
17
- async getData() {
18
+ async getData(parameters) {
18
19
  return (0, blue_sdk_viem_1.fetchAccrualVaultV2)(this.vault, this.client.viemClient, {
20
+ ...parameters,
19
21
  chainId: this.chainId,
20
22
  deployless: this.client.options.supportDeployless,
21
23
  });
@@ -28,7 +30,14 @@ class MorphoVaultV2 {
28
30
  chainId: this.chainId,
29
31
  deployless: this.client.options.supportDeployless,
30
32
  });
31
- const maxSharePrice = blue_sdk_1.MathLib.min(blue_sdk_1.MathLib.mulDivUp(assets, blue_sdk_1.MathLib.wToRay(blue_sdk_1.MathLib.WAD + slippageTolerance), vaultData.toShares(assets)), blue_sdk_1.MathLib.RAY * 100n);
33
+ if (slippageTolerance > constant_1.MAX_SLIPPAGE_TOLERANCE) {
34
+ throw new types_1.ExcessiveSlippageToleranceError(slippageTolerance);
35
+ }
36
+ const shares = vaultData.toShares(assets);
37
+ if (shares === 0n) {
38
+ throw new types_1.ZeroSharesAmountError(this.vault);
39
+ }
40
+ const maxSharePrice = blue_sdk_1.MathLib.min(blue_sdk_1.MathLib.mulDivUp(assets, blue_sdk_1.MathLib.wToRay(blue_sdk_1.MathLib.WAD + slippageTolerance), shares), blue_sdk_1.MathLib.RAY * 100n);
32
41
  return {
33
42
  getRequirements: async (params) => await (0, actions_1.getRequirements)(this.client.viemClient, {
34
43
  address: vaultData.asset,
@@ -58,6 +67,9 @@ class MorphoVaultV2 {
58
67
  };
59
68
  }
60
69
  withdraw({ assets, userAddress }) {
70
+ if (this.client.viemClient.chain?.id !== this.chainId) {
71
+ throw new types_1.ChainIdMismatchError(this.client.viemClient.chain?.id, this.chainId);
72
+ }
61
73
  return {
62
74
  buildTx: () => (0, actions_1.vaultV2Withdraw)({
63
75
  vault: { address: this.vault },
@@ -71,6 +83,9 @@ class MorphoVaultV2 {
71
83
  };
72
84
  }
73
85
  redeem({ shares, userAddress }) {
86
+ if (this.client.viemClient.chain?.id !== this.chainId) {
87
+ throw new types_1.ChainIdMismatchError(this.client.viemClient.chain?.id, this.chainId);
88
+ }
74
89
  return {
75
90
  buildTx: () => (0, actions_1.vaultV2Redeem)({
76
91
  vault: { address: this.vault },
@@ -83,5 +98,43 @@ class MorphoVaultV2 {
83
98
  }),
84
99
  };
85
100
  }
101
+ forceWithdraw({ deallocations, withdraw, userAddress, }) {
102
+ if (this.client.viemClient.chain?.id !== this.chainId) {
103
+ throw new types_1.ChainIdMismatchError(this.client.viemClient.chain?.id, this.chainId);
104
+ }
105
+ return {
106
+ buildTx: () => (0, actions_1.vaultV2ForceWithdraw)({
107
+ vault: { address: this.vault },
108
+ args: {
109
+ deallocations,
110
+ withdraw: {
111
+ assets: withdraw.assets,
112
+ recipient: userAddress,
113
+ },
114
+ onBehalf: userAddress,
115
+ },
116
+ metadata: this.client.options.metadata,
117
+ }),
118
+ };
119
+ }
120
+ forceRedeem({ deallocations, redeem, userAddress, }) {
121
+ if (this.client.viemClient.chain?.id !== this.chainId) {
122
+ throw new types_1.ChainIdMismatchError(this.client.viemClient.chain?.id, this.chainId);
123
+ }
124
+ return {
125
+ buildTx: () => (0, actions_1.vaultV2ForceRedeem)({
126
+ vault: { address: this.vault },
127
+ args: {
128
+ deallocations,
129
+ redeem: {
130
+ shares: redeem.shares,
131
+ recipient: userAddress,
132
+ },
133
+ onBehalf: userAddress,
134
+ },
135
+ metadata: this.client.options.metadata,
136
+ }),
137
+ };
138
+ }
86
139
  }
87
140
  exports.MorphoVaultV2 = MorphoVaultV2;
@@ -0,0 +1 @@
1
+ export declare const MAX_SLIPPAGE_TOLERANCE: bigint;
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.MAX_SLIPPAGE_TOLERANCE = void 0;
4
+ const blue_sdk_1 = require("@morpho-org/blue-sdk");
5
+ exports.MAX_SLIPPAGE_TOLERANCE = blue_sdk_1.MathLib.WAD / 10n;
@@ -0,0 +1,10 @@
1
+ import { type Address, type Hex } from "viem";
2
+ import { type Deallocation } from "../types";
3
+ /**
4
+ * Encodes a single `forceDeallocate` call as ABI-encoded calldata.
5
+ *
6
+ * @param deallocation - A deallocation entry.
7
+ * @param onBehalf - The address from which the penalty is taken (share owner).
8
+ * @returns The ABI-encoded calldata for `VaultV2.forceDeallocate`.
9
+ */
10
+ export declare function encodeForceDeallocateCall(deallocation: Deallocation, onBehalf: Address): Hex;
@@ -0,0 +1,37 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.encodeForceDeallocateCall = encodeForceDeallocateCall;
4
+ const blue_sdk_1 = require("@morpho-org/blue-sdk");
5
+ const blue_sdk_viem_1 = require("@morpho-org/blue-sdk-viem");
6
+ const viem_1 = require("viem");
7
+ const types_1 = require("../types");
8
+ /**
9
+ * Encodes the adapter-specific `data` bytes for a `forceDeallocate` call.
10
+ *
11
+ * @param deallocation - A deallocation entry.
12
+ * @returns The ABI-encoded bytes to pass as `data` to VaultV2.forceDeallocate.
13
+ */
14
+ function encodeDeallocateData(deallocation) {
15
+ if (deallocation.marketParams) {
16
+ return (0, viem_1.encodeAbiParameters)([blue_sdk_1.marketParamsAbi], [deallocation.marketParams]);
17
+ }
18
+ return "0x";
19
+ }
20
+ /**
21
+ * Encodes a single `forceDeallocate` call as ABI-encoded calldata.
22
+ *
23
+ * @param deallocation - A deallocation entry.
24
+ * @param onBehalf - The address from which the penalty is taken (share owner).
25
+ * @returns The ABI-encoded calldata for `VaultV2.forceDeallocate`.
26
+ */
27
+ function encodeForceDeallocateCall(deallocation, onBehalf) {
28
+ if (deallocation.assets === 0n) {
29
+ throw new types_1.ZeroAssetAmountError(deallocation.adapter);
30
+ }
31
+ const data = encodeDeallocateData(deallocation);
32
+ return (0, viem_1.encodeFunctionData)({
33
+ abi: blue_sdk_viem_1.vaultV2Abi,
34
+ functionName: "forceDeallocate",
35
+ args: [deallocation.adapter, data, deallocation.assets, onBehalf],
36
+ });
37
+ }
@@ -1,4 +1,5 @@
1
1
  import type { Address, Client, Hex } from "viem";
2
+ import type { Deallocation } from "./deallocation";
2
3
  export interface BaseAction<TType extends string = string, TArgs extends Record<string, unknown> = Record<string, unknown>> {
3
4
  readonly type: TType;
4
5
  readonly args: TArgs;
@@ -30,7 +31,27 @@ export interface VaultV2RedeemAction extends BaseAction<"vaultV2Redeem", {
30
31
  recipient: Address;
31
32
  }> {
32
33
  }
33
- export type TransactionAction = ERC20ApprovalAction | VaultV2DepositAction | VaultV2WithdrawAction | VaultV2RedeemAction;
34
+ export interface VaultV2ForceWithdrawAction extends BaseAction<"vaultV2ForceWithdraw", {
35
+ vault: Address;
36
+ deallocations: readonly Deallocation[];
37
+ withdraw: {
38
+ assets: bigint;
39
+ recipient: Address;
40
+ };
41
+ onBehalf: Address;
42
+ }> {
43
+ }
44
+ export interface VaultV2ForceRedeemAction extends BaseAction<"vaultV2ForceRedeem", {
45
+ vault: Address;
46
+ deallocations: readonly Deallocation[];
47
+ redeem: {
48
+ shares: bigint;
49
+ recipient: Address;
50
+ };
51
+ onBehalf: Address;
52
+ }> {
53
+ }
54
+ export type TransactionAction = ERC20ApprovalAction | VaultV2DepositAction | VaultV2WithdrawAction | VaultV2RedeemAction | VaultV2ForceWithdrawAction | VaultV2ForceRedeemAction;
34
55
  export interface Transaction<TAction extends BaseAction = TransactionAction> {
35
56
  readonly to: Address;
36
57
  readonly value: bigint;
@@ -0,0 +1,2 @@
1
+ import type { CallParameters, UnionPick } from "viem";
2
+ export type FetchParameters = UnionPick<CallParameters, "account" | "blockNumber" | "blockTag" | "stateOverride">;
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,15 @@
1
+ import type { MarketParams } from "@morpho-org/blue-sdk";
2
+ import type { Address } from "viem";
3
+ /**
4
+ * A single deallocation entry for a `forceDeallocate` call.
5
+ *
6
+ * - When `marketParams` is provided, the adapter is treated as a Morpho Market V1 adapter
7
+ * and `data` is ABI-encoded from the given `MarketParams`.
8
+ * - When `marketParams` is omitted, empty bytes are passed as `data` (suitable for adapters
9
+ * such as Vault V1 that do not require market identification).
10
+ */
11
+ export interface Deallocation {
12
+ readonly adapter: Address;
13
+ readonly marketParams?: MarketParams;
14
+ readonly assets: bigint;
15
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -1,6 +1,6 @@
1
1
  import type { Address } from "viem";
2
2
  export declare class ZeroAssetAmountError extends Error {
3
- constructor(asset: Address);
3
+ constructor(origin: Address);
4
4
  }
5
5
  export declare class ZeroSharesAmountError extends Error {
6
6
  constructor(vault: Address);
@@ -20,3 +20,18 @@ export declare class MissingClientPropertyError extends Error {
20
20
  export declare class ApprovalAmountLessThanSpendAmountError extends Error {
21
21
  constructor();
22
22
  }
23
+ export declare class ExcessiveSlippageToleranceError extends Error {
24
+ constructor(slippageTolerance: bigint);
25
+ }
26
+ export declare class EmptyDeallocationsError extends Error {
27
+ constructor(vault: Address);
28
+ }
29
+ export declare class DepositAmountMismatchError extends Error {
30
+ constructor(depositAmount: bigint, signatureAmount: bigint);
31
+ }
32
+ export declare class DepositAssetMismatchError extends Error {
33
+ constructor(depositAsset: Address, signatureAsset: Address);
34
+ }
35
+ export declare class DeallocationsExceedWithdrawError extends Error {
36
+ constructor(vault: Address, withdrawAssets: bigint, totalDeallocated: bigint);
37
+ }
@@ -1,9 +1,9 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.ApprovalAmountLessThanSpendAmountError = exports.MissingClientPropertyError = exports.ChainIdMismatchError = exports.AddressMismatchError = exports.ZeroMaxSharePriceError = exports.ZeroSharesAmountError = exports.ZeroAssetAmountError = void 0;
3
+ exports.DeallocationsExceedWithdrawError = exports.DepositAssetMismatchError = exports.DepositAmountMismatchError = exports.EmptyDeallocationsError = exports.ExcessiveSlippageToleranceError = exports.ApprovalAmountLessThanSpendAmountError = exports.MissingClientPropertyError = exports.ChainIdMismatchError = exports.AddressMismatchError = exports.ZeroMaxSharePriceError = exports.ZeroSharesAmountError = exports.ZeroAssetAmountError = void 0;
4
4
  class ZeroAssetAmountError extends Error {
5
- constructor(asset) {
6
- super(`Asset amount cannot be zero for address: ${asset}`);
5
+ constructor(origin) {
6
+ super(`Asset amount cannot be zero for address ${origin}`);
7
7
  }
8
8
  }
9
9
  exports.ZeroAssetAmountError = ZeroAssetAmountError;
@@ -43,3 +43,33 @@ class ApprovalAmountLessThanSpendAmountError extends Error {
43
43
  }
44
44
  }
45
45
  exports.ApprovalAmountLessThanSpendAmountError = ApprovalAmountLessThanSpendAmountError;
46
+ class ExcessiveSlippageToleranceError extends Error {
47
+ constructor(slippageTolerance) {
48
+ super(`Slippage tolerance ${slippageTolerance} exceeds maximum allowed (10%)`);
49
+ }
50
+ }
51
+ exports.ExcessiveSlippageToleranceError = ExcessiveSlippageToleranceError;
52
+ class EmptyDeallocationsError extends Error {
53
+ constructor(vault) {
54
+ super(`Deallocations list cannot be empty for vault: ${vault}`);
55
+ }
56
+ }
57
+ exports.EmptyDeallocationsError = EmptyDeallocationsError;
58
+ class DepositAmountMismatchError extends Error {
59
+ constructor(depositAmount, signatureAmount) {
60
+ super(`Deposit amount ${depositAmount} does not match requirement signature amount ${signatureAmount}`);
61
+ }
62
+ }
63
+ exports.DepositAmountMismatchError = DepositAmountMismatchError;
64
+ class DepositAssetMismatchError extends Error {
65
+ constructor(depositAsset, signatureAsset) {
66
+ super(`Deposit asset ${depositAsset} does not match requirement signature asset ${signatureAsset}`);
67
+ }
68
+ }
69
+ exports.DepositAssetMismatchError = DepositAssetMismatchError;
70
+ class DeallocationsExceedWithdrawError extends Error {
71
+ constructor(vault, withdrawAssets, totalDeallocated) {
72
+ super(`Total deallocated assets (${totalDeallocated}) exceed withdraw amount (${withdrawAssets}) for vault: ${vault}`);
73
+ }
74
+ }
75
+ exports.DeallocationsExceedWithdrawError = DeallocationsExceedWithdrawError;
@@ -1,5 +1,6 @@
1
1
  export * from "./action";
2
2
  export * from "./client";
3
+ export * from "./deallocation";
3
4
  export * from "./entity";
4
5
  export * from "./error";
5
6
  export * from "./metadata";
@@ -16,6 +16,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
17
  __exportStar(require("./action"), exports);
18
18
  __exportStar(require("./client"), exports);
19
+ __exportStar(require("./deallocation"), exports);
19
20
  __exportStar(require("./entity"), exports);
20
21
  __exportStar(require("./error"), exports);
21
22
  __exportStar(require("./metadata"), exports);
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@morpho-org/consumer-sdk",
3
3
  "description": "Abstraction layer for Morpho's complexity.",
4
- "version": "0.1.8",
4
+ "version": "0.3.0",
5
5
  "author": "Morpho Association <contact@morpho.org>",
6
6
  "contributors": [
7
7
  "Foulks-Plb <https://x.com/FoulkPlb>"
@@ -20,7 +20,7 @@
20
20
  "devDependencies": {
21
21
  "@biomejs/biome": "2.3.3",
22
22
  "@changesets/cli": "^2.29.8",
23
- "@morpho-org/test": "2.6.7",
23
+ "@morpho-org/test": "2.7.0",
24
24
  "@types/node": "^24.9.1",
25
25
  "@vitest/coverage-v8": "3.2.4",
26
26
  "@vitest/ui": "3.2.4",