From 63d4b67bc31af059fd16f9dd418e6e4d910a88af Mon Sep 17 00:00:00 2001 From: EthanBizzy Date: Sat, 6 Apr 2024 16:14:02 +0800 Subject: [PATCH] basic 81 task: web3j erc20 --- README-CN.md | 6 + README.md | 3 +- basic/81-web3j-erc20/README-cn.md | 352 ++++++++++++++++++ basic/81-web3j-erc20/Web3App/build.gradle | 100 +++++ basic/81-web3j-erc20/Web3App/settings.gradle | 10 + .../src/main/java/org/web3j/Erc20Query.java | 33 ++ .../src/main/java/org/web3j/Web3App.java | 32 ++ .../Web3App/src/main/solidity/ERC20Token.sol | 23 ++ .../generated/contracts/ERC20TokenTest.java | 83 +++++ basic/81-web3j-erc20/assets/web3j_network.png | Bin 0 -> 71671 bytes 10 files changed, 641 insertions(+), 1 deletion(-) create mode 100644 basic/81-web3j-erc20/README-cn.md create mode 100644 basic/81-web3j-erc20/Web3App/build.gradle create mode 100644 basic/81-web3j-erc20/Web3App/settings.gradle create mode 100644 basic/81-web3j-erc20/Web3App/src/main/java/org/web3j/Erc20Query.java create mode 100644 basic/81-web3j-erc20/Web3App/src/main/java/org/web3j/Web3App.java create mode 100644 basic/81-web3j-erc20/Web3App/src/main/solidity/ERC20Token.sol create mode 100644 basic/81-web3j-erc20/Web3App/src/test/java/org/web3j/generated/contracts/ERC20TokenTest.java create mode 100644 basic/81-web3j-erc20/assets/web3j_network.png diff --git a/README-CN.md b/README-CN.md index 5cc935bd1..746f3cba3 100644 --- a/README-CN.md +++ b/README-CN.md @@ -194,6 +194,12 @@ DAPP架构请参考文章--[从架构维度看Web2.0与Web3.0应用之别](https 74. [erc20-meta-token](https://github.com/0xsequence/erc20-meta-token) 75. [golang-dapp](basic/75-golang-dapp) ✅ 76. [Push Protocol](https://docs.epns.io/developers) +77. [orbit](basic/77-orbit) +78. [wallet connect](basic/78-wallet-connect) +79. [hardhat-foundry](basic/79-hardhat-foundry) +80. [Circle CCTP](basic/80-crossChainTransfer) +81. [Web3j-erc20](./basic/81-web3j-erc20/README-cn.md) + ## 项目任务 diff --git a/README.md b/README.md index eda123dee..4c6605714 100644 --- a/README.md +++ b/README.md @@ -190,7 +190,8 @@ You are welcome to PR improvements to existing tutorial projects or to create mo 77. [orbit](basic/77-orbit) 78. [wallet connect](basic/78-wallet-connect) 79. [hardhat-foundry](basic/79-hardhat-foundry) -80. [Circle CCTP](basic/80-circle-cctp) +80. [Circle CCTP](basic/80-crossChainTransfer) +81. [Web3j-erc20](./basic/81-web3j-erc20/README-cn.md) Welcome to submit pull request, [Add a new basic task or update the above task](https://github.com/Dapp-Learning-DAO/Dapp-Learning/issues/new) diff --git a/basic/81-web3j-erc20/README-cn.md b/basic/81-web3j-erc20/README-cn.md new file mode 100644 index 000000000..4620d8993 --- /dev/null +++ b/basic/81-web3j-erc20/README-cn.md @@ -0,0 +1,352 @@ +中文 + +## 前言 + +Web3j是一个高度模块化、反应式、类型安全的Java和Android库,用于处理智能合约并与以太坊网络上的客户端(节点)集成: + +![web3j_network](assets/web3j_network.png) + +这使您能够在以太坊区块链上进行工作,而无需额外编写自己的平台集成代码。 + +本样例演示了利用web3j部署和调用 ERC20 合约, 帮助开发者了解快速上手web3j。 + + +## 项目创建流程 +以下以Mac系统为例,介绍对应的安装流程。 + +为了大幅降低web3j的使用门槛,官方提供了Web3j Cli来提升用户体验,并且提供了一个脚手架的功能。 + +1. 安装依赖 + +```sh + brew install jq +``` + +由于web3j生成的项目,默认兼容jdk17,建议安装好jdk17的环境。 + +2. 安装Web3j客户端 + + ```sh + curl -L get.web3j.io | sh && source ~/.web3j/source.sh + ``` + +3. 创建新的erc20项目 + + ```sh + web3j new erc20 + ``` +会依次要求输入项目的token name/symbol/totalSupply: + +```sh +↑2 ~/tmp → web3j new erc20 + _ _____ _ + | | |____ (_) +__ _____| |__ / /_ +\ \ /\ / / _ \ '_ \ \ \ | + \ V V / __/ |_) |.___/ / | + \_/\_/ \___|_.__/ \____/| | + _/ | + |__/ +by Web3Labs +Please enter the token name [ERC20]: +byd +Please enter the token symbol [erc20]: +byd +Please enter the token initial supply in Wei [1000000000]: + +[ ― ] Creating and building ERC20 project ... Subsequent builds will be faster + +Project Created Successfully +``` + +执行成功后,会在当前目录自动创建Web3App的项目。 + +可以使用IDE导入这个java项目。 + +## 项目路径说明 +我们可以发现,通过Web3j Cli创建的项目,已经被正确初始化,且合约已经被正确编译,和生成了对应的Java Wrapper文件。 +该文件位于build/generated目录下面。 + +``` +4688 ./node_modules/@openzeppelin ##依赖的合约库代码 +4696 ./node_modules +120 ./gradle +189968 ./.gradle +48 ./build/generated #自动生成的合约java代码 +184 ./build/classes +232 ./build/resources +8 ./build/kotlin +88 ./build/libs +8 ./src/test #测试代码 +24 ./src/main #项目代码 +``` + +## 部署Erc20合约 +1. 配置环境变量 +打开`./Web3App/src/main/java/org/web3j/Web3App.java`文件,编辑对应的环境变量.(可以直接在文件上替换为自己的,也可以通过在操作系统或IDE中配置环境变量的方式) +``` + // node url既可以被配置为本地的evm peer,也可以被配置为infura的peer + private static final String nodeUrl = System.getenv().getOrDefault("WEB3J_NODE_URL", ""); + private static final String pk1 = System.getenv().getOrDefault("PK_ACCT1", ""); +``` + +在本实例中,配置了Sepolia的测试网络的Infura peer. + +2. 执行代码 +运行Web3App的main函数,代码自动执行。我们可以看到合约被自动部署成功。日志如下: + +``` +13:48:14: Executing ':Web3App.main()'... + +> Task :compileKotlin NO-SOURCE +> Task :nodeSetup UP-TO-DATE +> Task :npmSetup SKIPPED +> Task :resolveSolidity UP-TO-DATE +> Task :npmInstall UP-TO-DATE +> Task :compileSolidity UP-TO-DATE +> Task :generateContractWrappers UP-TO-DATE +> Task :compileJava UP-TO-DATE +> Task :processResources NO-SOURCE +> Task :classes UP-TO-DATE +> Task :jar UP-TO-DATE +> Task :inspectClassesForKotlinIC UP-TO-DATE + +> Task :Web3App.main() +nodeUrl is: https://sepolia.infura.io/v3/[your_infura_id] +private key is: [your_private_key] +Deploying ERC20 contract ... +13:48:14.980 [main] DEBUG org.web3j.protocol.http.HttpService -- --> POST https://sepolia.infura.io/v3/[your_infura_id] +13:48:14.980 [main] DEBUG org.web3j.protocol.http.HttpService -- Content-Type: application/json; charset=utf-8 +13:48:14.980 [main] DEBUG org.web3j.protocol.http.HttpService -- Content-Length: 125 +13:48:14.980 [main] DEBUG org.web3j.protocol.http.HttpService -- +13:48:14.981 [main] DEBUG org.web3j.protocol.http.HttpService -- {"jsonrpc":"2.0","method":"eth_getTransactionCount","params":["0xaa0087f012d788a11369c2a211f14f767aafdb16","pending"],"id":0} +13:48:14.981 [main] DEBUG org.web3j.protocol.http.HttpService -- --> END POST (125-byte body) +SLF4J(W): Class path contains multiple SLF4J providers. +SLF4J(W): Found provider [ch.qos.logback.classic.spi.LogbackServiceProvider@3bf7ca37] +SLF4J(W): Found provider [org.apache.logging.slf4j.SLF4JServiceProvider@79079097] +SLF4J(W): See https://www.slf4j.org/codes.html#multiple_bindings for an explanation. +SLF4J(I): Actual provider is of type [ch.qos.logback.classic.spi.LogbackServiceProvider@3bf7ca37] +13:48:18.352 [main] DEBUG org.web3j.protocol.http.HttpService -- <-- 200 https://sepolia.infura.io/v3/[your_infura_id] (3371ms) +13:48:18.353 [main] DEBUG org.web3j.protocol.http.HttpService -- date: Sat, 06 Apr 2024 05:48:18 GMT +13:48:18.353 [main] DEBUG org.web3j.protocol.http.HttpService -- content-type: application/json +13:48:18.353 [main] DEBUG org.web3j.protocol.http.HttpService -- content-length: 39 +13:48:18.353 [main] DEBUG org.web3j.protocol.http.HttpService -- vary: Origin +13:48:18.353 [main] DEBUG org.web3j.protocol.http.HttpService -- vary: Accept-Encoding +13:48:18.353 [main] DEBUG org.web3j.protocol.http.HttpService -- +13:48:18.353 [main] DEBUG org.web3j.protocol.http.HttpService -- {"jsonrpc":"2.0","id":0,"result":"0x0"} +13:48:18.353 [main] DEBUG org.web3j.protocol.http.HttpService -- <-- END HTTP (39-byte body) +13:48:18.406 [main] DEBUG org.web3j.protocol.http.HttpService -- --> POST https://sepolia.infura.io/v3/[your_infura_id] +13:48:18.406 [main] DEBUG org.web3j.protocol.http.HttpService -- Content-Type: application/json; charset=utf-8 +13:48:18.406 [main] DEBUG org.web3j.protocol.http.HttpService -- Content-Length: 6880 +13:48:18.406 [main] DEBUG org.web3j.protocol.http.HttpService -- +13:48:18.407 [main] DEBUG org.web3j.protocol.http.HttpService -- {"jsonrpc":"2.0","method":"eth_sendRawTransaction","params":["0xf90d488084f4610900838954408080b90cf6608060405234801561001057600080fd5b50604051610c16380380610c1683398101604081905261002f916102d7565b8282600361003d83826103e7565b50600461004a82826103e7565b50505061005d338261006560201b60201c565b5050506104e6565b6001600160a01b0382166100ad576040517fec442f05000000000000000000000000000000000000000000000000000000008152600060048201526024015b60405180910390fd5b6100b9600083836100bd565b5050565b6001600160a01b0383166100e85780600260008282546100dd91906104a6565b909155506101739050565b6001600160a01b03831660009081526020819052604090205481811015610154576040517fe450d38c0000000000000000000000000000000000000000000000000000000081526001600160a01b038516600482015260248101829052604481018390526064016100a4565b6001600160a01b03841660009081526020819052604090209082900390555b6001600160a01b03821661018f576002805482900390556101ae565b6001600160a01b03821660009081526020819052604090208054820190555b816001600160a01b0316836001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef836040516101f391815260200190565b60405180910390a3505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600082601f83011261024057600080fd5b81516001600160401b038082111561025a5761025a610200565b604051601f8301601f19908116603f0116810190828211818310171561028257610282610200565b816040528381526020925086602085880101111561029f57600080fd5b600091505b838210156102c157858201830151818301840152908201906102a4565b6000602085830101528094505050505092915050565b6000806000606084860312156102ec57600080fd5b83516001600160401b038082111561030357600080fd5b61030f8783880161022f565b9450602086015191508082111561032557600080fd5b506103328682870161022f565b925050604084015190509250925092565b600181811c9082168061035757607f821691505b602082108103610390577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b601f8211156103e2576000816000526020600020601f850160051c810160208610156103bf5750805b601f850160051c820191505b818110156103de578281556001016103cb565b5050505b505050565b81516001600160401b0381111561040057610400610200565b6104148161040e8454610343565b84610396565b602080601f83116001811461044957600084156104315750858301515b600019600386901b1c1916600185901b1785556103de565b600085815260208120601f198616915b8281101561047857888601518255948401946001909101908401610459565b50858210156104965787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b808201808211156104e0577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b92915050565b610721806104f56000396000f3fe608060405234801561001057600080fd5b50600436106100935760003560e01c8063313ce56711610066578063313ce567146100fe57806370a082311461010d57806395d89b4114610136578063a9059cbb1461013e578063dd62ed3e1461015157600080fd5b806306fdde0314610098578063095ea7b3146100b657806318160ddd146100d957806323b872dd146100eb575b600080fd5b6100a061018a565b6040516100ad919061056a565b60405180910390f35b6100c96100c43660046105d5565b61021c565b60405190151581526020016100ad565b6002545b6040519081526020016100ad565b6100c96100f93660046105ff565b610236565b604051601281526020016100ad565b6100dd61011b36600461063b565b6001600160a01b031660009081526020819052604090205490565b6100a061025a565b6100c961014c3660046105d5565b610269565b6100dd61015f36600461065d565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b60606003805461019990610690565b80601f01602080910402602001604051908101604052809291908181526020018280546101c590610690565b80156102125780601f106101e757610100808354040283529160200191610212565b820191906000526020600020905b8154815290600101906020018083116101f557829003601f168201915b5050505050905090565b60003361022a818585610277565b60019150505b92915050565b600033610244858285610289565b61024f85858561030c565b506001949350505050565b60606004805461019990610690565b60003361022a81858561030c565b610284838383600161036b565b505050565b6001600160a01b03838116600090815260016020908152604080832093861683529290522054600019811461030657818110156102f757604051637dc7a0d960e11b81526001600160a01b038416600482015260248101829052604481018390526064015b60405180910390fd5b6103068484848403600061036b565b50505050565b6001600160a01b03831661033657604051634b637e8f60e11b8152600060048201526024016102ee565b6001600160a01b0382166103605760405163ec442f0560e01b8152600060048201526024016102ee565b610284838383610440565b6001600160a01b0384166103955760405163e602df0560e01b8152600060048201526024016102ee565b6001600160a01b0383166103bf57604051634a1406b160e11b8152600060048201526024016102ee565b6001600160a01b038085166000908152600160209081526040808320938716835292905220829055801561030657826001600160a01b0316846001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9258460405161043291815260200190565b60405180910390a350505050565b6001600160a01b03831661046b57806002600082825461046091906106ca565b909155506104dd9050565b6001600160a01b038316600090815260208190526040902054818110156104be5760405163391434e360e21b81526001600160a01b038516600482015260248101829052604481018390526064016102ee565b6001600160a01b03841660009081526020819052604090209082900390555b6001600160a01b0382166104f957600280548290039055610518565b6001600160a01b03821660009081526020819052604090208054820190555b816001600160a01b0316836001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8360405161055d91815260200190565b60405180910390a3505050565b60006020808352835180602085015260005b818110156105985785810183015185820160400152820161057c565b506000604082860101526040601f19601f8301168501019250505092915050565b80356001600160a01b03811681146105d057600080fd5b919050565b600080604083850312156105e857600080fd5b6105f1836105b9565b946020939093013593505050565b60008060006060848603121561061457600080fd5b61061d846105b9565b925061062b602085016105b9565b9150604084013590509250925092565b60006020828403121561064d57600080fd5b610656826105b9565b9392505050565b6000806040838503121561067057600080fd5b610679836105b9565b9150610687602084016105b9565b90509250929050565b600181811c908216806106a457607f821691505b6020821081036106c457634e487b7160e01b600052602260045260246000fd5b50919050565b8082018082111561023057634e487b7160e01b600052601160045260246000fdfea264697066735822122080acf06e1b95d43c83c8428e0609fb7d11ff29753a63f5676f876109fc574dae64736f6c63430008190033000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000003b9aca0000000000000000000000000000000000000000000000000000000000000000036279640000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000362796400000000000000000000000000000000000000000000000000000000001ba0040c5c6a2b8c88fdd4752f1d57b688720c47660152a2dcc44dd88a08ed293f4fa01a2c8a5dc9acd27b9c5bc0c0951d3f51a7e69c5ce90b2453d8b8acb250009a8a"],"id":1} +13:48:18.407 [main] DEBUG org.web3j.protocol.http.HttpService -- --> END POST (6880-byte body) +13:48:18.752 [main] DEBUG org.web3j.protocol.http.HttpService -- <-- 200 https://sepolia.infura.io/v3/[your_infura_id] (345ms) +13:48:18.753 [main] DEBUG org.web3j.protocol.http.HttpService -- date: Sat, 06 Apr 2024 05:48:18 GMT +13:48:18.753 [main] DEBUG org.web3j.protocol.http.HttpService -- content-type: application/json +13:48:18.753 [main] DEBUG org.web3j.protocol.http.HttpService -- content-length: 102 +13:48:18.753 [main] DEBUG org.web3j.protocol.http.HttpService -- vary: Origin +13:48:18.753 [main] DEBUG org.web3j.protocol.http.HttpService -- vary: Accept-Encoding +13:48:18.753 [main] DEBUG org.web3j.protocol.http.HttpService -- +13:48:18.754 [main] DEBUG org.web3j.protocol.http.HttpService -- {"jsonrpc":"2.0","id":1,"result":"0x56ea32823805a3a7f46fe1af0214d809e53e8a1b4228c1b187d015b8de0905be"} +13:48:18.754 [main] DEBUG org.web3j.protocol.http.HttpService -- <-- END HTTP (102-byte body) +13:48:18.764 [main] DEBUG org.web3j.protocol.http.HttpService -- --> POST https://sepolia.infura.io/v3/[your_infura_id] +13:48:18.765 [main] DEBUG org.web3j.protocol.http.HttpService -- Content-Type: application/json; charset=utf-8 +13:48:18.765 [main] DEBUG org.web3j.protocol.http.HttpService -- Content-Length: 141 +13:48:18.765 [main] DEBUG org.web3j.protocol.http.HttpService -- +13:48:18.765 [main] DEBUG org.web3j.protocol.http.HttpService -- {"jsonrpc":"2.0","method":"eth_getTransactionReceipt","params":["0x56ea32823805a3a7f46fe1af0214d809e53e8a1b4228c1b187d015b8de0905be"],"id":2} +13:48:18.765 [main] DEBUG org.web3j.protocol.http.HttpService -- --> END POST (141-byte body) +13:48:19.047 [main] DEBUG org.web3j.protocol.http.HttpService -- <-- 200 https://sepolia.infura.io/v3/[your_infura_id] (282ms) +13:48:19.047 [main] DEBUG org.web3j.protocol.http.HttpService -- date: Sat, 06 Apr 2024 05:48:18 GMT +13:48:19.048 [main] DEBUG org.web3j.protocol.http.HttpService -- content-type: application/json +13:48:19.048 [main] DEBUG org.web3j.protocol.http.HttpService -- content-length: 38 +13:48:19.048 [main] DEBUG org.web3j.protocol.http.HttpService -- vary: Origin +13:48:19.048 [main] DEBUG org.web3j.protocol.http.HttpService -- vary: Accept-Encoding +13:48:19.048 [main] DEBUG org.web3j.protocol.http.HttpService -- +13:48:19.048 [main] DEBUG org.web3j.protocol.http.HttpService -- {"jsonrpc":"2.0","id":2,"result":null} +13:48:19.048 [main] DEBUG org.web3j.protocol.http.HttpService -- <-- END HTTP (38-byte body) +13:48:34.075 [main] DEBUG org.web3j.protocol.http.HttpService -- --> POST https://sepolia.infura.io/v3/[your_infura_id] +13:48:34.076 [main] DEBUG org.web3j.protocol.http.HttpService -- Content-Type: application/json; charset=utf-8 +13:48:34.076 [main] DEBUG org.web3j.protocol.http.HttpService -- Content-Length: 141 +13:48:34.076 [main] DEBUG org.web3j.protocol.http.HttpService -- +13:48:34.076 [main] DEBUG org.web3j.protocol.http.HttpService -- {"jsonrpc":"2.0","method":"eth_getTransactionReceipt","params":["0x56ea32823805a3a7f46fe1af0214d809e53e8a1b4228c1b187d015b8de0905be"],"id":3} +13:48:34.076 [main] DEBUG org.web3j.protocol.http.HttpService -- --> END POST (141-byte body) +13:48:34.427 [main] DEBUG org.web3j.protocol.http.HttpService -- <-- 200 https://sepolia.infura.io/v3/[your_infura_id] (350ms) +13:48:34.428 [main] DEBUG org.web3j.protocol.http.HttpService -- date: Sat, 06 Apr 2024 05:48:34 GMT +13:48:34.428 [main] DEBUG org.web3j.protocol.http.HttpService -- content-type: application/json +13:48:34.428 [main] DEBUG org.web3j.protocol.http.HttpService -- vary: Origin +13:48:34.428 [main] DEBUG org.web3j.protocol.http.HttpService -- vary: Accept-Encoding +13:48:34.428 [main] DEBUG org.web3j.protocol.http.HttpService -- +13:48:34.428 [main] DEBUG org.web3j.protocol.http.HttpService -- {"jsonrpc":"2.0","id":3,"result":{"blockHash":"0x966c3a8a35999ea01615bea15e449968c78c2999253ee11de12bb19c1cd0b661","blockNumber":"0x560c23","contractAddress":"0x70cbbb4f4f51a392a68aaffc3aae4fda6eb89081","cumulativeGasUsed":"0x9a0d6","effectiveGasPrice":"0xf4610900","from":"0xaa0087f012d788a11369c2a211f14f767aafdb16","gasUsed":"0x886ad","logs":[{"address":"0x70cbbb4f4f51a392a68aaffc3aae4fda6eb89081","blockHash":"0x966c3a8a35999ea01615bea15e449968c78c2999253ee11de12bb19c1cd0b661","blockNumber":"0x560c23","data":"0x000000000000000000000000000000000000000000000000000000003b9aca00","logIndex":"0x2","removed":false,"topics":["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef","0x0000000000000000000000000000000000000000000000000000000000000000","0x000000000000000000000000aa0087f012d788a11369c2a211f14f767aafdb16"],"transactionHash":"0x56ea32823805a3a7f46fe1af0214d809e53e8a1b4228c1b187d015b8de0905be","transactionIndex":"0x2"}],"logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000200000000000000000000000000000000020000000000000000000800000000000000000000000010000000000000000000000000000000000000000000000000000000800000000000000000000000010000000000000000000000000000000000000000000000000000000000000002000000000000000001000000000000000000000000000000000020000000000000000100000000000000000000000100000000000000000000000000","status":"0x1","to":null,"transactionHash":"0x56ea32823805a3a7f46fe1af0214d809e53e8a1b4228c1b187d015b8de0905be","transactionIndex":"0x2","type":"0x0"}} +13:48:34.428 [main] DEBUG org.web3j.protocol.http.HttpService -- <-- END HTTP (1629-byte body) +Contract address: 0x70cbbb4f4f51a392a68aaffc3aae4fda6eb89081 + +Deprecated Gradle features were used in this build, making it incompatible with Gradle 8.0. + +You can use '--warning-mode all' to show the individual deprecation warnings and determine if they come from your own scripts or plugins. + +See https://docs.gradle.org/7.6/userguide/command_line_interface.html#sec:command_line_warnings + +BUILD SUCCESSFUL in 20s +9 actionable tasks: 1 executed, 8 up-to-date +13:48:34: Execution finished ':Web3App.main()'. + +``` + + +## 部署合约的代码逻辑说明 +在[Web3App.java](./Web3App/src/main/java/org/web3j/Web3App.java)中,定义详细的部署Erc20合约的逻辑。 + +1. 读取节点或代理服务的url + 同时需要注意的是, 这里我们通过 infura 向对应的区块链网络发送交易, 而 INFURA_ID 这个变量值也需要配置在环境变量文件中, 具体如何获取 infura_id, 可自行搜索查找相关文档 + + ```java + String nodeUrl = System.getenv().getOrDefault("WEB3J_NODE_URL", ""); + ``` + +2. 读取私钥 + 处于安全考虑, 私钥没有进行硬编码, 而是通过环境变量的方式进行获取. 启动测试时, dotenv 插件自动读取 .env 配置文件中的配置项, 然后加载为环境变量, 之后在代码中可以通过 process.env 读取私钥 ( 也包括其他环境变量 ) + + ```java + private static final String pk1 = System.getenv().getOrDefault("PK_ACCT1", ""); + Credentials credentials = Credentials.create(pk1); + ``` + +3. 构造 web3j 对象 + 通过 web3j 对象可以很方便的发送相应的交易到区块链网络, 同时获取区块链的处理结果. + 构造 web3j 对象时, 主要需要传入一个参数, 就是对应的区块链网络, 包括 sepolia 等测试网络, 或是 mainnet 主网. + 这里我们使用 sepolia 测试网络. 如果没有 sepolia 网络的测试币, 可以切换到其他的测试网络. + + ```java + Web3j web3j = Web3j.build(new HttpService(nodeUrl)); + ``` + +4. 部署合约 + 这里发送签名后的交易到区块链网络, 同时得到返回的交易回执. 从返回的交易回执中可以得到此次部署的合约的地址 + + ```java + ERC20Token erc20Token = ERC20Token.deploy(web3j, credentials, new DefaultGasProvider(), NAME, SYMBOL, INITIAL_SUPPLY).send(); + ``` + + +## 载入和查询合约 +根据已部署的合约,可以自行编写代码,实现对合约的查询。 +在[Erc20Query.java](./Web3App/src/main/java/org/web3j/Erc20Query.java) +可以参考Erc20Query文件,以下为核心的代码: +``` + //刚才所部署的合约的地址 + private static final String erc20Addr = System.getenv().getOrDefault("ERC20_ADDR", "0x70cbbb4f4f51a392a68aaffc3aae4fda6eb89081"); + + + public static void main(String[] args) throws Exception { + Web3j web3j = Web3j.build(new HttpService(nodeUrl)); + Credentials credentials = Credentials.create(pk1); + ERC20Token eRC20Token= ERC20Token.load(erc20Addr, web3j, credentials, new DefaultGasProvider()); + //检查合约是否载入成功 + if (eRC20Token.isValid()) { + String name = eRC20Token.name().send(); + System.out.println("token name is " + name); + String symbol = eRC20Token.symbol().send(); + System.out.println("token symbol is " + symbol); + BigInteger totalSupply = eRC20Token.totalSupply().send(); + System.out.println("total supply is " + totalSupply); + } + web3j.shutdown(); + } +``` + +执行的结果如下: + +``` +14:38:46.954 [main] DEBUG org.web3j.protocol.http.HttpService -- --> POST https://sepolia.infura.io/v3/[your_infura_id] +14:38:46.955 [main] DEBUG org.web3j.protocol.http.HttpService -- Content-Type: application/json; charset=utf-8 +14:38:46.955 [main] DEBUG org.web3j.protocol.http.HttpService -- Content-Length: 112 +14:38:46.955 [main] DEBUG org.web3j.protocol.http.HttpService -- +14:38:46.955 [main] DEBUG org.web3j.protocol.http.HttpService -- {"jsonrpc":"2.0","method":"eth_getCode","params":["0x70cbbb4f4f51a392a68aaffc3aae4fda6eb89081","latest"],"id":0} +14:38:46.956 [main] DEBUG org.web3j.protocol.http.HttpService -- --> END POST (112-byte body) +SLF4J(W): Class path contains multiple SLF4J providers. +SLF4J(W): Found provider [ch.qos.logback.classic.spi.LogbackServiceProvider@4cb2c100] +SLF4J(W): Found provider [org.apache.logging.slf4j.SLF4JServiceProvider@6fb554cc] +SLF4J(W): See https://www.slf4j.org/codes.html#multiple_bindings for an explanation. +SLF4J(I): Actual provider is of type [ch.qos.logback.classic.spi.LogbackServiceProvider@4cb2c100] +14:38:48.725 [main] DEBUG org.web3j.protocol.http.HttpService -- <-- 200 https://sepolia.infura.io/v3/[your_infura_id] (1769ms) +14:38:48.727 [main] DEBUG org.web3j.protocol.http.HttpService -- date: Sat, 06 Apr 2024 06:38:48 GMT +14:38:48.727 [main] DEBUG org.web3j.protocol.http.HttpService -- content-type: application/json +14:38:48.727 [main] DEBUG org.web3j.protocol.http.HttpService -- vary: Origin +14:38:48.727 [main] DEBUG org.web3j.protocol.http.HttpService -- vary: Accept-Encoding +14:38:48.728 [main] DEBUG org.web3j.protocol.http.HttpService -- +14:38:48.728 [main] DEBUG org.web3j.protocol.http.HttpService -- {"jsonrpc":"2.0","id":0,"result":"0x608060405234801561001057600080fd5b50600436106100935760003560e01c8063313ce56711610066578063313ce567146100fe57806370a082311461010d57806395d89b4114610136578063a9059cbb1461013e578063dd62ed3e1461015157600080fd5b806306fdde0314610098578063095ea7b3146100b657806318160ddd146100d957806323b872dd146100eb575b600080fd5b6100a061018a565b6040516100ad919061056a565b60405180910390f35b6100c96100c43660046105d5565b61021c565b60405190151581526020016100ad565b6002545b6040519081526020016100ad565b6100c96100f93660046105ff565b610236565b604051601281526020016100ad565b6100dd61011b36600461063b565b6001600160a01b031660009081526020819052604090205490565b6100a061025a565b6100c961014c3660046105d5565b610269565b6100dd61015f36600461065d565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b60606003805461019990610690565b80601f01602080910402602001604051908101604052809291908181526020018280546101c590610690565b80156102125780601f106101e757610100808354040283529160200191610212565b820191906000526020600020905b8154815290600101906020018083116101f557829003601f168201915b5050505050905090565b60003361022a818585610277565b60019150505b92915050565b600033610244858285610289565b61024f85858561030c565b506001949350505050565b60606004805461019990610690565b60003361022a81858561030c565b610284838383600161036b565b505050565b6001600160a01b03838116600090815260016020908152604080832093861683529290522054600019811461030657818110156102f757604051637dc7a0d960e11b81526001600160a01b038416600482015260248101829052604481018390526064015b60405180910390fd5b6103068484848403600061036b565b50505050565b6001600160a01b03831661033657604051634b637e8f60e11b8152600060048201526024016102ee565b6001600160a01b0382166103605760405163ec442f0560e01b8152600060048201526024016102ee565b610284838383610440565b6001600160a01b0384166103955760405163e602df0560e01b8152600060048201526024016102ee565b6001600160a01b0383166103bf57604051634a1406b160e11b8152600060048201526024016102ee565b6001600160a01b038085166000908152600160209081526040808320938716835292905220829055801561030657826001600160a01b0316846001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9258460405161043291815260200190565b60405180910390a350505050565b6001600160a01b03831661046b57806002600082825461046091906106ca565b909155506104dd9050565b6001600160a01b038316600090815260208190526040902054818110156104be5760405163391434e360e21b81526001600160a01b038516600482015260248101829052604481018390526064016102ee565b6001600160a01b03841660009081526020819052604090209082900390555b6001600160a01b0382166104f957600280548290039055610518565b6001600160a01b03821660009081526020819052604090208054820190555b816001600160a01b0316836001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8360405161055d91815260200190565b60405180910390a3505050565b60006020808352835180602085015260005b818110156105985785810183015185820160400152820161057c565b506000604082860101526040601f19601f8301168501019250505092915050565b80356001600160a01b03811681146105d057600080fd5b919050565b600080604083850312156105e857600080fd5b6105f1836105b9565b946020939093013593505050565b60008060006060848603121561061457600080fd5b61061d846105b9565b925061062b602085016105b9565b9150604084013590509250925092565b60006020828403121561064d57600080fd5b610656826105b9565b9392505050565b6000806040838503121561067057600080fd5b610679836105b9565b9150610687602084016105b9565b90509250929050565b600181811c908216806106a457607f821691505b6020821081036106c457634e487b7160e01b600052602260045260246000fd5b50919050565b8082018082111561023057634e487b7160e01b600052601160045260246000fdfea264697066735822122080acf06e1b95d43c83c8428e0609fb7d11ff29753a63f5676f876109fc574dae64736f6c63430008190033"} +14:38:48.728 [main] DEBUG org.web3j.protocol.http.HttpService -- <-- END HTTP (3688-byte body) +14:38:48.765 [main] DEBUG org.web3j.protocol.http.HttpService -- --> POST https://sepolia.infura.io/v3/[your_infura_id] +14:38:48.765 [main] DEBUG org.web3j.protocol.http.HttpService -- Content-Type: application/json; charset=utf-8 +14:38:48.765 [main] DEBUG org.web3j.protocol.http.HttpService -- Content-Length: 188 +14:38:48.765 [main] DEBUG org.web3j.protocol.http.HttpService -- +14:38:48.765 [main] DEBUG org.web3j.protocol.http.HttpService -- {"jsonrpc":"2.0","method":"eth_call","params":[{"from":"0xaa0087f012d788a11369c2a211f14f767aafdb16","to":"0x70cbbb4f4f51a392a68aaffc3aae4fda6eb89081","data":"0x06fdde03"},"latest"],"id":1} +14:38:48.765 [main] DEBUG org.web3j.protocol.http.HttpService -- --> END POST (188-byte body) +14:38:49.049 [main] DEBUG org.web3j.protocol.http.HttpService -- <-- 200 https://sepolia.infura.io/v3/[your_infura_id] (283ms) +14:38:49.050 [main] DEBUG org.web3j.protocol.http.HttpService -- date: Sat, 06 Apr 2024 06:38:49 GMT +14:38:49.050 [main] DEBUG org.web3j.protocol.http.HttpService -- content-type: application/json +14:38:49.050 [main] DEBUG org.web3j.protocol.http.HttpService -- content-length: 230 +14:38:49.050 [main] DEBUG org.web3j.protocol.http.HttpService -- vary: Origin +14:38:49.050 [main] DEBUG org.web3j.protocol.http.HttpService -- vary: Accept-Encoding +14:38:49.050 [main] DEBUG org.web3j.protocol.http.HttpService -- +14:38:49.050 [main] DEBUG org.web3j.protocol.http.HttpService -- {"jsonrpc":"2.0","id":1,"result":"0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000036279640000000000000000000000000000000000000000000000000000000000"} +14:38:49.050 [main] DEBUG org.web3j.protocol.http.HttpService -- <-- END HTTP (230-byte body) +token name is byd +14:38:49.072 [main] DEBUG org.web3j.protocol.http.HttpService -- --> POST https://sepolia.infura.io/v3/[your_infura_id] +14:38:49.072 [main] DEBUG org.web3j.protocol.http.HttpService -- Content-Type: application/json; charset=utf-8 +14:38:49.072 [main] DEBUG org.web3j.protocol.http.HttpService -- Content-Length: 188 +14:38:49.072 [main] DEBUG org.web3j.protocol.http.HttpService -- +14:38:49.072 [main] DEBUG org.web3j.protocol.http.HttpService -- {"jsonrpc":"2.0","method":"eth_call","params":[{"from":"0xaa0087f012d788a11369c2a211f14f767aafdb16","to":"0x70cbbb4f4f51a392a68aaffc3aae4fda6eb89081","data":"0x95d89b41"},"latest"],"id":2} +14:38:49.072 [main] DEBUG org.web3j.protocol.http.HttpService -- --> END POST (188-byte body) +14:38:49.422 [main] DEBUG org.web3j.protocol.http.HttpService -- <-- 200 https://sepolia.infura.io/v3/[your_infura_id] (349ms) +14:38:49.422 [main] DEBUG org.web3j.protocol.http.HttpService -- date: Sat, 06 Apr 2024 06:38:49 GMT +14:38:49.422 [main] DEBUG org.web3j.protocol.http.HttpService -- content-type: application/json +14:38:49.422 [main] DEBUG org.web3j.protocol.http.HttpService -- content-length: 230 +14:38:49.422 [main] DEBUG org.web3j.protocol.http.HttpService -- vary: Origin +14:38:49.422 [main] DEBUG org.web3j.protocol.http.HttpService -- vary: Accept-Encoding +14:38:49.423 [main] DEBUG org.web3j.protocol.http.HttpService -- +14:38:49.423 [main] DEBUG org.web3j.protocol.http.HttpService -- {"jsonrpc":"2.0","id":2,"result":"0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000036279640000000000000000000000000000000000000000000000000000000000"} +14:38:49.423 [main] DEBUG org.web3j.protocol.http.HttpService -- <-- END HTTP (230-byte body) +token symbol is byd +14:38:49.425 [main] DEBUG org.web3j.protocol.http.HttpService -- --> POST https://sepolia.infura.io/v3/[your_infura_id] +14:38:49.425 [main] DEBUG org.web3j.protocol.http.HttpService -- Content-Type: application/json; charset=utf-8 +14:38:49.425 [main] DEBUG org.web3j.protocol.http.HttpService -- Content-Length: 188 +14:38:49.425 [main] DEBUG org.web3j.protocol.http.HttpService -- +14:38:49.425 [main] DEBUG org.web3j.protocol.http.HttpService -- {"jsonrpc":"2.0","method":"eth_call","params":[{"from":"0xaa0087f012d788a11369c2a211f14f767aafdb16","to":"0x70cbbb4f4f51a392a68aaffc3aae4fda6eb89081","data":"0x18160ddd"},"latest"],"id":3} +14:38:49.425 [main] DEBUG org.web3j.protocol.http.HttpService -- --> END POST (188-byte body) +14:38:49.728 [main] DEBUG org.web3j.protocol.http.HttpService -- <-- 200 https://sepolia.infura.io/v3/[your_infura_id] (302ms) +14:38:49.728 [main] DEBUG org.web3j.protocol.http.HttpService -- date: Sat, 06 Apr 2024 06:38:49 GMT +14:38:49.728 [main] DEBUG org.web3j.protocol.http.HttpService -- content-type: application/json +14:38:49.728 [main] DEBUG org.web3j.protocol.http.HttpService -- content-length: 102 +14:38:49.728 [main] DEBUG org.web3j.protocol.http.HttpService -- vary: Origin +14:38:49.728 [main] DEBUG org.web3j.protocol.http.HttpService -- vary: Accept-Encoding +14:38:49.728 [main] DEBUG org.web3j.protocol.http.HttpService -- +14:38:49.729 [main] DEBUG org.web3j.protocol.http.HttpService -- {"jsonrpc":"2.0","id":3,"result":"0x000000000000000000000000000000000000000000000000000000003b9aca00"} +14:38:49.729 [main] DEBUG org.web3j.protocol.http.HttpService -- <-- END HTTP (102-byte body) +total supply is 1000000000 + +``` + + +## Erc20 合约功能说明 + +- IERC20 + totalSupply: 获取该合约内总的 ERC20 Token 总量 + balanceOf: 获取特定账户的 ERC20 Token 总量 + transfer: 向目标账户转移特定数量的 ERC20 Token + allowance: 获取目标账户能够使用的源账户的 ERC20 Token 数量 + approve: 向目标账户授权, 可以转移指定额度的 ERC20 Token 数量 + transferFrom: ( 第三方调用 ) 从源账户向目标账户转移制定数量的 ERC20 Token + +- IERC20Metadata + name: 返回 Token 的名称 + symbol: 返回 Token 的符号 + decimals: 返回 Token 所支持的精度 + + +## 参考文档 +- Web3j 项目地址: https://github.com/web3j/web3j +- Web3j docs: https://docs.web3j.io/4.11.0/ +- Web3j Client 说明: https://docs.web3j.io/4.8.7/command_line_tools/ +- ERC20 接口及合约说明:https://docs.openzeppelin.com/contracts/2.x/api/token/erc20 diff --git a/basic/81-web3j-erc20/Web3App/build.gradle b/basic/81-web3j-erc20/Web3App/build.gradle new file mode 100644 index 000000000..0faa391fb --- /dev/null +++ b/basic/81-web3j-erc20/Web3App/build.gradle @@ -0,0 +1,100 @@ +plugins { + id 'java' + id 'org.jetbrains.kotlin.jvm' version '1.8.10' + id 'application' + id "com.github.johnrengelman.shadow" version "5.2.0" + id 'org.web3j' version '4.11.2' +} + +group 'org.web3j' +version '0.1.0' + +sourceCompatibility = 17 + +repositories { + mavenLocal() + mavenCentral() + maven { url "https://hyperledger.jfrog.io/hyperledger/besu-maven" } + maven { url "https://artifacts.consensys.net/public/maven/maven/" } + maven { url "https://splunk.jfrog.io/splunk/ext-releases-local" } +} + +web3j { + generatedPackageName = 'org.web3j.generated.contracts' + includedContracts = ['ERC20Token'] +} + +node { + nodeProjectDir.set(file("$projectDir")) +} + +ext { + web3jVersion = '4.11.2' + logbackVersion = '1.4.14' + klaxonVersion = '5.5' + besuPluginVersion = '24.1.1' + besuInternalVersion = '24.1.1' + besuInternalCryptoVersion = '23.1.3' + besuCryptoDepVersion = '0.8.3' +} + +dependencies { + implementation "org.web3j:core:$web3jVersion", + "ch.qos.logback:logback-core:$logbackVersion", + "ch.qos.logback:logback-classic:$logbackVersion", + "com.beust:klaxon:$klaxonVersion" + implementation "org.web3j:web3j-unit:$web3jVersion" + implementation "org.web3j:web3j-evm:$web3jVersion" + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8" + testImplementation 'org.junit.jupiter:junit-jupiter-api:5.3.1' + testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.3.1' + + implementation "org.hyperledger.besu:plugin-api:$besuPluginVersion" + implementation "org.hyperledger.besu.internal:besu:$besuInternalVersion" + implementation "org.hyperledger.besu.internal:api:$besuInternalVersion" + implementation "org.hyperledger.besu:evm:$besuPluginVersion" + implementation "org.hyperledger.besu.internal:config:$besuInternalVersion" + implementation "org.hyperledger.besu.internal:core:$besuInternalVersion" + implementation "org.hyperledger.besu.internal:crypto:$besuInternalCryptoVersion" + implementation "org.hyperledger.besu.internal:rlp:$besuInternalVersion" + implementation "org.hyperledger.besu.internal:kvstore:$besuInternalVersion" + implementation "org.hyperledger.besu.internal:metrics-core:$besuInternalVersion" + implementation "org.hyperledger.besu.internal:trie:$besuInternalVersion" + implementation "org.hyperledger.besu.internal:util:$besuInternalVersion" + implementation "org.hyperledger.besu:bls12-381:$besuCryptoDepVersion" + implementation "org.hyperledger.besu:secp256k1:$besuCryptoDepVersion" +} + +jar { + manifest { + attributes( + 'Main-Class': 'org.web3j.Web3App', + 'Multi-Release':'true' + ) + } +} + +application { + mainClassName = 'org.web3j.Web3App' +} + +test { + useJUnitPlatform() +} + +compileKotlin { + kotlinOptions.jvmTarget = "17" +} + +compileTestKotlin { + kotlinOptions.jvmTarget = "17" +} + +solidity { + evmVersion = 'constantinople' +} + +shadowJar { + zip64 = true +} + diff --git a/basic/81-web3j-erc20/Web3App/settings.gradle b/basic/81-web3j-erc20/Web3App/settings.gradle new file mode 100644 index 000000000..a88c03afa --- /dev/null +++ b/basic/81-web3j-erc20/Web3App/settings.gradle @@ -0,0 +1,10 @@ +pluginManagement { + repositories { + mavenLocal() + gradlePluginPortal() + maven { url "https://hyperledger.jfrog.io/hyperledger/besu-maven" } + maven { url "https://artifacts.consensys.net/public/maven/maven/" } + maven { url "https://splunk.jfrog.io/splunk/ext-releases-local" } + } +} +rootProject.name = 'Web3App'; diff --git a/basic/81-web3j-erc20/Web3App/src/main/java/org/web3j/Erc20Query.java b/basic/81-web3j-erc20/Web3App/src/main/java/org/web3j/Erc20Query.java new file mode 100644 index 000000000..3e15ff75a --- /dev/null +++ b/basic/81-web3j-erc20/Web3App/src/main/java/org/web3j/Erc20Query.java @@ -0,0 +1,33 @@ +package org.web3j; + +import org.web3j.crypto.Credentials; +import org.web3j.generated.contracts.ERC20Token; +import org.web3j.protocol.Web3j; +import org.web3j.protocol.http.HttpService; +import org.web3j.tx.gas.DefaultGasProvider; + +import java.math.BigInteger; + +public class Erc20Query { + + private static final String nodeUrl = System.getenv().getOrDefault("WEB3J_NODE_URL", ""); + private static final String pk1 = System.getenv().getOrDefault("PK_ACCT1", ""); + + private static final String erc20Addr = System.getenv().getOrDefault("ERC20_ADDR", "0x70cbbb4f4f51a392a68aaffc3aae4fda6eb89081"); + + + public static void main(String[] args) throws Exception { + Web3j web3j = Web3j.build(new HttpService(nodeUrl)); + Credentials credentials = Credentials.create(pk1); + ERC20Token eRC20Token= ERC20Token.load(erc20Addr, web3j, credentials, new DefaultGasProvider()); + if (eRC20Token.isValid()) { + String name = eRC20Token.name().send(); + System.out.println("token name is " + name); + String symbol = eRC20Token.symbol().send(); + System.out.println("token symbol is " + symbol); + BigInteger totalSupply = eRC20Token.totalSupply().send(); + System.out.println("total supply is " + totalSupply); + } + web3j.shutdown(); + } +} diff --git a/basic/81-web3j-erc20/Web3App/src/main/java/org/web3j/Web3App.java b/basic/81-web3j-erc20/Web3App/src/main/java/org/web3j/Web3App.java new file mode 100644 index 000000000..0f4388dd6 --- /dev/null +++ b/basic/81-web3j-erc20/Web3App/src/main/java/org/web3j/Web3App.java @@ -0,0 +1,32 @@ +package org.web3j; + +import org.web3j.crypto.Credentials; +import org.web3j.crypto.WalletUtils; +import org.web3j.protocol.Web3j; +import org.web3j.protocol.http.HttpService; +import org.web3j.tx.gas.DefaultGasProvider; + +import java.math.BigInteger; + +import org.web3j.generated.contracts.ERC20Token; + +public class Web3App { + + // ERC20 token deployment parameters + private static final String NAME = "byd"; + private static final String SYMBOL = "byd"; + private static final BigInteger INITIAL_SUPPLY = new BigInteger("1000000000"); + private static final String nodeUrl = System.getenv().getOrDefault("WEB3J_NODE_URL", ""); + private static final String pk1 = System.getenv().getOrDefault("PK_ACCT1", ""); + + + public static void main(String[] args) throws Exception { + System.out.println("nodeUrl is: " + nodeUrl); + System.out.println("private key is: [" + pk1 +"]"); + Credentials credentials = Credentials.create(pk1); + Web3j web3j = Web3j.build(new HttpService(nodeUrl)); + System.out.println("Deploying ERC20 contract ..."); + ERC20Token erc20Token = ERC20Token.deploy(web3j, credentials, new DefaultGasProvider(), NAME, SYMBOL, INITIAL_SUPPLY).send(); + System.out.println("Contract address: " + erc20Token.getContractAddress()); + } +} diff --git a/basic/81-web3j-erc20/Web3App/src/main/solidity/ERC20Token.sol b/basic/81-web3j-erc20/Web3App/src/main/solidity/ERC20Token.sol new file mode 100644 index 000000000..6c8186926 --- /dev/null +++ b/basic/81-web3j-erc20/Web3App/src/main/solidity/ERC20Token.sol @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: Apache-2.0 +pragma solidity ^0.8.0; + +import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; + +/** + * @title ERC20Token + * @dev Simple ERC20 Token based on OpenZeppelin implementation, where all tokens are pre-assigned to the creator. + * Note they can later distribute these tokens as they wish using `transfer` and other + * `ERC20`. + */ +contract ERC20Token is ERC20 { + + /** + * @dev Constructor that gives msg.sender all of existing tokens. + */ + constructor ( + string memory name, + string memory symbol, + uint256 initialSupply) public ERC20(name, symbol) { + _mint(msg.sender, initialSupply); + } +} diff --git a/basic/81-web3j-erc20/Web3App/src/test/java/org/web3j/generated/contracts/ERC20TokenTest.java b/basic/81-web3j-erc20/Web3App/src/test/java/org/web3j/generated/contracts/ERC20TokenTest.java new file mode 100644 index 000000000..f6b80fd0f --- /dev/null +++ b/basic/81-web3j-erc20/Web3App/src/test/java/org/web3j/generated/contracts/ERC20TokenTest.java @@ -0,0 +1,83 @@ +package org.web3j.generated.contracts; + +import java.lang.Exception; +import java.lang.String; +import java.math.BigInteger; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.web3j.EVMTest; +import org.web3j.protocol.Web3j; +import org.web3j.protocol.core.methods.response.TransactionReceipt; +import org.web3j.tx.TransactionManager; +import org.web3j.tx.gas.ContractGasProvider; + +@EVMTest +class ERC20TokenTest { + private static ERC20Token eRC20Token; + + @Test + public void transferFrom() throws Exception { + TransactionReceipt transactionReceiptVar = eRC20Token.transferFrom("REPLACE_ME", "REPLACE_ME", BigInteger.ONE).send(); + Assertions.assertTrue(transactionReceiptVar.isStatusOK()); + } + + @Test + public void name() throws Exception { + String stringVar = eRC20Token.name().send(); + Assertions.assertEquals("REPLACE_ME", stringVar); + } + + @Test + public void transfer() throws Exception { + TransactionReceipt transactionReceiptVar = eRC20Token.transfer("REPLACE_ME", BigInteger.ONE).send(); + Assertions.assertTrue(transactionReceiptVar.isStatusOK()); + } + + @Test + public void symbol() throws Exception { + String stringVar = eRC20Token.symbol().send(); + Assertions.assertEquals("REPLACE_ME", stringVar); + } + + @Test + public void totalSupply() throws Exception { + BigInteger bigIntegerVar = eRC20Token.totalSupply().send(); + Assertions.assertEquals(BigInteger.ONE, bigIntegerVar); + } + + @Test + public void getDeploymentBinary() throws Exception { + String stringVar = eRC20Token.getDeploymentBinary().send(); + Assertions.assertEquals("REPLACE_ME", stringVar); + } + + @BeforeAll + static void deploy(Web3j web3j, TransactionManager transactionManager, ContractGasProvider contractGasProvider) throws Exception { + eRC20Token = ERC20Token.deploy(web3j, transactionManager, contractGasProvider, "REPLACE_ME", "REPLACE_ME", BigInteger.ONE).send(); + } + + @Test + public void balanceOf() throws Exception { + BigInteger bigIntegerVar = eRC20Token.balanceOf("REPLACE_ME").send(); + Assertions.assertEquals(BigInteger.ONE, bigIntegerVar); + } + + @Test + public void decimals() throws Exception { + BigInteger bigIntegerVar = eRC20Token.decimals().send(); + Assertions.assertEquals(BigInteger.ONE, bigIntegerVar); + } + + @Test + public void allowance() throws Exception { + BigInteger bigIntegerVar = eRC20Token.allowance("REPLACE_ME", "REPLACE_ME").send(); + Assertions.assertEquals(BigInteger.ONE, bigIntegerVar); + } + + @Test + public void approve() throws Exception { + TransactionReceipt transactionReceiptVar = eRC20Token.approve("REPLACE_ME", BigInteger.ONE).send(); + Assertions.assertTrue(transactionReceiptVar.isStatusOK()); + } +} diff --git a/basic/81-web3j-erc20/assets/web3j_network.png b/basic/81-web3j-erc20/assets/web3j_network.png new file mode 100644 index 0000000000000000000000000000000000000000..2ee7caa6d993c433b3e29b8ae633301d409ed369 GIT binary patch literal 71671 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