获取账户的Nonce
public static BigInteger getNonce(Web3j web3j, String addr) {
try {
EthGetTransactionCount getNonce = web3j.ethGetTransactionCount(addr,DefaultBlockParameterName.PENDING).send();
if (getNonce == null){
throw new RuntimeException("net error");
}
return getNonce.getTransactionCount();
} 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;
}
}
获取代币余额 方法一
public static BigInteger getTokenBalance(Web3j web3j, String fromAddress, String contractAddress) {
String methodName = "balanceOf";
List<Type> inputParameters = new ArrayList<>();
List<TypeReference<?>> outputParameters = new ArrayList<>();
Address address = new Address(fromAddress);
inputParameters.add(address);
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(fromAddress, contractAddress, data);
EthCall ethCall;
BigInteger balanceValue = BigInteger.ZERO;
try {
ethCall = web3j.ethCall(transaction, DefaultBlockParameterName.LATEST).send();
List<Type> results = FunctionReturnDecoder.decode(ethCall.getValue(), function.getOutputParameters());
balanceValue = (BigInteger) results.get(0).getValue();
} catch (IOException e) {
e.printStackTrace();
}
return balanceValue;
}
获取代币余额 方法二 (仅支持主链上的代币)
String tokenBanceUrl = "https://api.etherscan.io/api?module=account&action=tokenbalance"
+ "&contractaddress=0x5aA8D6dE8CBf23DAC734E6f904B93bD056B15b81"//Token合约地址
+ "&address=0xd4279e30e27f52ca60fac3cc9670c7b9b1eeefdc"//要查询额的账户余地址
+ "&tag=latest&apikey=YourApiKeyToken";
String result = HttpRequestUtil.sendGet(tokenBanceUrl, "");
TokenBalanceResult tokenBalanceResult = JSON.parseObject(result, TokenBalanceResult.class);
System.out.println(tokenBalanceResult.toString());
if (tokenBalanceResult.getStatus() == 1) {
BigDecimal tokenCount = new BigDecimal(tokenBalanceResult.getResult())
.divide(new BigDecimal(10).pow(FinalValue.TOKEN_DECIMALS));
return tokenCount.floatValue();
}
构造交易
// 构造eth交易
Transaction transaction = Transaction.createEtherTransaction(fromAddr, nonce, gasPrice, null, toAddr, value);
// 构造合约调用交易
Transaction transaction = Transaction.createFunctionCallTransaction(fromAddr, nonce, gasPrice, null, contractAddr, funcABI);
估算手续费上限
public static BigInteger getTransactionGasLimit(Web3j web3j, 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 String transferETH(Web3j web3j, String fromAddr, String privateKey, String toAddr, BigDecimal amount, String data){
// 获得nonce
BigInteger nonce = getNonce(web3j, fromAddr);
// value 转换
BigInteger value = Convert.toWei(amount, Convert.Unit.ETHER).toBigInteger();
// 构建交易
Transaction transaction = Transaction.createEtherTransaction(fromAddr, nonce, gasPrice, null, toAddr, value);
// 计算gasLimit
BigInteger gasLimit = getTransactionGasLimit(web3j, transaction);
// 查询调用者余额,检测余额是否充足
BigDecimal ethBalance = getBalance(web3j, fromAddr);
BigDecimal balance = Convert.toWei(ethBalance, Convert.Unit.ETHER);
// balance < amount + gasLimit ??
if (balance.compareTo(amount.add(new BigDecimal(gasLimit.toString()))) < 0) {
throw new RuntimeException("余额不足,请核实");
}
return signAndSend(web3j, nonce, gasPrice, gasLimit, toAddr, value, data, chainId, privateKey);
}
转账代币
public static String transferToken(Web3j web3j, String fromAddr, String privateKey, String toAddr, String contractAddr, long amount) {
BigInteger nonce = getNonce(web3j, fromAddr);
// 构建方法调用信息
String method = "transfer";
// 构建输入参数
List<Type> inputArgs = new ArrayList<>();
inputArgs.add(new Address(toAddr));
inputArgs.add(new Uint256(BigDecimal.valueOf(amount).multiply(BigDecimal.TEN.pow(18)).toBigInteger()));
// 合约返回值容器
List<TypeReference<?>> outputArgs = new ArrayList<>();
String funcABI = FunctionEncoder.encode(new Function(method, inputArgs, outputArgs));
Transaction transaction = Transaction.createFunctionCallTransaction(fromAddr, nonce, gasPrice, null, contractAddr, funcABI);
RawTransaction rawTransaction = RawTransaction.createTransaction(nonce, gasPrice, null, contractAddr, null, funcABI);
BigInteger gasLimit = getTransactionGasLimit(web3j, transaction);
// 获得余额
BigDecimal ethBalance = getBalance(web3j, fromAddr);
BigInteger tokenBalance = getTokenBalance(web3j, fromAddr, contractAddr);
BigInteger balance = Convert.toWei(ethBalance, Convert.Unit.ETHER).toBigInteger();
if (balance.compareTo(gasLimit) < 0) {
throw new RuntimeException("手续费不足,请核实");
}
if (tokenBalance.compareTo(BigDecimal.valueOf(amount).toBigInteger()) < 0) {
throw new RuntimeException("代币不足,请核实");
}
return signAndSend(web3j, nonce, gasPrice, gasLimit, contractAddr, BigInteger.ZERO, funcABI, chainId, privateKey);
}
转账代币方法二
public static String transferToken2(String fromAddr,String toAddr,String amount) {
String contractAddress = "0xa22c2217e785f7796c9e8826c6be55c2e481f9f5";
Web3j web3j =MyWalletUtils.getWeb3j();
Credentials credentials = MyWalletUtils.getCredentials();
System.out.println("我的钱包地址:"+credentials.getAddress());
try {
EthGetTransactionCount ethGetTransactionCount = web3j.ethGetTransactionCount(
fromAddr, DefaultBlockParameterName.LATEST).sendAsync().get();
BigInteger nonce = ethGetTransactionCount.getTransactionCount();
Function function = new Function(
"transfer",
Arrays.asList(new Address(toAddr), new Uint256(new BigInteger(amount))),
Arrays.asList(new TypeReference<Type>() {
}));
String encodedFunction = FunctionEncoder.encode(function);
RawTransaction rawTransaction = RawTransaction.createTransaction(nonce, Convert.toWei("18", Convert.Unit.GWEI).toBigInteger(),
Convert.toWei("100000", Convert.Unit.WEI).toBigInteger(), contractAddress, encodedFunction);
byte[] signedMessage = TransactionEncoder.signMessage(rawTransaction, credentials);
String hexValue = Numeric.toHexString(signedMessage);
System.out.println("transfer hexValue:" + hexValue);
EthSendTransaction ethSendTransaction = web3j.ethSendRawTransaction(hexValue).sendAsync().get();
if (ethSendTransaction.hasError()) {
System.out.println("transfer error:"+ ethSendTransaction.getError().getMessage());
return ethSendTransaction.getError().getMessage();
} else {
String transactionHash = ethSendTransaction.getTransactionHash();
return "";
}
} catch (Exception e) {
e.printStackTrace();
return e.getMessage();
}
}
对交易签名,并发送交易
public static String signAndSend(Web3j web3j, BigInteger nonce, BigInteger gasPrice, BigInteger gasLimit, String to, BigInteger value, String data, byte chainId, String privateKey) {
String txHash = "";
RawTransaction rawTransaction = RawTransaction.createTransaction(nonce, gasPrice, gasLimit, to, value, data);
if (privateKey.startsWith("0x")){
privateKey = privateKey.substring(2);
}
ECKeyPair ecKeyPair = ECKeyPair.create(new BigInteger(privateKey, 16));
Credentials credentials = Credentials.create(ecKeyPair);
byte[] signMessage;
// 主网是1 responst测试网是3 具体查看ChainId
if (chainId > ChainId.NONE){
signMessage = TransactionEncoder.signMessage(rawTransaction, chainId, credentials);
} else {
signMessage = TransactionEncoder.signMessage(rawTransaction, credentials);
}
String signData = Numeric.toHexString(signMessage);
if (!"".equals(signData)) {
try {
EthSendTransaction send = web3j.ethSendRawTransaction(signData).send();
txHash = send.getTransactionHash();
System.out.println(JSON.toJSONString(send));
} catch (IOException e) {
throw new RuntimeException("交易异常");
}
}
return txHash;
}
获取代理额度
public static BigInteger getAllowanceBalance(Web3j web3j, String fromAddr, String toAddr, String contractAddress) {
String methodName = "allowance";
List<Type> inputParameters = new ArrayList<>();
inputParameters.add(new Address(fromAddr));
inputParameters.add(new Address(toAddr));
List<TypeReference<?>> outputs = new ArrayList<>();
TypeReference<Uint256> typeReference = new TypeReference<Uint256>() {
};
outputs.add(typeReference);
Function function = new Function(methodName, inputParameters, outputs);
String data = FunctionEncoder.encode(function);
Transaction transaction = Transaction.createEthCallTransaction(fromAddr, contractAddress, data);
EthCall ethCall;
BigInteger balanceValue = BigInteger.ZERO;
try {
ethCall = web3j.ethCall(transaction, DefaultBlockParameterName.LATEST).send();
List<Type> result = FunctionReturnDecoder.decode(ethCall.getValue(), function.getOutputParameters());
balanceValue = (BigInteger) result.get(0).getValue();
} catch (IOException e) {
e.printStackTrace();
}
return balanceValue;
}
动态gas价格与限价
在使用智能合约时,你可能需要根据调用函数指定不同的gas价格和最大值。你可以通过为智能合约封装包创建自己的ContractGasProvider来实现这一点。
每一个生成的封装包都包含作为常量的所有智能合约方法名称,这有助于通过switch
来进行编译时间匹配。
例如,使用Greeter合约:
Greeter greeter = new Greeter(...);
greeter.setGasProvider(new DefaultGasProvider() {
@Override
public BigInteger getGasPrice(String contractFunc) {
switch (contractFunc) {
case Greeter.FUNC_GREET: return BigInteger.valueOf(22_000_000_000L);
case Greeter.FUNC_KILL: return BigInteger.valueOf(44_000_000_000L);
default: throw new NotImplementedException();
}
}
@Override
public BigInteger getGasLimit(String contractFunc) {
switch (contractFunc) {
case Greeter.FUNC_GREET: return BigInteger.valueOf(4_300_000);
case Greeter.FUNC_KILL: return BigInteger.valueOf(5_300_000);
default: throw new NotImplementedException();
}
}
});
如何加快以太坊交易确认被打包的的速度---gasprice
https://ethgasstation.info/json/ethgasAPI.json
结果:
{
"average":25, //平均值(Gwei*10的结果)
"fastestWait":0.5,
"fastWait":0.7,
"fast":36, //最快(Gwei*10的结果)
"safeLowWait":1.2,
"blockNum":6274955,
"avgWait":1.2,
"block_time":13.876288659793815,
"speed":0.9481897143119544,
"fastest":330,
"safeLow":25 //安全最低值(Gwei*10的结果)
}
发送交易平均正常速度被打包gasprice,单位是wei
var average_gasprice_wei = average*10e8;
发送交易超快被打包的gasprice,单位是wei
var fast_gasprice_wei = fast*10e8;
发送交易最慢被打包的gasprice,单位是wei
var safeLow_gasprice_wei = safeLow*10e8;