This repository has been archived by the owner on Jan 15, 2025. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 36
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
8c9c971
commit 50d3fae
Showing
6 changed files
with
177 additions
and
1 deletion.
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,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; | ||
} |
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,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}`); | ||
}); | ||
}); |
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
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