Full Code of jambestwick/web3jdemo for AI

master f96d92fbef28 cached
52 files
146.8 KB
38.7k tokens
272 symbols
1 requests
Download .txt
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<T> 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
 * <p>
 * 对基于 {@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.<TypeReference<?>>asList(new TypeReference<Address>(true) {
            }, new TypeReference<Address>(true) {
            }, new TypeReference<Uint256>(false) {
            }));
    ;

    public static final Event BURN_EVENT = new Event("Burn",
            Arrays.<TypeReference<?>>asList(new TypeReference<Address>(true) {
            }, new TypeReference<Uint256>(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<String> name() {
        final Function function = new Function(FUNC_NAME,
                Arrays.<Type>asList(),
                Arrays.<TypeReference<?>>asList(new TypeReference<Utf8String>() {
                }));
        return executeRemoteCallSingleValueReturn(function, String.class);
    }

    public RemoteCall<TransactionReceipt> approve(String _spender, BigInteger _value) {
        final Function function = new Function(
                FUNC_APPROVE,
                Arrays.<Type>asList(new Address(_spender),
                        new Uint256(_value)),
                Collections.<TypeReference<?>>emptyList());
        return executeRemoteCallTransaction(function);
    }

    public RemoteCall<BigInteger> totalSupply() {
        final Function function = new Function(FUNC_TOTALSUPPLY,
                Arrays.<Type>asList(),
                Arrays.<TypeReference<?>>asList(new TypeReference<Uint256>() {
                }));
        return executeRemoteCallSingleValueReturn(function, BigInteger.class);
    }

    public RemoteCall<TransactionReceipt> transferFrom(String _from, String _to, BigInteger _value) {
        final Function function = new Function(
                FUNC_TRANSFERFROM,
                Arrays.<Type>asList(new Address(_from),
                        new Address(_to),
                        new Uint256(_value)),
                Collections.<TypeReference<?>>emptyList());
        return executeRemoteCallTransaction(function);
    }

    public RemoteCall<BigInteger> decimals() {
        final Function function = new Function(FUNC_DECIMALS,
                Arrays.<Type>asList(),
                Arrays.<TypeReference<?>>asList(new TypeReference<Uint8>() {
                }));
        return executeRemoteCallSingleValueReturn(function, BigInteger.class);
    }

    public RemoteCall<TransactionReceipt> burn(BigInteger _value) {
        final Function function = new Function(
                FUNC_BURN,
                Arrays.<Type>asList(new Uint256(_value)),
                Collections.<TypeReference<?>>emptyList());
        return executeRemoteCallTransaction(function);
    }

    public RemoteCall<BigInteger> balanceOf(String param0) {
        final Function function = new Function(FUNC_BALANCEOF,
                Arrays.<Type>asList(new Address(param0)),
                Arrays.<TypeReference<?>>asList(new TypeReference<Uint256>() {
                }));
        return executeRemoteCallSingleValueReturn(function, BigInteger.class);
    }

    public RemoteCall<TransactionReceipt> burnFrom(String _from, BigInteger _value) {
        final Function function = new Function(
                FUNC_BURNFROM,
                Arrays.<Type>asList(new Address(_from),
                        new Uint256(_value)),
                Collections.<TypeReference<?>>emptyList());
        return executeRemoteCallTransaction(function);
    }

    public RemoteCall<String> symbol() {
        final Function function = new Function(FUNC_SYMBOL,
                Arrays.<Type>asList(),
                Arrays.<TypeReference<?>>asList(new TypeReference<Utf8String>() {
                }));
        return executeRemoteCallSingleValueReturn(function, String.class);
    }

    public RemoteCall<TransactionReceipt> transfer(String _to, BigInteger _value) {
        final Function function = new Function(
                FUNC_TRANSFER,
                Arrays.<Type>asList(new Address(_to),
                        new Uint256(_value)),
                Collections.<TypeReference<?>>emptyList());
        return executeRemoteCallTransaction(function);
    }

    public RemoteCall<TransactionReceipt> approveAndCall(String _spender, BigInteger _value, byte[] _extraData) {
        final Function function = new Function(
                FUNC_APPROVEANDCALL,
                Arrays.<Type>asList(new Address(_spender),
                        new Uint256(_value),
                        new org.web3j.abi.datatypes.DynamicBytes(_extraData)),
                Collections.<TypeReference<?>>emptyList());
        return executeRemoteCallTransaction(function);
    }

    public RemoteCall<BigInteger> allowance(String param0, String param1) {
        final Function function = new Function(FUNC_ALLOWANCE,
                Arrays.<Type>asList(new Address(param0),
                        new Address(param1)),
                Arrays.<TypeReference<?>>asList(new TypeReference<Uint256>() {
                }));
        return executeRemoteCallSingleValueReturn(function, BigInteger.class);
    }

    public static RemoteCall<TokenERC20> deploy(Web3j web3j, Credentials credentials, BigInteger gasPrice, BigInteger gasLimit, BigInteger initialSupply, String tokenName, String tokenSymbol) {
        String encodedConstructor = FunctionEncoder.encodeConstructor(Arrays.<Type>asList(new Uint256(initialSupply),
                new Utf8String(tokenName),
                new Utf8String(tokenSymbol)));
        return deployRemoteCall(TokenERC20.class, web3j, credentials, gasPrice, gasLimit, BINARY, encodedConstructor);
    }

    public static RemoteCall<TokenERC20> deploy(Web3j web3j, TransactionManager transactionManager, BigInteger gasPrice, BigInteger gasLimit, BigInteger initialSupply, String tokenName, String tokenSymbol) {
        String encodedConstructor = FunctionEncoder.encodeConstructor(Arrays.<Type>asList(new Uint256(initialSupply),
                new Utf8String(tokenName),
                new Utf8String(tokenSymbol)));
        return deployRemoteCall(TokenERC20.class, web3j, transactionManager, gasPrice, gasLimit, BINARY, encodedConstructor);
    }

    public List<TransferEventResponse> getTransferEvents(TransactionReceipt transactionReceipt) {
        List<EventValuesWithLog> valueList = extractEventParametersWithLog(TRANSFER_EVENT, transactionReceipt);
        ArrayList<TransferEventResponse> responses = new ArrayList<TransferEventResponse>(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<TransferEventResponse> transferEventObservable(EthFilter filter) {
        return web3j.ethLogObservable(filter).map(new Func1<Log, TransferEventResponse>() {
            @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<TransferEventResponse> transferEventObservable(DefaultBlockParameter startBlock, DefaultBlockParameter endBlock) {
        EthFilter filter = new EthFilter(startBlock, endBlock, getContractAddress());
        filter.addSingleTopic(EventEncoder.encode(TRANSFER_EVENT));
        return transferEventObservable(filter);
    }

    public List<BurnEventResponse> getBurnEvents(TransactionReceipt transactionReceipt) {
        List<EventValuesWithLog> valueList = extractEventParametersWithLog(BURN_EVENT, transactionReceipt);
        ArrayList<BurnEventResponse> responses = new ArrayList<BurnEventResponse>(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<BurnEventResponse> burnEventObservable(EthFilter filter) {
        return web3j.ethLogObservable(filter).map(new Func1<Log, BurnEventResponse>() {
            @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<BurnEventResponse> 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
 * <p>
 * 合约测试
 ***/

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);
    }


    /**
     * *****
     * *******创建一个智能合约******
     * <p>
     * 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 <compiled smart contract code>");
// 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<TokenERC20> 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.<TypeReference<?>>asList(
                        new TypeReference<?>[]{new TypeReference<Address>(true) {
                        }, new TypeReference<Address>(true) {
                        }, new TypeReference<Uint256>(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<String> 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<Log>() {
            @Override
            public void call(Log log) {
                System.out.println("transBlockNo:" + log.getBlockNumber());
                System.out.println("transHash:" + log.getTransactionHash());
                List<String> topics = log.getTopics();
                for (String topic : topics) {
                    System.out.println("transTopic:" + topic);
                }
            }
        });
        NFTMonitor.getInstance().setWeb3j(web3j);
        /***
         * Loot的合约
         *
         * ***/
        NFTMonitor.getInstance().subscribeClaim("0xff9c1b15b16263c61d017ee9f65c50e4ae0113d7", new Action1<Log>() {
            @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<EthBlock>() {
//            @Override
//            public void call(EthBlock ethBlock) {
//                System.out.println("block:" + ethBlock.getBlock().getHash() + ",author" + ethBlock.getBlock().getAuthor());
//            }
//        });
//
//        TransMonitor.getInstance().subscribeHasTrans(new Action1<Transaction>() {
//            @Override
//            public void call(Transaction transaction) {
//                System.out.println("from:" + transaction.getFrom() + ",to" + transaction.getTo());
//            }
//        });
//
//        TransMonitor.getInstance().subscribePendingTrans(new Action1<Transaction>() {
//            @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<String, String> buildInviteParam(String address, String inviteCode, String signature) {

        Map<String, String> map = new HashMap<>();

        map.put("address", address);
        map.put("invite_code", inviteCode);
        map.put("signature", signature);
        return map;

    }

    public static Map<String, String> 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<String, String> 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<String, String> requestMap, Map<String, String> 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;

/**
 * <pre>
 *     author: Blankj
 *     blog  : http://blankj.com
 *     time  : 2016/10/9
 *     desc  : IO关闭相关工具类
 * </pre>
 */
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;

/**
 * <p>文件描述:文件工具类<p>
 * <p>作者:jambestwick<p>
 * <p>创建时间:2020/5/28<p>
 * <p>更新时间:2020/5/28<p>
 * <p>版本号:${VERSION}<p>
 * <p>邮箱:jambestwick@126.com<p>
 */
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}: 写入成功<br>{@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}: 写入成功<br>{@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}: 写入成功<br>{@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}: 存在或创建成功<br>{@code false}: 不存在或创建失败
     */
    public static boolean createOrExistsFile(String filePath) {
        return createOrExistsFile(getFileByPath(filePath));
    }

    /**
     * 判断文件是否存在,不存在则判断是否创建成功
     *
     * @param file 文件
     * @return {@code true}: 存在或创建成功<br>{@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}: 存在或创建成功<br>{@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}: 删除成功<br>{@code false}: 删除失败
     */
    public static boolean deleteDir(String dirPath) {
        return deleteDir(getFileByPath(dirPath));
    }

    /**
     * 删除目录
     *
     * @param dirPath 目录路径
     * @param days    多少天前创建的文件
     * @return {@code true}: 删除成功<br>{@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}: 删除成功<br>{@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}: 删除成功<br>{@code false}: 删除失败
     */
    public static boolean deleteFile(String srcFilePath) {
        return deleteFile(getFileByPath(srcFilePath));
    }

    /**
     * 删除文件
     *
     * @param file 文件
     * @return {@code true}: 删除成功<br>{@code false}: 删除失败
     */
    public static boolean deleteFile(File file) {
        return file != null && (!file.exists() || file.isFile() && file.delete());
    }

    /**
     * 删除目录下的所有文件
     *
     * @param dirPath 目录路径
     * @return {@code true}: 删除成功<br>{@code false}: 删除失败
     */
    public static boolean deleteFilesInDir(String dirPath) {
        return deleteFilesInDir(getFileByPath(dirPath));
    }

    /**
     * 删除目录下的所有文件
     *
     * @param dir 目录
     * @return {@code true}: 删除成功<br>{@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<File> getLogFileAcrossDay(String rootPath, int day) {
        List<File> 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<File> getLogFileAcrossDay(String rootPath, List<String> days) {
        List<File> 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<File> getLogFilesWithOutExist(String rootPath, List<String> days) {
        List<File> 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<File> findFileByStartEndTime(String dir, long startTime, long endTime) {
        File file = new File(dir);
        if (!file.exists()) {
            return null;
        }
        ArrayList<File> 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<String> findFilePathByStartEndTime(String dir, long startTime, long endTime) {
        File file = new File(dir);
        if (!file.exists()) {
            return null;
        }
        ArrayList<String> 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<File> getFilesByCreateTime(String filePath, int day) {
        List<File> 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<String, BigInteger> getListBalanceOf(Web3j web3j, String... addresses) {
        Map<String, BigInteger> 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<String, BigInteger> getListBalanceOf(Web3j web3j, List<String> addresses) {
        Map<String, BigInteger> 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.
     * <p>
     *     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.
     * </p>
     * @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.*;

/**
 * <p>文件描述:时间转换工具<p>
 * <p>author:jambestwick<p>
 * <p>创建时间:2019/11/29<p>
 * <p>更新时间:2019/11/29<p>
 * <p>邮箱:jambestwick@126.com<p>
 */
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<Date> getBetweenDates(Date start, Date end) {
        List<Date> 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<? super Log> 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.<TypeReference<?>>asList(
                        new TypeReference<Address>(true) {
                        },
                        new TypeReference<Address>(true) {
                        },

                        new TypeReference<Uint256>(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<Type>() {
                }));

        String data = FunctionEncoder.encode(function);
        Transaction transaction = Transaction.createEthCallTransaction(fromAddr, contractAddress, data);

        EthCall ethCall;
        try {
            ethCall = web3j.ethCall(transaction, DefaultBlockParameterName.LATEST).sendAsync().get();
            //List<Type> 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<Type>() {
                }));

        String data = FunctionEncoder.encode(function);
        Transaction transaction = Transaction.createEthCallTransaction(fromAddr, contractAddress, data);

        EthCall ethCall;
        try {
            ethCall = web3j.ethCall(transaction, DefaultBlockParameterName.LATEST).sendAsync().get();
            //List<Type> 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
 * <p>
 * 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<Type> inputParameters = new ArrayList<>();
        List<TypeReference<?>> outputParameters = new ArrayList<>();

        TypeReference<Uint256> typeReference = new TypeReference<Uint256>() {
        };
        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<Type> 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<Type> inputParameters = new ArrayList<>();
        Address userAddress = new Address(address);
        inputParameters.add(userAddress);

        List<TypeReference<?>> outputParameters = new ArrayList<>();
        TypeReference<Uint256> typeReference = new TypeReference<Uint256>() {
        };
        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<Type> 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<Type>() {
                }));


        //获取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<Type> inputParameters = new ArrayList<>();
        Address userAddress = new Address(owner);
        inputParameters.add(userAddress);
        Address spenderAddress = new Address(spender);
        inputParameters.add(spenderAddress);

        List<TypeReference<?>> outputParameters = new ArrayList<>();
        TypeReference<Uint256> typeReference = new TypeReference<Uint256>() {
        };
        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<Type> 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<Type>() {
                    }));

            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<Type>() {
                }));

        String data = FunctionEncoder.encode(function);
        Transaction transaction = Transaction.createEthCallTransaction(fromAddr, contractAddress, data);

        EthCall ethCall;
        try {
            ethCall = web3j.ethCall(transaction, DefaultBlockParameterName.LATEST).sendAsync().get();
            //List<Type> 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<? super EthBlock> 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<? super Transaction> 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<? super Transaction> 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<? super Log> 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.<TypeReference<?>>asList(
                        new TypeReference<Address>(true) {
                        },
                        new TypeReference<Address>(true) {
                        },

                        new TypeReference<Uint256>(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<? super Log> 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.<TypeReference<?>>asList(
                        new TypeReference<Address>(true) {//address indexed _owner
                        },
                        new TypeReference<Address>(true) {// address indexed _spender
                        },

                        new TypeReference<Uint256>(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<ReceiveAccount> 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<Type>() {
                }));

        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<ReceiveAccount> 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<String> 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<?, EthTransaction> 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<?, EthBlock> 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
Download .txt
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
Download .txt
SYMBOL INDEX (272 symbols across 40 files)

FILE: src/main/java/com/we3j/demo/Application.java
  class Application (line 19) | @SpringBootApplication
    method main (line 23) | public static void main(String[] args) {

FILE: src/main/java/com/we3j/demo/bean/Account.java
  class Account (line 11) | public class Account implements Serializable {
    method getAddress (line 17) | public String getAddress() {
    method setAddress (line 21) | public void setAddress(String address) {
    method getBalance (line 25) | public BigInteger getBalance() {
    method setBalance (line 29) | public void setBalance(BigInteger balance) {
    method getPrivateKey (line 33) | public String getPrivateKey() {
    method setPrivateKey (line 37) | public void setPrivateKey(String privateKey) {
    method getPublicKey (line 41) | public String getPublicKey() {
    method setPublicKey (line 45) | public void setPublicKey(String publicKey) {
    method toString (line 49) | @Override

FILE: src/main/java/com/we3j/demo/bean/bo/ReceiveAccount.java
  class ReceiveAccount (line 13) | public class ReceiveAccount extends Account implements Serializable {
    method getSendAmount (line 16) | public BigDecimal getSendAmount() {
    method setSendAmount (line 20) | public void setSendAmount(BigDecimal sendAmount) {

FILE: src/main/java/com/we3j/demo/controller/TestController.java
  class TestController (line 20) | @RestController
    method batchUpdateLabelGPS (line 31) | @RequestMapping(value = "/account", method = RequestMethod.POST)

FILE: src/main/java/com/we3j/demo/service/etherscan_api/Endpoint.java
  class Endpoint (line 8) | public class Endpoint {

FILE: src/main/java/com/we3j/demo/service/etherscan_api/key/ApiKey.java
  class ApiKey (line 9) | public class ApiKey {

FILE: src/main/java/com/we3j/demo/service/etherscan_api/params/Sort.java
  type Sort (line 8) | public enum Sort {
    method Sort (line 13) | Sort(String sort) {

FILE: src/main/java/com/we3j/demo/service/etherscan_api/params/accounts/AccountAPI.java
  type AccountAPI (line 15) | @RetrofitClient(baseUrl = "${base.url}")
    method getSingleAddressBalance (line 26) | @GET("api")
    method getMultipleAddressBalance (line 29) | @GET("api")
    method getListNormalTransactionByAddress (line 36) | @GET("api")
    method getListInternalTransactionByAddress (line 42) | @GET("api")
    method getListInternalTransactionByHash (line 45) | @GET("api")
    method getListInternalTransactionByBlockRange (line 48) | @GET("api")
    method getContractTransactionByAddress (line 51) | @GET("api")
    method getNFTTransactionByAddress (line 54) | @GET("api")
    method getListMinedByAddress (line 57) | @GET("api")
    method getHistoricalBalanceByBlockNoAddress (line 60) | @GET("api")

FILE: src/main/java/com/we3j/demo/service/etherscan_api/params/blocks/BlockOrder.java
  type BlockOrder (line 8) | public enum BlockOrder {
    method BlockOrder (line 13) | BlockOrder(String key) {

FILE: src/main/java/com/we3j/demo/service/etherscan_api/params/blocks/BlocksAPI.java
  type BlocksAPI (line 14) | @RetrofitClient(baseUrl = "${base.url}")
    method getBlockAndUncleRewardsByBlockNo (line 16) | @GET("api")
    method getEstimatedBlockCountdownTimeByBlockNo (line 19) | @GET("api")
    method getBlockNumberByTimestamp (line 25) | @GET("api")
    method getDailyAverageBlockSize (line 32) | @GET("api")
    method getDailyBlockCountAndRewards (line 39) | @GET("api")
    method getDailyBlockRewards (line 46) | @GET("api")
    method getDailyAverageBlockTime (line 53) | @GET("api")
    method getDailyUncleBlockCountAndRewards (line 60) | @GET("api")

FILE: src/main/java/com/we3j/demo/service/etherscan_api/params/contracts/ContractAPI.java
  type ContractAPI (line 13) | @RetrofitClient(baseUrl = "${base.url}")
    method getContractABI (line 15) | @GET("api")
    method getContractSourceCode (line 18) | @GET("api")

FILE: src/main/java/com/we3j/demo/service/etherscan_api/params/gas_tracker/GasTackerAPI.java
  type GasTackerAPI (line 14) | @RetrofitClient(baseUrl = "${base.url}")
    method getEstimationConfirmationTime (line 16) | @GET("api")
    method getGasOracle (line 19) | @GET("api")
    method getDailyAverageGasLimit (line 22) | @GET("api")
    method getDailyTotalGasUsed (line 25) | @GET("api")
    method getDailyAverageGasPrice (line 28) | @GET("api")

FILE: src/main/java/com/we3j/demo/service/etherscan_api/params/logs/logAPI.java
  type logAPI (line 13) | @RetrofitClient(baseUrl = "${base.url}")
    method getSampleLog (line 17) | @GET("api")

FILE: src/main/java/com/we3j/demo/service/etherscan_api/params/stats/StatsAPI.java
  type StatsAPI (line 14) | @RetrofitClient(baseUrl = "${base.url}")
    method getTotalSupplyEther (line 17) | @GET("api")
    method getTotalSupplyEther2 (line 20) | @GET("api")
    method getEtherLastPrice (line 23) | @GET("api")
    method getEtherNodesSize (line 26) | @GET("api")
    method getTotalNodesCount (line 29) | @GET("api")
    method getDailyTxnFee (line 32) | @GET("api")
    method getDailyNewAddressCount (line 35) | @GET("api")
    method getDailyNetUtilization (line 38) | @GET("api")
    method getDailyAverageHashRate (line 41) | @GET("api")
    method getDailyTxCount (line 44) | @GET("api")
    method getDailyAverageNetDifficulty (line 47) | @GET("api")
    method getEtherDailyPrice (line 50) | @GET("api")

FILE: src/main/java/com/we3j/demo/service/etherscan_api/params/tokens/TokensAPI.java
  type TokensAPI (line 13) | @RetrofitClient(baseUrl = "${base.url}")
    method getTokenTotalSupplyByContractAddress (line 16) | @GET("api")
    method getTokenAccountBalanceForTokenContractAddress (line 19) | @GET("api")
    method getHistoricalTokenTotalSupplyByContractAddressAndBlockNo (line 22) | @GET("api")
    method getHistoricalTokenAccountBalanceByContractAddressAndBlockNo (line 25) | @GET("api")
    method getTokenInfoByContractAddress (line 28) | @GET("api")

FILE: src/main/java/com/we3j/demo/service/etherscan_api/params/transactions/TransactionsAPI.java
  type TransactionsAPI (line 13) | @RetrofitClient(baseUrl = "${base.url}")
    method checkContractExecutionStatus (line 16) | @GET("api")
    method checkTransactionReceiptStatus (line 19) | @GET("api")

FILE: src/main/java/com/we3j/demo/service/etherscan_api/request/Method.java
  type Method (line 8) | public enum Method {

FILE: src/main/java/com/we3j/demo/service/etherscan_api/response/ApiResponse.java
  class ApiResponse (line 10) | public class ApiResponse<T> implements Serializable {
    method getStatus (line 15) | public String getStatus() {
    method setStatus (line 19) | public void setStatus(String status) {
    method getMessage (line 23) | public String getMessage() {
    method setMessage (line 27) | public void setMessage(String message) {
    method getResult (line 31) | public T getResult() {
    method setResult (line 35) | public void setResult(T result) {
    method toString (line 39) | @Override

FILE: src/main/java/com/we3j/demo/sol/TokenERC20.java
  class TokenERC20 (line 39) | public class TokenERC20 extends Contract {
    method TokenERC20 (line 81) | protected TokenERC20(String contractAddress, Web3j web3j, Credentials ...
    method TokenERC20 (line 85) | protected TokenERC20(String contractAddress, Web3j web3j, TransactionM...
    method name (line 89) | public RemoteCall<String> name() {
    method approve (line 97) | public RemoteCall<TransactionReceipt> approve(String _spender, BigInte...
    method totalSupply (line 106) | public RemoteCall<BigInteger> totalSupply() {
    method transferFrom (line 114) | public RemoteCall<TransactionReceipt> transferFrom(String _from, Strin...
    method decimals (line 124) | public RemoteCall<BigInteger> decimals() {
    method burn (line 132) | public RemoteCall<TransactionReceipt> burn(BigInteger _value) {
    method balanceOf (line 140) | public RemoteCall<BigInteger> balanceOf(String param0) {
    method burnFrom (line 148) | public RemoteCall<TransactionReceipt> burnFrom(String _from, BigIntege...
    method symbol (line 157) | public RemoteCall<String> symbol() {
    method transfer (line 165) | public RemoteCall<TransactionReceipt> transfer(String _to, BigInteger ...
    method approveAndCall (line 174) | public RemoteCall<TransactionReceipt> approveAndCall(String _spender, ...
    method allowance (line 184) | public RemoteCall<BigInteger> allowance(String param0, String param1) {
    method deploy (line 193) | public static RemoteCall<TokenERC20> deploy(Web3j web3j, Credentials c...
    method deploy (line 200) | public static RemoteCall<TokenERC20> deploy(Web3j web3j, TransactionMa...
    method getTransferEvents (line 207) | public List<TransferEventResponse> getTransferEvents(TransactionReceip...
    method transferEventObservable (line 221) | public Observable<TransferEventResponse> transferEventObservable(EthFi...
    method transferEventObservable (line 236) | public Observable<TransferEventResponse> transferEventObservable(Defau...
    method getBurnEvents (line 242) | public List<BurnEventResponse> getBurnEvents(TransactionReceipt transa...
    method burnEventObservable (line 255) | public Observable<BurnEventResponse> burnEventObservable(EthFilter fil...
    method burnEventObservable (line 269) | public Observable<BurnEventResponse> burnEventObservable(DefaultBlockP...
    method load (line 275) | public static TokenERC20 load(String contractAddress, Web3j web3j, Cre...
    method load (line 279) | public static TokenERC20 load(String contractAddress, Web3j web3j, Tra...
    class TransferEventResponse (line 283) | public static class TransferEventResponse {
    class BurnEventResponse (line 293) | public static class BurnEventResponse {

FILE: src/main/java/com/we3j/demo/sol/TokenERC71.java
  class TokenERC71 (line 8) | public class TokenERC71  {

FILE: src/main/java/com/we3j/demo/test/ContractDemo.java
  class ContractDemo (line 37) | public class ContractDemo {
    method main (line 43) | public static void main(String[] args) {
    method run (line 47) | private void run() {
    method connectETHClient (line 61) | private void connectETHClient() throws IOException {
    method loadWalletByPrivateKey (line 73) | private void loadWalletByPrivateKey(String inputPrivateKey) {
    method createContract (line 96) | public void createContract(String from) throws InterruptedException, E...
    method createContract (line 113) | public void createContract(String from, BigInteger ethAmount) throws I...
    method getTransactionGasLimit (line 128) | public static BigInteger getTransactionGasLimit(Web3j web3j, org.web3j...
    method getBalance (line 141) | public static BigDecimal getBalance(Web3j web3j, String address) {
    method getContractAddress (line 152) | private String getContractAddress(String transactionHash) throws IOExc...
    method listenContract (line 182) | private void listenContract(String contractAddress) {

FILE: src/main/java/com/we3j/demo/test/WalletDemo.java
  class WalletDemo (line 40) | @Service
    method main (line 50) | public static void main(String[] args) throws Exception {
    method run1 (line 55) | private void run1() throws Exception {
    method connectETHClient (line 163) | private void connectETHClient() throws IOException {
    method creatAccount (line 176) | private void creatAccount() throws NoSuchAlgorithmException, NoSuchPro...
    method loadWallet (line 208) | private void loadWallet(String password, String walletFilePath) throws...
    method loadWalletByPrimaryKeyPassword (line 224) | private void loadWalletByPrimaryKeyPassword(String password, String mn...
    method loadWalletByPrivateKey (line 240) | private void loadWalletByPrivateKey(String inputPrivateKey) {
    method transto (line 255) | private void transto() throws Exception {
    method sign (line 275) | private String sign(String message) throws Exception {
    method getBlanceOf (line 290) | private void getBlanceOf() throws IOException {
    method initAdmin (line 310) | private Admin initAdmin() {
    method getService (line 315) | private HttpService getService() {

FILE: src/main/java/com/we3j/demo/test/mona/BuildInviteCodeRequest.java
  class BuildInviteCodeRequest (line 11) | public class BuildInviteCodeRequest {
    method buildInviteParam (line 13) | public static Map<String, String> buildInviteParam(String address, Str...
    method buildHead (line 24) | public static Map<String, String> buildHead(String accept

FILE: src/main/java/com/we3j/demo/test/mona/Constants.java
  class Constants (line 6) | public class Constants{

FILE: src/main/java/com/we3j/demo/test/mona/RandomUtil.java
  class RandomUtil (line 8) | public class RandomUtil {
    method randomNumDigest (line 11) | public static String randomNumDigest() {

FILE: src/main/java/com/we3j/demo/test/mona/RequestUtil.java
  class RequestUtil (line 16) | public class RequestUtil {
    method requestGet (line 20) | public static String requestGet(String url) {
    method requestPost (line 37) | public static String requestPost(String url, Map<String, String> reque...

FILE: src/main/java/com/we3j/demo/utils/AccountUtil.java
  class AccountUtil (line 20) | public class AccountUtil {
    method unlockAccount (line 23) | public static boolean unlockAccount(String address, String passphrase)...
    method lockAccount (line 30) | public static boolean lockAccount(String address) throws IOException {

FILE: src/main/java/com/we3j/demo/utils/CloseUtils.java
  class CloseUtils (line 14) | public class CloseUtils {
    method CloseUtils (line 16) | private CloseUtils() {
    method closeIO (line 25) | public static void closeIO(Closeable... closeables) {
    method closeIOQuietly (line 43) | public static void closeIOQuietly(Closeable... closeables) {

FILE: src/main/java/com/we3j/demo/utils/Environment.java
  class Environment (line 11) | public class Environment {

FILE: src/main/java/com/we3j/demo/utils/FileUtil.java
  class FileUtil (line 39) | public class FileUtil {
    method deleteFolderFile (line 49) | public static void deleteFolderFile(String filePath, boolean deleteThi...
    method writeFileFromString (line 82) | public static boolean writeFileFromString(File file, String content, b...
    method writeFileFromLineString (line 98) | public static boolean writeFileFromLineString(File file, String conten...
    method writeFileFromIS (line 124) | public static boolean writeFileFromIS(File file, InputStream is, boole...
    method writeFileFromByte (line 153) | public static boolean writeFileFromByte(File file, byte[] data, boolea...
    method createOrExistsFile (line 175) | public static boolean createOrExistsFile(String filePath) {
    method createOrExistsFile (line 185) | public static boolean createOrExistsFile(File file) {
    method getFileByPath (line 204) | public static File getFileByPath(String filePath) {
    method createOrExistsDir (line 214) | public static boolean createOrExistsDir(File file) {
    method readFile2String (line 226) | public static String readFile2String(File file, String charsetName) {
    method readFileNull2String (line 257) | public static String readFileNull2String(File file, String charsetName) {
    method deleteDir (line 287) | public static boolean deleteDir(String dirPath) {
    method deleteDirBeforeDays (line 298) | public static boolean deleteDirBeforeDays(String dirPath, long days) {
    method deleteDir (line 302) | private static boolean deleteDir(File dir, long days) {
    method deleteDir (line 327) | public static boolean deleteDir(File dir) {
    method deleteFile (line 353) | public static boolean deleteFile(String srcFilePath) {
    method deleteFile (line 363) | public static boolean deleteFile(File file) {
    method deleteFilesInDir (line 373) | public static boolean deleteFilesInDir(String dirPath) {
    method deleteFilesInDir (line 383) | public static boolean deleteFilesInDir(File dir) {
    method deleteLogFileMyself (line 410) | public static void deleteLogFileMyself(String path, int day, String pd...
    method getLogFileAcrossDay (line 453) | public static List<File> getLogFileAcrossDay(String rootPath, int day) {
    method getLogFileAcrossDay (line 488) | public static List<File> getLogFileAcrossDay(String rootPath, List<Str...
    method getLogFilesWithOutExist (line 511) | public static List<File> getLogFilesWithOutExist(String rootPath, List...
    method getFileCreateTime (line 545) | public static Long getFileCreateTime(String filePath) {
    method findFileByStartEndTime (line 558) | public static ArrayList<File> findFileByStartEndTime(String dir, long ...
    method findFilePathByStartEndTime (line 574) | public static ArrayList<String> findFilePathByStartEndTime(String dir,...
    method getFilesByCreateTime (line 593) | public static List<File> getFilesByCreateTime(String filePath, int day) {

FILE: src/main/java/com/we3j/demo/utils/NormalUtil.java
  class NormalUtil (line 23) | public class NormalUtil {
    method getBalanceOfString (line 26) | public static String getBalanceOfString(Web3j web3j, String address) t...
    method getBalanceOf (line 35) | public static BigInteger getBalanceOf(Web3j web3j, String address) thr...
    method getListBalanceOf (line 44) | public static Map<String, BigInteger> getListBalanceOf(Web3j web3j, St...
    method getListBalanceOf (line 59) | public static Map<String, BigInteger> getListBalanceOf(Web3j web3j, Li...
    method getNonce (line 81) | public static BigInteger getNonce(Web3j web3j, String from) throws Exe...
    method requestCurrentGasPrice (line 99) | public static BigInteger requestCurrentGasPrice(Web3j web3j) throws IO...

FILE: src/main/java/com/we3j/demo/utils/RSAEncrypt.java
  class RSAEncrypt (line 13) | public class RSAEncrypt {
    method main (line 15) | public static void main(String[] args) {
    method bytesToString (line 42) | protected String bytesToString(byte[] bytes) {
    method encrypt (line 55) | protected byte[] encrypt(RSAPublicKey publicKey, byte[] obj) {
    method decrypt (line 75) | protected byte[] decrypt(RSAPrivateKey privateKey, byte[] obj) {

FILE: src/main/java/com/we3j/demo/utils/ScheduleTask.java
  class ScheduleTask (line 16) | public class ScheduleTask {
    method timer (line 26) | @Scheduled(cron = "0/2 * * * * *")
    method testTasks (line 34) | @Scheduled(cron = "0 05 03 ? * *")

FILE: src/main/java/com/we3j/demo/utils/TimeUtil.java
  class TimeUtil (line 13) | public class TimeUtil {
    method str2Date (line 42) | public static Date str2Date(String str, String format) {
    method str2Long (line 61) | public static long str2Long(String str, String format) {
    method date2Str (line 65) | public static String date2Str(Date date, String formart) {
    method long2Str (line 70) | public static String long2Str(long millTime, String formart) {
    method now_mill (line 74) | public static String now_mill() {
    method now_day (line 78) | public static String now_day() {
    method now_minute (line 81) | public static String now_minute(){
    method now_second (line 85) | public static String now_second() {
    method monthDay (line 89) | public static String monthDay(Date date) {
    method passParamsMillTime (line 94) | public static boolean passParamsMillTime(long lastMillTime, long param...
    method getNextDate (line 98) | public static Date getNextDate(Date date) {
    method getPreDate (line 106) | public static Date getPreDate(Date date) {
    method getStartTime (line 114) | public static Date getStartTime(Date date) {
    method hour12to24 (line 124) | public static String hour12to24(String hh_mm_ss) {
    method getBetweenDates (line 145) | public static List<Date> getBetweenDates(Date start, Date end) {
    method getBeforeDay (line 160) | public static Date getBeforeDay(Date plusDate, Long cycleDate) {
    method getDay (line 169) | public static String getDay() {
    method getDate (line 176) | public static String getDate() {
    method getDateString (line 183) | public static String getDateString() {
    method getDateStr (line 189) | public static String getDateStr() {
    method getDateString (line 196) | public static String getDateString(Date date) {
    method getDateString (line 202) | public static String getDateString(long time) {
    method utc2Time (line 211) | public static Date utc2Time(String utcTime) {

FILE: src/main/java/com/we3j/demo/wallet/NFTMonitor.java
  class NFTMonitor (line 31) | public class NFTMonitor {
    method getInstance (line 36) | public static NFTMonitor getInstance() {
    method getWeb3j (line 47) | public Web3j getWeb3j() {
    method setWeb3j (line 51) | public void setWeb3j(Web3j web3j) {
    method setCredentials (line 55) | public void setCredentials(Credentials credentials) {
    method subscribeClaim (line 62) | public Subscription subscribeClaim(String contractAddress, final Actio...
    method unsubscribeClaim (line 83) | public void unsubscribeClaim(Subscription subscription) {
    method mintNFTByAmount (line 97) | public  boolean mintNFTByAmount(Web3j web3j, String contractAddress, i...
    method mintNFTByAmountAndAddress (line 125) | public  boolean mintNFTByAmountAndAddress(Web3j web3j, Credentials cre...

FILE: src/main/java/com/we3j/demo/wallet/TokenClient.java
  class TokenClient (line 34) | public class TokenClient {
    method getTokenTotalSupply (line 45) | public static BigInteger getTokenTotalSupply(Web3j web3j, String contr...
    method getAddressBalanceOf (line 77) | public static BigInteger getAddressBalanceOf(Web3j web3j, String contr...
    method approve (line 115) | public static boolean approve(Web3j web3j, Credentials credentials, St...
    method allowance (line 163) | public static BigInteger allowance(Web3j web3j, String contractAddress...
    method transferFrom (line 202) | public static boolean transferFrom(Web3j web3j,
    method claimNFT (line 248) | public static boolean claimNFT(Web3j web3j, String contractAddress, In...

FILE: src/main/java/com/we3j/demo/wallet/TransMonitor.java
  class TransMonitor (line 31) | public class TransMonitor {
    method getInstance (line 35) | public static TransMonitor getInstance() {
    method getWeb3j (line 46) | public Web3j getWeb3j() {
    method setWeb3j (line 50) | public void setWeb3j(Web3j web3j) {
    method subscribeBlock (line 54) | public Subscription subscribeBlock(final Action1<? super EthBlock> onN...
    method unsubscribeBlock (line 59) | public void unsubscribeBlock(Subscription subscription) {
    method subscribeHasTrans (line 69) | public Subscription subscribeHasTrans(final Action1<? super Transactio...
    method unsubscribeHasTrans (line 77) | public void unsubscribeHasTrans(Subscription subscription) {
    method subscribePendingTrans (line 85) | public Subscription subscribePendingTrans(final Action1<? super Transa...
    method unsubscribePendingTrans (line 93) | public void unsubscribePendingTrans(Subscription subscription) {
    method subscribeContract (line 102) | public Subscription subscribeContract(String contractAddress, final Ac...
    method unsubscribeContract (line 124) | public void unsubscribeContract(Subscription subscription) {
    method subscribeApproval (line 133) | public Subscription subscribeApproval(String contractAddress, final Ac...
    method unsubscribeApproval (line 158) | public void unsubscribeApproval(Subscription subscription) {

FILE: src/main/java/com/we3j/demo/wallet/TransferToken.java
  class TransferToken (line 43) | public class TransferToken {
    method transfer (line 48) | public static boolean transfer(Web3j web3j, Credentials credentials, S...
    method transferAsync (line 76) | public static void transferAsync(Web3j web3j, Credentials credentials,...
    method transferBatch (line 103) | public static void transferBatch(Web3j web3j, Credentials credentials,...
    method transferERC20 (line 111) | public static EthSendTransaction transferERC20(Web3j web3j,
    method transferERC20Batch (line 152) | public static void transferERC20Batch(Web3j web3j,
    method transferERC20Batch (line 169) | public static void transferERC20Batch(Web3j web3j,
    method getTransactionByHash (line 188) | public static EthTransaction getTransactionByHash(Web3j web3j, String ...
    method getBlockEthBlock (line 200) | public static EthBlock getBlockEthBlock(Web3j web3j, Integer blockNumb...

FILE: src/main/java/com/we3j/demo/wallet/WalletTools.java
  class WalletTools (line 20) | public class WalletTools {
    method createWallet (line 22) | public static boolean createWallet(String filePath, String destFile) t...
    method createWalletBatch (line 36) | public static void createWalletBatch(int count, String filePath, Strin...
    method createWalletFull (line 47) | public static String createWalletFull(String password, String destFile...
    method createWalletLight (line 55) | public static String createWalletLight(String password, String destFil...
    method loadWallet (line 64) | public static Credentials loadWallet(String password, String walletFil...
    method loadWalletByMnemonic (line 80) | public static Credentials loadWalletByMnemonic(String password, String...
    method loadWalletByPrivateKey (line 98) | public static Credentials loadWalletByPrivateKey(String inputPrivateKe...
    method decryptWallet (line 116) | public static String decryptWallet(String keystore, String password) {

FILE: src/main/java/com/we3j/demo/wallet/Web3jInfo.java
  class Web3jInfo (line 12) | public class Web3jInfo {
    method connect (line 18) | public static Web3j connect(){
    method connect (line 25) | public static Web3j connect(String localPointUrl){
Condensed preview — 52 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (166K chars).
[
  {
    "path": ".github/FUNDING.yml",
    "chars": 251,
    "preview": "github: [NateRiver, jambestwick]\ncustom: [\"https://github.com/jambestwick/jambestwick/blob/master/src/images/1f7d1b1642b"
  },
  {
    "path": ".gitignore",
    "chars": 694,
    "preview": "# Created by .ignore support plugin (hsz.mobi)\n### Java template\n*.class\n\n# Mobile Tools for Java (J2ME)\n.mtj.tmp/\n\n# Pa"
  },
  {
    "path": "README.EN.MD",
    "chars": 1210,
    "preview": "## Introduction  \n### **[chinese doc](https://github.com/jambestwick/we3jdemo/blob/master/README.md)**\n# simple web3j De"
  },
  {
    "path": "README.md",
    "chars": 852,
    "preview": "## 简介\n[![](https://jitpack.io/v/jambestwick/web3jdemo.svg)](https://jitpack.io/#jambestwick/web3jdemo)\n### **[english do"
  },
  {
    "path": "build.gradle",
    "chars": 1594,
    "preview": "buildscript {\n    ext {\n        springBootVersion = '1.5.7.RELEASE'\n    }\n    repositories {\n        maven { url 'http:/"
  },
  {
    "path": "gradle/wrapper/gradle-wrapper.properties",
    "chars": 231,
    "preview": "#Mon Apr 09 11:54:45 CST 2018\ndistributionBase=GRADLE_USER_HOME\ndistributionPath=wrapper/dists\nzipStoreBase=GRADLE_USER_"
  },
  {
    "path": "gradlew",
    "chars": 5296,
    "preview": "#!/usr/bin/env sh\n\n##############################################################################\n##\n##  Gradle start up"
  },
  {
    "path": "gradlew.bat",
    "chars": 2260,
    "preview": "@if \"%DEBUG%\" == \"\" @echo off\r\n@rem ##########################################################################\r\n@rem\r\n@r"
  },
  {
    "path": "settings.gradle",
    "chars": 31,
    "preview": "rootProject.name = 'we3jdemo'\n\n"
  },
  {
    "path": "src/main/java/com/we3j/demo/Application.java",
    "chars": 666,
    "preview": "package com.we3j.demo;\n\nimport com.github.lianjiatech.retrofit.spring.boot.annotation.RetrofitScan;\nimport com.we3j.demo"
  },
  {
    "path": "src/main/java/com/we3j/demo/bean/Account.java",
    "chars": 1257,
    "preview": "package com.we3j.demo.bean;\n\nimport java.io.Serializable;\nimport java.math.BigInteger;\n\n/**\n * * Created by jambestwick@"
  },
  {
    "path": "src/main/java/com/we3j/demo/bean/bo/ReceiveAccount.java",
    "chars": 475,
    "preview": "package com.we3j.demo.bean.bo;\n\nimport com.we3j.demo.bean.Account;\n\nimport java.io.Serializable;\nimport java.math.BigDec"
  },
  {
    "path": "src/main/java/com/we3j/demo/controller/TestController.java",
    "chars": 1419,
    "preview": "package com.we3j.demo.controller;\n\nimport com.we3j.demo.service.etherscan_api.key.ApiKey;\nimport com.we3j.demo.service.e"
  },
  {
    "path": "src/main/java/com/we3j/demo/service/etherscan_api/Endpoint.java",
    "chars": 997,
    "preview": "package com.we3j.demo.service.etherscan_api;\n\n/**\n * * An API key generated on Etherscan ​ can be used across all mainne"
  },
  {
    "path": "src/main/java/com/we3j/demo/service/etherscan_api/key/ApiKey.java",
    "chars": 472,
    "preview": "package com.we3j.demo.service.etherscan_api.key;\n\n/**\n * *\n *\n * @see {etherenum -scan }https://docs.etherscan.io/\n * AP"
  },
  {
    "path": "src/main/java/com/we3j/demo/service/etherscan_api/params/Sort.java",
    "chars": 257,
    "preview": "package com.we3j.demo.service.etherscan_api.params;\n\n/**\n * * Created by jambestwick@126.com\n * * on 2021/12/7\n * *\n */\n"
  },
  {
    "path": "src/main/java/com/we3j/demo/service/etherscan_api/params/accounts/AccountAPI.java",
    "chars": 3541,
    "preview": "package com.we3j.demo.service.etherscan_api.params.accounts;\n\nimport com.github.lianjiatech.retrofit.spring.boot.annotat"
  },
  {
    "path": "src/main/java/com/we3j/demo/service/etherscan_api/params/blocks/BlockOrder.java",
    "chars": 280,
    "preview": "package com.we3j.demo.service.etherscan_api.params.blocks;\n\n/**\n * * Created by jambestwick@126.com\n * * on 2021/12/7\n *"
  },
  {
    "path": "src/main/java/com/we3j/demo/service/etherscan_api/params/blocks/BlocksAPI.java",
    "chars": 2977,
    "preview": "package com.we3j.demo.service.etherscan_api.params.blocks;\n\nimport com.github.lianjiatech.retrofit.spring.boot.annotatio"
  },
  {
    "path": "src/main/java/com/we3j/demo/service/etherscan_api/params/contracts/ContractAPI.java",
    "chars": 780,
    "preview": "package com.we3j.demo.service.etherscan_api.params.contracts;\n\nimport com.github.lianjiatech.retrofit.spring.boot.annota"
  },
  {
    "path": "src/main/java/com/we3j/demo/service/etherscan_api/params/gas_tracker/GasTackerAPI.java",
    "chars": 1587,
    "preview": "package com.we3j.demo.service.etherscan_api.params.gas_tracker;\n\nimport com.github.lianjiatech.retrofit.spring.boot.anno"
  },
  {
    "path": "src/main/java/com/we3j/demo/service/etherscan_api/params/logs/logAPI.java",
    "chars": 674,
    "preview": "package com.we3j.demo.service.etherscan_api.params.logs;\n\nimport com.github.lianjiatech.retrofit.spring.boot.annotation."
  },
  {
    "path": "src/main/java/com/we3j/demo/service/etherscan_api/params/stats/StatsAPI.java",
    "chars": 3060,
    "preview": "package com.we3j.demo.service.etherscan_api.params.stats;\n\nimport com.github.lianjiatech.retrofit.spring.boot.annotation"
  },
  {
    "path": "src/main/java/com/we3j/demo/service/etherscan_api/params/tokens/TokensAPI.java",
    "chars": 1628,
    "preview": "package com.we3j.demo.service.etherscan_api.params.tokens;\n\nimport com.github.lianjiatech.retrofit.spring.boot.annotatio"
  },
  {
    "path": "src/main/java/com/we3j/demo/service/etherscan_api/params/transactions/TransactionsAPI.java",
    "chars": 791,
    "preview": "package com.we3j.demo.service.etherscan_api.params.transactions;\n\nimport com.github.lianjiatech.retrofit.spring.boot.ann"
  },
  {
    "path": "src/main/java/com/we3j/demo/service/etherscan_api/request/Method.java",
    "chars": 144,
    "preview": "package com.we3j.demo.service.etherscan_api.request;\n\n/**\n * *\n * Request for API\n * *\n */\npublic enum Method {\n    GET,"
  },
  {
    "path": "src/main/java/com/we3j/demo/service/etherscan_api/response/ApiResponse.java",
    "chars": 945,
    "preview": "package com.we3j.demo.service.etherscan_api.response;\n\nimport java.io.Serializable;\n\n/**\n * * Created by jambestwick@126"
  },
  {
    "path": "src/main/java/com/we3j/demo/sol/TokenERC20.java",
    "chars": 18366,
    "preview": "package com.we3j.demo.sol;\n\nimport java.math.BigInteger;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport jav"
  },
  {
    "path": "src/main/java/com/we3j/demo/sol/TokenERC71.java",
    "chars": 124,
    "preview": "package com.we3j.demo.sol;\n\n/**\n * * Created by jambestwick@126.com\n * * on 2021/12/2\n * *\n */\npublic class TokenERC71  "
  },
  {
    "path": "src/main/java/com/we3j/demo/test/ContractDemo.java",
    "chars": 7842,
    "preview": "package com.we3j.demo.test;\n\nimport com.we3j.demo.utils.Environment;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFac"
  },
  {
    "path": "src/main/java/com/we3j/demo/test/WalletDemo.java",
    "chars": 12807,
    "preview": "package com.we3j.demo.test;\n\nimport com.we3j.demo.utils.Environment;\nimport com.we3j.demo.wallet.NFTMonitor;\nimport com."
  },
  {
    "path": "src/main/java/com/we3j/demo/test/mona/BuildInviteCodeRequest.java",
    "chars": 1731,
    "preview": "package com.we3j.demo.test.mona;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\n/**\n * @Author jambestwick\n * @create"
  },
  {
    "path": "src/main/java/com/we3j/demo/test/mona/Constants.java",
    "chars": 303,
    "preview": "\npackage com.we3j.demo.test.mona;\n\n\n\npublic class Constants{\n\n    //request Get\n    public static final String GET_MESSA"
  },
  {
    "path": "src/main/java/com/we3j/demo/test/mona/RandomUtil.java",
    "chars": 1144,
    "preview": "package com.we3j.demo.test.mona;\n\n/**\n * @Author jambestwick\n * @create 2021/11/30 0030  0:38\n * @email jambestwick@126."
  },
  {
    "path": "src/main/java/com/we3j/demo/test/mona/RequestUtil.java",
    "chars": 2109,
    "preview": "package com.we3j.demo.test.mona;\n\nimport okhttp3.*;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport jav"
  },
  {
    "path": "src/main/java/com/we3j/demo/utils/AccountUtil.java",
    "chars": 1278,
    "preview": "package com.we3j.demo.utils;\n\nimport org.web3j.protocol.admin.Admin;\nimport org.web3j.protocol.admin.methods.response.Bo"
  },
  {
    "path": "src/main/java/com/we3j/demo/utils/CloseUtils.java",
    "chars": 1225,
    "preview": "package com.we3j.demo.utils;\n\nimport java.io.Closeable;\nimport java.io.IOException;\n\n/**\n * <pre>\n *     author: Blankj\n"
  },
  {
    "path": "src/main/java/com/we3j/demo/utils/Environment.java",
    "chars": 335,
    "preview": "package com.we3j.demo.utils;\n\n/**\n * * Created by jambestwick@126.com\n * * on 2021/12/2\n *\n * personal RPC\n * register o"
  },
  {
    "path": "src/main/java/com/we3j/demo/utils/FileUtil.java",
    "chars": 19136,
    "preview": "package com.we3j.demo.utils;\n\nimport org.springframework.util.StringUtils;\n\nimport java.io.BufferedOutputStream;\nimport "
  },
  {
    "path": "src/main/java/com/we3j/demo/utils/NormalUtil.java",
    "chars": 4045,
    "preview": "package com.we3j.demo.utils;\n\nimport org.web3j.protocol.Web3j;\nimport org.web3j.protocol.core.DefaultBlockParameter;\nimp"
  },
  {
    "path": "src/main/java/com/we3j/demo/utils/RSAEncrypt.java",
    "chars": 2494,
    "preview": "package com.we3j.demo.utils;\n\nimport java.security.KeyPair;\nimport java.security.KeyPairGenerator;\nimport java.security."
  },
  {
    "path": "src/main/java/com/we3j/demo/utils/ScheduleTask.java",
    "chars": 966,
    "preview": "package com.we3j.demo.utils;\n\nimport org.springframework.scheduling.annotation.Scheduled;\n\nimport java.text.SimpleDateFo"
  },
  {
    "path": "src/main/java/com/we3j/demo/utils/TimeUtil.java",
    "chars": 7359,
    "preview": "package com.we3j.demo.utils;\n\nimport java.text.SimpleDateFormat;\nimport java.util.*;\n\n/**\n * <p>文件描述:时间转换工具<p>\n * <p>aut"
  },
  {
    "path": "src/main/java/com/we3j/demo/wallet/NFTMonitor.java",
    "chars": 5073,
    "preview": "package com.we3j.demo.wallet;\n\nimport org.web3j.abi.EventEncoder;\nimport org.web3j.abi.FunctionEncoder;\nimport org.web3j"
  },
  {
    "path": "src/main/java/com/we3j/demo/wallet/TokenClient.java",
    "chars": 10113,
    "preview": "package com.we3j.demo.wallet;\n\nimport com.we3j.demo.utils.NormalUtil;\nimport org.web3j.abi.FunctionEncoder;\nimport org.w"
  },
  {
    "path": "src/main/java/com/we3j/demo/wallet/TransMonitor.java",
    "chars": 4811,
    "preview": "package com.we3j.demo.wallet;\n\nimport org.web3j.abi.EventEncoder;\nimport org.web3j.abi.TypeReference;\nimport org.web3j.a"
  },
  {
    "path": "src/main/java/com/we3j/demo/wallet/TransferToken.java",
    "chars": 8445,
    "preview": "package com.we3j.demo.wallet;\n\nimport com.we3j.demo.bean.bo.ReceiveAccount;\nimport com.we3j.demo.test.WalletDemo;\nimport"
  },
  {
    "path": "src/main/java/com/we3j/demo/wallet/WalletTools.java",
    "chars": 5409,
    "preview": "package com.we3j.demo.wallet;\n\nimport com.fasterxml.jackson.databind.ObjectMapper;\nimport com.we3j.demo.utils.FileUtil;\n"
  },
  {
    "path": "src/main/java/com/we3j/demo/wallet/Web3jInfo.java",
    "chars": 596,
    "preview": "package com.we3j.demo.wallet;\n\nimport com.we3j.demo.utils.Environment;\nimport org.web3j.protocol.Web3j;\nimport org.web3j"
  },
  {
    "path": "src/main/resources/application-dev.properties",
    "chars": 167,
    "preview": "debug=true\nserver.port=8000\n#database\n#base.url = https://api.etherscan.io/\nbase.url = https://visitor-badge.laobi.icu/\n"
  },
  {
    "path": "src/main/resources/application.properties",
    "chars": 26,
    "preview": "spring.profiles.active=dev"
  }
]

// ... and 1 more files (download for full content)

About this extraction

This page contains the full source code of the jambestwick/web3jdemo GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 52 files (146.8 KB), approximately 38.7k tokens, and a symbol index with 272 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!