一.通过web3j 来查询
这里使用的是ropsten 测试网络
1.连接以太网网络
web3j 连接以太网的第一步是要有一个以太网客户端,(例如本地客户端,或云客户端),web3j推荐的使用infura 的云客户端
例如: Web3j web3j = Web3j.build(new HttpService("https://ropsten.infura.io/mew")); 这里token是mew,是MyEtherWallet 在infura 的token
我这里使用的是infura的云客户端,可以去infura 注册自己的token,然后就可以连上以太坊网络了
2.获得 ERC20 合约的java 实现版本,这里 web3j 是通过web3j 自带的命令行工具实现的(需要合约的二进制文件 和 abi 接口)
/*TODO通过编译器 获得 bin 有问题,验证的时候,无法验证通过
比如我在http://remix.ethereum.org 这个在线编译器上编写了一个合约(这个时候可以在remix 的右边compiler 工具框中选择 Details 可以查看合约的二进制代码和 abi 接口)*/
实际上发布了合约之后,应该在区块链浏览器(tetherscan.io)中,验证合约代码,验证通过后,会看到合约的创建的二进制代码,在abi 文件的下面,这里的二进制代码才是完整的,然后生成的合约对象,通过 合约对象.isValid(),返回true ,可以验证通过
在本地启动命令行工具,工具会一闪而过,web3j.bat 不是双击运行,进入文件位置,直接web3j.bat回车 ,出现web3j.io 图标说明成功,然后直接输入web3j 命令.
例如: 需要通过web3j 命令行工具生成 合约的java 对象
* 需要获得合约的二进制代码 保存: 名称.bin
* 需要获得合约的abi数据 保存为: 名称.abi
-o 是输出的文件夹名称
-p 后面是保存的包名
* 命令实例: web3j solidity generate TokenDemo.bin TokenDemo.abi -o /java -p com.your.organisation.name
3. 获得查询对象余额
package test;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.BigInteger;
import org.web3j.crypto.Credentials;
import org.web3j.protocol.Web3j;
import org.web3j.protocol.admin.Admin;
import org.web3j.protocol.core.DefaultBlockParameterName;
import org.web3j.protocol.core.RemoteCall;
import org.web3j.protocol.http.HttpService;
import org.web3j.tx.Contract;
import contract.MttContract;
/**
* 获取用户钱包地址 余额,包括 智能合约地址余额
*/
public class TestGetBalance {
/**
* 查询以太币
* @param args
* @throws Exception
*/
public static void main(String[] args) throws Exception {
Web3j web3j = getWeb3j(StaticValue.ropstenService);
getEthBanlance(web3j,StaticValue.account2);
//获取指定钱包的指定币种余额
Contract erc20Contract = getERC20Contract(web3j, StaticValue.MttContractAddress, StaticValue.account2Pri);
getERC20Balance(web3j,erc20Contract,StaticValue.account2,8);
close(web3j);
}
/**
* 连接网络
* @param netUrl
* @return
*/
public static Web3j getWeb3j(String netUrl){
Admin web3j = Admin.build(new HttpService(netUrl));
return web3j;
}
/**
* 关闭网络
* @param web3j
*/
public static void close(Web3j web3j){
web3j.shutdown();
}
/**
* 查询以太币账户余额
* @throws IOException
*/
public static String getEthBanlance(Web3j web3j,String userAddress) throws IOException {
//获取指定钱包的以太币余额
BigInteger integer=web3j.ethGetBalance(userAddress,DefaultBlockParameterName.LATEST).send().getBalance();
//eth默认会部18个0这里处理比较随意
String decimal = toDecimal(18,integer);
System.out.println(decimal);
//因为是按18位来算的,所有在倒数18位前面加 小数点
/*String str = integer.toString();
String decimal = toDecimal(18,str);
System.out.println(decimal);*/
return decimal;
}
/**
* 获得 erc20 合约 实例
* @return
*/
public static Contract getERC20Contract(Web3j web3j,String contractAddress,String userPri){
BigInteger GAS_PRICE = BigInteger.valueOf(22_000_000_000L);
BigInteger GAS_LIMIT = BigInteger.valueOf(4_300_000);
Credentials credentials = Credentials.create(userPri);//获得信任凭证
MttContract contract = MttContract.load(
contractAddress, web3j, credentials, GAS_PRICE, GAS_LIMIT);
return contract;
}
/**
* 查询erc 20 代币价格
* @throws Exception
*/
public static String getERC20Balance(Web3j web3j,Contract contract,String userAddress,int decimal) throws Exception{
// Web3ClientVersion web3ClientVersion = web3j.web3ClientVersion().send();//send 是同步请求
// Web3ClientVersion web3ClientVersion = web3.web3ClientVersion().sendAsync().get(); //sendAsync(), 使用CompletableFuture(Android上的Future)发送异步请求:
// String clientVersion = web3ClientVersion.getWeb3ClientVersion();
// System.out.println(clientVersion);//查看版本信息
//或者 RxJava Observable:
/*Web3j web3 = Web3j.build(new HttpService()); // defaults to http://localhost:8545/
web3.web3ClientVersion().observable().subscribe(x -> {
String clientVersion = x.getWeb3ClientVersion();
...
});*/
RemoteCall balanceOf = ((MttContract) contract).balanceOf(userAddress);
BigInteger send2 = balanceOf.send();
String result = toDecimal(8, send2);
System.out.println(result);
return result;
}
/**
* 转换成符合 decimal 的数值
* @param decimal
* @param str
* @return
*/
public static String toDecimal(int decimal,BigInteger integer){
// String substring = str.substring(str.length() - decimal);
StringBuffer sbf = new StringBuffer("1");
for (int i = 0; i < decimal; i++) {
sbf.append("0");
}
String balance = new BigDecimal(integer).divide(new BigDecimal(sbf.toString()), 18, BigDecimal.ROUND_DOWN).toPlainString();
return balance;
}
}
StaticValue.class
package test;
public class StaticValue {
public static final String ropstenService = "https://ropsten.infura.io/mew";//模仿 myEtherWallet 钱包请求 infura 网络
public static final String account1 = "我的测试钱包地址";
public static final String account2 = "我的测试钱包地址2";
public static final String account1Pri = "我的测试钱包地址1私钥";//私钥
public static final String account2Pri = "我的测试钱包地址2私钥";//私钥
public static final String MttContractAddress = "部署的erc20 的合约地址";
}
二.通过etherscan.io 的接口来查询ERC20 代币余额
decimal 是合约创建时指定的精度,这里url 是指etherscan连接的网络,例如ropsten测试网络 : http://api-ropsten.etherscan.io/api
apikey 是指在etherscan 获得token,contractAddress 是合约地址,address 账户地址,
这里请求使用的okhttp3,TestOKHttp 类是自己封装过,对结果的json 进行处理使用的是jackson 2.8.5
/**
* https://api.etherscan.io/api?module=account&action=tokenbalance&contractaddress=0x57d90b64a1a57749b0f932f1a3395792e12e7055&address=0xe04f27eb70e025b78871a2ad7eabe85e61212761&tag=latest&apikey=YourApiKeyToken
* 查询 账户 ERC20 代币余额
* @param url
* @param contractAddress
* @param address
* @param decimal
* @return
*/
public static String getERC20Balance(String url,String contractAddress,String address,int decimal){
TreeMap treeMap = new TreeMap<>();
treeMap.put("module", "account");
treeMap.put("action", "tokenbalance");
treeMap.put("contractaddress", contractAddress);
treeMap.put("address", address);
treeMap.put("tag", "latest");
treeMap.put("apikey", StaticValue.etherscanToken);
StringBuffer sbf = new StringBuffer();
for (String str : treeMap.keySet()) {
sbf.append(str).append("=").append(treeMap.get(str)).append("&");
}
url = url.concat("?").concat(sbf.substring(0, sbf.length() - 1));
Object send = send(url);
return TestUtil.toDecimal(decimal,new BigInteger(String.valueOf(send)));
}
/**
* 获得以太币价格
* @param url
* @return
*/
public static String getEthPrice(String url){
TreeMap treeMap = new TreeMap<>();
treeMap.put("module", "stats");
treeMap.put("action", "ethprice");
treeMap.put("apikey", StaticValue.etherscanToken);
StringBuffer sbf = new StringBuffer();
for (String str : treeMap.keySet()) {
sbf.append(str).append("=").append(treeMap.get(str)).append("&");
}
url = url.concat("?").concat(sbf.substring(0, sbf.length() - 1));
Object send = send(url);
return String.valueOf(send);
}
public static Object send(String url){
String responseMessageGet = TestOKHttp.getResponseMessageGet(url);
ObjectMapper mapper = new ObjectMapper();
Map reMap = null;
try {
reMap = mapper.readValue(responseMessageGet, new TypeReference
decimal 方法是转换精度的,以太坊默认是18,但其他代币就不一定,
/**
* 转换成符合 decimal 的数值
* @param decimal
* @param str
* @return
*/
public static String toDecimal(int decimal,BigInteger integer){
// String substring = str.substring(str.length() - decimal);
StringBuffer sbf = new StringBuffer("1");
for (int i = 0; i < decimal; i++) {
sbf.append("0");
}
String balance = new BigDecimal(integer).divide(new BigDecimal(sbf.toString()), 18, BigDecimal.ROUND_DOWN).toPlainString();
return balance;
}
TestOKHttp 类
/**
* okhttp get 请求
*/
public static ResponseBody testGetClient(String url){
OkHttpClient okClient = new OkHttpClient();
Request request = new Request.Builder()
.get().url(url).build();
ResponseBody resBody = null;
try {
Response response = okClient.newCall(request).execute();
resBody = response.body();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return resBody;
}
public static String getResponseMessageGet(String url) {
ResponseBody body = null;String string = null;
body = testGetClient(url);
if(checkEmpty(body)) return null;
try {
string = body.string();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return string;
}
public static boolean checkEmpty(Object obj){
if(null!=obj && !obj.toString().trim().equals("")){
return false;
}
return true;
}
转载请注明来处