web3j 查詢ERC20 代幣餘額

一.通過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;
		
	}

轉載請註明來處

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章