Repository: jambestwick/web3jdemo Branch: master Commit: f96d92fbef28 Files: 52 Total size: 146.8 KB Directory structure: gitextract_jzx28jab/ ├── .github/ │ └── FUNDING.yml ├── .gitignore ├── README.EN.MD ├── README.md ├── build.gradle ├── gradle/ │ └── wrapper/ │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── settings.gradle └── src/ └── main/ ├── java/ │ └── com/ │ └── we3j/ │ └── demo/ │ ├── Application.java │ ├── bean/ │ │ ├── Account.java │ │ └── bo/ │ │ └── ReceiveAccount.java │ ├── controller/ │ │ └── TestController.java │ ├── service/ │ │ └── etherscan_api/ │ │ ├── Endpoint.java │ │ ├── key/ │ │ │ └── ApiKey.java │ │ ├── params/ │ │ │ ├── Sort.java │ │ │ ├── accounts/ │ │ │ │ └── AccountAPI.java │ │ │ ├── blocks/ │ │ │ │ ├── BlockOrder.java │ │ │ │ └── BlocksAPI.java │ │ │ ├── contracts/ │ │ │ │ └── ContractAPI.java │ │ │ ├── gas_tracker/ │ │ │ │ └── GasTackerAPI.java │ │ │ ├── logs/ │ │ │ │ └── logAPI.java │ │ │ ├── stats/ │ │ │ │ └── StatsAPI.java │ │ │ ├── tokens/ │ │ │ │ └── TokensAPI.java │ │ │ └── transactions/ │ │ │ └── TransactionsAPI.java │ │ ├── request/ │ │ │ └── Method.java │ │ └── response/ │ │ └── ApiResponse.java │ ├── sol/ │ │ ├── TokenERC20.java │ │ └── TokenERC71.java │ ├── test/ │ │ ├── ContractDemo.java │ │ ├── WalletDemo.java │ │ └── mona/ │ │ ├── BuildInviteCodeRequest.java │ │ ├── Constants.java │ │ ├── RandomUtil.java │ │ └── RequestUtil.java │ ├── utils/ │ │ ├── AccountUtil.java │ │ ├── CloseUtils.java │ │ ├── Environment.java │ │ ├── FileUtil.java │ │ ├── NormalUtil.java │ │ ├── RSAEncrypt.java │ │ ├── ScheduleTask.java │ │ └── TimeUtil.java │ └── wallet/ │ ├── NFTMonitor.java │ ├── TokenClient.java │ ├── TransMonitor.java │ ├── TransferToken.java │ ├── WalletTools.java │ └── Web3jInfo.java └── resources/ ├── application-dev.properties └── application.properties ================================================ FILE CONTENTS ================================================ ================================================ FILE: .github/FUNDING.yml ================================================ github: [NateRiver, jambestwick] custom: ["https://github.com/jambestwick/jambestwick/blob/master/src/images/1f7d1b1642bda36dab989af741e3f5b.jpg","https://github.com/jambestwick/jambestwick/blob/master/src/images/4b1d5a5b28c6f45bc5e5bf2a6f59548.jpg"] ================================================ FILE: .gitignore ================================================ # Created by .ignore support plugin (hsz.mobi) ### Java template *.class # Mobile Tools for Java (J2ME) .mtj.tmp/ # Package Files # *.jar *.war *.ear # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml hs_err_pid* ### Gradle template .gradle /build /out */build/ */out/ gradle.properties # Ignore Gradle GUI config gradle-app.setting # Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored) !gradle-wrapper.jar # Cache of project .gradletasknamecache # Work around https://youtrack.jetbrains.com/issue/IDEA-116898 # gradle/wrapper/gradle-wrapper.properties .idea *.iml geth.sh # Sphinx generated docs docs/build # OS X .DS_Store ================================================ FILE: README.EN.MD ================================================ ## Introduction ### **[chinese doc](https://github.com/jambestwick/we3jdemo/blob/master/README.md)** # simple web3j Demo to be continue,use web3j Brainless Trading,tool for arbitrage automatic trading, copying other transfer,tracking agency addresses, setting profit points, setting prices, grabbing blocks ... ... 1. open Source。 2. web3j It's a lightweight java library for accessing Ethereum, used to connect the client to the Ethereum blockchain node。 ## Related functions: 1 Connect to the Ethereum client 2 Create a cold wallet 3 Load wallet 4 Transfer ETH, transfer ERC20 tokens, batch transfer function 5 Check balances 6 Deploy the contract 7 Read & update smart contract data 8 Observe the smart contract event 9 lock/unlock account 10 Generate wallet mnemonics in batches and save files line by line 11 call the contract function approve,transfer,transferForm 12.add contract Approve,Transfer Event Listener ## Documentation continue updating...... original blog :[old blog http://blog.csdn.net/baidu_30084597](http://blog.csdn.net/baidu_30084597) blog [now blog https://blog.csdn.net/weixin_41602901](https://blog.csdn.net/weixin_41602901) ================================================ FILE: README.md ================================================ ## 简介 [![](https://jitpack.io/v/jambestwick/web3jdemo.svg)](https://jitpack.io/#jambestwick/web3jdemo) ### **[english doc](https://github.com/jambestwick/we3jdemo/blob/master/README.EN.MD)** # 基础web3j基础上手款Demo 持续更新,做到web3j无脑交易 套利第一工具,自动买卖、跟单、追踪机构地址、设置利润点、设置价格、抢跑区块等... ... 1. 代码开源。 2. web3j是一个用于访问以太坊的轻量级的java库,用于连接客户端和以太坊区块链结点。 ## 相关功能: 1 连接以太坊客户端 2 创建冷钱包 3 加载钱包文件 4 转账ETH,转账ERC20代币,批量转账功能 5 查询余额 6 部署合约 7 读取&更新 智能合约的数据 8 观察智能合约event 9 账号的锁定与解锁 10 批量生成钱包助记词,逐行保存文件 11.完善合约函数调用approve,transfer,transferForm等 12.增加Approve,Transfer Event监听 13.增加mint,定时任务,NFT...... ## 说明文档 持续更新中...... web3j对基础开发者调用不太友好, JS版本对开发周期和成本相对比较简单. 描述上述功能均为组合功能,需要对基础方法有一定了解,设计好流程思路, 声明:恶意使用,组合编码,产生法律风险自负 原博客 http://blog.csdn.net/baidu_30084597 现博客 https://blog.csdn.net/weixin_41602901 抽空把所有功能更新全吧,再做个网页提供使用 说实在的,写脚本真的很无聊 ================================================ FILE: build.gradle ================================================ buildscript { ext { springBootVersion = '1.5.7.RELEASE' } repositories { maven { url 'http://maven.aliyun.com/nexus/content/groups/public/' } mavenCentral() mavenLocal() } dependencies { classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}") } } group 'com.web3j.demo' version '1.0.2' apply plugin: 'java' apply plugin: 'idea' apply plugin: 'org.springframework.boot' sourceCompatibility = 1.8 repositories { maven { url 'http://maven.aliyun.com/nexus/content/groups/public/' } mavenCentral() mavenLocal() } dependencies { compile( "org.springframework.boot:spring-boot-starter-web", "org.springframework.boot:spring-boot-starter-aop", "org.springframework.boot:spring-boot-starter-websocket" ) compile "org.web3j:core:3.6.0" compile "org.web3j:geth:3.6.0" compile "org.bitcoinj:bitcoinj-core:0.14.6" compile "ch.qos.logback:logback-core:1.2.3" compile "ch.qos.logback:logback-classic:1.2.3" testCompile "junit:junit:4.12" // https://mvnrepository.com/artifact/com.squareup.retrofit2/retrofit // https://mvnrepository.com/artifact/com.github.lianjiatech/retrofit-spring-boot-starter compile 'com.github.lianjiatech:retrofit-spring-boot-starter:2.2.17' compile 'com.alibaba:fastjson:1.2.78' compile group: 'org.apache.shiro', name: 'shiro-spring', version: '1.4.0' testCompile group: 'junit', name: 'junit', version: '4.12' testCompile('org.springframework.boot:spring-boot-starter-test') } ================================================ FILE: gradle/wrapper/gradle-wrapper.properties ================================================ #Mon Apr 09 11:54:45 CST 2018 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-4.10-bin.zip ================================================ FILE: gradlew ================================================ #!/usr/bin/env sh ############################################################################## ## ## Gradle start up script for UN*X ## ############################################################################## # Attempt to set APP_HOME # Resolve links: $0 may be a link PRG="$0" # Need this for relative symlinks. while [ -h "$PRG" ] ; do ls=`ls -ld "$PRG"` link=`expr "$ls" : '.*-> \(.*\)$'` if expr "$link" : '/.*' > /dev/null; then PRG="$link" else PRG=`dirname "$PRG"`"/$link" fi done SAVED="`pwd`" cd "`dirname \"$PRG\"`/" >/dev/null APP_HOME="`pwd -P`" cd "$SAVED" >/dev/null APP_NAME="Gradle" APP_BASE_NAME=`basename "$0"` # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS="" # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD="maximum" warn () { echo "$*" } die () { echo echo "$*" echo exit 1 } # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false case "`uname`" in CYGWIN* ) cygwin=true ;; Darwin* ) darwin=true ;; MINGW* ) msys=true ;; NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables JAVACMD="$JAVA_HOME/jre/sh/java" else JAVACMD="$JAVA_HOME/bin/java" fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else JAVACMD="java" which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi # Increase the maximum file descriptors if we can. if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then MAX_FD_LIMIT=`ulimit -H -n` if [ $? -eq 0 ] ; then if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then MAX_FD="$MAX_FD_LIMIT" fi ulimit -n $MAX_FD if [ $? -ne 0 ] ; then warn "Could not set maximum file descriptor limit: $MAX_FD" fi else warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" fi fi # For Darwin, add options to specify how the application appears in the dock if $darwin; then GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" fi # For Cygwin, switch paths to Windows format before running java if $cygwin ; then APP_HOME=`cygpath --path --mixed "$APP_HOME"` CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` JAVACMD=`cygpath --unix "$JAVACMD"` # We build the pattern for arguments to be converted via cygpath ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` SEP="" for dir in $ROOTDIRSRAW ; do ROOTDIRS="$ROOTDIRS$SEP$dir" SEP="|" done OURCYGPATTERN="(^($ROOTDIRS))" # Add a user-defined pattern to the cygpath arguments if [ "$GRADLE_CYGPATTERN" != "" ] ; then OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" fi # Now convert the arguments - kludge to limit ourselves to /bin/sh i=0 for arg in "$@" ; do CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` else eval `echo args$i`="\"$arg\"" fi i=$((i+1)) done case $i in (0) set -- ;; (1) set -- "$args0" ;; (2) set -- "$args0" "$args1" ;; (3) set -- "$args0" "$args1" "$args2" ;; (4) set -- "$args0" "$args1" "$args2" "$args3" ;; (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; esac fi # Escape application args save () { for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done echo " " } APP_ARGS=$(save "$@") # Collect all arguments for the java command, following the shell quoting and substitution rules eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then cd "$(dirname "$0")" fi exec "$JAVACMD" "$@" ================================================ FILE: gradlew.bat ================================================ @if "%DEBUG%" == "" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @rem @rem ########################################################################## @rem Set local scope for the variables with windows NT shell if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 if "%DIRNAME%" == "" set DIRNAME=. set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. set DEFAULT_JVM_OPTS= @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if "%ERRORLEVEL%" == "0" goto init echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :findJavaFromJavaHome set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto init echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :init @rem Get command-line arguments, handling Windows variants if not "%OS%" == "Windows_NT" goto win9xME_args :win9xME_args @rem Slurp the command line arguments. set CMD_LINE_ARGS= set _SKIP=2 :win9xME_args_slurp if "x%~1" == "x" goto execute set CMD_LINE_ARGS=%* :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% :end @rem End local scope for the variables with windows NT shell if "%ERRORLEVEL%"=="0" goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 exit /b 1 :mainEnd if "%OS%"=="Windows_NT" endlocal :omega ================================================ FILE: settings.gradle ================================================ rootProject.name = 'we3jdemo' ================================================ FILE: src/main/java/com/we3j/demo/Application.java ================================================ package com.we3j.demo; import com.github.lianjiatech.retrofit.spring.boot.annotation.RetrofitScan; import com.we3j.demo.test.WalletDemo; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.scheduling.annotation.EnableScheduling; /** * 本案例作为web3j的示例项目 * 1 连接以太坊客户端 * 2 创建冷钱包 * 3 加载钱包文件 * 4 转账 * 5 部署合约 * 6 读取&更新 智能合约的数据 * 7 观察智能合约event */ @SpringBootApplication @EnableScheduling @RetrofitScan("com.web3j.demo.controller") public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } } ================================================ FILE: src/main/java/com/we3j/demo/bean/Account.java ================================================ package com.we3j.demo.bean; import java.io.Serializable; import java.math.BigInteger; /** * * Created by jambestwick@126.com * * on 2021/12/3 * * */ public class Account implements Serializable { private String address; private BigInteger balance;//wei private String privateKey; private String publicKey; public String getAddress() { return address; } public void setAddress(String address) { this.address = address; } public BigInteger getBalance() { return balance; } public void setBalance(BigInteger balance) { this.balance = balance; } public String getPrivateKey() { return privateKey; } public void setPrivateKey(String privateKey) { this.privateKey = privateKey; } public String getPublicKey() { return publicKey; } public void setPublicKey(String publicKey) { this.publicKey = publicKey; } @Override public String toString() { return "Account{" + "address='" + address + '\'' + ", balance=" + balance + ", privateKey='" + privateKey + '\'' + ", publicKey='" + publicKey + '\'' + '}'; } } ================================================ FILE: src/main/java/com/we3j/demo/bean/bo/ReceiveAccount.java ================================================ package com.we3j.demo.bean.bo; import com.we3j.demo.bean.Account; import java.io.Serializable; import java.math.BigDecimal; /** * * Created by jambestwick@126.com * * on 2021/12/3 * * */ public class ReceiveAccount extends Account implements Serializable { private BigDecimal sendAmount; public BigDecimal getSendAmount() { return sendAmount; } public void setSendAmount(BigDecimal sendAmount) { this.sendAmount = sendAmount; } } ================================================ FILE: src/main/java/com/we3j/demo/controller/TestController.java ================================================ package com.we3j.demo.controller; import com.we3j.demo.service.etherscan_api.key.ApiKey; import com.we3j.demo.service.etherscan_api.params.accounts.AccountAPI; import com.we3j.demo.service.etherscan_api.params.tokens.TokensAPI; import com.we3j.demo.service.etherscan_api.params.transactions.TransactionsAPI; import com.we3j.demo.service.etherscan_api.response.ApiResponse; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.RestController; import javax.annotation.Resource; /** * * Created by jambestwick@126.com * * on 2021/12/8 * * */ @RestController @RequestMapping("/test") public class TestController { @Resource AccountAPI accountAPI; @Resource TransactionsAPI transactionsAPI; @Resource TokensAPI tokensAPI; @RequestMapping(value = "/account", method = RequestMethod.POST) @ResponseBody public ApiResponse batchUpdateLabelGPS() { try { ApiResponse result = accountAPI.getSingleAddressBalance("account", "balance", "0x0fb6160F1738ee5243cB3ED421dc0CEa2cf1C0D4", "latest", ApiKey.KEY); System.out.println("res:" + result); return null; } catch (Exception e) { e.printStackTrace(); return null; } } } ================================================ FILE: src/main/java/com/we3j/demo/service/etherscan_api/Endpoint.java ================================================ package com.we3j.demo.service.etherscan_api; /** * * An API key generated on Etherscan ​ can be used across all mainnet and testnet explorers. * * Similarly, all endpoints and parameter formatting remain the same across testnet explorers, you are only required to change the relevant API endpoint URL as follows. * https://docs.etherscan.io/getting-started/endpoint-urls */ public class Endpoint { //https://docs.etherscan.io public static String MAIN_NET = "https://api.etherscan.io/"; //https://docs.etherscan.io/v/goerli-etherscan public static String GOERLI = "https://api-goerli.etherscan.io/"; //https://docs.etherscan.io/v/kovan-etherscan public static String KOVAN = "https://api-kovan.etherscan.io/"; //https://docs.etherscan.io/v/rinkeby-etherscan public static String RINKEBY = "https://api-rinkeby.etherscan.io/"; //https://docs.etherscan.io/v/ropsten-etherscan public static String ROPSTEN = "https://api-ropsten.etherscan.io/"; } ================================================ FILE: src/main/java/com/we3j/demo/service/etherscan_api/key/ApiKey.java ================================================ package com.we3j.demo.service.etherscan_api.key; /** * * * * @see {etherenum -scan }https://docs.etherscan.io/ * API keys created from your account dashboard can also be used for the Kovan, Rinkeby, Ropsten, and Goerli testnet explorers . */ public class ApiKey { /*** * * API keys created on Etherscan.io can be used for the Kovan, Rinkeby, Ropsten, and Goerli Testnets. */ public static String KEY = "9I3278RVSCFIA8BP9WIVCDYJSTKUHYGJ86"; } ================================================ FILE: src/main/java/com/we3j/demo/service/etherscan_api/params/Sort.java ================================================ package com.we3j.demo.service.etherscan_api.params; /** * * Created by jambestwick@126.com * * on 2021/12/7 * * */ public enum Sort { ASC("asc"), DESC("desc"); private String sort; Sort(String sort) { this.sort = sort; } } ================================================ FILE: src/main/java/com/we3j/demo/service/etherscan_api/params/accounts/AccountAPI.java ================================================ package com.we3j.demo.service.etherscan_api.params.accounts; import com.github.lianjiatech.retrofit.spring.boot.annotation.RetrofitClient; import com.we3j.demo.service.etherscan_api.params.Sort; import com.we3j.demo.service.etherscan_api.response.ApiResponse; import retrofit2.http.GET; import retrofit2.http.Query; /** * * Created by jambestwick@126.com * * on 2021/12/7 * {@link [document-account] https://docs.etherscan.io/api-endpoints/accounts} * * */ @RetrofitClient(baseUrl = "${base.url}") public interface AccountAPI { /** * eg. * "module=account\n" + * " &action=balance\n" + * " &address=0xde0b295669a9fd93d5f28d9ec85e40f4cb697bae\n" + * " &tag=latest\n" + * " &apikey=YourApiKeyToken"; */ //public static final String Single_Address_Ether_Balance ; @GET("api") ApiResponse getSingleAddressBalance(@Query("module") String api, @Query("action") String action, @Query("address") String address, @Query("tag") String tag, @Query("apikey") String apiKey); @GET("api") String getMultipleAddressBalance(@Query("module") String api, @Query("action") String action, @Query("address") String addresses, @Query("tag") String tag, @Query("apikey") String apiKey); /** * @return records maximum of 10000 records only */ @GET("api") String getListNormalTransactionByAddress(@Query("module") String api, @Query("action") String action, @Query("address") String address, @Query("startblock") long startBlock, @Query("endblock") long endBlock, @Query("sort") Sort sort, @Query("apikey") String apiKey); /** * @return records maximum of 10000 records only */ @GET("api") String getListInternalTransactionByAddress(@Query("module") String api, @Query("action") String action, @Query("address") String address, @Query("startblock") long startBlock, @Query("endblock") long endBlock, @Query("sort") Sort sort, @Query("apikey") String apiKey); @GET("api") String getListInternalTransactionByHash(@Query("module") String api, @Query("action") String action, @Query("txhash") String transHash, @Query("apikey") String apiKey); @GET("api") String getListInternalTransactionByBlockRange(@Query("module") String api, @Query("action") String action, @Query("startblock") long startBlock, @Query("endblock") long endBlock, @Query("sort") Sort sort, @Query("apikey") String apiKey); @GET("api") String getContractTransactionByAddress(@Query("module") String api, @Query("action") String action, @Query("contractaddress") String contractAddress, @Query("address") String walletAddress, @Query("startblock") long startBlock, @Query("endblock") long endBlock, @Query("sort") Sort sort, @Query("apikey") String apiKey); @GET("api") String getNFTTransactionByAddress(@Query("module") String api, @Query("action") String action, @Query("contractaddress") String contractAddress, @Query("address") String walletAddress, @Query("startblock") long startBlock, @Query("endblock") long endBlock, @Query("sort") Sort sort, @Query("apikey") String apiKey); @GET("api") String getListMinedByAddress(@Query("module") String api, @Query("action") String action, @Query("address") String walletAddress, @Query("blocktype") String blockType, @Query("apikey") String apiKey); @GET("api") String getHistoricalBalanceByBlockNoAddress(@Query("module") String api, @Query("action") String action, @Query("blockno") long blockNo, @Query("address") String walletAddress, @Query("apikey") String apiKey); } ================================================ FILE: src/main/java/com/we3j/demo/service/etherscan_api/params/blocks/BlockOrder.java ================================================ package com.we3j.demo.service.etherscan_api.params.blocks; /** * * Created by jambestwick@126.com * * on 2021/12/7 * * */ public enum BlockOrder { BEFORE("before"), AFTER("after"); private String key; BlockOrder(String key) { this.key = key; } } ================================================ FILE: src/main/java/com/we3j/demo/service/etherscan_api/params/blocks/BlocksAPI.java ================================================ package com.we3j.demo.service.etherscan_api.params.blocks; import com.github.lianjiatech.retrofit.spring.boot.annotation.RetrofitClient; import com.we3j.demo.service.etherscan_api.params.Sort; import retrofit2.http.GET; import retrofit2.http.Query; /** * * Created by jambestwick@126.com * * on 2021/12/7 * {@link [blocks-api] https://docs.etherscan.io/api-endpoints/blocks} * * */ @RetrofitClient(baseUrl = "${base.url}") public interface BlocksAPI { @GET("api") String getBlockAndUncleRewardsByBlockNo(@Query("module") String api, @Query(value = "action") String action, @Query("blockno") long blockNo, @Query("apikey") String apiKey); @GET("api") String getEstimatedBlockCountdownTimeByBlockNo(@Query("module") String api, @Query(value = "action") String action, @Query("blockno") long blockNo, @Query("apikey") String apiKey); /** * @param timestamp blockOrder before or after timestamp **/ @GET("api") String getBlockNumberByTimestamp(@Query("module") String api, @Query(value = "action") String action, @Query("timestamp") long timestamp, @Query("closest") BlockOrder closest, @Query("apikey") String apiKey); /** * @param startDate format eg.2019-02-01 * @param endDate format eg.2019-02-15 **/ @GET("api") String getDailyAverageBlockSize(@Query("module") String api, @Query(value = "action") String action, @Query("startdate") String startDate, @Query("enddate") String endDate, @Query("sort") Sort sort, @Query("apikey") String apiKey); /** * @param startDate format eg.2019-02-01 * @param endDate format eg.2019-02-15 **/ @GET("api") String getDailyBlockCountAndRewards(@Query("module") String api, @Query(value = "action") String action, @Query("startdate") String startDate, @Query("enddate") String endDate, @Query("sort") Sort sort, @Query("apikey") String apiKey); /** * @param startDate format eg.2019-02-01 * @param endDate format eg.2019-02-15 **/ @GET("api") String getDailyBlockRewards(@Query("module") String api, @Query(value = "action") String action, @Query("startdate") String startDate, @Query("enddate") String endDate, @Query("sort") Sort sort, @Query("apikey") String apiKey); /** * @param startDate format eg.2019-02-01 * @param endDate format eg.2019-02-15 **/ @GET("api") String getDailyAverageBlockTime(@Query("module") String api, @Query(value = "action") String action, @Query("startdate") String startDate, @Query("enddate") String endDate, @Query("sort") Sort sort, @Query("apikey") String apiKey); /** * @param startDate format eg.2019-02-01 * @param endDate format eg.2019-02-15 **/ @GET("api") String getDailyUncleBlockCountAndRewards(@Query("module") String api, @Query(value = "action") String action, @Query("startdate") String startDate, @Query("enddate") String endDate, @Query("sort") Sort sort, @Query("apikey") String apiKey); } ================================================ FILE: src/main/java/com/we3j/demo/service/etherscan_api/params/contracts/ContractAPI.java ================================================ package com.we3j.demo.service.etherscan_api.params.contracts; import com.github.lianjiatech.retrofit.spring.boot.annotation.RetrofitClient; import retrofit2.http.GET; import retrofit2.http.Query; /** * * Created by jambestwick@126.com * * on 2021/12/7 * {@link [contract-api] https://docs.etherscan.io/api-endpoints/contracts} * * */ @RetrofitClient(baseUrl = "${base.url}") public interface ContractAPI { @GET("api") String getContractABI(@Query("module") String api, @Query("action") String action, @Query("address") String contractAddress, @Query("apikey") String apiKey); @GET("api") String getContractSourceCode(@Query("module") String api, @Query("action") String action, @Query("address") String contractAddress, @Query("apikey") String apiKey); } ================================================ FILE: src/main/java/com/we3j/demo/service/etherscan_api/params/gas_tracker/GasTackerAPI.java ================================================ package com.we3j.demo.service.etherscan_api.params.gas_tracker; import com.github.lianjiatech.retrofit.spring.boot.annotation.RetrofitClient; import com.we3j.demo.service.etherscan_api.params.Sort; import retrofit2.http.GET; import retrofit2.http.Query; /** * @Author jambestwick * @create 2021/12/7 0007 21:04 * @email jambestwick@126.com * * {@link [gas-api] https://docs.etherscan.io/api-endpoints/gas-tracker} */ @RetrofitClient(baseUrl = "${base.url}") public interface GasTackerAPI { @GET("api") String getEstimationConfirmationTime(@Query("module") String api, @Query("action") String action, @Query("gasprice") long gasPrice, @Query("apikey") String apiKey);//The result is returned in seconds. @GET("api") String getGasOracle(@Query("module") String api, @Query("action") String action, @Query("apikey") String apiKey); @GET("api") String getDailyAverageGasLimit(@Query("module") String api, @Query("action") String action, @Query("startdate") String startDate, @Query("enddate") String endDate, @Query("sort") Sort sort, @Query("apikey") String apiKey); @GET("api") String getDailyTotalGasUsed(@Query("module") String api, @Query("action") String action, @Query("startdate") String startDate, @Query("enddate") String endDate, @Query("sort") Sort sort, @Query("apikey") String apiKey); @GET("api") String getDailyAverageGasPrice(@Query("module") String api, @Query("action") String action, @Query("startdate") String startDate, @Query("enddate") String endDate, @Query("sort") Sort sort, @Query("apikey") String apiKey); } ================================================ FILE: src/main/java/com/we3j/demo/service/etherscan_api/params/logs/logAPI.java ================================================ package com.we3j.demo.service.etherscan_api.params.logs; import com.github.lianjiatech.retrofit.spring.boot.annotation.RetrofitClient; import retrofit2.http.GET; import retrofit2.http.Query; /** * * Created by jambestwick@126.com * * on 2021/12/7 * {@link [log-api] https://docs.etherscan.io/api-endpoints/logs} * * */ @RetrofitClient(baseUrl = "${base.url}") public interface logAPI { @GET("api") String getSampleLog(@Query("module") String api, @Query(value = "action") String action, @Query("fromBlock") long fromBlock, @Query("toBlock") long toBlock, @Query("topic0") String topic, @Query("address") String address, @Query("apikey") String apiKey); } ================================================ FILE: src/main/java/com/we3j/demo/service/etherscan_api/params/stats/StatsAPI.java ================================================ package com.we3j.demo.service.etherscan_api.params.stats; import com.github.lianjiatech.retrofit.spring.boot.annotation.RetrofitClient; import com.we3j.demo.service.etherscan_api.params.Sort; import retrofit2.http.GET; import retrofit2.http.Query; /** * @Author jambestwick * @create 2021/12/7 0007 21:26 * @email jambestwick@126.com * * {@link [stats-api] https://docs.etherscan.io/api-endpoints/stats-1} */ @RetrofitClient(baseUrl = "${base.url}") public interface StatsAPI { @GET("api") String getTotalSupplyEther(@Query("module") String api, @Query("action") String action, @Query("apikey") String apiKey); @GET("api") String getTotalSupplyEther2(@Query("module") String api, @Query("action") String action, @Query("apikey") String apiKey); @GET("api") String getEtherLastPrice(@Query("module") String api, @Query("action") String action, @Query("apikey") String apiKey); @GET("api") String getEtherNodesSize(@Query("module") String api, @Query("action") String action, @Query("startdate") String startDate, @Query("enddate") String endDate, @Query("clienttype") String clientType, @Query("syncmode") String syncMode, @Query("sort") Sort sort, @Query("apikey") String apiKey); @GET("api") String getTotalNodesCount(@Query("module") String api, @Query("action") String action, @Query("apikey") String apiKey); @GET("api") String getDailyTxnFee(@Query("module") String api, @Query("action") String action, @Query("startdate") String startDate, @Query("enddate") String endDate, @Query("sort") Sort sort, @Query("apikey") String apiKey); @GET("api") String getDailyNewAddressCount(@Query("module") String api, @Query("action") String action, @Query("startdate") String startDate, @Query("enddate") String endDate, @Query("sort") Sort sort, @Query("apikey") String apiKey); @GET("api") String getDailyNetUtilization(@Query("module") String api, @Query("action") String action, @Query("startdate") String startDate, @Query("enddate") String endDate, @Query("sort") Sort sort, @Query("apikey") String apiKey); @GET("api") String getDailyAverageHashRate(@Query("module") String api, @Query("action") String action, @Query("startdate") String startDate, @Query("enddate") String endDate, @Query("sort") Sort sort, @Query("apikey") String apiKey); @GET("api") String getDailyTxCount(@Query("module") String api, @Query("action") String action, @Query("startdate") String startDate, @Query("enddate") String endDate, @Query("sort") Sort sort, @Query("apikey") String apiKey); @GET("api") String getDailyAverageNetDifficulty(@Query("module") String api, @Query("action") String action, @Query("startdate") String startDate, @Query("enddate") String endDate, @Query("sort") Sort sort, @Query("apikey") String apiKey); @GET("api") String getEtherDailyPrice(@Query("module") String api, @Query("action") String action, @Query("startdate") String startDate, @Query("enddate") String endDate, @Query("sort") Sort sort, @Query("apikey") String apiKey); } ================================================ FILE: src/main/java/com/we3j/demo/service/etherscan_api/params/tokens/TokensAPI.java ================================================ package com.we3j.demo.service.etherscan_api.params.tokens; import com.github.lianjiatech.retrofit.spring.boot.annotation.RetrofitClient; import retrofit2.http.GET; import retrofit2.http.Query; /** * * Created by jambestwick@126.com * * on 2021/12/7 * {@link [tokens-api] https://docs.etherscan.io/api-endpoints/tokens} * * */ @RetrofitClient(baseUrl = "${base.url}") public interface TokensAPI { @GET("api") String getTokenTotalSupplyByContractAddress(@Query("module") String api, @Query("action") String action, @Query("contractaddress") String contractAddress, @Query("apikey") String apiKey); @GET("api") String getTokenAccountBalanceForTokenContractAddress(@Query("module") String api, @Query("action") String action, @Query("contractaddress") String contractAddress, @Query("address") String address, @Query("apikey") String apiKey); @GET("api") String getHistoricalTokenTotalSupplyByContractAddressAndBlockNo(@Query("module") String api, @Query("action") String action, @Query("contractaddress") String contractAddress, @Query("blockno") long blockNo, @Query("apikey") String apiKey); @GET("api") String getHistoricalTokenAccountBalanceByContractAddressAndBlockNo(@Query("module") String api, @Query("action") String action, @Query("contractaddress") String contractAddress, @Query("address") String address, @Query("blockno") long blockNo, @Query("apikey") String apiKey); @GET("api") String getTokenInfoByContractAddress(@Query("module") String api, @Query("action") String action, @Query("contractaddress") String contractAddress, @Query("apikey") String apiKey); } ================================================ FILE: src/main/java/com/we3j/demo/service/etherscan_api/params/transactions/TransactionsAPI.java ================================================ package com.we3j.demo.service.etherscan_api.params.transactions; import com.github.lianjiatech.retrofit.spring.boot.annotation.RetrofitClient; import retrofit2.http.GET; import retrofit2.http.Query; /** * * Created by jambestwick@126.com * * on 2021/12/7 * {@link [transactions-api] https://docs.etherscan.io/api-endpoints/stats} * * */ @RetrofitClient(baseUrl = "${base.url}") public interface TransactionsAPI { @GET("api") String checkContractExecutionStatus(@Query("module") String api, @Query("action") String action, @Query("txhash") String txHash, @Query("apikey") String apiKey); @GET("api") String checkTransactionReceiptStatus(@Query("module") String api, @Query("action") String action, @Query("txhash") String txHash, @Query("apikey") String apiKey); } ================================================ FILE: src/main/java/com/we3j/demo/service/etherscan_api/request/Method.java ================================================ package com.we3j.demo.service.etherscan_api.request; /** * * * Request for API * * */ public enum Method { GET, POST, INPUT, STREAM; } ================================================ FILE: src/main/java/com/we3j/demo/service/etherscan_api/response/ApiResponse.java ================================================ package com.we3j.demo.service.etherscan_api.response; import java.io.Serializable; /** * * Created by jambestwick@126.com * * on 2021/12/8 * * */ public class ApiResponse implements Serializable { private String status; private String message; private T result; public String getStatus() { return status; } public void setStatus(String status) { this.status = status; } public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } public T getResult() { return result; } public void setResult(T result) { this.result = result; } @Override public String toString() { return "ApiResponse{" + "status='" + status + '\'' + ", message='" + message + '\'' + ", result=" + result + '}'; } } ================================================ FILE: src/main/java/com/we3j/demo/sol/TokenERC20.java ================================================ package com.we3j.demo.sol; import java.math.BigInteger; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; import org.web3j.abi.EventEncoder; import org.web3j.abi.FunctionEncoder; import org.web3j.abi.TypeReference; import org.web3j.abi.datatypes.Address; import org.web3j.abi.datatypes.Event; import org.web3j.abi.datatypes.Function; import org.web3j.abi.datatypes.Type; import org.web3j.abi.datatypes.Utf8String; import org.web3j.abi.datatypes.generated.Uint256; import org.web3j.abi.datatypes.generated.Uint8; import org.web3j.crypto.Credentials; import org.web3j.protocol.Web3j; import org.web3j.protocol.core.DefaultBlockParameter; import org.web3j.protocol.core.RemoteCall; import org.web3j.protocol.core.methods.request.EthFilter; import org.web3j.protocol.core.methods.response.Log; import org.web3j.protocol.core.methods.response.TransactionReceipt; import org.web3j.tx.Contract; import org.web3j.tx.TransactionManager; import rx.Observable; import rx.functions.Func1; /** * * Created by jambestwick@126.com * * on 2021/12/2 *

* 对基于 {@link "https://github.com/OpenZeppelin/openzeppelin-contracts" }合约的函数 监听的Demo , * 读取合约ABI二级制文件BINARY * * */ public class TokenERC20 extends Contract { private static final String BINARY = "60806040526002805460ff1916601217905534801561001d57600080fd5b506040516109c63803806109c683398101604090815281516020808401518385015160025460ff16600a0a84026003819055336000908152600485529586205590850180519395909491019261007592850190610092565b508051610089906001906020840190610092565b5050505061012d565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106100d357805160ff1916838001178555610100565b82800160010185558215610100579182015b828111156101005782518255916020019190600101906100e5565b5061010c929150610110565b5090565b61012a91905b8082111561010c5760008155600101610116565b90565b61088a8061013c6000396000f3006080604052600436106100b95763ffffffff7c010000000000000000000000000000000000000000000000000000000060003504166306fdde0381146100be578063095ea7b31461014857806318160ddd1461018057806323b872dd146101a7578063313ce567146101d157806342966c68146101fc57806370a082311461021457806379cc67901461023557806395d89b4114610259578063a9059cbb1461026e578063cae9ca5114610294578063dd62ed3e146102fd575b600080fd5b3480156100ca57600080fd5b506100d3610324565b6040805160208082528351818301528351919283929083019185019080838360005b8381101561010d5781810151838201526020016100f5565b50505050905090810190601f16801561013a5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561015457600080fd5b5061016c600160a060020a03600435166024356103b2565b604080519115158252519081900360200190f35b34801561018c57600080fd5b506101956103df565b60408051918252519081900360200190f35b3480156101b357600080fd5b5061016c600160a060020a03600435811690602435166044356103e5565b3480156101dd57600080fd5b506101e6610454565b6040805160ff9092168252519081900360200190f35b34801561020857600080fd5b5061016c60043561045d565b34801561022057600080fd5b50610195600160a060020a03600435166104d5565b34801561024157600080fd5b5061016c600160a060020a03600435166024356104e7565b34801561026557600080fd5b506100d36105b8565b34801561027a57600080fd5b50610292600160a060020a0360043516602435610612565b005b3480156102a057600080fd5b50604080516020600460443581810135601f810184900484028501840190955284845261016c948235600160a060020a03169460248035953695946064949201919081908401838280828437509497506106219650505050505050565b34801561030957600080fd5b50610195600160a060020a036004358116906024351661073a565b6000805460408051602060026001851615610100026000190190941693909304601f810184900484028201840190925281815292918301828280156103aa5780601f1061037f576101008083540402835291602001916103aa565b820191906000526020600020905b81548152906001019060200180831161038d57829003601f168201915b505050505081565b336000908152600560209081526040808320600160a060020a039590951683529390529190912055600190565b60035481565b600160a060020a038316600090815260056020908152604080832033845290915281205482111561041557600080fd5b600160a060020a038416600090815260056020908152604080832033845290915290208054839003905561044a848484610757565b5060019392505050565b60025460ff1681565b3360009081526004602052604081205482111561047957600080fd5b3360008181526004602090815260409182902080548690039055600380548690039055815185815291517fcc16f5dbb4873280815c1ee09dbd06736cffcc184412cf7a71a0fdb75d397ca59281900390910190a2506001919050565b60046020526000908152604090205481565b600160a060020a03821660009081526004602052604081205482111561050c57600080fd5b600160a060020a038316600090815260056020908152604080832033845290915290205482111561053c57600080fd5b600160a060020a0383166000818152600460209081526040808320805487900390556005825280832033845282529182902080548690039055600380548690039055815185815291517fcc16f5dbb4873280815c1ee09dbd06736cffcc184412cf7a71a0fdb75d397ca59281900390910190a250600192915050565b60018054604080516020600284861615610100026000190190941693909304601f810184900484028201840190925281815292918301828280156103aa5780601f1061037f576101008083540402835291602001916103aa565b61061d338383610757565b5050565b60008361062e81856103b2565b15610732576040517f8f4ffcb10000000000000000000000000000000000000000000000000000000081523360048201818152602483018790523060448401819052608060648501908152875160848601528751600160a060020a03871695638f4ffcb195948b94938b939192909160a490910190602085019080838360005b838110156106c65781810151838201526020016106ae565b50505050905090810190601f1680156106f35780820380516001836020036101000a031916815260200191505b5095505050505050600060405180830381600087803b15801561071557600080fd5b505af1158015610729573d6000803e3d6000fd5b50505050600191505b509392505050565b600560209081526000928352604080842090915290825290205481565b6000600160a060020a038316151561076e57600080fd5b600160a060020a03841660009081526004602052604090205482111561079357600080fd5b600160a060020a038316600090815260046020526040902054828101116107b957600080fd5b50600160a060020a038083166000818152600460209081526040808320805495891680855282852080548981039091559486905281548801909155815187815291519390950194927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef929181900390910190a3600160a060020a0380841660009081526004602052604080822054928716825290205401811461085857fe5b505050505600a165627a7a72305820a699795c1a251457c903be9b4228f16928a18279fb1c6adc9eadefb8a46ae9060029"; public static final String FUNC_NAME = "name"; public static final String FUNC_APPROVE = "approve"; public static final String FUNC_TOTALSUPPLY = "totalSupply"; public static final String FUNC_TRANSFERFROM = "transferFrom"; public static final String FUNC_DECIMALS = "decimals"; public static final String FUNC_BURN = "burn"; public static final String FUNC_BALANCEOF = "balanceOf"; public static final String FUNC_BURNFROM = "burnFrom"; public static final String FUNC_SYMBOL = "symbol"; public static final String FUNC_TRANSFER = "transfer"; public static final String FUNC_APPROVEANDCALL = "approveAndCall"; public static final String FUNC_ALLOWANCE = "allowance"; public static final String FUNC_MINT = "mint"; public static final Event TRANSFER_EVENT = new Event("Transfer", Arrays.>asList(new TypeReference

(true) { }, new TypeReference
(true) { }, new TypeReference(false) { })); ; public static final Event BURN_EVENT = new Event("Burn", Arrays.>asList(new TypeReference
(true) { }, new TypeReference(false) { })); ; protected TokenERC20(String contractAddress, Web3j web3j, Credentials credentials, BigInteger gasPrice, BigInteger gasLimit) { super(BINARY, contractAddress, web3j, credentials, gasPrice, gasLimit); } protected TokenERC20(String contractAddress, Web3j web3j, TransactionManager transactionManager, BigInteger gasPrice, BigInteger gasLimit) { super(BINARY, contractAddress, web3j, transactionManager, gasPrice, gasLimit); } public RemoteCall name() { final Function function = new Function(FUNC_NAME, Arrays.asList(), Arrays.>asList(new TypeReference() { })); return executeRemoteCallSingleValueReturn(function, String.class); } public RemoteCall approve(String _spender, BigInteger _value) { final Function function = new Function( FUNC_APPROVE, Arrays.asList(new Address(_spender), new Uint256(_value)), Collections.>emptyList()); return executeRemoteCallTransaction(function); } public RemoteCall totalSupply() { final Function function = new Function(FUNC_TOTALSUPPLY, Arrays.asList(), Arrays.>asList(new TypeReference() { })); return executeRemoteCallSingleValueReturn(function, BigInteger.class); } public RemoteCall transferFrom(String _from, String _to, BigInteger _value) { final Function function = new Function( FUNC_TRANSFERFROM, Arrays.asList(new Address(_from), new Address(_to), new Uint256(_value)), Collections.>emptyList()); return executeRemoteCallTransaction(function); } public RemoteCall decimals() { final Function function = new Function(FUNC_DECIMALS, Arrays.asList(), Arrays.>asList(new TypeReference() { })); return executeRemoteCallSingleValueReturn(function, BigInteger.class); } public RemoteCall burn(BigInteger _value) { final Function function = new Function( FUNC_BURN, Arrays.asList(new Uint256(_value)), Collections.>emptyList()); return executeRemoteCallTransaction(function); } public RemoteCall balanceOf(String param0) { final Function function = new Function(FUNC_BALANCEOF, Arrays.asList(new Address(param0)), Arrays.>asList(new TypeReference() { })); return executeRemoteCallSingleValueReturn(function, BigInteger.class); } public RemoteCall burnFrom(String _from, BigInteger _value) { final Function function = new Function( FUNC_BURNFROM, Arrays.asList(new Address(_from), new Uint256(_value)), Collections.>emptyList()); return executeRemoteCallTransaction(function); } public RemoteCall symbol() { final Function function = new Function(FUNC_SYMBOL, Arrays.asList(), Arrays.>asList(new TypeReference() { })); return executeRemoteCallSingleValueReturn(function, String.class); } public RemoteCall transfer(String _to, BigInteger _value) { final Function function = new Function( FUNC_TRANSFER, Arrays.asList(new Address(_to), new Uint256(_value)), Collections.>emptyList()); return executeRemoteCallTransaction(function); } public RemoteCall approveAndCall(String _spender, BigInteger _value, byte[] _extraData) { final Function function = new Function( FUNC_APPROVEANDCALL, Arrays.asList(new Address(_spender), new Uint256(_value), new org.web3j.abi.datatypes.DynamicBytes(_extraData)), Collections.>emptyList()); return executeRemoteCallTransaction(function); } public RemoteCall allowance(String param0, String param1) { final Function function = new Function(FUNC_ALLOWANCE, Arrays.asList(new Address(param0), new Address(param1)), Arrays.>asList(new TypeReference() { })); return executeRemoteCallSingleValueReturn(function, BigInteger.class); } public static RemoteCall deploy(Web3j web3j, Credentials credentials, BigInteger gasPrice, BigInteger gasLimit, BigInteger initialSupply, String tokenName, String tokenSymbol) { String encodedConstructor = FunctionEncoder.encodeConstructor(Arrays.asList(new Uint256(initialSupply), new Utf8String(tokenName), new Utf8String(tokenSymbol))); return deployRemoteCall(TokenERC20.class, web3j, credentials, gasPrice, gasLimit, BINARY, encodedConstructor); } public static RemoteCall deploy(Web3j web3j, TransactionManager transactionManager, BigInteger gasPrice, BigInteger gasLimit, BigInteger initialSupply, String tokenName, String tokenSymbol) { String encodedConstructor = FunctionEncoder.encodeConstructor(Arrays.asList(new Uint256(initialSupply), new Utf8String(tokenName), new Utf8String(tokenSymbol))); return deployRemoteCall(TokenERC20.class, web3j, transactionManager, gasPrice, gasLimit, BINARY, encodedConstructor); } public List getTransferEvents(TransactionReceipt transactionReceipt) { List valueList = extractEventParametersWithLog(TRANSFER_EVENT, transactionReceipt); ArrayList responses = new ArrayList(valueList.size()); for (EventValuesWithLog eventValues : valueList) { TransferEventResponse typedResponse = new TransferEventResponse(); typedResponse.log = eventValues.getLog(); typedResponse.from = (String) eventValues.getIndexedValues().get(0).getValue(); typedResponse.to = (String) eventValues.getIndexedValues().get(1).getValue(); typedResponse.value = (BigInteger) eventValues.getNonIndexedValues().get(0).getValue(); responses.add(typedResponse); } return responses; } public Observable transferEventObservable(EthFilter filter) { return web3j.ethLogObservable(filter).map(new Func1() { @Override public TransferEventResponse call(Log log) { EventValuesWithLog eventValues = extractEventParametersWithLog(TRANSFER_EVENT, log); TransferEventResponse typedResponse = new TransferEventResponse(); typedResponse.log = log; typedResponse.from = (String) eventValues.getIndexedValues().get(0).getValue(); typedResponse.to = (String) eventValues.getIndexedValues().get(1).getValue(); typedResponse.value = (BigInteger) eventValues.getNonIndexedValues().get(0).getValue(); return typedResponse; } }); } public Observable transferEventObservable(DefaultBlockParameter startBlock, DefaultBlockParameter endBlock) { EthFilter filter = new EthFilter(startBlock, endBlock, getContractAddress()); filter.addSingleTopic(EventEncoder.encode(TRANSFER_EVENT)); return transferEventObservable(filter); } public List getBurnEvents(TransactionReceipt transactionReceipt) { List valueList = extractEventParametersWithLog(BURN_EVENT, transactionReceipt); ArrayList responses = new ArrayList(valueList.size()); for (EventValuesWithLog eventValues : valueList) { BurnEventResponse typedResponse = new BurnEventResponse(); typedResponse.log = eventValues.getLog(); typedResponse.from = (String) eventValues.getIndexedValues().get(0).getValue(); typedResponse.value = (BigInteger) eventValues.getNonIndexedValues().get(0).getValue(); responses.add(typedResponse); } return responses; } public Observable burnEventObservable(EthFilter filter) { return web3j.ethLogObservable(filter).map(new Func1() { @Override public BurnEventResponse call(Log log) { EventValuesWithLog eventValues = extractEventParametersWithLog(BURN_EVENT, log); BurnEventResponse typedResponse = new BurnEventResponse(); typedResponse.log = log; typedResponse.from = (String) eventValues.getIndexedValues().get(0).getValue(); typedResponse.value = (BigInteger) eventValues.getNonIndexedValues().get(0).getValue(); return typedResponse; } }); } public Observable burnEventObservable(DefaultBlockParameter startBlock, DefaultBlockParameter endBlock) { EthFilter filter = new EthFilter(startBlock, endBlock, getContractAddress()); filter.addSingleTopic(EventEncoder.encode(BURN_EVENT)); return burnEventObservable(filter); } public static TokenERC20 load(String contractAddress, Web3j web3j, Credentials credentials, BigInteger gasPrice, BigInteger gasLimit) { return new TokenERC20(contractAddress, web3j, credentials, gasPrice, gasLimit); } public static TokenERC20 load(String contractAddress, Web3j web3j, TransactionManager transactionManager, BigInteger gasPrice, BigInteger gasLimit) { return new TokenERC20(contractAddress, web3j, transactionManager, gasPrice, gasLimit); } public static class TransferEventResponse { public Log log; public String from; public String to; public BigInteger value; } public static class BurnEventResponse { public Log log; public String from; public BigInteger value; } } ================================================ FILE: src/main/java/com/we3j/demo/sol/TokenERC71.java ================================================ package com.we3j.demo.sol; /** * * Created by jambestwick@126.com * * on 2021/12/2 * * */ public class TokenERC71 { } ================================================ FILE: src/main/java/com/we3j/demo/test/ContractDemo.java ================================================ package com.we3j.demo.test; import com.we3j.demo.utils.Environment; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.web3j.abi.EventEncoder; import org.web3j.abi.TypeReference; import org.web3j.abi.datatypes.Address; import org.web3j.abi.datatypes.Event; import org.web3j.abi.datatypes.generated.Uint256; import org.web3j.crypto.ContractUtils; import org.web3j.crypto.Credentials; import org.web3j.crypto.RawTransaction; import org.web3j.protocol.Web3j; import org.web3j.protocol.core.DefaultBlockParameterName; import org.web3j.protocol.core.methods.request.EthFilter; import org.web3j.protocol.core.methods.response.EthEstimateGas; import org.web3j.protocol.core.methods.response.EthGetBalance; import org.web3j.protocol.core.methods.response.EthGetTransactionCount; import org.web3j.protocol.core.methods.response.EthGetTransactionReceipt; import org.web3j.protocol.http.HttpService; import org.web3j.utils.Convert; import java.io.IOException; import java.math.BigDecimal; import java.math.BigInteger; import java.util.Arrays; import java.util.List; import java.util.concurrent.ExecutionException; /** * @auth jambestwick *

* 合约测试 ***/ public class ContractDemo { private static final Logger log = LoggerFactory.getLogger(ContractDemo.class); private Web3j web3j; private Credentials credentials; public static void main(String[] args) { new ContractDemo().run(); } private void run() { // try { // connectETHClient(); // listenContract("0x4c1ae77bc2df45fb68b13fa1b4f000305209b0cb"); // } catch (IOException e) { // e.printStackTrace(); // } } /*******连接以太坊客户端**************/ private void connectETHClient() throws IOException { //连接方式1:使用infura 提供的客户端 //mainnet https://mainnet.infura.io/v3/2b86c426683f4a6095fd175fe931d799 web3j = Web3j.build(new HttpService(Environment.RPC_URL));// TODO: 2018/4/10 节点更改为自己的或者主网 //连接方式2:使用本地客户端 //web3j = Web3j.build(new HttpService("127.0.0.1:7545")); //测试是否连接成功 String web3ClientVersion = web3j.web3ClientVersion().send().getWeb3ClientVersion(); log.info("version=" + web3ClientVersion); } /********根据私钥加载钱包 **********/ private void loadWalletByPrivateKey(String inputPrivateKey) { credentials = Credentials.create(inputPrivateKey); String address = credentials.getAddress(); BigInteger publicKey = credentials.getEcKeyPair().getPublicKey(); BigInteger privateKey = credentials.getEcKeyPair().getPrivateKey(); log.info("address=" + address); log.info("public key=" + publicKey); log.info("private key=" + privateKey); } /** * ***** * *******创建一个智能合约****** *

* nonce 当nonce太小,交易会被直接拒绝。 * 当nonce太大,交易会一直处于队列之中,这也就是导致我们上面描述的问题的原因; * 当发送一个比较大的nonce值,然后补齐开始nonce到那个值之间的nonce,那么交易依旧可以被执行。 * 当交易处于queue中时停止geth客户端,那么交易queue中的交易会被清除掉。 * 解决这个问题的方法是自己维护Nonce,同一个账户连续发送俩笔交易时,通过递增Nonce来防止Nonce重复。 * @param from the address to create Contract ***********/ public void createContract(String from) throws InterruptedException, ExecutionException { // using a raw transaction if (web3j == null) return; EthGetTransactionCount ethGetTransactionCount = web3j.ethGetTransactionCount( from, DefaultBlockParameterName.LATEST).sendAsync().get(); BigInteger nonce = ethGetTransactionCount.getTransactionCount(); //Generate a smart contract address. This enables you to identify what address a // * smart contract will be deployed to on the network. String result = ContractUtils.generateContractAddress(from, nonce); log.info("createContract web3j" + result); } public void createContract(String from, BigInteger ethAmount) throws InterruptedException, ExecutionException, IOException { if (web3j == null) return; EthGetTransactionCount ethGetTransactionCount = web3j.ethGetTransactionCount( from, DefaultBlockParameterName.LATEST).sendAsync().get(); BigInteger nonce = ethGetTransactionCount.getTransactionCount(); // using a raw transaction BigInteger gasPrice = web3j.ethGasPrice().send().getGasPrice(); //BigInteger gasLimit =getTransactionGasLimit(web3j,null);//每笔交易的gas最少21000 BigInteger gasLimit = new BigInteger(String.valueOf(21000L));//每笔交易的gas最少21000 RawTransaction rawTransaction = RawTransaction.createContractTransaction(nonce, gasPrice, gasLimit, ethAmount, "0x "); // send... } public static BigInteger getTransactionGasLimit(Web3j web3j, org.web3j.protocol.core.methods.request.Transaction transaction) { try { EthEstimateGas ethEstimateGas = web3j.ethEstimateGas(transaction).send(); if (ethEstimateGas.hasError()) { throw new RuntimeException(ethEstimateGas.getError().getMessage()); } return ethEstimateGas.getAmountUsed(); } catch (IOException e) { throw new RuntimeException("net error"); } } /************获取账户ETH余额***************/ public static BigDecimal getBalance(Web3j web3j, String address) { try { EthGetBalance ethGetBalance = web3j.ethGetBalance(address, DefaultBlockParameterName.LATEST).send(); return Convert.fromWei(new BigDecimal(ethGetBalance.getBalance()), Convert.Unit.ETHER); } catch (IOException e) { e.printStackTrace(); return null; } } /*********根据交易Hash获取合约地址***********/ private String getContractAddress(String transactionHash) throws IOException { // get contract address EthGetTransactionReceipt transactionReceipt = web3j.ethGetTransactionReceipt(transactionHash).send(); if (transactionReceipt.getTransactionReceipt().isPresent()) { return transactionReceipt.getResult().getContractAddress(); } return null; } // private void deploy() { // // Web3j web3j = Web3j.build(new HttpService(Environment.RPC_URL)); // RemoteCall deploy = TokenERC20.deploy(web3j, credentials, // Convert.toWei("10", Convert.Unit.GWEI).toBigInteger(), // BigInteger.valueOf(3000000), // BigInteger.valueOf(5201314), // "my token", "mt"); // try { // TokenERC20 tokenERC20 = deploy.send(); // tokenERC20.isValid(); // } catch (Exception e) { // e.printStackTrace(); // } // // } /***合约监听***/ private void listenContract(String contractAddress) { /** * 监听ERC20 token 交易 */ EthFilter filter = new EthFilter( DefaultBlockParameterName.EARLIEST, DefaultBlockParameterName.LATEST, contractAddress); org.web3j.abi.datatypes.Event event = new Event("Transfer", Arrays.>asList( new TypeReference[]{new TypeReference

(true) { }, new TypeReference
(true) { }, new TypeReference(false) { }}) ); String topicData = EventEncoder.encode(event); filter.addSingleTopic(topicData); System.out.println(topicData); web3j.ethLogObservable(filter).subscribe(log -> { System.out.println(log.getBlockNumber()); System.out.println(log.getTransactionHash()); List topics = log.getTopics(); for (String topic : topics) { System.out.println(topic); } }); } } ================================================ FILE: src/main/java/com/we3j/demo/test/WalletDemo.java ================================================ package com.we3j.demo.test; import com.we3j.demo.utils.Environment; import com.we3j.demo.wallet.NFTMonitor; import com.we3j.demo.wallet.TokenClient; import com.we3j.demo.wallet.TransMonitor; import com.we3j.demo.wallet.Web3jInfo; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Service; import org.web3j.crypto.*; import org.web3j.protocol.Web3j; import org.web3j.protocol.admin.Admin; import org.web3j.protocol.core.DefaultBlockParameter; import org.web3j.protocol.core.methods.response.EthGetBalance; import org.web3j.protocol.core.methods.response.Log; import org.web3j.protocol.core.methods.response.TransactionReceipt; import org.web3j.protocol.http.HttpService; import org.web3j.tx.Transfer; import org.web3j.utils.Convert; import rx.functions.Action1; import java.io.File; import java.io.IOException; import java.math.BigDecimal; import java.math.BigInteger; import java.security.InvalidAlgorithmParameterException; import java.security.NoSuchAlgorithmException; import java.security.NoSuchProviderException; import java.util.List; import java.util.Timer; import java.util.TimerTask; /** * @Author jambestwick * @create 2021/11/30 0030 0:09 * @email jambestwick1988@gmail.com */ @Service public class WalletDemo { private static final Logger log = LoggerFactory.getLogger(WalletDemo.class); private Web3j web3j; private Credentials credentials; String tempAddress; private HttpService httpService; public static void main(String[] args) throws Exception { new WalletDemo().run1(); } private void run1() throws Exception { log.info("hello eth,hello web3j"); Web3j web3j = Web3jInfo.connect(); BigInteger balance = TokenClient.getAddressBalanceOf(web3j, "0xc18360217d8f7ab5e7c516566761ea12ce7f9d72", "0x0fb6160F1738ee5243cB3ED421dc0CEa2cf1C0D4"); System.out.println("当前地址ENS的余额:" + balance); BigInteger total = TokenClient.getTokenTotalSupply(web3j, "0xff9c1b15b16263c61d017ee9f65c50e4ae0113d7"); System.out.println("loot(0xff9c1b15b16263c61d017ee9f65c50e4ae0113d7) total:" + total); TransMonitor.getInstance().setWeb3j(web3j); TransMonitor.getInstance().subscribeContract("0x1f9840a85d5af5bf1d1762f925bdaddc4201f984", new Action1() { @Override public void call(Log log) { System.out.println("transBlockNo:" + log.getBlockNumber()); System.out.println("transHash:" + log.getTransactionHash()); List topics = log.getTopics(); for (String topic : topics) { System.out.println("transTopic:" + topic); } } }); NFTMonitor.getInstance().setWeb3j(web3j); /*** * Loot的合约 * * ***/ NFTMonitor.getInstance().subscribeClaim("0xff9c1b15b16263c61d017ee9f65c50e4ae0113d7", new Action1() { @Override public void call(Log log) { /** * 这些tokeniD已经被抢走了,抢还没有claim的 * * **/ System.out.println("transBlockNo:" + log.getBlockNumber()); System.out.println("transHash:" + log.getTransactionHash()); } }); //轮巡器,或者job定时任务,抢NFT // new Timer().schedule(new TimerTask() { // @Override // public void run() { // //根据当前已出现的ID,找出还没出现在的,还未实现只是例子 // TokenClient.claimNFT(web3j, "0xff9c1b15b16263c61d017ee9f65c50e4ae0113d7", 9527); // } // }, 0L, 1000L);//每秒执行抢NFT逻辑 // TransMonitor.getInstance().setWeb3j(web3j); // TransMonitor.getInstance().subscribeBlock(new Action1() { // @Override // public void call(EthBlock ethBlock) { // System.out.println("block:" + ethBlock.getBlock().getHash() + ",author" + ethBlock.getBlock().getAuthor()); // } // }); // // TransMonitor.getInstance().subscribeHasTrans(new Action1() { // @Override // public void call(Transaction transaction) { // System.out.println("from:" + transaction.getFrom() + ",to" + transaction.getTo()); // } // }); // // TransMonitor.getInstance().subscribePendingTrans(new Action1() { // @Override // public void call(Transaction transaction) { // System.out.println("pending from:" + transaction.getFrom() + ",to" + transaction.getTo()+",gasPrice"+transaction.getGasPrice()); // } // }); // BigInteger total = TokenClient.getTokenTotalSupply(Web3jInfo.connect(),"0xff9c1b15b16263c61d017ee9f65c50e4ae0113d7"); // System.out.println("loot total:"+total); // Subscription sub = Web3jInfo.connect().transactionObservable().subscribe(tx -> { // System.out.println("hash: " + tx.getHash()); // System.out.println("from: " + tx.getFrom()); // System.out.println("to: " + tx.getTo()); // System.out.println("value:"+tx.getValue()); // }); //WalletTools.createWallet("d:\\keystore\\abs","d:\\keystore\\abs\\123"); // connectETHClient();//连接以太坊客户端 // creatAccount();//创建冷钱包 // String privateKey = ""; // String keyStoreDir = WalletUtils.getDefaultKeyDirectory(); // System.out.println("生成keyStore文件的默认目录:" + keyStoreDir); //通过密码及keystore目录生成钱包 //Bip39Wallet wallet = WalletUtils.generateBip39Wallet("123456", new File(keyStoreDir)); //keyStore文件名 // System.out.println(wallet.getFilename()); // //12个单词的助记词 // System.out.println(wallet.getMnemonic()); // Scanner scanner = new Scanner(System.in); // privateKey = scanner.next(); // // // loadWalletByPrivateKey(privateKey);//加载钱包 // //先获取Sign码 //getBlanceOf();//查询账户余额 //transto();//转账到指定地址 } /*******连接以太坊客户端**************/ private void connectETHClient() throws IOException { //连接方式1:使用infura 提供的客户端 //mainnet https://mainnet.infura.io/v3/2b86c426683f4a6095fd175fe931d799 web3j = Web3j.build(new HttpService(Environment.RPC_URL));// TODO: 2018/4/10 节点更改为自己的或者主网 //连接方式2:使用本地客户端 //web3j = Web3j.build(new HttpService("127.0.0.1:7545")); //测试是否连接成功 String web3ClientVersion = web3j.web3ClientVersion().send().getWeb3ClientVersion(); log.info("version=" + web3ClientVersion); } /*************创建一个钱包文件**************/ private void creatAccount() throws NoSuchAlgorithmException, NoSuchProviderException, InvalidAlgorithmParameterException, CipherException, IOException { String walletFileName0 = "";//文件名 String walletFilePath0 = "D:\\JavaWorkSpace\\we3jdemo\\src\\main\\java\\com\\we3j\\demo";//钱包文件保持路径,请替换位自己的某文件夹路径 //String walletFilePath0 = "/Users/jam/MyGitHub/z_wallet_temp";//钱包文件保持路径,请替换位自己的某文件夹路径 walletFileName0 = WalletUtils.generateNewWalletFile("123456", new File(walletFilePath0), false);//根据密码生成钱包到地址路径 //walletFileName0 = WalletUtils.generateLightNewWalletFile("password1", new File(walletFilePath0));// //WalletUtils.generateLightNewWalletFile("password2",new File(walletFilePath0)); //WalletUtils.generateBip39Wallet("password2",new File(walletFilePath0));//助记词钱包生成 log.info("walletName: " + walletFileName0); } // // /** // * 创建bip39钱包 // * // * @param password 钱包密码 // * @return CommonWallet // * @throws CipherException e // */ // public Bip39Wallet2 generateBip39Wallet(String password) throws CipherException { // byte[] initialEntropy = new byte[16]; // SecureRandom.getInstance().nextBytes(initialEntropy); // String mnemonic = MnemonicUtils.generateMnemonic(initialEntropy); // byte[] seed = MnemonicUtils.generateSeed(mnemonic, password); // ECKeyPair ecKeyPair = ECKeyPair.create(Hash.sha256(seed)); // WalletFile walletFile = WalletUtils.generateWalletFile(password, ecKeyPair, false,false); // return new Bip39Wallet2(walletFile.getAddress(), mnemonic, password, JSON.toJSONString(walletFile), ecKeyPair.getPrivateKey(), ecKeyPair.getPublicKey()); // } /********根据密码,钱包文件加载钱包文件**********/ private void loadWallet(String password, String walletFilePath) throws IOException, CipherException { // FIXME: 2018/4/15 替换为自己的钱包路径 //String walletFilePath = "/Users/jambestwick/MyGitHub/z_wallet_temp/UTC--2018-04-10T02-51-24.815000000Z--12571f46ec3f81f7ebe79112be5883194d683787.json"; //String password = "123456"; credentials = WalletUtils.loadCredentials(password, walletFilePath); String address = credentials.getAddress(); BigInteger publicKey = credentials.getEcKeyPair().getPublicKey(); BigInteger privateKey = credentials.getEcKeyPair().getPrivateKey(); log.info("address=" + address); log.info("public key=" + publicKey); log.info("private key=" + privateKey); } /********根据助记词加载钱包 **********/ private void loadWalletByPrimaryKeyPassword(String password, String mnemonic) { WalletUtils.loadBip39Credentials(password, mnemonic);//no need password // credentials = WalletUtils.loadBip39Credentials(password, // keyWords);//"cherry type collect echo derive shy balcony dog concert picture kid february" String address = credentials.getAddress(); BigInteger publicKey = credentials.getEcKeyPair().getPublicKey(); BigInteger privateKey = credentials.getEcKeyPair().getPrivateKey(); log.info("address=" + address); log.info("public key=" + publicKey); log.info("private key=" + privateKey); tempAddress = address; } /********根据私钥加载钱包 **********/ private void loadWalletByPrivateKey(String inputPrivateKey) { credentials = Credentials.create(inputPrivateKey); String address = credentials.getAddress(); BigInteger publicKey = credentials.getEcKeyPair().getPublicKey(); BigInteger privateKey = credentials.getEcKeyPair().getPrivateKey(); log.info("address=" + address); log.info("public key=" + publicKey); log.info("private key=" + privateKey); tempAddress = address; } /****************交易*****************/ private void transto() throws Exception { if (web3j == null) return; if (credentials == null) return; //开始发送0.01 =eth到指定地址 String address_to = "0x41F1dcbC0794BAD5e94c6881E7c04e4F98908a87"; //转账时最好判断地址的有效性,谨防由于错行少字,金额丢失 if (!WalletUtils.isValidAddress(address_to)) { return; } TransactionReceipt send = Transfer.sendFunds(web3j, credentials, address_to, BigDecimal.ONE, Convert.Unit.FINNEY).send(); log.info("Transaction complete:"); log.info("trans hash=" + send.getTransactionHash()); log.info("from :" + send.getFrom()); log.info("to:" + send.getTo()); log.info("gas used=" + send.getGasUsed()); log.info("status: " + send.getStatus()); } /********对指定信息签名**********/ private String sign(String message) throws Exception { if (web3j == null) return null; if (credentials == null) return null; byte[] hexMessage = Hash.sha3(message.getBytes()); Sign.SignatureData signatureData = Sign.signMessage(hexMessage, credentials.getEcKeyPair());//例如metamask 登录的签名信息 //EthSign ethSign = web3j.ethSign(address, Hash.sha3(message)).send(); String resultSignature = signatureData.toString(); log.info("sign hash=" + resultSignature); return resultSignature; } /***********查询指定地址的余额***********/ private void getBlanceOf() throws IOException { if (web3j == null) return; String address = "0x12571f46ec3f81f7ebe79112be5883194d683787";//等待查询余额的地址 //第二个参数:区块的参数,建议选最新区块 EthGetBalance balance = web3j.ethGetBalance(address, DefaultBlockParameter.valueOf("latest")).send(); //格式转化 wei-ether String blanceETH = Convert.fromWei(balance.getBalance().toString(), Convert.Unit.ETHER).toPlainString().concat(" ether"); log.info(blanceETH); } /***********查询指定地址的余额***********/ /** * 初始化admin级别操作的对象 * * @return Admin */ private Admin initAdmin() { return Admin.build(getService()); } private HttpService getService() { if (httpService == null) { httpService = new HttpService("https://mainnet.infura.io/v3/9eb78bae70c34116a2b28db3fdb96dd0"); } return httpService; } } ================================================ FILE: src/main/java/com/we3j/demo/test/mona/BuildInviteCodeRequest.java ================================================ package com.we3j.demo.test.mona; import java.util.HashMap; import java.util.Map; /** * @Author jambestwick * @create 2021/11/30 0030 0:09 * @email jambestwick@126.com */ public class BuildInviteCodeRequest { public static Map buildInviteParam(String address, String inviteCode, String signature) { Map map = new HashMap<>(); map.put("address", address); map.put("invite_code", inviteCode); map.put("signature", signature); return map; } public static Map buildHead(String accept , String accept_encoding , String accept_language , String content_type , String origin , String referer , String secChUa , String secChUaMobile , String secChUaPlatform , String secFetchDest , String secFetchMode , String secFetchSite , String token , String user_agent) { Map map = new HashMap<>(); map.put("accept", accept); map.put("accept-encoding", accept_encoding); map.put("accept-language", accept_language); map.put("content-type", content_type); map.put("origin", origin); map.put("referer", referer); map.put("sec-ch-ua", secChUa); map.put("sec-ch-ua-mobile", secChUaMobile); map.put("sec-ch-ua-platform", secChUaPlatform); map.put("sec-fetch-dest", secFetchDest); map.put("sec-fetch-mode", secFetchMode); map.put("sec-fetch-site", secFetchSite); map.put("token", token); map.put("user-agent", user_agent); return map; } } ================================================ FILE: src/main/java/com/we3j/demo/test/mona/Constants.java ================================================ package com.we3j.demo.test.mona; public class Constants{ //request Get public static final String GET_MESSAGE="https://api.monaconft.io/api/wallet/getMessageToSign"; //request Post public static final String POST_INVITE_CODE="https://api.monaconft.io/api/wallet/verifySignature"; } ================================================ FILE: src/main/java/com/we3j/demo/test/mona/RandomUtil.java ================================================ package com.we3j.demo.test.mona; /** * @Author jambestwick * @create 2021/11/30 0030 0:38 * @email jambestwick@126.com */ public class RandomUtil { public static String randomNumDigest() { StringBuilder stringBuilder=new StringBuilder(); for (int i = 0; i < 5; i++) { for (int j = 0; j < 6; j++) { double rand = Math.random(); double randTri = Math.random() * 3; if (randTri >= 0 && randTri < 1) { System.out.print((char) (rand * ('9' - '0') + '0')); stringBuilder.append((char) (rand * ('9' - '0') + '0')); } else if (randTri >= 1 && randTri < 2) { System.out.print((char) (rand * ('Z' - 'A') + 'A')); stringBuilder.append((char) (rand * ('Z' - 'A') + 'A')); } else { System.out.print((char) (rand * ('z' - 'a') + 'a')); stringBuilder.append((char) (rand * ('z' - 'a') + 'a')); } } System.out.println(); } return stringBuilder.toString(); } } ================================================ FILE: src/main/java/com/we3j/demo/test/mona/RequestUtil.java ================================================ package com.we3j.demo.test.mona; import okhttp3.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.IOException; import java.util.Map; import java.util.concurrent.TimeUnit; /** * @Author jambestwick * @create 2021/11/29 0029 23:45 * @email jambestwick@126.com */ public class RequestUtil { private static final Logger log = LoggerFactory.getLogger(RequestUtil.class); public static String requestGet(String url) { OkHttpClient client = new OkHttpClient.Builder().readTimeout(5, TimeUnit.SECONDS).build(); Request request = new Request.Builder().url(url) .get().build(); Call call = client.newCall(request); try { Response response = call.execute(); String result = response.body().string(); log.debug("response:" + result); return result; } catch (IOException e) { e.printStackTrace(); } return null; } public static String requestPost(String url, Map requestMap, Map headMap) { // &weaid=1&date=2018-08-13&appkey=10003&sign=b59bc3ef6191eb9f747dd4e83c99f2a4&format=json"; OkHttpClient okHttpClient = new OkHttpClient(); FormBody.Builder builder = new FormBody.Builder(); for (String key : requestMap.keySet()) { String value = requestMap.get(key); builder.add(key, value); } Headers headers = Headers.of(headMap); RequestBody body = builder.build(); okhttp3.Request request = new okhttp3.Request.Builder() .url(url) .headers(headers) .post(body) .build(); try { Call call = okHttpClient.newCall(request); Response response = call.execute(); if (response.code() == 200) { return response.body().toString(); } else { return null; } } catch (IOException e) { e.printStackTrace(); } return null; } } ================================================ FILE: src/main/java/com/we3j/demo/utils/AccountUtil.java ================================================ package com.we3j.demo.utils; import org.web3j.protocol.admin.Admin; import org.web3j.protocol.admin.methods.response.BooleanResponse; import org.web3j.protocol.admin.methods.response.PersonalUnlockAccount; import org.web3j.protocol.geth.Geth; import org.web3j.protocol.http.HttpService; import java.io.IOException; import java.util.concurrent.ExecutionException; /** * * Created by jambestwick@126.com * * on 2021/12/3 * 账号管理 * 对账号的锁定与解锁 * 保证安全 * * */ public class AccountUtil { /*******需要账户交易时才解锁账号*********/ public static boolean unlockAccount(String address, String passphrase) throws ExecutionException, InterruptedException { Admin admin = Admin.build(new HttpService(Environment.RPC_URL)); // defaults to http://localhost:8545/ PersonalUnlockAccount personalUnlockAccount = admin.personalUnlockAccount(address, passphrase).sendAsync().get(); return personalUnlockAccount.accountUnlocked(); } /********************锁定账号后无法进行交易,保证安全***************************/ public static boolean lockAccount(String address) throws IOException { Geth geth = Geth.build(new HttpService(Environment.RPC_URL)); BooleanResponse result = geth.personalLockAccount(address).send(); return result.success(); } } ================================================ FILE: src/main/java/com/we3j/demo/utils/CloseUtils.java ================================================ package com.we3j.demo.utils; import java.io.Closeable; import java.io.IOException; /** *
 *     author: Blankj
 *     blog  : http://blankj.com
 *     time  : 2016/10/9
 *     desc  : IO关闭相关工具类
 * 
*/ public class CloseUtils { private CloseUtils() { throw new UnsupportedOperationException("u can't instantiate me..."); } /** * 关闭IO * * @param closeables closeable */ public static void closeIO(Closeable... closeables) { if (closeables == null) return; for (Closeable closeable : closeables) { if (closeable != null) { try { closeable.close(); } catch (IOException e) { e.printStackTrace(); } } } } /** * 安静关闭IO * * @param closeables closeable */ public static void closeIOQuietly(Closeable... closeables) { if (closeables == null) return; for (Closeable closeable : closeables) { if (closeable != null) { try { closeable.close(); } catch (IOException ignored) { } } } } } ================================================ FILE: src/main/java/com/we3j/demo/utils/Environment.java ================================================ package com.we3j.demo.utils; /** * * Created by jambestwick@126.com * * on 2021/12/2 * * personal RPC * register on @see https://infura.io * * */ public class Environment { public static final String RPC_URL = "https://mainnet.infura.io/v3/9eb78bae70c34116a2b28db3fdb96dd0";//config your endpoint regesiter on infura.io } ================================================ FILE: src/main/java/com/we3j/demo/utils/FileUtil.java ================================================ package com.we3j.demo.utils; import org.springframework.util.StringUtils; import java.io.BufferedOutputStream; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.FileWriter; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.nio.file.Files; import java.nio.file.LinkOption; import java.nio.file.Path; import java.nio.file.Paths; import java.nio.file.attribute.BasicFileAttributeView; import java.nio.file.attribute.BasicFileAttributes; import java.text.DateFormat; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Calendar; import java.util.Date; import java.util.List; /** *

文件描述:文件工具类

*

作者:jambestwick

*

创建时间:2020/5/28

*

更新时间:2020/5/28

*

版本号:${VERSION}

*

邮箱:jambestwick@126.com

*/ public class FileUtil { private static final String TAG = FileUtil.class.getName(); /** * 删除指定目录下的文件,这里用于缓存的删除 * * @param filePath filePath * @param deleteThisPath deleteThisPath */ public static void deleteFolderFile(String filePath, boolean deleteThisPath) { if (!StringUtils.isEmpty(filePath)) { try { File file = new File(filePath); if (file.isDirectory()) { File files[] = file.listFiles(); for (File file1 : files) { deleteFolderFile(file1.getAbsolutePath(), true); } } if (deleteThisPath) { if (!file.isDirectory()) { file.delete(); } else { if (file.listFiles().length == 0) { file.delete(); } } } } catch (Exception e) { e.printStackTrace(); } } } /** * 将字符串写入文件 * * @param file 文件 * @param content 写入内容 * @param append 是否追加在文件末 * @return {@code true}: 写入成功
{@code false}: 写入失败 */ public static boolean writeFileFromString(File file, String content, boolean append) { if (file == null || content == null) return false; if (!createOrExistsFile(file)) return false; BufferedWriter bw = null; try { bw = new BufferedWriter(new FileWriter(file, append)); bw.write(content); return true; } catch (IOException e) { e.printStackTrace(); return false; } finally { CloseUtils.closeIO(bw); } } public static boolean writeFileFromLineString(File file, String content, boolean append) { if (file == null || content == null) return false; if (!createOrExistsFile(file)) return false; BufferedWriter bw = null; try { bw = new BufferedWriter(new FileWriter(file, append)); bw.write(content); bw.newLine(); return true; } catch (IOException e) { e.printStackTrace(); return false; } finally { CloseUtils.closeIO(bw); } } /** * 将输入流写入文件 * * @param file 文件 * @param is 输入流 * @param append 是否追加在文件末 * @return {@code true}: 写入成功
{@code false}: 写入失败 */ public static boolean writeFileFromIS(File file, InputStream is, boolean append) { if (file == null || is == null) return false; if (!createOrExistsFile(file)) return false; OutputStream os = null; try { os = new BufferedOutputStream(new FileOutputStream(file, append)); byte data[] = new byte[1024]; int len; while ((len = is.read(data, 0, 1024)) != -1) { os.write(data, 0, len); } return true; } catch (IOException e) { e.printStackTrace(); return false; } finally { CloseUtils.closeIO(is, os); } } /** * 将输入流写入文件 * * @param file 文件 * @param data 输入流 * @param append 是否追加在文件末 * @return {@code true}: 写入成功
{@code false}: 写入失败 */ public static boolean writeFileFromByte(File file, byte[] data, boolean append) { if (file == null || data == null) return false; if (!createOrExistsFile(file)) return false; OutputStream os = null; try { os = new BufferedOutputStream(new FileOutputStream(file, append)); os.write(data); return true; } catch (IOException e) { e.printStackTrace(); return false; } finally { CloseUtils.closeIO(os); } } /** * 判断文件是否存在,不存在则判断是否创建成功 * * @param filePath 文件路径 * @return {@code true}: 存在或创建成功
{@code false}: 不存在或创建失败 */ public static boolean createOrExistsFile(String filePath) { return createOrExistsFile(getFileByPath(filePath)); } /** * 判断文件是否存在,不存在则判断是否创建成功 * * @param file 文件 * @return {@code true}: 存在或创建成功
{@code false}: 不存在或创建失败 */ public static boolean createOrExistsFile(File file) { if (file == null) return false; // 如果存在,是文件则返回true,是目录则返回false if (file.exists()) return file.isFile(); if (!createOrExistsDir(file.getParentFile())) return false; try { return file.createNewFile(); } catch (IOException e) { e.printStackTrace(); return false; } } /** * 根据文件路径获取文件 * * @param filePath 文件路径 * @return 文件 */ public static File getFileByPath(String filePath) { return StringUtils.isEmpty(filePath) ? null : new File(filePath); } /** * 判断目录是否存在,不存在则判断是否创建成功 * * @param file 文件 * @return {@code true}: 存在或创建成功
{@code false}: 不存在或创建失败 */ public static boolean createOrExistsDir(File file) { // 如果存在,是目录则返回true,是文件则返回false,不存在则返回是否创建成功 return file != null && (file.exists() ? file.isDirectory() : file.mkdirs()); } /** * 指定编码按行读取文件到字符串中 * * @param file 文件 * @param charsetName 编码格式 * @return 字符串 */ public static String readFile2String(File file, String charsetName) { if (file == null) return null; BufferedReader reader = null; try { StringBuilder sb = new StringBuilder(); if (StringUtils.isEmpty(charsetName)) { reader = new BufferedReader(new InputStreamReader(new FileInputStream(file))); } else { reader = new BufferedReader(new InputStreamReader(new FileInputStream(file), charsetName)); } String line; while ((line = reader.readLine()) != null) { sb.append(line).append("\r\n");// windows系统换行为\r\n,Linux为\n } // 要去除最后的换行符 return sb.delete(sb.length() - 2, sb.length()).toString(); } catch (IOException e) { e.printStackTrace(); return null; } finally { CloseUtils.closeIO(reader); } } /** * 指定编码按行读取文件到字符串中 * * @param file 文件 * @param charsetName 编码格式 * @return 字符串 */ public static String readFileNull2String(File file, String charsetName) { if (file == null) return null; BufferedReader reader = null; try { StringBuilder sb = new StringBuilder(); if (StringUtils.isEmpty(charsetName)) { reader = new BufferedReader(new InputStreamReader(new FileInputStream(file))); } else { reader = new BufferedReader(new InputStreamReader(new FileInputStream(file), charsetName)); } String line; while ((line = reader.readLine()) != null) { sb.append(line).append("\r\n");// windows系统换行为\r\n,Linux为\n } // 要去除最后的换行符 return sb.toString(); } catch (IOException e) { e.printStackTrace(); return null; } finally { CloseUtils.closeIO(reader); } } /** * 删除目录 * * @param dirPath 目录路径 * @return {@code true}: 删除成功
{@code false}: 删除失败 */ public static boolean deleteDir(String dirPath) { return deleteDir(getFileByPath(dirPath)); } /** * 删除目录 * * @param dirPath 目录路径 * @param days 多少天前创建的文件 * @return {@code true}: 删除成功
{@code false}: 删除失败 */ public static boolean deleteDirBeforeDays(String dirPath, long days) { return deleteDir(getFileByPath(dirPath), days); } private static boolean deleteDir(File dir, long days) { if (dir == null) return false; // 目录不存在返回true if (!dir.exists()) return true; // 不是目录返回false if (!dir.isDirectory()) return false; File[] files = dir.listFiles(); if (files != null) { Date clearDay = TimeUtil.getBeforeDay(new Date(), days); for (int i = 0; i < files.length; i++) { long createMillTime = FileUtil.getFileCreateTime(files[i].getAbsolutePath()); if (createMillTime <= clearDay.getTime()) { files[i].delete(); } } } return true; } /** * 删除目录 * * @param dir 目录 * @return {@code true}: 删除成功
{@code false}: 删除失败 */ public static boolean deleteDir(File dir) { if (dir == null) return false; // 目录不存在返回true if (!dir.exists()) return true; // 不是目录返回false if (!dir.isDirectory()) return false; // 现在文件存在且是文件夹 File[] files = dir.listFiles(); if (files != null && files.length != 0) { for (File file : files) { if (file.isFile()) { if (!deleteFile(file)) return false; } else if (file.isDirectory()) { if (!deleteDir(file)) return false; } } } return dir.delete(); } /** * 删除文件 * * @param srcFilePath 文件路径 * @return {@code true}: 删除成功
{@code false}: 删除失败 */ public static boolean deleteFile(String srcFilePath) { return deleteFile(getFileByPath(srcFilePath)); } /** * 删除文件 * * @param file 文件 * @return {@code true}: 删除成功
{@code false}: 删除失败 */ public static boolean deleteFile(File file) { return file != null && (!file.exists() || file.isFile() && file.delete()); } /** * 删除目录下的所有文件 * * @param dirPath 目录路径 * @return {@code true}: 删除成功
{@code false}: 删除失败 */ public static boolean deleteFilesInDir(String dirPath) { return deleteFilesInDir(getFileByPath(dirPath)); } /** * 删除目录下的所有文件 * * @param dir 目录 * @return {@code true}: 删除成功
{@code false}: 删除失败 */ public static boolean deleteFilesInDir(File dir) { if (dir == null) return false; // 目录不存在返回true if (!dir.exists()) return true; // 不是目录返回false if (!dir.isDirectory()) return false; // 现在文件存在且是文件夹 File[] files = dir.listFiles(); if (files != null && files.length != 0) { for (File file : files) { if (file.isFile()) { if (!deleteFile(file)) return false; } else if (file.isDirectory()) { if (!deleteDir(file)) return false; } } } return true; } /** * 定时删除日志 * * @param path 日志路径 * @param day 最近几天 * @param pdate 计划日期 */ public static void deleteLogFileMyself(String path, int day, String pdate) { File file = new File(path); Calendar calendar = Calendar.getInstance(); DateFormat df = new SimpleDateFormat(TimeUtil.DEFAULT_HOUR_FORMAT); Date currentDate = null; try { currentDate = df.parse(pdate); } catch (ParseException e) { e.printStackTrace(); } calendar.setTime(currentDate); calendar.add(Calendar.DATE, -day); //得到前几天 Date date = calendar.getTime(); if (file.isDirectory()) { File[] files = file.listFiles(); if (files == null) { return; } for (File f : files) {//xxxx_2019-09-05_2325 try { Date logdate = df.parse(f.getName().split("Log")[0]); //若是文件夹且在设定日期之前 if (logdate.before(date)) { f.delete(); } } catch (ParseException e) { try { f.delete(); } catch (Exception e1) { e1.printStackTrace(); } //e.printStackTrace(); } } } } /*** * 查询指定日期文件的集合 * * **/ public static List getLogFileAcrossDay(String rootPath, int day) { List resultFiles = new ArrayList<>(); File file = new File(rootPath); Calendar calendar = Calendar.getInstance(); DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH"); Date currentDate = new Date(); calendar.setTime(currentDate); calendar.add(Calendar.DATE, -day); //得到前几天 Date date = calendar.getTime(); if (file.isDirectory()) { File[] files = file.listFiles(); for (File f : files) {//xxxx_2019-09-05_2325 Date logdate = null; try { logdate = df.parse(f.getName().split("Log")[0]); //若是文件夹且在设定日期之前 if (logdate.after(date)) { resultFiles.add(f); } } catch (ParseException e) { e.printStackTrace(); } } } return resultFiles; } /*** * 查询指定日期文件的集合 * @param days 指定的日期集合 * * **/ public static List getLogFileAcrossDay(String rootPath, List days) { List resultFiles = new ArrayList<>(); File file = new File(rootPath); if (file.isDirectory()) { File[] files = file.listFiles(); for (File f : files) {//xxxx_2019-09-05_2325 for (int i = 0; i < days.size(); i++) { try { String logdate = f.getName().split("Log")[0]; if (logdate.contains(days.get(i))) { resultFiles.add(f); } } catch (Exception e) { e.printStackTrace(); } } } } return resultFiles; } public static List getLogFilesWithOutExist(String rootPath, List days) { List resultFiles = new ArrayList<>(); File file = new File(rootPath); if (file.isDirectory()) { File[] files = file.listFiles(); for (int i = 0; i < days.size(); i++) { for (int j = 0; j < files.length; j++) {//xxxx_2019-09-05_2325 try { String logdate = files[i].getName().split("Log")[0].replaceAll(" ", ""); if (logdate.contains(days.get(i))) { resultFiles.add(files[i]); break; } if (j == files.length - 1) { Date logDate = TimeUtil.str2Date(days.get(i), TimeUtil.INTEGER_HOUR_FORMAT); String filePath = file.getAbsoluteFile() + "/" + TimeUtil.date2Str(logDate, TimeUtil.DEFAULT_HOUR_FORMAT) + "Log.txt"; FileUtil.createOrExistsFile(filePath); resultFiles.add(new File(filePath)); } } catch (Exception e) { e.printStackTrace(); } } } } return resultFiles; } /*** * 获取文件的时间 * **/ public static Long getFileCreateTime(String filePath) { File file = new File(filePath); try { Path path = Paths.get(filePath); BasicFileAttributeView basicView = Files.getFileAttributeView(path, BasicFileAttributeView.class, LinkOption.NOFOLLOW_LINKS); BasicFileAttributes attr = basicView.readAttributes(); return attr.creationTime().toMillis(); } catch (Exception e) { e.printStackTrace(); return file.lastModified(); } } public static ArrayList findFileByStartEndTime(String dir, long startTime, long endTime) { File file = new File(dir); if (!file.exists()) { return null; } ArrayList resultList = new ArrayList<>(); File[] files = file.listFiles(); for (int i = 0; i < files.length; i++) { long createTime = getFileCreateTime(files[i].getAbsolutePath()); if (createTime >= startTime && createTime <= endTime) { resultList.add(files[i]); } } return resultList; } public static ArrayList findFilePathByStartEndTime(String dir, long startTime, long endTime) { File file = new File(dir); if (!file.exists()) { return null; } ArrayList resultList = new ArrayList<>(); File[] files = file.listFiles(); for (File value : files) { long createTime = getFileCreateTime(value.getAbsolutePath()); if (createTime >= startTime && createTime <= endTime) { resultList.add(value.getAbsolutePath()); } } return resultList; } /*** * 获取文件夹里的所有在指定时间内的文件 * **/ public static List getFilesByCreateTime(String filePath, int day) { List resultFile = new ArrayList<>(); long current = System.currentTimeMillis(); File file = new File(filePath); if (file.isDirectory() && file.exists()) { File[] files = file.listFiles(); for (int i = 0; i < files.length; i++) { long fileCreateTime = getFileCreateTime(files[i].getAbsolutePath()); if (current - fileCreateTime < day * 24 * 3600 * 1000L) { resultFile.add(files[i]); } } } return resultFile; } } ================================================ FILE: src/main/java/com/we3j/demo/utils/NormalUtil.java ================================================ package com.we3j.demo.utils; import org.web3j.protocol.Web3j; import org.web3j.protocol.core.DefaultBlockParameter; import org.web3j.protocol.core.DefaultBlockParameterName; import org.web3j.protocol.core.methods.response.EthGasPrice; import org.web3j.protocol.core.methods.response.EthGetBalance; import org.web3j.protocol.core.methods.response.EthGetTransactionCount; import org.web3j.utils.Convert; import java.io.IOException; import java.math.BigInteger; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.concurrent.ExecutionException; /** * * Created by jambestwick@126.com * * on 2021/12/3 * * */ public class NormalUtil { /***********查询指定地址的余额***********/ public static String getBalanceOfString(Web3j web3j, String address) throws IOException { BigInteger balance = getBalanceOf(web3j, address); if (balance != null) { return Convert.fromWei(balance.toString(), Convert.Unit.ETHER).toPlainString(); } return null; } /***********查询指定地址的余额***********/ public static BigInteger getBalanceOf(Web3j web3j, String address) throws IOException { if (web3j == null) return null; //第二个参数:区块的参数,建议选最新区块 EthGetBalance balance = web3j.ethGetBalance(address, DefaultBlockParameterName.LATEST).send(); //格式转化 wei-ether 10`18 =1 ETH return balance.getBalance(); } /***********查询多个地址的余额***********/ public static Map getListBalanceOf(Web3j web3j, String... addresses) { Map balanceMap = new HashMap<>(); for (String address : addresses) { BigInteger addressBalance = null; try { addressBalance = getBalanceOf(web3j, address); balanceMap.put(address, addressBalance); } catch (IOException e) { e.printStackTrace(); } } return balanceMap; } /****************查询多个地址的余额*******************/ public static Map getListBalanceOf(Web3j web3j, List addresses) { Map balanceMap = new HashMap<>(); for (String address : addresses) { BigInteger addressBalance = null; try { addressBalance = getBalanceOf(web3j, address); balanceMap.put(address, addressBalance); } catch (IOException e) { e.printStackTrace(); } } return balanceMap; } /** * 获取nonce,交易笔数 * * @param from address * @return * @throws ExecutionException * @throws InterruptedException */ public static BigInteger getNonce(Web3j web3j, String from) throws ExecutionException, InterruptedException { if (web3j == null) return null; EthGetTransactionCount transactionCount = web3j.ethGetTransactionCount(from, DefaultBlockParameterName.LATEST).sendAsync().get(); return transactionCount.getTransactionCount(); } /** * Return the current gas price from the ethereum node. *

* Note: this method was previously called {@code getGasPrice} but was renamed to * distinguish it when a bean accessor method on {@link org.web3j.tx.Contract} was added with that name. * If you have a Contract subclass that is calling this method (unlikely since those * classes are usually generated and until very recently those generated subclasses were * marked {@code final}), then you will need to change your code to call this method * instead, if you want the dynamic behavior. *

* @return the current gas price, determined dynamically at invocation * @throws IOException if there's a problem communicating with the ethereum node */ public static BigInteger requestCurrentGasPrice(Web3j web3j) throws IOException { EthGasPrice ethGasPrice = web3j.ethGasPrice().send(); return ethGasPrice.getGasPrice(); } } ================================================ FILE: src/main/java/com/we3j/demo/utils/RSAEncrypt.java ================================================ package com.we3j.demo.utils; import java.security.KeyPair; import java.security.KeyPairGenerator; import java.security.interfaces.RSAPrivateKey; import java.security.interfaces.RSAPublicKey; import java.util.Base64; import javax.crypto.Cipher; /** * RSA加密类 */ public class RSAEncrypt { public static void main(String[] args) { try { RSAEncrypt encrypt = new RSAEncrypt(); String encryptText = "123456mPU5amu6Zr"; KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA"); keyPairGen.initialize(1024); KeyPair keyPair = keyPairGen.generateKeyPair(); RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate(); // 私钥 RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic(); // 公钥 System.out.println("¥¥¥¥¥¥¥¥"+publicKey); System.out.println("¥¥¥¥¥¥¥¥"+publicKey); byte[] e = encrypt.encrypt(publicKey, encryptText.getBytes()); byte[] de = encrypt.decrypt(privateKey, e); System.out.println("¥¥¥¥¥¥¥¥ "+encrypt.bytesToString(e)); System.out.println("¥¥¥¥¥¥¥¥ "+encrypt.bytesToString(de)); } catch (Exception e) { e.printStackTrace(); } } /** * byte数组转为string * * @return */ protected String bytesToString(byte[] bytes) { String result = ""; result = Base64.getEncoder().encodeToString(bytes); return result; } /** * 加密方法 * * @param publicKey * @param obj * @return */ protected byte[] encrypt(RSAPublicKey publicKey, byte[] obj) { if (publicKey != null) { try { Cipher cipher = Cipher.getInstance("RSA"); cipher.init(Cipher.ENCRYPT_MODE, publicKey); return cipher.doFinal(obj); } catch (Exception e) { e.printStackTrace(); } } return null; } /** * 解密方法 * * @param privateKey * @param obj * @return */ protected byte[] decrypt(RSAPrivateKey privateKey, byte[] obj) { if (privateKey != null) { try { Cipher cipher = Cipher.getInstance("RSA"); cipher.init(Cipher.DECRYPT_MODE, privateKey); return cipher.doFinal(obj); } catch (Exception e) { e.printStackTrace(); } } return null; } } ================================================ FILE: src/main/java/com/we3j/demo/utils/ScheduleTask.java ================================================ package com.we3j.demo.utils; import org.springframework.scheduling.annotation.Scheduled; import java.text.SimpleDateFormat; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; import java.util.Date; /** * @Author jambestwick * @create 2022/1/10 0010 1:17 * @email jambestwick@126.com * 定时器写法 定时监听器 */ public class ScheduleTask { /**** * * 定时器cron 原理规则 https://cron.qqe2.com/ * ***/ private static final SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm:ss"); //表示每2秒执行一次 @Scheduled(cron = "0/2 * * * * *") public void timer(){ //获取当前时间 LocalDateTime localDateTime =LocalDateTime.now(); System.out.println("当前时间为:" + localDateTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))); } //每天3:05执行 @Scheduled(cron = "0 05 03 ? * *") public void testTasks() { System.out.println("定时任务执行时间:" + dateFormat.format(new Date())); } } ================================================ FILE: src/main/java/com/we3j/demo/utils/TimeUtil.java ================================================ package com.we3j.demo.utils; import java.text.SimpleDateFormat; import java.util.*; /** *

文件描述:时间转换工具

*

author:jambestwick

*

创建时间:2019/11/29

*

更新时间:2019/11/29

*

邮箱:jambestwick@126.com

*/ public class TimeUtil { private static final String TAG = TimeUtil.class.getName(); /** * 整型日期格式 */ public static final String INTEGER_DATE_FORMAT = "yyyyMMdd"; public static final String INTEGER_HOUR_FORMAT = "yyyyMMddHH"; public static final String INTEGER_MINUTE_FORMAT = "yyyyMMddHHmm"; public static final String NUMBER_TIME_FORMAT = "yyyyMMddHHmmss"; public static final String NUMBER_TIME_FORMAT_MS = "yyyyMMddHHmmssSSS"; public static final String DEFAULT_DATE_FORMAT = "yyyy-MM-dd"; public static final String DEFAULT_HOUR_FORMAT = "yyyy-MM-dd HH"; public static final String DEFAULT_MINUTE_FORMAT = "yyyy-MM-dd HH:mm"; public static final String DEFAULT_TIME_FORMAT = "yyyy-MM-dd HH:mm:ss"; public static final String DEFAULT_TIME_FORMAT_MS = "yyyy-MM-dd HH:mm:ss SSS"; public static final String DEFAULT_TIME_FORMAT_MS_1 = "yyyy-MM-dd HH:mm:ss.SSS"; public static final String DEFAULT_MONTH_DATE = "MM-dd"; public static final String DEFAULT_SECOND_FORMAT = "HH:mm:ss"; public static final String ACTION_CLOCK_RESTART = "ACTION_CLOCK_RESTART"; /** * 字符串转换成日期 如果转换格式为空,则利用默认格式进行转换操作 * * @param str 字符串 * @param format 日期格式 * @return 日期 */ public static Date str2Date(String str, String format) { if (null == str || "".equals(str)) { return new Date(); } // 如果没有指定字符串转换的格式,则用默认格式进行转换 if (null == format || "".equals(format)) { format = DEFAULT_TIME_FORMAT; } SimpleDateFormat sdf = new SimpleDateFormat(format); Date date = null; try { date = sdf.parse(str); return date; } catch (Exception e) { e.printStackTrace(); } return new Date(); } public static long str2Long(String str, String format) { return str2Date(str, format).getTime(); } public static String date2Str(Date date, String formart) { SimpleDateFormat sdf = new SimpleDateFormat(formart); return sdf.format(date); } public static String long2Str(long millTime, String formart) { return date2Str(new Date(millTime), formart); } public static String now_mill() { return long2Str(System.currentTimeMillis(), TimeUtil.DEFAULT_TIME_FORMAT_MS); } public static String now_day() { return date2Str(new Date(), TimeUtil.DEFAULT_HOUR_FORMAT); } public static String now_minute(){ return date2Str(new Date(),TimeUtil.DEFAULT_MINUTE_FORMAT); } public static String now_second() { return date2Str(new Date(), TimeUtil.NUMBER_TIME_FORMAT); } public static String monthDay(Date date) { return date2Str(date, TimeUtil.DEFAULT_MONTH_DATE); } public static boolean passParamsMillTime(long lastMillTime, long paramsPassMill) { return System.currentTimeMillis() - lastMillTime >= paramsPassMill; } public static Date getNextDate(Date date) { Calendar calendar = Calendar.getInstance(); calendar.setTime(date); calendar.add(Calendar.DAY_OF_YEAR, +1); //今天的时间加一天 date = calendar.getTime(); return date; } public static Date getPreDate(Date date) { Calendar calendar = Calendar.getInstance(); calendar.setTime(date); calendar.add(Calendar.DAY_OF_YEAR, -1); //获取前一天日期 date = calendar.getTime(); return date; } public static Date getStartTime(Date date) { Calendar todayStart = Calendar.getInstance(); todayStart.setTime(date); todayStart.set(Calendar.HOUR_OF_DAY, 0); todayStart.set(Calendar.MINUTE, 0); todayStart.set(Calendar.SECOND, 0); todayStart.set(Calendar.MILLISECOND, 0); return todayStart.getTime(); } public static String hour12to24(String hh_mm_ss) { String hms[] = hh_mm_ss.split(":"); hms[0] = (Integer.parseInt(hms[0]) + 12) + ""; String s = ""; for (int i = 0; i < hms.length; i++) { if (i == hms.length - 1) s += hms[i]; else { s += hms[i] + ":"; } } return s; } /** * 获取两个日期之间的日期 * * @param start 开始日期 * @param end 结束日期 * @return 日期集合 */ public static List getBetweenDates(Date start, Date end) { List result = new ArrayList<>(); Calendar tempStart = Calendar.getInstance(); tempStart.setTime(start); //tempStart.add(Calendar.DAY_OF_YEAR, 1); Calendar tempEnd = Calendar.getInstance(); tempEnd.setTime(end); while (tempStart.before(tempEnd)) { result.add(tempStart.getTime()); tempStart.add(Calendar.DAY_OF_YEAR, 1); } return result; } public static Date getBeforeDay(Date plusDate, Long cycleDate) { long time = plusDate.getTime(); // 得到指定日期的毫秒数 cycleDate = cycleDate * 24 * 60 * 60 * 1000; // 要加上的天数转换成毫秒数 time -= cycleDate; // 相加得到新的毫秒数 return new Date(time); // 将毫秒数转换成日期 } public static String getDay() { Date day = new Date(); SimpleDateFormat df = new SimpleDateFormat(INTEGER_DATE_FORMAT); return df.format(day); } public static String getDate() { Date day = new Date(); SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm"); return df.format(day); } //生成日期字符串 public static String getDateString() { Date day = new Date(); SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); return df.format(day).replace(" ", "-").replace(":", "-"); } public static String getDateStr() { Date day = new Date(); SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); return df.format(day); } //生成日期字符串 public static String getDateString(Date date) { SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); return df.format(date).replace(" ", "-").replace(":", "-"); } //生成日期字符串 public static String getDateString(long time) { SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS"); return df.format(new Date(time)).replace("-", "").replace(":", "").replace(" ", ""); } /*** * @param utcTime hhmmss.ss * * */ public static Date utc2Time(String utcTime) { String currentDay = getDay(); utcTime = currentDay + utcTime.replace(".", "") + "0"; SimpleDateFormat sdf = new SimpleDateFormat(INTEGER_DATE_FORMAT + "HHmmssSSS"); sdf.setTimeZone(TimeZone.getTimeZone("UTC")); Date utcDate; Date locatlDate = null; try { utcDate = sdf.parse(utcTime); sdf.setTimeZone(TimeZone.getDefault()); String localTime = sdf.format(utcDate.getTime()); locatlDate = sdf.parse(localTime); } catch (Exception e) { e.printStackTrace(); } return locatlDate; } } ================================================ FILE: src/main/java/com/we3j/demo/wallet/NFTMonitor.java ================================================ package com.we3j.demo.wallet; import org.web3j.abi.EventEncoder; import org.web3j.abi.FunctionEncoder; import org.web3j.abi.TypeReference; import org.web3j.abi.datatypes.Address; import org.web3j.abi.datatypes.Event; import org.web3j.abi.datatypes.Function; import org.web3j.abi.datatypes.Type; import org.web3j.abi.datatypes.generated.Uint256; import org.web3j.crypto.Credentials; import org.web3j.protocol.Web3j; import org.web3j.protocol.core.DefaultBlockParameter; import org.web3j.protocol.core.DefaultBlockParameterName; import org.web3j.protocol.core.methods.request.EthFilter; import org.web3j.protocol.core.methods.request.Transaction; import org.web3j.protocol.core.methods.response.EthCall; import org.web3j.protocol.core.methods.response.Log; import rx.Subscription; import rx.functions.Action1; import java.math.BigInteger; import java.util.Arrays; import java.util.concurrent.ExecutionException; /** * * Created by jambestwick * * on 2021/12/8 * * */ public class NFTMonitor { private static NFTMonitor instance; private Web3j web3j; private Credentials credentials; public static NFTMonitor getInstance() { if (instance == null) { synchronized (NFTMonitor.class) { if (instance == null) { instance = new NFTMonitor(); } } } return instance; } public Web3j getWeb3j() { return web3j; } public void setWeb3j(Web3j web3j) { this.web3j = web3j; } public void setCredentials(Credentials credentials) { this.credentials = credentials; } /** * 监听合约的交易事件 **/ public Subscription subscribeClaim(String contractAddress, final Action1 onNext) { if (this.web3j == null) return null; // 要监听的合约事件 交易 EthFilter filter = new EthFilter( DefaultBlockParameter.valueOf(BigInteger.valueOf(0L)),//监听从0区块 DefaultBlockParameterName.LATEST,//到最新的区块 contractAddress); Event eventClaim = new Event("Transfer", Arrays.>asList( new TypeReference

(true) { }, new TypeReference
(true) { }, new TypeReference(false) { })); filter.addSingleTopic(EventEncoder.encode(eventClaim)); return web3j.ethLogObservable(filter).subscribe(onNext); } public void unsubscribeClaim(Subscription subscription) { if (this.web3j == null) return; subscription.unsubscribe(); } private static String emptyAddress = "0x0000000000000000000000000000000000000000"; /** * 调用NFT的Mint方法根据合约有两种 * Function: mint(uint256 _mintAmount) * ,即铸造生成NFT到自己的钱包 * * @param amount 你要mint的NFT数量 ***/ public boolean mintNFTByAmount(Web3j web3j, String contractAddress, int amount) { if (web3j == null) return false; String methodName = "mint"; String fromAddr = emptyAddress; Function function = new Function( methodName, Arrays.asList(new Uint256(amount)), Arrays.asList(new TypeReference() { })); String data = FunctionEncoder.encode(function); Transaction transaction = Transaction.createEthCallTransaction(fromAddr, contractAddress, data); EthCall ethCall; try { ethCall = web3j.ethCall(transaction, DefaultBlockParameterName.LATEST).sendAsync().get(); //List results = FunctionReturnDecoder.decode(ethCall.getValue(), function.getOutputParameters()); } catch (InterruptedException | ExecutionException e) { e.printStackTrace(); } return true; } /** * 调用NFT的Mint方法根据合约有两种 * Function: mint(address _to, uint256 _mintAmount) ***/ public boolean mintNFTByAmountAndAddress(Web3j web3j, Credentials credentials, String contractAddress, int amount) { if (web3j == null) return false; if (credentials == null) return false; String methodName = "mint"; String fromAddr = emptyAddress; Function function = new Function( methodName, Arrays.asList(new Address(credentials.getAddress()), new Uint256(amount)), Arrays.asList(new TypeReference() { })); String data = FunctionEncoder.encode(function); Transaction transaction = Transaction.createEthCallTransaction(fromAddr, contractAddress, data); EthCall ethCall; try { ethCall = web3j.ethCall(transaction, DefaultBlockParameterName.LATEST).sendAsync().get(); //List results = FunctionReturnDecoder.decode(ethCall.getValue(), function.getOutputParameters()); } catch (InterruptedException | ExecutionException e) { e.printStackTrace(); } return true; } } ================================================ FILE: src/main/java/com/we3j/demo/wallet/TokenClient.java ================================================ package com.we3j.demo.wallet; import com.we3j.demo.utils.NormalUtil; import org.web3j.abi.FunctionEncoder; import org.web3j.abi.FunctionReturnDecoder; import org.web3j.abi.datatypes.generated.Uint256; import org.web3j.crypto.Credentials; import org.web3j.crypto.RawTransaction; import org.web3j.crypto.TransactionEncoder; import org.web3j.protocol.Web3j; import org.web3j.abi.TypeReference; import org.web3j.abi.datatypes.*; import org.web3j.protocol.core.DefaultBlockParameterName; import org.web3j.protocol.core.methods.request.Transaction; import org.web3j.protocol.core.methods.response.EthCall; import org.web3j.protocol.core.methods.response.EthSendTransaction; import org.web3j.tx.Contract; import org.web3j.utils.Numeric; import java.io.IOException; import java.math.BigInteger; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.concurrent.ExecutionException; /** * @Author jambestwick * @create 2021/12/5 0005 21:04 * @email jambestwick@126.com *

* ERC20的代币 */ public class TokenClient { private static String emptyAddress = "0x0000000000000000000000000000000000000000"; /** * 查询代币发行总量 * * @param web3j * @param contractAddress * @return */ public static BigInteger getTokenTotalSupply(Web3j web3j, String contractAddress) { if (web3j == null) return null; String methodName = "totalSupply"; String fromAddr = emptyAddress; BigInteger totalSupply = BigInteger.ZERO; List inputParameters = new ArrayList<>(); List> outputParameters = new ArrayList<>(); TypeReference typeReference = new TypeReference() { }; outputParameters.add(typeReference); Function function = new Function(methodName, inputParameters, outputParameters); String data = FunctionEncoder.encode(function); Transaction transaction = Transaction.createEthCallTransaction(fromAddr, contractAddress, data); EthCall ethCall; try { ethCall = web3j.ethCall(transaction, DefaultBlockParameterName.LATEST).sendAsync().get(); List results = FunctionReturnDecoder.decode(ethCall.getValue(), function.getOutputParameters()); totalSupply = (BigInteger) results.get(0).getValue(); } catch (InterruptedException | ExecutionException e) { e.printStackTrace(); } return totalSupply; } /** * 查询指定账户 * 指定 ERC-20 余额 **/ public static BigInteger getAddressBalanceOf(Web3j web3j, String contractAddress, String address) { if (web3j == null) return null; String methodName = "balanceOf"; String fromAddr = emptyAddress; BigInteger tokenBalance = BigInteger.ZERO; List inputParameters = new ArrayList<>(); Address userAddress = new Address(address); inputParameters.add(userAddress); List> outputParameters = new ArrayList<>(); TypeReference typeReference = new TypeReference() { }; outputParameters.add(typeReference); Function function = new Function(methodName, inputParameters, outputParameters); String data = FunctionEncoder.encode(function); Transaction transaction = Transaction.createEthCallTransaction(fromAddr, contractAddress, data); EthCall ethCall; try { ethCall = web3j.ethCall(transaction, DefaultBlockParameterName.LATEST).sendAsync().get(); List results = FunctionReturnDecoder.decode(ethCall.getValue(), function.getOutputParameters()); tokenBalance = (BigInteger) results.get(0).getValue(); } catch (InterruptedException | ExecutionException e) { e.printStackTrace(); } return tokenBalance; } /*** * ERC20的授权操作 * 1.先调用授权 2.再调用transfer * approve授权 * * **/ public static boolean approve(Web3j web3j, Credentials credentials, String contractAddress, String address, BigInteger value) { if (web3j == null) return false; if (credentials == null) return false; String methodName = "approve"; String fromAddr = emptyAddress; boolean approveFlag = false; Function function = new Function( methodName, Arrays.asList(new Address(address), new Uint256(value)), Arrays.asList(new TypeReference() { })); //获取nonce,交易笔数 try { BigInteger nonce = NormalUtil.getNonce(web3j, address); //get gasPrice BigInteger gasPrice = NormalUtil.requestCurrentGasPrice(web3j); BigInteger gasLimit = Contract.GAS_LIMIT; String encodedFunction = FunctionEncoder.encode(function); RawTransaction rawTransaction = RawTransaction.createTransaction(nonce, gasPrice, gasLimit, contractAddress, encodedFunction); byte[] signMessage = TransactionEncoder.signMessage(rawTransaction, credentials); String hexValue = Numeric.toHexString(signMessage); //异步发送交易 EthSendTransaction send = web3j.ethSendRawTransaction(hexValue).sendAsync().get(); approveFlag = true; } catch (ExecutionException e) { e.printStackTrace(); } catch (InterruptedException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } return approveFlag; } /** * Returns the amount which _spender is still allowed to withdraw from _owner. **/ public static BigInteger allowance(Web3j web3j, String contractAddress, String owner, String spender) { if (web3j == null) return null; String methodName = "allowance"; String fromAddr = emptyAddress; BigInteger allowedAmount = BigInteger.ZERO; List inputParameters = new ArrayList<>(); Address userAddress = new Address(owner); inputParameters.add(userAddress); Address spenderAddress = new Address(spender); inputParameters.add(spenderAddress); List> outputParameters = new ArrayList<>(); TypeReference typeReference = new TypeReference() { }; outputParameters.add(typeReference); Function function = new Function(methodName, inputParameters, outputParameters); String data = FunctionEncoder.encode(function); Transaction transaction = Transaction.createEthCallTransaction(fromAddr, contractAddress, data); EthCall ethCall; try { ethCall = web3j.ethCall(transaction, DefaultBlockParameterName.LATEST).sendAsync().get(); List results = FunctionReturnDecoder.decode(ethCall.getValue(), function.getOutputParameters()); allowedAmount = (BigInteger) results.get(0).getValue(); } catch (InterruptedException | ExecutionException e) { e.printStackTrace(); } return allowedAmount; } /*********** * A允许B从A那里转多少钱给C, * 先用A调用approve方法,传入B账户; * 然后调用transferFrom方法,from参数传A账户,to参数传B账户,最后账户地址要改为B的账户来调用 * ****************/ public static boolean transferFrom(Web3j web3j, Credentials credentials, String from, String to, BigInteger value, String contractAddress) throws ExecutionException, IOException, InterruptedException { //获取nonce,交易笔数 BigInteger nonce = NormalUtil.getNonce(web3j, from); //get gasPrice BigInteger gasPrice = NormalUtil.requestCurrentGasPrice(web3j); BigInteger gasLimit = Contract.GAS_LIMIT; //创建RawTransaction交易对象 try { Function function = new Function( "transferFrom", Arrays.asList(new Address(from), new Address(to), new Uint256(value)), Arrays.asList(new TypeReference() { })); String encodedFunction = FunctionEncoder.encode(function); RawTransaction rawTransaction = RawTransaction.createTransaction(nonce, gasPrice, gasLimit, contractAddress, encodedFunction); //签名Transaction,这里要对交易做签名 byte[] signMessage = TransactionEncoder.signMessage(rawTransaction, credentials); String hexValue = Numeric.toHexString(signMessage); //异步发送交易 EthSendTransaction send = web3j.ethSendRawTransaction(hexValue).sendAsync().get(); return true; } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } return false; } /**** * 调用claim方法抢NFT Token * ***/ public static boolean claimNFT(Web3j web3j, String contractAddress, Integer tokenId) { if (web3j == null) return false; String methodName = "claim"; String fromAddr = emptyAddress; Function function = new Function( methodName, Arrays.asList(new Uint256(tokenId)), Arrays.asList(new TypeReference() { })); String data = FunctionEncoder.encode(function); Transaction transaction = Transaction.createEthCallTransaction(fromAddr, contractAddress, data); EthCall ethCall; try { ethCall = web3j.ethCall(transaction, DefaultBlockParameterName.LATEST).sendAsync().get(); //List results = FunctionReturnDecoder.decode(ethCall.getValue(), function.getOutputParameters()); } catch (InterruptedException | ExecutionException e) { e.printStackTrace(); } return true; } } ================================================ FILE: src/main/java/com/we3j/demo/wallet/TransMonitor.java ================================================ package com.we3j.demo.wallet; import org.web3j.abi.EventEncoder; import org.web3j.abi.TypeReference; import org.web3j.abi.datatypes.Address; import org.web3j.abi.datatypes.Event; import org.web3j.abi.datatypes.Uint; import org.web3j.abi.datatypes.generated.Uint256; import org.web3j.protocol.Web3j; import org.web3j.protocol.core.DefaultBlockParameter; import org.web3j.protocol.core.DefaultBlockParameterName; import org.web3j.protocol.core.methods.request.EthFilter; import org.web3j.protocol.core.methods.response.EthBlock; import org.web3j.protocol.core.methods.response.Log; import org.web3j.protocol.core.methods.response.Transaction; import rx.Subscription; import rx.functions.Action1; import java.math.BigInteger; import java.util.Arrays; /** * * Created by jambestwick@126.com * * on 2021/12/5 * * EIP-20 基础定义 * https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md * * * 交易监听器 */ public class TransMonitor { private static TransMonitor instance; private Web3j web3j; public static TransMonitor getInstance() { if (instance == null) { synchronized (TransMonitor.class) { if (instance == null) { instance = new TransMonitor(); } } } return instance; } public Web3j getWeb3j() { return web3j; } public void setWeb3j(Web3j web3j) { this.web3j = web3j; } public Subscription subscribeBlock(final Action1 onNext) { if (this.web3j == null) return null; return this.web3j.blockObservable(true).subscribe(onNext); } public void unsubscribeBlock(Subscription subscription) { if (this.web3j == null) return; subscription.unsubscribe(); } /** * 监听新交易事件 * 已经交易的事件 * mark **/ public Subscription subscribeHasTrans(final Action1 onNext) { if (this.web3j == null) return null; return web3j.transactionObservable().subscribe(onNext); } /** * 取消订阅信息 **/ public void unsubscribeHasTrans(Subscription subscription) { if (this.web3j == null) return; subscription.unsubscribe(); } /** * 监听待定交易 */ public Subscription subscribePendingTrans(final Action1 onNext) { if (this.web3j == null) return null; return web3j.pendingTransactionObservable().subscribe(onNext); } /** * 取消订阅信息 **/ public void unsubscribePendingTrans(Subscription subscription) { if (this.web3j == null) return; subscription.unsubscribe(); } /** * 监听合约的交易事件 **/ public Subscription subscribeContract(String contractAddress, final Action1 onNext) { if (this.web3j == null) return null; // 要监听的合约事件 交易 EthFilter filter = new EthFilter( DefaultBlockParameter.valueOf(BigInteger.valueOf(0L)), DefaultBlockParameterName.LATEST, contractAddress); Event event = new Event("Transfer", Arrays.>asList( new TypeReference

(true) { }, new TypeReference
(true) { }, new TypeReference(false) { })); filter.addSingleTopic(EventEncoder.encode(event)); return web3j.ethLogObservable(filter).subscribe(onNext); } public void unsubscribeContract(Subscription subscription) { if (this.web3j == null) return; subscription.unsubscribe(); } /** * 监听合约授权事件 **/ public Subscription subscribeApproval(String contractAddress, final Action1 onNext) { if (this.web3j == null) return null; // 要监听的合约事件 交易 EthFilter filter = new EthFilter( DefaultBlockParameter.valueOf(BigInteger.valueOf(0L)), DefaultBlockParameterName.LATEST, contractAddress); Event event = new Event("Approval", Arrays.>asList( new TypeReference
(true) {//address indexed _owner }, new TypeReference
(true) {// address indexed _spender }, new TypeReference(false) {//amount })); filter.addSingleTopic(EventEncoder.encode(event)); return web3j.ethLogObservable(filter).subscribe(onNext); } /** * 取消监听 */ public void unsubscribeApproval(Subscription subscription) { if (this.web3j == null) return; subscription.unsubscribe(); } } ================================================ FILE: src/main/java/com/we3j/demo/wallet/TransferToken.java ================================================ package com.we3j.demo.wallet; import com.we3j.demo.bean.bo.ReceiveAccount; import com.we3j.demo.test.WalletDemo; import com.we3j.demo.utils.NormalUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.web3j.abi.FunctionEncoder; import org.web3j.abi.TypeReference; import org.web3j.abi.datatypes.Address; import org.web3j.abi.datatypes.Function; import org.web3j.abi.datatypes.Type; import org.web3j.abi.datatypes.generated.Uint256; import org.web3j.crypto.Credentials; import org.web3j.crypto.RawTransaction; import org.web3j.crypto.TransactionEncoder; import org.web3j.crypto.WalletUtils; import org.web3j.protocol.Web3j; import org.web3j.protocol.core.DefaultBlockParameter; import org.web3j.protocol.core.DefaultBlockParameterName; import org.web3j.protocol.core.DefaultBlockParameterNumber; import org.web3j.protocol.core.Request; import org.web3j.protocol.core.methods.response.*; import org.web3j.protocol.exceptions.TransactionException; import org.web3j.tx.Contract; import org.web3j.tx.Transfer; import org.web3j.utils.Convert; import org.web3j.utils.Numeric; import java.io.IOException; import java.math.BigDecimal; import java.math.BigInteger; import java.util.Arrays; import java.util.List; import java.util.concurrent.ExecutionException; /** * * Created by jambestwick@126.com * * on 2021/12/3 * 转账 * * */ public class TransferToken { private static final Logger log = LoggerFactory.getLogger(TransferToken.class); /****************转账****************/ public static boolean transfer(Web3j web3j, Credentials credentials, String toAddress, BigDecimal amount) throws Exception { if (web3j == null) return false; if (credentials == null) return false; if (!WalletUtils.isValidAddress(toAddress) || !WalletUtils.isValidAddress(credentials.getAddress())) { log.info("invalid address"); return false; } BigInteger balance = NormalUtil.getBalanceOf(web3j, credentials.getAddress()); if (balance == null) { log.info("can't find wallet balance"); return false; } if (balance.compareTo(amount.toBigInteger()) <= 0) {//wallet balance must greater than trans amount log.info("wallet balance is less than trans amount"); return false; } TransactionReceipt send = Transfer.sendFunds(web3j, credentials, toAddress, amount, Convert.Unit.WEI).send(); log.info("trans hash=" + send.getTransactionHash()); log.info("from :" + send.getFrom()); log.info("to:" + send.getTo()); log.info("gas used=" + send.getGasUsed()); log.info("status: " + send.getStatus()); return true; } /****************异步转账****************/ public static void transferAsync(Web3j web3j, Credentials credentials, String toAddress, BigDecimal amount) throws InterruptedException, IOException, TransactionException, ExecutionException { if (web3j == null) return; if (credentials == null) return; if (!WalletUtils.isValidAddress(toAddress) || !WalletUtils.isValidAddress(credentials.getAddress())) { log.info("invalid address"); return; } BigInteger balance = NormalUtil.getBalanceOf(web3j, credentials.getAddress()); if (balance == null) { log.info("can't find wallet balance"); return; } if (balance.compareTo(amount.toBigInteger()) <= 0) {//wallet balance must greater than trans amount log.info("wallet balance is less than trans amount"); return; } TransactionReceipt send = Transfer.sendFunds(web3j, credentials, toAddress, amount, Convert.Unit.WEI).sendAsync().get(); log.info("trans hash=" + send.getTransactionHash()); log.info("from :" + send.getFrom()); log.info("to:" + send.getTo()); log.info("gas used=" + send.getGasUsed()); log.info("status: " + send.getStatus()); } /***************向多地址异步批量转账*****************/ public static void transferBatch(Web3j web3j, Credentials credentials, List receiveAccountList) throws InterruptedException, TransactionException, IOException, ExecutionException { for (ReceiveAccount receiveAccount : receiveAccountList) { transferAsync(web3j, credentials, receiveAccount.getAddress(), receiveAccount.getSendAmount()); } } /***********转账ERC20协议的代币*****************/ public static EthSendTransaction transferERC20(Web3j web3j, Credentials credentials, String from, String to, BigInteger value, String contractAddress) throws ExecutionException, IOException, InterruptedException { //获取nonce,交易笔数 BigInteger nonce = NormalUtil.getNonce(web3j, from); //get gasPrice BigInteger gasPrice = NormalUtil.requestCurrentGasPrice(web3j); BigInteger gasLimit = Contract.GAS_LIMIT; //创建RawTransaction交易对象 Function function = new Function( "transfer", Arrays.asList(new Address(to), new Uint256(value)), Arrays.asList(new TypeReference() { })); String encodedFunction = FunctionEncoder.encode(function); RawTransaction rawTransaction = RawTransaction.createTransaction(nonce, gasPrice, gasLimit, contractAddress, encodedFunction); //签名Transaction,这里要对交易做签名 byte[] signMessage = TransactionEncoder.signMessage(rawTransaction, credentials); String hexValue = Numeric.toHexString(signMessage); //异步发送交易 EthSendTransaction send = web3j.ethSendRawTransaction(hexValue).sendAsync().get(); log.info("trans hash=" + send.getTransactionHash()); log.info("rawResponse :" + send.getRawResponse()); log.info("result:" + send.getResult()); return send; } /************************** 批量转账ERC20 Token***************************************/ public static void transferERC20Batch(Web3j web3j, Credentials credentials, String from, String contractAddress, List receiveAccountList) throws InterruptedException, ExecutionException, IOException { for (ReceiveAccount receiveAccount : receiveAccountList) { transferERC20(web3j, credentials, from, receiveAccount.getAddress(), receiveAccount.getSendAmount().toBigInteger(), contractAddress); } } /** * 批量转账ERC20 Token * * @param destAddresses 目的地址的集合 * @param sendAmount 每个地址要发送的金额 ***********************************/ public static void transferERC20Batch(Web3j web3j, Credentials credentials, String from, String contractAddress, List destAddresses , BigInteger sendAmount) throws InterruptedException, ExecutionException, IOException { for (String dest : destAddresses) { transferERC20(web3j, credentials, from, dest, sendAmount, contractAddress); } } /** * 根据hash值获取交易 * * @param hash * @return * @throws IOException */ public static EthTransaction getTransactionByHash(Web3j web3j, String hash) throws IOException { Request request = web3j.ethGetTransactionByHash(hash); return request.send(); } /** * 获得ethblock * * @param blockNumber 根据区块编号 * @return * @throws IOException */ public static EthBlock getBlockEthBlock(Web3j web3j, Integer blockNumber) throws IOException { DefaultBlockParameter defaultBlockParameter = new DefaultBlockParameterNumber(blockNumber); Request request = web3j.ethGetBlockByNumber(defaultBlockParameter, true); EthBlock ethBlock = request.send(); return ethBlock; } } ================================================ FILE: src/main/java/com/we3j/demo/wallet/WalletTools.java ================================================ package com.we3j.demo.wallet; import com.fasterxml.jackson.databind.ObjectMapper; import com.we3j.demo.utils.FileUtil; import org.web3j.crypto.*; import org.web3j.protocol.ObjectMapperFactory; import java.io.File; import java.io.IOException; import java.math.BigInteger; import java.security.InvalidAlgorithmParameterException; import java.security.NoSuchAlgorithmException; import java.security.NoSuchProviderException; /** * * Created by jambestwick@126.com * * on 2021/12/4 * * about some method create and load wallet */ public class WalletTools { public static boolean createWallet(String filePath, String destFile) throws CipherException, IOException { FileUtil.createOrExistsDir(new File(filePath)); Bip39Wallet bip39Wallet = WalletUtils.generateBip39Wallet("", new File(filePath));//助记词钱包生成 bip39Wallet.getMnemonic(); System.out.println("生成助记词, generate mnemonic:" + bip39Wallet.getMnemonic()); return FileUtil.writeFileFromLineString(new File(destFile), bip39Wallet.getMnemonic(), true); } /****************** * **批量生成钱包(助记词)到指定文件中 * @param destFile eg. "d:\\keystore" * @param count 需要生成的数量 * *********************/ public static void createWalletBatch(int count, String filePath, String destFile) throws CipherException, IOException { for (int i = 0; i < count; i++) { createWallet(filePath, destFile); } } /** * return fileName * **/ public static String createWalletFull(String password, String destFile) throws CipherException, InvalidAlgorithmParameterException, NoSuchAlgorithmException, NoSuchProviderException, IOException { FileUtil.createOrExistsDir(new File(destFile)); return WalletUtils.generateFullNewWalletFile(password, new File(destFile)); } /** * return fileName ***/ public static String createWalletLight(String password, String destFile) throws CipherException, InvalidAlgorithmParameterException, NoSuchAlgorithmException, NoSuchProviderException, IOException { FileUtil.createOrExistsDir(new File(destFile)); return WalletUtils.generateLightNewWalletFile(password, new File(destFile)); } /** *根据私钥文件路径加载钱包 * **/ public static Credentials loadWallet(String password, String walletFilePath) throws IOException, CipherException { // FIXME: 2018/4/15 替换为自己的钱包路径 //String walletFilePath = "/Users/jambestwick/MyGitHub/z_wallet_temp/UTC--2018-04-10T02-51-24.815000000Z--12571f46ec3f81f7ebe79112be5883194d683787.json"; //String password = "123456"; Credentials credentials = WalletUtils.loadCredentials(password, walletFilePath); String address = credentials.getAddress(); BigInteger publicKey = credentials.getEcKeyPair().getPublicKey(); BigInteger privateKey = credentials.getEcKeyPair().getPrivateKey(); System.out.println("address=" + address); System.out.println("public key=" + publicKey); System.out.println("private key=" + privateKey); return credentials; } /********根据助记词加载钱包 **********/ public static Credentials loadWalletByMnemonic(String password, String mnemonic) { Credentials credentials = WalletUtils.loadBip39Credentials(password, mnemonic);//no need password // credentials = WalletUtils.loadBip39Credentials(password, // keyWords);//"cherry type collect echo derive shy balcony dog concert picture kid february" String address = credentials.getAddress(); BigInteger publicKey = credentials.getEcKeyPair().getPublicKey(); BigInteger privateKey = credentials.getEcKeyPair().getPrivateKey(); System.out.println("address=" + address); System.out.println("public key=" + publicKey); System.out.println("private key=" + privateKey); return credentials; } /** * 根据私钥加载钱包 * * **/ public static Credentials loadWalletByPrivateKey(String inputPrivateKey) { Credentials credentials = Credentials.create(inputPrivateKey); String address = credentials.getAddress(); BigInteger publicKey = credentials.getEcKeyPair().getPublicKey(); BigInteger privateKey = credentials.getEcKeyPair().getPrivateKey(); System.out.println("address=" + address); System.out.println("public key=" + publicKey); System.out.println("private key=" + privateKey); return credentials; } /** * 解密keystore 得到私钥 * * @param keystore * @param password */ public static String decryptWallet(String keystore, String password) { String privateKey = null; ObjectMapper objectMapper = ObjectMapperFactory.getObjectMapper(); try { WalletFile walletFile = objectMapper.readValue(keystore, WalletFile.class); ECKeyPair ecKeyPair = null; ecKeyPair = Wallet.decrypt(password, walletFile); privateKey = ecKeyPair.getPrivateKey().toString(16); System.out.println(privateKey); } catch (CipherException e) { if ("Invalid password provided".equals(e.getMessage())) { System.out.println("密码错误"); } e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } return privateKey; } } ================================================ FILE: src/main/java/com/we3j/demo/wallet/Web3jInfo.java ================================================ package com.we3j.demo.wallet; import com.we3j.demo.utils.Environment; import org.web3j.protocol.Web3j; import org.web3j.protocol.http.HttpService; /** * * Created by jambestwick@126.com * * on 2021/12/4 * * */ public class Web3jInfo { /** * 必须先连接节点才能进行后续线上操作 * * ***/ public static Web3j connect(){ return Web3j.build(new HttpService(Environment.RPC_URL));// TODO: 2018/4/10 节点更改为自己的或者主网 } /*** * 根据本地节点连接web3 * **/ public static Web3j connect(String localPointUrl){ return Web3j.build(new HttpService(localPointUrl)); } } ================================================ FILE: src/main/resources/application-dev.properties ================================================ debug=true server.port=8000 #database #base.url = https://api.etherscan.io/ base.url = https://visitor-badge.laobi.icu/ github.url = https://profile-counter.glitch.me/ ================================================ FILE: src/main/resources/application.properties ================================================ spring.profiles.active=dev