UNPKG

@agentek/tools

Version:

Blockchain tools for AI agents

96 lines 3.76 kB
import { z } from "zod"; import { createTool } from "../client.js"; import { encodeFunctionData, erc20Abi, parseUnits, } from "viem"; import { erc20Chains } from "./constants.js"; const intentApproveParameters = z.object({ token: z.string().describe("The token address"), amount: z.string().describe("The amount to approve"), spender: z.string().describe("The spender address to approve"), chainId: z.number().optional().describe("Optional specific chain to use"), }); export const ETH_ADDRESS = "0x0000000000000000000000000000000000000000"; const getTokenDecimals = async (publicClient, token) => { if (token == ETH_ADDRESS) { return 18; } else { return await publicClient.readContract({ abi: erc20Abi, functionName: "decimals", address: token, }); } }; export const intentApproveTool = createTool({ name: "intentApprove", description: "Creates an intent to approve token spending", supportedChains: erc20Chains, parameters: intentApproveParameters, execute: async (client, args) => { const { token, amount, spender, chainId } = args; const chains = client.filterSupportedChains(erc20Chains, chainId); const from = await client.getAddress(); if (token === ETH_ADDRESS) { throw new Error("Cannot approve ETH, only ERC20 tokens"); } const chainsInfo = (await Promise.all(chains.map(async (chain) => { try { const publicClient = client.getPublicClient(chain.id); const decimals = await getTokenDecimals(publicClient, token); const amountBigInt = parseUnits(amount, decimals); return { chain, amount: amountBigInt, decimals, }; } catch (error) { console.error(`Error processing chain ${chain.id}:`, error); return undefined; } }))).filter((chainInfo) => chainInfo !== undefined); let executionChain; if (chainsInfo.length === 0) { throw new Error("No supported chains found with valid token information"); } else { executionChain = await Promise.all(chainsInfo.map(async (chainInfo) => { const publicClient = client.getPublicClient(chainInfo.chain.id); const gasPrice = await publicClient.getGasPrice(); return { ...chainInfo, gasPrice, }; })).then((chains) => chains.reduce((cheapest, current) => current.gasPrice < cheapest.gasPrice ? current : cheapest)); } const walletClient = client.getWalletClient(executionChain.chain.id); const ops = [ { target: token, value: "0", data: encodeFunctionData({ abi: erc20Abi, functionName: "approve", args: [spender, executionChain.amount], }), }, ]; if (!walletClient) { return { intent: `approve ${amount.toString()} ${token} for spender ${spender}`, ops, chain: executionChain.chain.id, }; } else { const hash = await client.executeOps(ops, executionChain.chain.id); return { intent: `Approve ${amount.toString()} ${token} from ${from} for spender ${spender}`, ops, chain: executionChain.chain.id, hash: hash, }; } }, }); //# sourceMappingURL=intents.js.map