web3-eth-contract 4.x 版本演进全解析:从 1.x 破坏性变更到现代智能合约交互
2026/9/20 18:07:24 网站建设 项目流程
  • 区块链
  • Web3

【免费下载链接】web3.js

Collection of comprehensive TypeScript libraries for Interaction with the Ethereum JSON RPC API and utility functions.

项目地址:https://gitcode.com/gh_mirrors/we/web3.js
点击查看免费下载

web3-eth-contract是 web3.js 生态中负责与以太坊智能合约交互的核心模块,覆盖合约实例化、方法调用、交易发送、事件订阅与合约部署等全部场景。本文以该模块的 CHANGELOG.md 为骨架,完整梳理 4.x 从4.0.0-alpha.0一路走到4.7.2的过程中每一项破坏性变更(Breaking Changes)与能力演进,并结合 contract.ts、types.ts、contract-deployer-method-class.ts 等源码与测试验证底层行为。读完本文,你将能准确评估 1.x 代码迁移到 4.x 所需的每一处改动,并掌握dataInputFillpopulateTransactiondecodeMethodData、事务中间件等 4.x 独有能力的用法与原理。

一、从 1.x 到 4.x:必须知道的七项破坏性变更

4.x 的首个版本4.0.0-alpha.0集中引入了与 1.x 不兼容的 API 变化。这些变更大多围绕"让返回值更符合以太坊规范、让事件回调更一致、让类型更严格"三条主线展开。

1.1 收据状态(receipt.status):布尔值 → 无符号整数(BigInt)

1.x 中交易收据的status字段是布尔值,而以太坊执行层 API 规范中status实际定义为无符号整数(0 表示失败、1 表示成功)。4.x 将其对齐为无符号整数,以符合规范定义:

// 1.x myContract.methods .MyMethod() .send() .on('receipt', receipt => { console.log(receipt.status); // true | false }); // 4.x myContract.methods .MyMethod() .send() .on('receipt', receipt => { console.log(receipt.status); // BigInt(0) | BigInt(1) });

注意status的实际类型取决于你在实例化时指定的数据格式(DataFormat),默认格式下为bigint。在源码中,这一约定同样体现在合约部署路径上——DeployerMethodClass在部署成功后会检查receipt.status === BigInt(0),若等于0则抛出 "code couldn't be stored" 错误(见 contract-deployer-method-class.ts)。

1.2 合约 send 方法直接以 receipt 兑现(resolve)

1.x 中contract.methods.myMethod().send()兑现(resolve)的是transactionHash,用户需要额外发起一次 RPC 调用才能获取收据等更多信息。4.x 直接以完整的receipt对象兑现:

// 1.x const transactionHash = await myContract.methods.MyMethod().send(); // 4.x const receipt = await myContract.methods.MyMethod().send(); const transactionHash = receipt.transactionHash;

这一点在 types.ts 的send签名中可以得到印证:其返回类型为Web3PromiEvent<FormatType<TransactionReceipt, typeof DEFAULT_RETURN_FORMAT>, SendTransactionEvents<...>>,即 Promise 部分兑现的是格式化后的TransactionReceipt

1.3 deploy 的 sending / sent 事件只携带交易对象

1.x 中deploy().send().on('sending', payload => {})回调收到的是完整的 JSON-RPC 负载,需要从payload.params[0]中取出交易;4.x 直接回调即将被发送的交易对象:

// 1.x myContract .deploy() .send() .on('send', payload => { console.log(payload); // {id: <1>, jsonrpc: '2.0', method: 'eth_sendTransaction', params: [txObject] } }); // 4.x myContract .deploy() .send() .on('send', txObject => { console.log(txObject); // {id: <>, gas: <>, ...} });

这一改动让事件处理器不必再关心 JSON-RPC 封装细节,直接消费交易字段即可。

1.4 confirmations 回调统一为单一对象参数

1.x 中confirmation处理器以多个位置参数调用:(confirmations, receipt, latestBlockHash);4.x 改为单一对象参数,但属性保持相同:

// 1.x myContract.send().on('confirmation', (confirmations, receipt, latestBlockHash) => {}) // 4.x myContract.send().on('confirmation', ({confirmations, receipt, latestBlockHash}) => {})

注意 4.x 中confirmations字段类型为bigint(在默认返回格式下),比 1.x 的number更能覆盖超出Number.MAX_SAFE_INTEGER的确认计数场景。

1.5 encodeABI 开启严格校验

encodeABI现在对 ABI 类型执行严格校验,且校验是通用的(不限于下列用例)。此前一些"能编码但语义错误"的输入现在会直接抛错:

  • 此前bytes32类型在输入字节数不足时仍能成功编码,现在会抛错;
  • 此前bytes32类型在传入空字节时仍能编码,现在会抛错。

这一行为与 4.x 全线采用的严格校验策略一致:web3-validator会在方法调用前对输入参数做格式校验(见 contract.ts 中_getAbiParams通过transformJsonDataToAbiFormat转换并捕获错误的逻辑)。

1.6 缺少 new 关键字时的错误消息变化

4.x 中尝试不使用new直接调用Contract构造器时,错误消息不再是指令性文案,而是标准 ES 类构造错误:

// 1.x Please use the "new" keyword to instantiate a web3.eth.Contract() object! // 4.x Class constructor ContractBuilder cannot be invoked without 'new'

这一变化源自 4.x 将合约构造器重构为真正的 TypeScript 类,并配合new.target检查机制,错误信息更贴近底层运行时语义。

1.7 事件订阅传入 toBlock 不再告警

1.x 中向事件订阅选项传入toBlock会收到警告 "Invalid option: toBlock. Use getPastEvents for specific range.";4.x 不再输出该警告,但toBlock依然不生效。若要获取指定区块范围的历史事件,应使用getPastEvents(对应方法签名见 contract.ts 的多重重载)。

二、Alpha / RC 阶段:核心能力的逐步落地

4.0.1-alpha.14.0.1-rc.2,合约模块在类型系统、错误处理、事件与区块标签支持等方面快速补齐能力,多数特性延续至今。

2.1 EIP-838 错误数据解码与 BigInt 返回值

4.0.1-alpha.1起,合约模块开始使用 Error ABI 对合约调用返回的错误数据进行解码(遵循 EIP-838,即把错误数据放在eth_call的返回数据中)。实现位于_contractMethodCall_contractMethodSend_contractMethodCreateAccessList三处:当捕获到ContractExecutionError时,调用web3-eth-abi导出的decodeContractErrorData(errorsAbi, error.cause)解析错误原因(见 contract.ts)。同版本Web3ContractError类被迁移到web3-error包,作为跨包共享的合约错误基类。

同时,配合web3-eth-abi的更新,从函数调用或事件中返回的大数(large numbers)现在以BigInt形式提供,避免精度丢失。

2.2 泛型输出重载与类型增强

4.0.1-alpha.2引入了两个重要的类型能力:

  • SpecialOutput作为call函数的泛型参数,允许调用方重新指定输出类型。对应实现见 types.ts:call<SpecialOutput = Outputs>(tx?, block?)
  • ContractOverloadedMethodInputsContractOverloadedMethodOutputs类型用于描述 Solidity 函数重载场景下的多组输入/输出签名,其递归类型定义位于 contract.ts。

2.3 事件订阅与历史事件查询补强

  • contract.events.someEventName传入fromBlock时,现在会从该区块开始(而非从默认区块)发出过去的事件(#5201)。订阅相关选项(filterfromBlocktopics)的定义见 types.ts。
  • 4.0.1-rc.2getPastEvents增加了对allEvents和具体事件的过滤支持(#6010)。getPastEvents内部通过encodeEventABI构造过滤参数,再调用getLogs获取日志并逐条decodeEventABI解码,最后按filter键做客户端侧二次过滤(见 contract.ts)。4.0.2进一步修复了使用字符串类型参数(indexed 与 non-indexed)进行事件过滤的问题(#6167)。

2.4 createAccessList 与 safe / finalized 区块标签

4.0.1-rc.0为合约方法增加了createAccessList能力,用于生成 EIP-2930 访问列表。调用时需指定from地址,gas未指定时也会被使用;返回结果包含accessListgasUsed字段(示例见 types.ts)。底层实现调用web3-ethcreateAccessListRPC 包装(见 contract.ts)。

同版本还加入了对safefinalized区块标签的支持(#5823),这两个标签可同时用于方法callblock参数与事件查询的fromBlock

2.5 input 与 data:交易数据字段的规范化

4.0.1-rc.1是数据字段语义的重要转折点:

  • ContractInitOptions接受input作为data的替代属性(二者皆可,但Contract类内部统一使用input);
  • 若同时传入datainput,构造器会抛出新增的ContractTransactionDataAndInputError。对应校验逻辑位于 contract.ts:当options.dataoptions.input均非空且config.contractDataInputFill !== 'both'时抛错;
  • getSendTxParams返回的交易参数对象中改用input而非data
  • data属性从ContractOptions类型中移除。

2.6 构建与打包:ESM / CJS 混合构建

4.0.1-rc.1起该包提供 ESM 与 CJS 混合构建(hybrid build)。从 package.json 可以看到,包的exports字段分别指向lib/esm/index.jsimport)与lib/commonjs/index.jsrequire),类型声明位于lib/types/index.d.ts。构建脚本(build:cjs/build:esm/build:types)分别使用tsconfig.cjs.jsontsconfig.esm.jsontsconfig.types.json完成编译,并写入对应的package.json标记模块类型。

三、稳定版 4.x:面向实战的功能演进

正式版之后,合约模块进入快速迭代期,几乎每个小版本都为日常开发场景贡献了新能力。

3.1 4.1.0:dataInputFill 与 contractDataInputFill

这是 4.x 中极具代表性的配置化能力:允许用户选择合约方法调用发送给 RPC 提供者时,使用datainput还是both(两者都填)属性。

  • 实例级配置:dataInputFill作为ContractInitOptions传入;
  • 全局配置:Web3Config上的contractDataInputFill属性,作用于该上下文下创建的所有合约。

源码层面,web3-core的默认配置中contractDataInputFill的默认值为'data'(见 web3_config.ts),且提供了对应的 getter/setter 并触发CONFIG_CHANGE事件(见 web3_config.ts)。在Contract构造器中,实例级dataInputFill会覆盖全局配置:this.config.contractDataInputFill = options?.dataInputFill ?? this.config.contractDataInputFill(见 contract.ts)。随后callsendestimateGascreateAccessListpopulateTransaction均通过this.config.contractDataInputFill透传到参数构建函数。

配置演进4.1.3修复了 MetaMask provider 场景下合约交易应填data而非input的问题(#6534);4.1.4起合约方法调用默认填充data(#6622),与全局默认值保持一致。

3.2 4.1.1:收据中的 events 属性

receipt对象新增events属性,其中按事件名组织了解码后的事件日志(同名事件多次出现时为数组)。send回调中的完整 receipt 结构示例(含events字段)见 types.ts。

3.3 4.2.0:无 ABI 的 deploy 与上下文钱包修复

  • deploy函数现在允许在未向Contract提供 ABI 的情况下接受构造参数(#6635);
  • 修复contract.getPastEventscontract.events.allEvents()在无匹配事件时抛错的问题(#6647);
  • 修复传入 context 时合约未使用 context 钱包的问题(#6661)。对应源码中,构造器会从Web3Context实例同步walletaccountProvider(见 contract.ts)。

3.4 4.4.0:函数重载的健壮化与数据解码

  • 修复 Solidity 函数重载相关问题(#6922);
  • 对参数重载导致的方法调用歧义输出控制台警告(#6942)。实现位于_createContractMethod:当多个 ABI 片段都能匹配给定参数时,会在控制台列出所有兼容方法与签名,并提示将使用第一个(见 contract.ts);
  • 新增contract.deploy(...).decodeData(...)contract.decodeMethodData(...),基于 ABI 解码调用数据(#6950)。

decodeMethodData的实现思路清晰:取数据前 4 字节(10 个十六进制字符)作为方法签名,在 ABI 中查找匹配的 function 片段,再调用web3-eth-abidecodeFunctionCall还原方法名与参数(见 contract.ts)。方法的decodeData则直接基于当前方法 ABI 解码(见 contract.ts)。这在调试合约交互、审计交易数据时非常实用。

3.5 4.5.0:defaultReturnFormat 全面落地

所有带ReturnType参数的方法都支持defaultReturnFormat(#6947),允许统一控制返回值的数据格式(如{ number: 'bigint' }{ number: 'string' }等)。合约实例的默认返回格式在构造时通过isDataFormat判断并设置(见 contract.ts),estimateGasgetPastEventscall等方法均默认继承该格式。

3.6 4.6.0:populateTransaction 与事务中间件

  • 合约方法新增populateTransaction,可在不发送交易的情况下生成完整的交易对象(TransactionCall),便于离线签名、多签准备或人工审查(签名见 types.ts)。其内部通过getSendTxParams构建交易,并显式移除多余的dataInputFill字段(见 contract.ts);
  • Contract新增setTransactionMiddleware/getTransactionMiddleware,自动将中间件传递给deploysend的底层sendTransaction调用(#7138)。在_contractMethodSend中可以看到:存在中间件时,sendTransaction会以中间件作为第五个参数调用(见 contract.ts),DeployerMethodClass的部署发送路径同样遵循这一逻辑。

3.7 4.7.x:DeployerMethodClass 与 TypeScript 5

4.7.0contract.deploy(...)的返回结构重构为由新类DeployerMethodClass承载(#7197),并为其增加了populateTransaction(#7197,见 contract-deployer-method-class.ts)。该类在构造时计算构造参数、构造函数 ABI、合约选项与部署数据(calculateDeployParams),若既无input也无data会抛出 "contract creation without any data provided."(见 contract-deployer-method-class.ts)。部署成功后的transactionResolver会基于收据中的contractAddress克隆出一个指向新地址的合约实例作为 Promise 兑现值(见 contract-deployer-method-class.ts)。

4.7.1修复了合约方法输入参数类型退化为any[]的问题(#7340);4.7.2将 TypeScript 依赖升级至 5.x(#7272),为更严格的类型推断与更快的编译速度奠定基础。

四、从变更记录看 4.x 的三条设计主线

纵观整个 CHANGELOG,web3-eth-contract4.x 的演进可以归纳为三条清晰的设计主线:

  1. 向规范对齐receipt.status改为无符号整数、confirmations等字段使用bigint、支持safe/finalized区块标签、按 EIP-838 解码错误数据,都是为了让返回值与执行层 API 和链上语义严格一致。
  2. 向类型安全收敛SpecialOutput、重载类型、ABI 参数类型自动检测(4.0.1-rc.2,#6137)、严格encodeABI校验、ContractTransactionDataAndInputError等,共同构建了从"能跑就行"到"编译期可查"的类型体系。
  3. 向可组合性演进dataInputFill双配置、populateTransaction、事务中间件、defaultReturnFormat、混合构建(ESM/CJS),让合约模块既能独立使用,也能无缝嵌入web3主包或自定义插件体系。

对于仍停留在 1.x 的开发者,迁移时建议按本文第一部分的七项破坏性变更逐项核对代码;对于已在使用 4.x 的开发者,则可根据第三部分的小版本能力清单,按需启用populateTransactiondecodeMethodData、事务中间件等特性,进一步精简合约交互代码。更完整的 API 细节可继续阅读 contract.ts 的 JSDoc(涵盖methodseventsdeploygetPastEventsclone的完整用法与示例),以及 types.ts 中NonPayableMethodObject/PayableMethodObject的逐方法签名。

  • 区块链
  • Web3

【免费下载链接】web3.js

Collection of comprehensive TypeScript libraries for Interaction with the Ethereum JSON RPC API and utility functions.

项目地址:https://gitcode.com/gh_mirrors/we/web3.js
点击查看免费下载

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询