Web3j ERC20 示例工程实战:Solidity 合约、Wrapper 生成、事件订阅与 @EVMTest 全链路解析
区块链Web3后端【免费下载链接】web3jLightweight Java and Android library for integration with Ethereum clients项目地址https://gitcode.com/gh_mirrors/we/web3j点击查看免费下载本指南以 web3j 仓库中的 ERC20 示例 starter 资产.agents/skills/web3j/assets/erc20-example/为主体完整讲解一条最短可运行的 JVM 侧 ERC20 应用链路Solidity 源码放在src/main/solidity、由 Web3j Gradle 插件生成 Java Wrapper、Wrapper 完成部署/读取/转账、类型化的Transfer事件订阅以及 Web3j Unit 的EVMTest合约测试。读完本文你将能够独立搭建一个可复制的 ERC20 工程并理解 Web3j 各模块core、Gradle 插件、Web3j Unit/Web3j EVM、CLI、Sokt在实际工程中的拼接方式。一、示例资产定位一条最短的全链路演示仓库内的.agents/skills/web3j/assets/erc20-example/目录定位明确当用户想要一个同时展示 Web3j 各模块如何围绕 ERC20 合约协同工作的单一示例时优先使用这里提供的 starter 资产。它不是一个浏览器 UI 工程而是刻意保持精简的 JVM 端 starter如果需要 HTTP 层官方推荐保留同样的合约与测试流程再叠加web3j_openapi生成 Web 面。该目录包含两类内容总览文档README.md说明模板结构、Agent 复制与适配工作流、配套工具的边界模板工程basic-erc20-app/真正可编译、可测试、可运行的完整示例。而.agents/skills/web3j/references/erc20-example.md则从提示词路由角度给出了决策规则先判断用户要的是 CLI 脚手架web3j new的erc20模板、可复制的仓库级示例还是 HTTP/OpenAPI 面当用户要最短可运行且同时包含测试与事件的示例时默认答案就是本地 starter 资产。二、工程结构与文件职责basic-erc20-app/是 Gradle 工程rootProject.name basic-erc20-app见 settings.gradle其文件布局如下文件职责src/main/solidity/ExampleToken.sol带Transfer/Approval事件的迷你 ERC20 合约源码src/main/java/example/Erc20ExampleApp.java部署 Wrapper、读取代币状态、执行转账、订阅Transfer事件的主程序src/test/java/example/Erc20EvmTest.java在EVMTest下运行同一模式部署→转账→事件流的 JUnit 测试build.gradle应用 Web3j Gradle 插件并将生成的 Wrapper 固定到example.contracts包settings.gradle工程名配置这个结构本身就是在演示一条固定的零件拼接顺序Solidity 合约源码 → Gradle 插件生成 Wrapper → Java 应用部署与调用 → 事件 Flowable 类型化订阅 → Web3j Unit 驱动EVMTest合约测试。从源码结构可以推断Wrapper 被固定放在example.contracts包build.gradle中的generatedPackageName example.contracts保证了import example.contracts.ExampleToken;的稳定导入路径。三、合约源码一个精炼的 ERC20 变体ExampleToken.sol 使用pragma solidity ^0.8.20实现了 ERC20 的核心状态与接口且刻意保持最短可读状态变量name、symbol、decimals常量 18、totalSupply以及两个mappingbalanceOf、双层allowance事件Transfer(address indexed from, address indexed to, uint256 value)与Approval(address indexed owner, address indexed spender, uint256 value)均带indexed参数这正是后面类型化事件订阅的基础构造器接收initialSupply、tokenName、tokenSymbol将总供应量记到msg.sender名下并发出首个Transfer(address(0), msg.sender, initialSupply)铸造事件方法transfer、approve、transferFrom三者都包含基础require校验recipient 非零、余额/授权充足并在状态变更后触发对应事件。值得注意构造器参数顺序initialSupply, tokenName, tokenSymbol直接决定了 Wrapper 的deploy(...)签名顺序示例程序与测试均按此顺序传参这是Solidity 签名 → Java Wrapper 签名一一对应的直观体现。四、Wrapper 生成Web3j Gradle 插件的接入方式build.gradle 是 Wrapper 生成链路的关键plugins { id java id application id org.web3j version 5.0.3 } web3j { generatedPackageName example.contracts } dependencies { implementation org.web3j:core:5.0.3 implementation org.web3j:web3j-sokt:0.2.1 testImplementation platform(org.junit:junit-bom:5.10.2) testImplementation org.junit.jupiter:junit-jupiter testImplementation(org.web3j:web3j-unit:5.0.3) { exclude group: org.web3j } } application { mainClass example.Erc20ExampleApp } tasks.named(compileJava) { dependsOn(tasks.named(generateContractWrappers)) } tasks.named(compileTestJava) { dependsOn(tasks.named(generateContractWrappers)) }要点拆解插件坐标与 Java 版本org.web3j插件5.0.3并声明 Java 21 toolchain生成包名固定generatedPackageName example.contracts保证生成类可被源码稳定引用编译顺序依赖compileJava与compileTestJava都dependsOn(generateContractWrappers)确保任何编译动作之前先生成 Wrapper测试框架JUnit 5useJUnitPlatform()并显式开启junit.jupiter.extensions.autodetection.enabledtrue这是EVMTest扩展能被自动发现的前提——仓库自身的 integration-tests/build.gradle 也采用了完全相同的testImplementation(org.web3j:web3j-unit:$web3jUnitVersion)与 JUnit Jupiter 扩展自动探测配置可互为印证Sokt 依赖示例引入了web3j-sokt:0.2.1作为编译器辅助依赖但保持最短路径在 Gradle 插件侧完成 Wrapper 生成的定位。关于如何生成 Wrapper还有另一条 CLI 路径.agents/skills/web3j/references/smart-contracts.md有完整命令先用solc编译出.bin/.abi再用web3j generate solidity -b ... -a ... -o ... -p ...生成 Java Wrapper本仓库的 contracts/scripts/generateWrappers.sh 走的就是同一套流程其参数-a、-b、-o、-p、-c、-B、-r在 SolidityFunctionWrapperGenerator.java 中均有定义。五、主程序部署、读取、转账、事件订阅的完整流程Erc20ExampleApp.java 是整条链路的运行中枢main方法按四步推进第一步组装 Web3j 客户端、凭证与 Gas 提供器Web3j web3j Web3j.build(new HttpService(endpoint)); Credentials credentials Credentials.create(privateKey); ContractGasProvider gasProvider new DefaultGasProvider();Web3j.build(new HttpService(endpoint))通过 HTTP JSON-RPC 连接节点endpoint 来自WEB3J_HTTP_URL默认http://localhost:8545Credentials.create(privateKey)由私钥直接构造凭证私钥来自WEB3J_PRIVATE_KEYrequiredEnv保证缺失即抛出IllegalStateExceptionDefaultGasProvider是静态 Gas 提供器GAS_PRICE 4_100_000_000 wei、GAS_LIMIT 9_000_000见 core/src/main/java/org/web3j/tx/gas/DefaultGasProvider.java其底层 StaticGasProvider.java 实现ContractGasProvider接口返回固定 gasPrice 与 gasLimit。第二步部署 Wrapper 并读取只读状态ExampleToken token ExampleToken.deploy(web3j, credentials, gasProvider, initialSupply, tokenName, tokenSymbol).send(); System.out.println(Contract address: token.getContractAddress()); System.out.println(Token name: token.name().send()); System.out.println(Token symbol: token.symbol().send()); System.out.println(Total supply: token.totalSupply().send()); System.out.println(Deployer balance: token.balanceOf(credentials.getAddress()).send());ExampleToken.deploy(...).send()是生成 Wrapper 的部署入口deploy返回RemoteFunctionCall.send()同步等待交易上链并返回合约实例四个构造参数与 Solidity 构造器参数一一对应name()、symbol()、totalSupply()、balanceOf(...)都是只读调用eth_call返回类型由生成器从 ABI 推断String、BigInteger等。第三步建立 Transfer 事件的双通道监听示例同时演示了事件消费的两种形态——实时流与回执提取CountDownLatch eventSeen new CountDownLatch(1); transferSubscription token.transferEventFlowable( DefaultBlockParameterName.EARLIEST, DefaultBlockParameterName.LATEST) .subscribe(event - { System.out.printf(Transfer event: from%s to%s value%s%n, event._from, event._to, event._value); eventSeen.countDown(); }, error - { ... }); TransactionReceipt receipt token.transfer(recipient, transferAmount).send(); ListExampleToken.TransferEventResponse receiptEvents token.getTransferEvents(receipt);transferEventFlowable(EARLIEST, LATEST)返回 RxJavaFlowableTransferEventResponse事件字段以_from、_to、_value命名并带精确类型token.transfer(recipient, transferAmount).send()执行转账交易返回TransactionReceiptgetTransferEvents(receipt)从回执日志中解码同一笔交易产生的事件两条路径结果应一致形成交叉验证。主程序用CountDownLatch.await(10, TimeUnit.SECONDS)等待 Flowable 至少观测到一次事件并在finally中dispose()订阅、web3j.shutdown()释放连接——这呼应了官方事件文档references/events.md中用完必须释放订阅的硬性要求。六、事件订阅的底层原理与仓库佐证...EventFlowable(...)方法并非手写而是 Wrapper 生成器产出的标准能力。在 codegen/src/main/java/org/web3j/codegen/SolidityFunctionWrapper.java 中buildEventFlowableFunction生成的代码形态为web3j.ethLogFlowable(filter).map(log - ...)对应源码第 2006–2023 行区域即生成的 Flowable 方法内部构造日志过滤器通过ethLogFlowable拉取日志流再解码为类型化响应对象同时生成带默认区块参数的...EventFlowable(startBlock, endBlock)重载buildDefaultEventFlowableFunction第 2029 行区域。仓库中同款模式的两个权威示例integration-tests/src/test/java/org/web3j/protocol/scenarios/HumanStandardTokenGeneratedIT.java以EVMTest(type NodeType.BESU)运行覆盖 deploy→totalSupply/balanceOf 断言→transferEventFlowable订阅→approve→transferFrom→getTransferEvents提取的完整场景还演示了 Bob 通过HumanStandardToken.load(contractAddress, web3j, BOB, gasProvider)加载同一合约的第二个实例integration-tests/src/test/java/org/web3j/protocol/scenarios/EventFilterIT.java演示无 Wrapper 时的底层EthFilter手动过滤与日志解码兜底路径。七、EVMTest 合约测试测试路径的运行范式Erc20EvmTest.java 展示 Web3j Unit 的核心用法EVMTest(type NodeType.BESU) class Erc20EvmTest { Test void deploysTransfersAndStreamsEvents( Web3j web3j, TransactionManager transactionManager, ContractGasProvider gasProvider) throws Exception { ExampleToken token ExampleToken.deploy(web3j, transactionManager, gasProvider, BigInteger.valueOf(1_000_000L), Skill Token, SKILL).send(); assertTrue(token.isValid()); assertEquals(Skill Token, token.name().send()); ... } }关键点EVMTest(type NodeType.BESU)是 Web3j Unit 提供的 JUnit 5 扩展注解测试方法直接注入Web3j、TransactionManager、ContractGasProvider三个参数官方文档对EVMTest/EVMComposeTest及注入机制有明确描述见 references/web3j-unit.md与主程序用Credentials DefaultGasProvider不同测试走TransactionManager 注入的 ContractGasProvider这正是测试环境由扩展托管签名与 Gas的设计断言覆盖token.isValid()部署成功、name()/symbol()/totalSupply()返回值、转账后getTransferEvents(receipt).get(0)的_to/_value字段、balanceOf(recipient)余额以及eventSeen.await(5, TimeUnit.SECONDS)验证事件流确实推送测试结尾同样transferSubscription.dispose()与主程序保持一致的资源管理纪律。需要说明边界web3j-unit与web3j-evm是官方文档中独立定位的配套生态工具references/web3j-evm.md 明确指出本仓库主模块中不存在独立的web3j-evm模块而EVMTest是当前仓库上下文中在本地 EVM 上跑合约测试最直接可运行的入口。八、运行方式与全部环境变量两条官方命令路径见 basic-erc20-app/README.md测试路径无需节点由EVMTest启动嵌入式 Besu EVM./gradlew test运行路径需要节点与私钥执行部署/交互/事件全流程WEB3J_PRIVATE_KEY0xyourprivatekey ./gradlew run环境变量一览均为可选带默认值变量默认值说明WEB3J_HTTP_URLhttp://localhost:8545节点 HTTP JSON-RPC 端点WEB3J_PRIVATE_KEY无必须提供部署与签名账户的私钥缺失时requiredEnv直接抛错WEB3J_TOKEN_NAMESkill Token代币名称WEB3J_TOKEN_SYMBOLSKILL代币符号WEB3J_INITIAL_SUPPLY1000000初始总供应量WEB3J_TRANSFER_TO部署者地址转账接收方默认发给部署者自身使转账路径无需第二个账户即可运行WEB3J_TRANSFER_AMOUNT1转账金额注意这套WEB3J_*环境变量是示例工程自行约定的运行参数主程序用envOrDefault/requiredEnv解析与 CLI 生成工程的WEB3J_ENDPOINT、WEB3J_WALLET_PATH、WEB3J_WALLET_PASSWORD、WEB3J_PRIVATE_KEY等运行时变量见 references/cli.md属于两个不同的约定体系适配模板时不要混用。九、适配工作流如何把 starter 复制进自己的项目总览文档给出的 Agent 适配流程同样适用于开发者手工复制将basic-erc20-app/整个目录复制到目标位置保留包名与 Wrapper 包example/example.contracts除非明确要求重命名——因为Erc20ExampleApp与Erc20EvmTest的 import 依赖这两个固定包名仅在用户给出具体值时才修补代币元数据名称/符号、endpoint 默认值与转账相关环境变量若用户要的是 CLI 生成模板则改走web3j new官方v5.0.3文档表明其内置helloworld、erc20、erc777等命名模板仅当用户想在相同合约流程之上叠加 HTTP 层时才引入web3j_openapi——该场景下仍以本 starter 的合约与测试为基线再按 references/web3j-openapi.md 生成 Web 面。十、配套工具边界CLI、Sokt 与 OpenAPI 的分工示例文档特别强调了几组边界避免概念混淆Gradle 插件 vs Sokt本 starter 把 Wrapper 生成的最短可运行路径放在org.web3jGradle 插件侧generateContractWrappers任务web3j-sokt官方坐标org.web3j:web3j-sokt:0.2.1见 references/web3j-sokt.md定位是solc的 Kotlin 封装负责从 Soliditypragma解析理想编译器版本并原生执行编译其文档形态为SolidityFile - getCompilerInstance() - execute(...)。当用户明确要代码内直接做编译器解析时才切换到 Sokt 路径示例中不做多余的本地拼装。CLI 脚手架 vs 库 APIweb3j new含erc20模板是终端侧脚手架库侧的 deploy/load/call/event 则走 Wrapper API二者不能互相替代。HTTP/Web 层web3j_openapi是独立文档区域用于在相同合约流程之上生成 OpenAPI/HTTP 服务面本 starter 明确是 JVM 侧 starter不包含浏览器 UI。这套最短路径 明确边界的组织方式恰好回答了.agents/skills/web3j/SKILL.md中Web3j 分为 Java 库接口与 CLI 接口两条界面不应混淆的总原则——围绕一个 ERC20 合约从源码到 Wrapper、从部署到事件、从单元测试到 Web 层每一块都有清晰归属。十一、进一步探索仓库内的延伸阅读路径如果希望把本示例的各个零件放大到仓库级源码Wrapper 生成参数与 CLIcodegen/src/main/java/org/web3j/codegen/SolidityFunctionWrapperGenerator.java、contracts/scripts/generateWrappers.sh已生成的 ERC20/ERC721 Wrapper 的事件助手形态contracts/src/main/java/org/web3j/contracts/eip20/generated/ERC20.java其中transferEventFlowable(EthFilter)与transferEventFlowable(DefaultBlockParameter, DefaultBlockParameter)两个重载与示例用法完全一致端到端集成测试基线integration-tests/src/test/java/org/web3j/protocol/scenarios/HumanStandardTokenIT.java、HumanStandardTokenGeneratedIT.java、FunctionWrappersIT.java、EventFilterIT.javaWeb3j Unit 的仓库落地方式integration-tests/build.gradle中web3j-unit依赖与 JUnit Jupiter 扩展自动探测配置。本示例是理解 Web3j 从合约到应用全链路的最短入口跑通./gradlew test验证测试路径再配好私钥跑./gradlew run观察部署、转账与事件流的完整输出即可在此基础上按需替换合约、调整参数或叠加 OpenAPI 层。赞分享区块链Web3后端【免费下载链接】web3jLightweight Java and Android library for integration with Ethereum clients项目地址https://gitcode.com/gh_mirrors/we/web3j点击查看免费下载相关推荐Web3j ERC20 完整实战从 Solidity 合约、Wrapper 生成到事件订阅与 EVMTest 测试Web3j ERC20 完整实战从 Solidity 合约、Wrapper 生成到事件订阅与 EVMTest 测试 本文以 web3j 仓库内置的 basi区块链Web3后端web3j ERC20 实战入门用 Gradle 插件生成 Wrapper完成部署、调用、转账与 EVMTest 测试全链路web3j ERC20 实战入门用 Gradle 插件生成 Wrapper完成部署、调用、转账与 EVMTest 测试全链路 本指南以 web3j 仓库内区块链Web3后端web3j 智能合约开发指南从 solc 编译、Wrapper 生成到部署、调用与事件订阅的完整实战web3j 智能合约开发指南从 solc 编译、Wrapper 生成到部署、调用与事件订阅的完整实战 本篇指南以 web3j 仓库中的智能合约实践文档 .a区块链Web3后端上一篇DownKyi技术解析从源码到8K超高清下载全流程下一篇FlyingMouse Format 0.7.8 启动兼容性修复全解析原生启动器资源自检、ACL 最小修复与沙箱保持创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考