Skip to content
This repository has been archived by the owner on Jan 15, 2025. It is now read-only.

[AgentKit] Wrap ETH Tool #56

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions cdp-agentkit-core/src/actions/cdp/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { RegisterBasenameAction } from "./register_basename";
import { RequestFaucetFundsAction } from "./request_faucet_funds";
import { TradeAction } from "./trade";
import { TransferAction } from "./transfer";
import { WrapEthAction } from "./wrap_eth";
import { WOW_ACTIONS } from "./defi/wow";

/**
Expand All @@ -27,6 +28,7 @@ export function getAllCdpActions(): CdpAction<CdpActionSchemaAny>[] {
new RequestFaucetFundsAction(),
new TradeAction(),
new TransferAction(),
new WrapEthAction(),
];
}

Expand All @@ -44,4 +46,5 @@ export {
RequestFaucetFundsAction,
TradeAction,
TransferAction,
WrapEthAction,
};
89 changes: 89 additions & 0 deletions cdp-agentkit-core/src/actions/cdp/wrap_eth.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import { CdpAction } from "./cdp_action";
import { Wallet } from "@coinbase/coinbase-sdk";
import { z } from "zod";

export const WETH_ADDRESS = "0x4200000000000000000000000000000000000006";

export const WETH_ABI = [
{
inputs: [],
name: "deposit",
outputs: [],
stateMutability: "payable",
type: "function",
},
{
inputs: [
{
name: "account",
type: "address",
},
],
name: "balanceOf",
outputs: [
{
type: "uint256",
},
],
stateMutability: "view",
type: "function",
},
];

const WRAP_ETH_PROMPT = `
This tool can only be used to wrap ETH to WETH.
Do not use this tool for any other purpose, or trading other assets.

Inputs:
- Amount of ETH to wrap.

Important notes:
- The amount is a string and cannot have any decimal points, since the unit of measurement is wei.
- Make sure to use the exact amount provided, and if there's any doubt, check by getting more information before continuing with the action.
- 1 wei = 0.000000000000000001 WETH
- Minimum purchase amount is 100000000000000 wei (0.0000001 WETH)
- Only supported on the following networks:
- Base Sepolia (ie, 'base-sepolia')
- Base Mainnet (ie, 'base', 'base-mainnnet')
`;

export const WrapEthInput = z
.object({
amountToWrap: z.string().describe("Amount of ETH to wrap in wei"),
})
.strip()
.describe("Instructions for wrapping ETH to WETH");

/**
* Wraps ETH to WETH
*
* @param wallet - The wallet to create the token from.
* @param args - The input arguments for the action.
* @returns A message containing the wrapped ETH details.
*/
export async function wrapEth(wallet: Wallet, args: z.infer<typeof WrapEthInput>): Promise<string> {
try {
const invocation = await wallet.invokeContract({
contractAddress: WETH_ADDRESS,
method: "deposit",
abi: WETH_ABI,
args: {},
amount: BigInt(args.amountToWrap),
assetId: "wei",
});
const result = await invocation.wait();
return `Wrapped ETH with transaction hash: ${result.getTransaction().getTransactionHash()}`;
} catch (error) {
return `Error wrapping ETH: ${error}`;
}
}

/**
* Wrap ETH to WETH on Base action.
*/
export class WrapEthAction implements CdpAction<typeof WrapEthInput> {
public name = "wrap_eth";
public description = WRAP_ETH_PROMPT;
public argsSchema = WrapEthInput;
public func = wrapEth;
}
80 changes: 80 additions & 0 deletions cdp-agentkit-core/src/tests/wrap_eth_test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import { ContractInvocation, Wallet } from "@coinbase/coinbase-sdk";

import { WETH_ABI, WETH_ADDRESS, wrapEth, WrapEthInput } from "../actions/cdp/wrap_eth";

const MOCK_AMOUNT_TO_WRAP = "100000000000000000";

describe("Wrap Eth", () => {
it("should successfully parse valid input", () => {
const validInput = {
amountToWrap: MOCK_AMOUNT_TO_WRAP,
};

const result = WrapEthInput.safeParse(validInput);

expect(result.success).toBe(true);
expect(result.data).toEqual(validInput);
});

it("should fail parsing empty input", () => {
const emptyInput = {};
const result = WrapEthInput.safeParse(emptyInput);

expect(result.success).toBe(false);
});
});

describe("Wrap Eth Action", () => {
const TRANSACTION_HASH = "0xghijkl987654321";

let mockContractInvocation: jest.Mocked<ContractInvocation>;
let mockWallet: jest.Mocked<Wallet>;

beforeEach(() => {
mockWallet = {
invokeContract: jest.fn(),
} as unknown as jest.Mocked<Wallet>;

mockContractInvocation = {
wait: jest.fn().mockResolvedValue({
getTransaction: jest.fn().mockReturnValue({
getTransactionHash: jest.fn().mockReturnValue(TRANSACTION_HASH),
}),
}),
} as unknown as jest.Mocked<ContractInvocation>;

mockWallet.invokeContract.mockResolvedValue(mockContractInvocation);
});

it("should successfully wrap ETH", async () => {
const args = {
amountToWrap: MOCK_AMOUNT_TO_WRAP,
};

const response = await wrapEth(mockWallet, args);

expect(mockWallet.invokeContract).toHaveBeenCalledWith({
contractAddress: WETH_ADDRESS,
method: "deposit",
abi: WETH_ABI,
args: {},
amount: BigInt(args.amountToWrap),
assetId: "wei",
});
expect(response).toContain(`Wrapped ETH with transaction hash: ${TRANSACTION_HASH}`);
});

it("should fail with an error", async () => {
const args = {
amountToWrap: MOCK_AMOUNT_TO_WRAP,
};

const error = new Error("Failed to execute transfer");
mockWallet.invokeContract.mockRejectedValue(error);

const response = await wrapEth(mockWallet, args);

expect(mockWallet.invokeContract).toHaveBeenCalled();
expect(response).toContain(`Error wrapping ETH: ${error}`);
});
});
1 change: 1 addition & 0 deletions cdp-langchain/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ The toolkit provides the following tools:
10. **wow_create_token** - Deploy a token using [Zora's Wow Launcher](https://wow.xyz/mechanics) (Bonding Curve)
11. **wow_buy_token** - Buy [Zora Wow](https://wow.xyz/) ERC-20 memecoin with ETH
12. **wow_sell_token** - Sell [Zora Wow](https://wow.xyz/) ERC-20 memecoin for ETH
13. **wrap_eth** - Wrap ETH as WETH

### Using with an Agent

Expand Down
4 changes: 3 additions & 1 deletion cdp-langchain/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@
"license": "Apache-2.0",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"files": ["dist"],
"files": [
"dist"
],
"scripts": {
"build": "tsc",
"lint": "npx --yes eslint -c .eslintrc.json src/**/*.ts",
Expand Down
1 change: 1 addition & 0 deletions cdp-langchain/src/toolkits/cdp_toolkit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ import { CdpTool } from "../tools/cdp_tool";
* // - wow_create_token
* // - wow_buy_token
* // - wow_sell_token
* // - wrap_eth
* ```
*/
export class CdpToolkit extends Toolkit {
Expand Down
Loading