-
Notifications
You must be signed in to change notification settings - Fork 161
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(ts): morpho vault deposit & withdraw actions (#114)
- Loading branch information
Showing
11 changed files
with
713 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
export const ERC20_APPROVE_ABI = [ | ||
{ | ||
constant: false, | ||
inputs: [ | ||
{ internalType: "address", name: "spender", type: "address" }, | ||
{ internalType: "uint256", name: "value", type: "uint256" }, | ||
], | ||
name: "approve", | ||
outputs: [{ internalType: "bool", name: "", type: "bool" }], | ||
payable: false, | ||
stateMutability: "nonpayable", | ||
type: "function", | ||
}, | ||
]; |
25 changes: 25 additions & 0 deletions
25
cdp-agentkit-core/typescript/src/actions/cdp/defi/morpho/constants.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
export const MORPHO_BASE_ADDRESS = "0xBBBBBbbBBb9cC5e90e3b3Af64bdAF62C37EEFFCb"; | ||
|
||
export const METAMORPHO_ABI = [ | ||
{ | ||
inputs: [ | ||
{ internalType: "uint256", name: "assets", type: "uint256" }, | ||
{ internalType: "address", name: "receiver", type: "address" }, | ||
], | ||
name: "deposit", | ||
outputs: [{ internalType: "uint256", name: "shares", type: "uint256" }], | ||
stateMutability: "nonpayable", | ||
type: "function", | ||
}, | ||
{ | ||
inputs: [ | ||
{ internalType: "uint256", name: "assets", type: "uint256" }, | ||
{ internalType: "address", name: "receiver", type: "address" }, | ||
{ internalType: "address", name: "owner", type: "address" }, | ||
], | ||
name: "withdraw", | ||
outputs: [{ internalType: "uint256", name: "shares", type: "uint256" }], | ||
stateMutability: "nonpayable", | ||
type: "function", | ||
}, | ||
]; |
112 changes: 112 additions & 0 deletions
112
cdp-agentkit-core/typescript/src/actions/cdp/defi/morpho/deposit.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
import { Asset, Wallet } from "@coinbase/coinbase-sdk"; | ||
import { z } from "zod"; | ||
import { Decimal } from "decimal.js"; | ||
|
||
import { CdpAction } from "../../cdp_action"; | ||
import { approve } from "../../utils"; | ||
|
||
import { METAMORPHO_ABI } from "./constants"; | ||
|
||
const DEPOSIT_PROMPT = ` | ||
This tool allows depositing assets into a Morpho Vault. | ||
It takes: | ||
- vaultAddress: The address of the Morpho Vault to deposit to | ||
- assets: The amount of assets to deposit in whole units | ||
Examples for WETH: | ||
- 1 WETH | ||
- 0.1 WETH | ||
- 0.01 WETH | ||
- receiver: The address to receive the shares | ||
- tokenAddress: The address of the token to approve | ||
Important notes: | ||
- Make sure to use the exact amount provided. Do not convert units for assets for this action. | ||
- Please use a token address (example 0x4200000000000000000000000000000000000006) for the tokenAddress field. If you are unsure of the token address, please clarify what the requested token address is before continuing. | ||
`; | ||
|
||
/** | ||
* Input schema for Morpho Vault deposit action. | ||
*/ | ||
export const MorphoDepositInput = z | ||
.object({ | ||
assets: z | ||
.string() | ||
.regex(/^\d+(\.\d+)?$/, "Must be a valid integer or decimal value") | ||
.describe("The quantity of assets to deposit, in whole units"), | ||
receiver: z | ||
.string() | ||
.regex(/^0x[a-fA-F0-9]{40}$/, "Invalid Ethereum address format") | ||
.describe( | ||
"The address that will own the position on the vault which will receive the shares", | ||
), | ||
tokenAddress: z | ||
.string() | ||
.regex(/^0x[a-fA-F0-9]{40}$/, "Invalid Ethereum address format") | ||
.describe("The address of the assets token to approve for deposit"), | ||
vaultAddress: z | ||
.string() | ||
.regex(/^0x[a-fA-F0-9]{40}$/, "Invalid Ethereum address format") | ||
.describe("The address of the Morpho Vault to deposit to"), | ||
}) | ||
.describe("Input schema for Morpho Vault deposit action"); | ||
|
||
/** | ||
* Deposits assets into a Morpho Vault | ||
* @param Wallet - The wallet instance to execute the transaction | ||
* @param args - The input arguments for the action | ||
* @returns A success message with transaction details or an error message | ||
*/ | ||
export async function depositToMorpho( | ||
wallet: Wallet, | ||
args: z.infer<typeof MorphoDepositInput>, | ||
): Promise<string> { | ||
const assets = new Decimal(args.assets); | ||
|
||
if (assets.comparedTo(new Decimal(0.0)) != 1) { | ||
return "Error: Assets amount must be greater than 0"; | ||
} | ||
|
||
try { | ||
const tokenAsset = await Asset.fetch(wallet.getNetworkId(), args.tokenAddress); | ||
const atomicAssets = tokenAsset.toAtomicAmount(assets); | ||
|
||
const approvalResult = await approve( | ||
wallet, | ||
args.tokenAddress, | ||
args.vaultAddress, | ||
atomicAssets, | ||
); | ||
if (approvalResult.startsWith("Error")) { | ||
return `Error approving Morpho Vault as spender: ${approvalResult}`; | ||
} | ||
|
||
const contractArgs = { | ||
assets: atomicAssets.toString(), | ||
receiver: args.receiver, | ||
}; | ||
|
||
const invocation = await wallet.invokeContract({ | ||
contractAddress: args.vaultAddress, | ||
method: "deposit", | ||
abi: METAMORPHO_ABI, | ||
args: contractArgs, | ||
}); | ||
|
||
const result = await invocation.wait(); | ||
|
||
return `Deposited ${args.assets} to Morpho Vault ${args.vaultAddress} with transaction hash: ${result.getTransactionHash()} and transaction link: ${result.getTransactionLink()}`; | ||
} catch (error) { | ||
return `Error depositing to Morpho Vault: ${error}`; | ||
} | ||
} | ||
|
||
/** | ||
* Morpho Vault deposit action. | ||
*/ | ||
export class MorphoDepositAction implements CdpAction<typeof MorphoDepositInput> { | ||
public name = "morpho_deposit"; | ||
public description = DEPOSIT_PROMPT; | ||
public argsSchema = MorphoDepositInput; | ||
public func = depositToMorpho; | ||
} |
18 changes: 18 additions & 0 deletions
18
cdp-agentkit-core/typescript/src/actions/cdp/defi/morpho/index.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
import { CdpAction, CdpActionSchemaAny } from "../../cdp_action"; | ||
|
||
import { MorphoDepositAction } from "./deposit"; | ||
import { MorphoWithdrawAction } from "./withdraw"; | ||
|
||
/** | ||
* Retrieves all Morpho action instances. | ||
* WARNING: All new Morpho action classes must be instantiated here to be discovered. | ||
* | ||
* @returns - Array of Morpho action instances | ||
*/ | ||
export function getAllMorphoActions(): CdpAction<CdpActionSchemaAny>[] { | ||
return [new MorphoDepositAction(), new MorphoWithdrawAction()]; | ||
} | ||
|
||
export const MORPHO_ACTIONS = getAllMorphoActions(); | ||
|
||
export { MorphoDepositAction, MorphoWithdrawAction }; |
79 changes: 79 additions & 0 deletions
79
cdp-agentkit-core/typescript/src/actions/cdp/defi/morpho/withdraw.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
import { Asset, Wallet } from "@coinbase/coinbase-sdk"; | ||
import { z } from "zod"; | ||
|
||
import { CdpAction } from "../../cdp_action"; | ||
import { METAMORPHO_ABI } from "./constants"; | ||
|
||
const WITHDRAW_PROMPT = ` | ||
This tool allows withdrawing assets from a Morpho Vault. It takes: | ||
- vaultAddress: The address of the Morpho Vault to withdraw from | ||
- assets: The amount of assets to withdraw in atomic units | ||
- receiver: The address to receive the shares | ||
`; | ||
|
||
/** | ||
* Input schema for Morpho Vault withdraw action. | ||
*/ | ||
export const MorphoWithdrawInput = z | ||
.object({ | ||
vaultAddress: z | ||
.string() | ||
.regex(/^0x[a-fA-F0-9]{40}$/, "Invalid Ethereum address format") | ||
.describe("The address of the Morpho Vault to withdraw from"), | ||
assets: z | ||
.string() | ||
.regex(/^\d+$/, "Must be a valid whole number") | ||
.describe("The amount of assets to withdraw in atomic units e.g. 1"), | ||
receiver: z | ||
.string() | ||
.regex(/^0x[a-fA-F0-9]{40}$/, "Invalid Ethereum address format") | ||
.describe("The address to receive the shares"), | ||
}) | ||
.strip() | ||
.describe("Input schema for Morpho Vault withdraw action"); | ||
|
||
/** | ||
* Withdraw assets from a Morpho Vault. | ||
* | ||
* @param wallet - The wallet to execute the withdrawal from | ||
* @param args - The input arguments for the action | ||
* @returns A success message with transaction details or error message | ||
*/ | ||
export async function withdrawFromMorpho( | ||
wallet: Wallet, | ||
args: z.infer<typeof MorphoWithdrawInput>, | ||
): Promise<string> { | ||
if (BigInt(args.assets) <= 0) { | ||
return "Error: Assets amount must be greater than 0"; | ||
} | ||
|
||
try { | ||
const invocation = await wallet.invokeContract({ | ||
contractAddress: args.vaultAddress, | ||
method: "withdraw", | ||
abi: METAMORPHO_ABI, | ||
args: { | ||
assets: args.assets, | ||
receiver: args.receiver, | ||
owner: args.receiver, | ||
}, | ||
}); | ||
|
||
const result = await invocation.wait(); | ||
|
||
return `Withdrawn ${args.assets} from Morpho Vault ${args.vaultAddress} with transaction hash: ${result.getTransaction().getTransactionHash()} and transaction link: ${result.getTransaction().getTransactionLink()}`; | ||
} catch (error) { | ||
return `Error withdrawing from Morpho Vault: ${error}`; | ||
} | ||
} | ||
|
||
/** | ||
* Morpho Vault withdraw action. | ||
*/ | ||
export class MorphoWithdrawAction implements CdpAction<typeof MorphoWithdrawInput> { | ||
public name = "morpho_withdraw"; | ||
public description = WITHDRAW_PROMPT; | ||
public argsSchema = MorphoWithdrawInput; | ||
public func = withdrawFromMorpho; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
import { Wallet } from "@coinbase/coinbase-sdk"; | ||
|
||
import { ERC20_APPROVE_ABI } from "./constants"; | ||
|
||
/** | ||
* Approve a spender to spend a specified amount of tokens. | ||
* @param wallet - The wallet to execute the approval from | ||
* @param tokenAddress - The address of the token contract | ||
* @param spender - The address of the spender | ||
* @param amount - The amount of tokens to approve | ||
* @returns A success message with transaction hash or error message | ||
*/ | ||
export async function approve( | ||
wallet: Wallet, | ||
tokenAddress: string, | ||
spender: string, | ||
amount: bigint, | ||
): Promise<string> { | ||
try { | ||
const invocation = await wallet.invokeContract({ | ||
contractAddress: tokenAddress, | ||
method: "approve", | ||
abi: ERC20_APPROVE_ABI, | ||
args: { | ||
spender: spender, | ||
value: amount.toString(), | ||
}, | ||
}); | ||
|
||
const result = await invocation.wait(); | ||
|
||
return `Approved ${amount} tokens for ${spender} with transaction hash: ${result.getTransactionHash()}`; | ||
} catch (error) { | ||
return `Error approving tokens: ${error}`; | ||
} | ||
} |
Oops, something went wrong.