UniversalDeFi AI

Official
import { ethers, JsonRpcProvider, Wallet } from "ethers"; import { GetWalletDetailsSchema, TransferNativeTokenSchema, DeployContractSchema, CallContractSchema } from "./schemas.js"; import { z } from "zod"; import { constructTransactionUrl } from "../../utils/index.js"; import { compileSourceString } from "solc-typed-ast"; import { Abi, AbiFunction } from "viem"; export async function getWalletDetailsHandler(wallet: Wallet, provider: JsonRpcProvider, args: z.infer<typeof GetWalletDetailsSchema>): Promise<string> { const balance = await provider.getBalance(wallet.address); return JSON.stringify({ chain: provider.getNetwork().then(network => network.name), address: wallet.address, balance: ethers.formatEther(balance) }); } export async function transferNativeTokenHandler( wallet: Wallet, provider: JsonRpcProvider, args: z.infer<typeof TransferNativeTokenSchema> ): Promise<string> { const hash = await wallet.sendTransaction({ to: args.toAddress, value: ethers.parseEther(args.amount) }); return JSON.stringify({ hash: hash, from: wallet.address, to: args.toAddress, amount: args.amount, scanUrl: constructTransactionUrl('bsc', hash.hash) }); } export async function deployContractHandler( wallet: Wallet, provider: JsonRpcProvider, args: z.infer<typeof DeployContractSchema> ): Promise<string> { const sourceCode = args.sourceCode; const contractName = args.contractName; const compileResult = await compileSourceString(contractName, sourceCode, "auto"); const contractFile = Object.keys(compileResult.data.contracts).find((file) => Object.keys(compileResult.data.contracts[file]).includes(contractName) ); if (!contractFile) { throw new Error(`Contract ${contractName} not found in source code`); } const targetContract = compileResult.data.contracts[contractFile][contractName]; const abi = targetContract.abi; const bytecode = "0x" + targetContract.evm.bytecode.object; const factory = new ethers.ContractFactory( abi, // ABI will be generated from source bytecode, // Bytecode from source wallet // Signer ); // Deploy the contract const contract = await factory.deploy(...(args.constructorArgs || [])); await contract.waitForDeployment(); const address = await contract.getAddress(); const deployTx = contract.deploymentTransaction(); if (!deployTx) { throw new Error("Deployment transaction not found"); } return JSON.stringify({ contractAddress: address, deploymentHash: deployTx.hash, from: wallet.address, network: provider.getNetwork().then(network => network.name), transactionUrl: constructTransactionUrl('bsc', deployTx.hash) }); } export async function callContractHandler( wallet: Wallet, provider: JsonRpcProvider, args: z.infer<typeof CallContractSchema> ) { let abiString: string = args.abi; let abi: Abi = JSON.parse(abiString) as Abi; if (!ethers.isAddress(args.contractAddress)) { throw new Error(`Invalid contract address: ${args.contractAddress}`); } const contract = new ethers.Contract(args.contractAddress, abiString, wallet); let functionAbi: AbiFunction | undefined; try { functionAbi = abi.find( (item) => "name" in item && item.name === args.functionName, ) as AbiFunction; } catch (error) { throw new Error(`Invalid function name: ${args.functionName}`); } if ( functionAbi.stateMutability === "view" || functionAbi.stateMutability === "pure" ) { return await contract.getFunction(args.functionName)(...args.args); } const contractFunction = contract.getFunction(args.functionName); const txResponse = await contractFunction(...args.args); const txReceipt = await txResponse.wait(); return JSON.stringify({ hash: txReceipt.hash, transactionUrl: constructTransactionUrl('bsc', txReceipt.hash), }); }