Ethers.js TypeScript合约类型定义与类变量赋值技术咨询
关于Ethers.js TypeScript合约类型问题的解答
1. 能否将BaseContract作为类型来定义接口?
可以直接使用ethers.BaseContract作为基类型来定义合约接口,它是ethers.js中所有合约实例的通用基类,包含connect、address等核心方法。如果需要包含合约的特定方法,可基于它扩展自定义接口:
import { BaseContract } from "ethers"; interface IUniswapFactoryContract extends BaseContract { getPair: (tokenA: string, tokenB: string) => Promise<string>; // 按需添加其他合约方法 }
2. 在Ethers.js的TypeScript环境中,能否将类变量设置为new ethers.Contract(...)返回的对象类型?
完全可以。ethers.Contract构造函数返回的实例类型就是ethers.Contract(或TypeChain生成的更具体合约类型)。直接将类变量类型声明为ethers.Contract即可:
import { Contract } from "ethers"; class Exchange { private factoryContract: Contract; constructor() { this.factoryContract = new ethers.Contract( V2_FACTORY_ADDRESSES[ChainId.MAINNET], CONTRACTABI.uniswap.factory, ProviderSingleton.getWebSocket() ); } }
如果需要更精准的类型提示,推荐使用TypeChain生成的专属合约类型,或手动继承BaseContract定义接口。
3. 声明类变量为Contract时系统识别为hardhat内部类型,TypeChain未生成匹配类型?
这是因为导入了错误的Contract类型——Hardhat内部也有一个同名类型,但你需要的是ethers.js提供的版本。确保导入语句为:
import { Contract, BaseContract } from "ethers";
针对TypeChain生成失败的问题,检查以下步骤:
- 安装依赖:
npm install typechain @typechain/ethers-v5 --save-dev - 在
hardhat.config.ts中配置TypeChain:
import "@typechain/hardhat"; export default { // 其他Hardhat配置... typechain: { outDir: "typechain-types", target: "ethers-v5", // 对应你的ethers版本,v6则用@typechain/ethers-v6 }, };
- 运行生成命令:
npx hardhat typechain,生成的类型会放在typechain-types目录下。
如果ABI是手动维护的(非Hardhat编译生成),直接用TypeChain处理ABI文件:npx typechain --target ethers-v5 ./path/to/abis/*.json
4. 创建同时访问Factory与Router的交易所类并实现getPair
结合上述解决方案,下面是完整实现示例:
方案1:手动定义接口(无TypeChain)
import { Contract, BaseContract, Provider } from "ethers"; import { V2_FACTORY_ADDRESSES, V2_ROUTER_ADDRESSES } from "./constants"; import { ChainId } from "./chain"; import { CONTRACTABI } from "./abis"; // 定义Factory合约接口 interface IUniswapV2Factory extends BaseContract { getPair: (tokenA: string, tokenB: string) => Promise<string>; } // 定义Router合约接口 interface IUniswapV2Router extends BaseContract { swapExactTokensForTokens: ( amountIn: bigint, amountOutMin: bigint, path: string[], to: string, deadline: bigint ) => Promise<string>; } class Exchange { private factoryContract: IUniswapV2Factory; private routerContract: IUniswapV2Router; constructor(provider: Provider) { this.factoryContract = new Contract( V2_FACTORY_ADDRESSES[ChainId.MAINNET], CONTRACTABI.uniswap.factory, provider ) as IUniswapV2Factory; this.routerContract = new Contract( V2_ROUTER_ADDRESSES[ChainId.MAINNET], CONTRACTABI.uniswap.router, provider ) as IUniswapV2Router; } // 实现getPair方法 async getPair(tokenA: string, tokenB: string): Promise<string> { return this.factoryContract.getPair(tokenA, tokenB); } // 可扩展Router相关方法 async swapExactTokens( amountIn: bigint, amountOutMin: bigint, path: string[], to: string, deadline: bigint ): Promise<string> { return this.routerContract.swapExactTokensForTokens(amountIn, amountOutMin, path, to, deadline); } }
方案2:使用TypeChain生成的类型(推荐)
import { Provider } from "ethers"; import { V2_FACTORY_ADDRESSES, V2_ROUTER_ADDRESSES } from "./constants"; import { ChainId } from "./chain"; import { UniswapV2Factory__factory, UniswapV2Router02__factory } from "./typechain-types"; class Exchange { private factoryContract: UniswapV2Factory; private routerContract: UniswapV2Router02; constructor(provider: Provider) { this.factoryContract = UniswapV2Factory__factory.connect( V2_FACTORY_ADDRESSES[ChainId.MAINNET], provider ); this.routerContract = UniswapV2Router02__factory.connect( V2_ROUTER_ADDRESSES[ChainId.MAINNET], provider ); } async getPair(tokenA: string, tokenB: string): Promise<string> { return this.factoryContract.getPair(tokenA, tokenB); } }
内容的提问来源于stack exchange,提问作者Esko918
相关产品推荐
相关产品推荐

