一.通過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<BigInteger> 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<String,String> 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<String,String> 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<String,String> reMap = null;
try {
reMap = mapper.readValue(responseMessageGet, new TypeReference<Map<String,Object>>(){});
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return reMap.get("result");
}
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;
}
轉載請註明來處