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

Commit

Permalink
[AgentKit] Wrap ETH Tool (#56)
Browse files Browse the repository at this point in the history
  • Loading branch information
derekbrown authored Jan 13, 2025
1 parent 8c9c971 commit 50d3fae
Show file tree
Hide file tree
Showing 6 changed files with 177 additions and 1 deletion.
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

0 comments on commit 50d3fae

Please sign in to comment.