@morpho-org/consumer-sdk
v0.6.0
Published
Abstraction layer for Morpho's complexity.
Keywords
Readme
Consumer SDK
⚠️ Experimental package: This SDK is currently in experimental phase.
The abstraction layer that simplifies Morpho protocol
Entities & Actions
| Entity | Action | Route | Why |
| ------------ | ------------------------ | ------------------------- | --------------------------------------------------------------------------------------------------- |
| VaultV2 | deposit | Bundler (general adapter) | Enforces maxSharePrice — inflation attack prevention. Supports native token wrapping. |
| | withdraw | Direct vault call | No attack surface, no bundler overhead needed |
| | redeem | Direct vault call | No attack surface, no bundler overhead needed |
| | forceWithdraw | Vault multicall | N forceDeallocate + 1 withdraw in a single tx |
| | forceRedeem | Vault multicall | N forceDeallocate + 1 redeem in a single tx |
| VaultV1 | deposit | Bundler (general adapter) | Same ERC-4626 inflation attack prevention as V2. Supports native token wrapping. |
| | withdraw | Direct vault call | No attack surface |
| | redeem | Direct vault call | No attack surface |
| | migrateToV2 | Bundler (general adapter) | Atomic V1 → V2 migration: redeem V1 shares + deposit into V2 in one tx. Slippage-protected. |
| MarketV1 | supplyCollateral | Bundler (general adapter) | erc20TransferFrom + morphoSupplyCollateral. Supports native wrapping. |
| | borrow | Bundler (general adapter) | morphoBorrow with minSharePrice slippage protection. Requires GA1 auth. Supports reallocations. |
| | supplyCollateralBorrow | Bundler (general adapter) | Atomic supply + borrow. LLTV buffer prevents instant liquidation. Supports reallocations. |
VaultV2
import { MorphoClient } from "@morpho-org/consumer-sdk";
import { createPublicClient, http } from "viem";
import { mainnet } from "viem/chains";
const viemClient = createPublicClient({ chain: mainnet, transport: http() });
const morpho = new MorphoClient(viemClient);
const vault = morpho.vaultV2("0xVault...", 1);Deposit
const { buildTx, getRequirements } = await vault.deposit({
amount: 1000000000000000000n,
userAddress: "0xUser...",
});
const requirements = await getRequirements();
const tx = buildTx(requirementSignature);Deposit with native token wrapping
For vaults whose underlying asset is wNative, you can deposit native token that will be automatically wrapped:
// Native ETH only — wraps 1 ETH to WETH and deposits
const { buildTx, getRequirements } = await vault.deposit({
nativeAmount: 1000000000000000000n,
userAddress: "0xUser...",
});
// Mixed — 0.5 WETH (ERC-20) + 0.5 native ETH wrapped to WETH
const { buildTx, getRequirements } = await vault.deposit({
amount: 500000000000000000n,
nativeAmount: 500000000000000000n,
userAddress: "0xUser...",
});The bundler atomically transfers native token, wraps it to wNative, and deposits alongside any ERC-20 amount. The transaction's value field is set to nativeAmount.
Withdraw
const { buildTx } = vault.withdraw({
amount: 500000000000000000n,
userAddress: "0xUser...",
});
const tx = buildTx();Redeem
const { buildTx } = vault.redeem({
shares: 1000000000000000000n,
userAddress: "0xUser...",
});
const tx = buildTx();Force Withdraw
const { buildTx } = vault.forceWithdraw({
deallocations: [{ adapter: "0xAdapter...", amount: 100n }],
withdraw: { amount: 500000000000000000n },
userAddress: "0xUser...",
});
const tx = buildTx();Force Redeem
const { buildTx } = vault.forceRedeem({
deallocations: [{ adapter: "0xAdapter...", amount: 100n }],
redeem: { shares: 1000000000000000000n },
userAddress: "0xUser...",
});
const tx = buildTx();VaultV1
const vault = morpho.vaultV1("0xVault...", 1);Deposit
const { buildTx, getRequirements } = await vault.deposit({
amount: 1000000000000000000n,
userAddress: "0xUser...",
});
const requirements = await getRequirements();
const tx = buildTx(requirementSignature);Withdraw
const { buildTx } = vault.withdraw({
amount: 500000000000000000n,
userAddress: "0xUser...",
});
const tx = buildTx();Redeem
const { buildTx } = vault.redeem({
shares: 1000000000000000000n,
userAddress: "0xUser...",
});
const tx = buildTx();Migrate to V2
Atomically migrate a full position from a VaultV1 (MetaMorpho) vault into a VaultV2 vault. The bundler redeems the V1 shares and deposits the resulting assets into V2 in a single transaction. Both vaults must share the same underlying asset.
const sourceVault = morpho.vaultV1("0xV1Vault...", 1);
const targetVault = morpho.vaultV2("0xV2Vault...", 1);
const { buildTx, getRequirements } = sourceVault.migrateToV2({
userAddress: "0xUser...",
sourceVault: await sourceVault.getData(),
targetVault: await targetVault.getData(),
shares: 1000000000000000000n,
});
const requirements = await getRequirements();
const tx = buildTx(requirementSignature);MarketV1
const market = morpho.marketV1(
{
loanToken: "0xLoan...",
collateralToken: "0xCollateral...",
oracle: "0xOracle...",
irm: "0xIrm...",
lltv: 860000000000000000n,
},
1
);Supply Collateral
const { buildTx, getRequirements } = market.supplyCollateral({
amount: 1000000000000000000n,
userAddress: "0xUser...",
});
const requirements = await getRequirements();
const tx = buildTx(requirementSignature);Borrow
const positionData = await market.getPositionData("0xUser...");
const { buildTx, getRequirements } = market.borrow({
amount: 500000000000000000n,
userAddress: "0xUser...",
positionData,
});
const requirements = await getRequirements();
const tx = buildTx();Supply Collateral & Borrow
const positionData = await market.getPositionData("0xUser...");
const { buildTx, getRequirements } = market.supplyCollateralBorrow({
amount: 1000000000000000000n,
borrowAmount: 500000000000000000n,
userAddress: "0xUser...",
positionData,
});
const requirements = await getRequirements();
const tx = buildTx(requirementSignature);Borrow with Shared Liquidity (Reallocations)
When a market lacks sufficient liquidity, you can reallocate liquidity from other markets managed by MetaMorpho Vaults via the PublicAllocator contract:
import type { VaultReallocation } from "@morpho-org/consumer-sdk";
const reallocations: VaultReallocation[] = [
{
vault: "0xVault...", // MetaMorpho vault to reallocate from
fee: 0n, // PublicAllocator fee in native token (can be 0)
withdrawals: [
{
marketParams: sourceMarketParams, // Source market to withdraw from
amount: 2000000000n, // Amount to withdraw
},
],
},
];
const positionData = await market.getPositionData("0xUser...");
// Borrow with reallocations
const { buildTx, getRequirements } = market.borrow({
amount: 500000000000000000n,
userAddress: "0xUser...",
positionData,
reallocations,
});
const requirements = await getRequirements();
const tx = buildTx();
// tx.value includes the sum of all reallocation feesReallocations also work with supplyCollateralBorrow:
const { buildTx, getRequirements } = market.supplyCollateralBorrow({
amount: 1000000000000000000n,
borrowAmount: 500000000000000000n,
userAddress: "0xUser...",
positionData,
reallocations,
});Architecture
graph LR
MC[MorphoClient]
MC -->|.vaultV1| MV1
MC -->|.vaultV2| MV2
MC -->|.marketV1| MM1
subgraph VaultV1 Flow
MV1[MorphoVaultV1]
MV1 --> V1D[vaultV1Deposit]
MV1 --> V1W[vaultV1Withdraw]
MV1 --> V1R[vaultV1Redeem]
MV1 --> V1M[vaultV1MigrateToV2]
V1D -->|nativeTransfer + wrapNative + erc4626Deposit| B1[Bundler3]
V1W -->|direct call| MM[MetaMorpho]
V1R -->|direct call| MM
V1M -->|erc20TransferFrom + erc4626Redeem + erc4626Deposit| B1
end
subgraph VaultV2 Flow
MV2[MorphoVaultV2]
MV2 --> V2D[vaultV2Deposit]
MV2 --> V2W[vaultV2Withdraw]
MV2 --> V2R[vaultV2Redeem]
MV2 --> V2FW[vaultV2ForceWithdraw]
MV2 --> V2FR[vaultV2ForceRedeem]
V2D -->|nativeTransfer + wrapNative + erc4626Deposit| B2[Bundler3]
V2W -->|direct call| V2C[VaultV2 Contract]
V2R -->|direct call| V2C
V2FW -->|multicall| V2C
V2FR -->|multicall| V2C
end
subgraph MarketV1 Flow
MM1[MorphoMarketV1]
MM1 --> M1SC[marketV1SupplyCollateral]
MM1 --> M1B[marketV1Borrow]
MM1 --> M1SCB[marketV1SupplyCollateralBorrow]
M1SC -->|erc20TransferFrom + morphoSupplyCollateral| B3[Bundler3]
M1B -->|reallocateTo? + morphoBorrow| B3
M1SCB -->|transfer + supplyCollateral + reallocateTo? + borrow| B3
B3 -.->|reallocateTo| PA[PublicAllocator]
end
subgraph Shared
REQ[getRequirements]
end
MV1 -.->|approval / permit| REQ
MV2 -.->|approval / permit| REQ
MM1 -.->|approval / permit / authorization| REQ
style B1 fill:#e8f5e9,stroke:#4caf50
style B2 fill:#e8f5e9,stroke:#4caf50
style B3 fill:#e8f5e9,stroke:#4caf50
style MM fill:#fff3e0,stroke:#ff9800
style V2C fill:#e3f2fd,stroke:#2196f3
style REQ fill:#f3e5f5,stroke:#9c27b0
style PA fill:#fff9c4,stroke:#f9a825Local Development
Link this package to your app for local debugging:
# In this consumer-sdk project
pnpm run build:linkIn your other project:
# Link the local package
pnpm link consumer-sdkContributing
Contributions are welcome! Feel free to open an issue or PR.
