引用的依賴(lài)
import 'package:web3dart/web3dart.dart';
import 'dart:math';
import 'package:http/http.dart';
import 'package:intl/intl.dart';
import 'dart:convert';
import 'package:flutter/services.dart' show rootBundle;
const String contarctChainaddress =
'0x1daEAaa139f801dA23153a381B78ec68D1551071'; //跨鏈合約地址
const String rpcUrl = 'https://mainnet.infura.io/v3/'; //默認(rèn)rpc節(jié)點(diǎn)靶累,這個(gè)需要自己更改,當(dāng)前為以太坊主網(wǎng)
const int gcdecimals = 18;
首先初始化web3,創(chuàng)建client
static Wbe3Api wbe3api;
static Web3Client client;
static DeployedContract contract;
static String _contractAddress;
static int decimals;
//使用單例模式,
Future<Wbe3Api> getInstances() async {
try {
if (wbe3api == null) {
wbe3api = Wbe3Api();
}
if (client == null) {
client = new Web3Client(rpcUrl, Client());
}
return wbe3api;
} catch (error) {
return null;
}
}
主鏈幣種操作:
1.獲取主鏈的余額,這里面要用到主鏈的精度款熬,也就是小數(shù)位
//獲取主鏈余額
Future<String> getBalance(String address) async {
try {
EtherAmount amount =
await client.getBalance(EthereumAddress.fromHex(address));
BigInt available = amount.getInWei;
String blance = (available / BigInt.from(pow(10, gcdecimals))).toString();
print("=====" + blance);
await client.dispose();
return formatFour(blance);
} catch (err) {
print(' 余額錯(cuò)誤: ${err.toString()}');
return formatFour('0.00');
}
}
//格式化小數(shù)點(diǎn)
String formatFour(String values) {
double value = double.tryParse(values) / pow(10, gcdecimals);
String newvalue = value.toStringAsFixed(8);
return newvalue.substring(0, newvalue.indexOf('.') + 7);
}
2.主鏈的交易
首先獲取礦工費(fèi)
//獲取主鏈礦工費(fèi),如果礦工費(fèi)給的不夠高攘乒,那就無(wú)法交易
Future<String> getdefaultEthfee() async {
EtherAmount gasprice = await client.getGasPrice();
print("==" + _tofee(BigInt.from(21000), gasprice));
return _tofee(BigInt.from(21000), gasprice);
}
/**
* 獲取手續(xù)費(fèi)
* gaslimit :最小gas,合約需要算出來(lái)贤牛,主鏈幣則默認(rèn)為21000
* gasprice:gas價(jià)格
*/
String _tofee(BigInt gaslimit, EtherAmount gasprice) {
var fee = gaslimit * gasprice.getInWei;
var result = fee / BigInt.from(pow(10, gcdecimals));
return result.toString();
}
之后發(fā)起交易
//判斷以太坊地址是否正確
Future<bool> getIsGCAddress(String maddress) async {
try {
EthereumAddress address = EthereumAddress.fromHex(maddress);
return true;
} catch (e) {
return false;
}
}
/**
* 發(fā)起普通交易
* fromaddress 發(fā)送地址
* toaddress 接收地址
* privatekey 私鑰
* fee 手續(xù)費(fèi)
* value 數(shù)量
*/
Future<String> signETHTransaction(String fromaddress, String toaddress,
String privatekey, String fee, String value) async {
try {
final credentials = EthPrivateKey.fromHex(privatekey);
EthereumAddress from = EthereumAddress.fromHex(fromaddress);
final receiver = EthereumAddress.fromHex(toaddress);
EtherAmount gasprice = await client.getGasPrice();
final networkId = await client.getNetworkId();
BigInt amount = tokenInt(value, gcdecimals);
BigInt gaslimit = BigInt.from(double.parse(fee) * pow(10, 9));
print("gaslimit ====" + gaslimit.toString());
print("GCstart ====");
var transaction = Transaction(
to: receiver,
gasPrice: gasprice,
maxGas: gaslimit.toInt(),
value: EtherAmount.fromUnitAndValue(EtherUnit.wei, amount),
);
var txHash = await client.sendTransaction(
credentials,
transaction,
chainId: networkId,
);
print('transferhash====' + txHash);
await client.dispose();
return txHash;
} catch (error) {
return error;
}
}
/**
* 通過(guò)精度格式化 傳入的數(shù)量
* value 數(shù)量
* decimals 精度(保留小數(shù)位)
*/
BigInt tokenInt(String value, int decimals) {
if (value == null) {
return BigInt.zero;
}
double v = 0;
try {
if (value.contains(',') || value.contains('.')) {
v = NumberFormat(",##0.${"0" * decimals}").parse(value);
} else {
v = double.parse(value);
}
} catch (err) {
print('Fmt.tokenInt() error: ${err.toString()}');
}
return BigInt.from(v * pow(10, decimals));
}
合約查詢(xún)和操作:
1.判斷合約地址
/**
* 判斷是否合約地址
* contractaddress 合約地址
*/
Future<bool> getIsContractAddress(String contractaddress) async {
if (contractaddress.length != 42) {
return false;
} else {
EthereumAddress address = EthereumAddress.fromHex(contractaddress);
var respons = await client.getCode(address);
print("respons ====" + respons.toString());
return respons.length > 0 ? true : false;
}
}
2.讀取合約abi
/**
* 設(shè)置全局合約,讀取abi
*/
setContaract(String contractaddress) async {
_contractAddress = contractaddress;
contract = await fromAssets(
'images/contract.json', _contractAddress);
if (contract != null) {
var result = await getContractInfo('decimals');
decimals = int.parse(result.toString());
print("==精度獲取==" + decimals.toString());
}
}
/**
* 將合約格式化
*/
Future<DeployedContract> fromAssets(
String path, String contractAddress) async {
final contractJson =
jsonDecode(await rootBundle.loadString(path));
return DeployedContract(ContractAbi.fromJson(jsonEncode(contractJson['abi']),contractJson['contractName'] as String),
EthereumAddress.fromHex(contractAddress));
}
abi為json则酝,需要在yaml文件中讀取
assets:
- images/home/
- images/assets/
- images/contract.json
abi為格式
{
"contractName": "TargaryenCoin",
"abi": [
{
"inputs": [
{
"internalType": "address",
"name": "owner",
"type": "address"
},
{
"internalType": "address",
"name": "spender",
"type": "address"
}
],
"name": "allowance",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "decimals",
"outputs": [
{
"internalType": "uint8",
"name": "",
"type": "uint8"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "name",
"outputs": [
{
"internalType": "string",
"name": "",
"type": "string"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "symbol",
"outputs": [
{
"internalType": "string",
"name": "",
"type": "string"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "to",
"type": "address"
},
{
"internalType": "uint256",
"name": "value",
"type": "uint256"
}
],
"name": "transfer",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
}
],
"name": "exchange",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "withdraw",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"stateMutability": "nonpayable",
"type": "function"
}殉簸,
{
"inputs": [
{
"internalType": "address",
"name": "owner",
"type": "address"
}
],
"name": "balanceOf",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
}
]
}
3.獲取合約基本參數(shù)
/**
* 讀取合約基本信息decimals和symbol
*/
Future<Map> adppContaractDecimals(String contractaddress) async {
int dappDecimals = 18;
// contract = await fromAssets(
// 'images/contract.json', contractaddress);
try {
var dec = await getContractInfo('decimals');
var type = await getContractInfo('symbol');
dappDecimals = int.parse(dec.toString());
print("adpp精度獲取==" + dappDecimals.toString());
return {'decimals': dappDecimals, 'coin': type};
} catch (error) {
return {'decimals': dappDecimals, 'coin': "ETH"};
}
}
/**
* 獲取合約基本信息
* functionname 方法名
* decimals:合約精度,小數(shù)位
* name 名字
* symbol 和名字一致
*/
Future<String> getContractInfo(String functionname) async {
try {
final response = await client.call(
contract: contract,
function: contract.function(functionname),
params: [],
);
print(response.first.toString());
return response.first.toString();
} catch (error) {
print(error);
return error.toString();
}
}
4.獲取合約余額沽讹,切記只能執(zhí)行abi里面的方法
//獲取合約余額
Future<String> getTokenBalance(String madress) async {
EthereumAddress adress = EthereumAddress.fromHex(madress);
final response = await client.call(
contract: contract,
function: contract.function('balanceOf'),
params: [adress],
);
print(response.toString());
String blance =
(response.first / BigInt.from(pow(10, decimals))).toString();
print('====' + blance);
return formatFour(blance);
}
5.合約交易
(1)礦工費(fèi)般卑,合約的任何交易都要手續(xù)費(fèi)
//轉(zhuǎn)出手續(xù)費(fèi)
Future<String> getTransferFee(
String fromaddress, String toaddress, String value) async {
BigInt amount = tokenInt(value, decimals);
EthereumAddress receiver = EthereumAddress.fromHex(toaddress);
return await getCommonFee(fromaddress, "transfer", [receiver, amount]);
}
//兌換手續(xù)費(fèi)
Future<void> getexchangeFee(
String fromaddress, String toaddress, String value) async {
BigInt amount = tokenInt(value, decimals);
await getCommonFee(fromaddress, "exchange", [amount]);
}
/*
* 獲取合約手續(xù)費(fèi)通用方法
* fromaddress 發(fā)送地址
* functionname 方法名
* parameters 合約參數(shù)
*/
Future<String> getCommonFee(
String from, String functionname, List<dynamic> parameters) async {
EthereumAddress fromaddress = EthereumAddress.fromHex(from);
final gasprice = await client.getGasPrice();
print('gasprice' + gasprice.toString());
var transaction = Transaction.callContract(
contract: contract,
function: contract.function(functionname),
parameters: parameters,
gasPrice: gasprice,
from: fromaddress);
print('檢測(cè)gaslimit');
var gaslimit = BigInt.from(21000);
try {
gaslimit = await client.estimateGas(
sender: fromaddress,
to: EthereumAddress.fromHex(_contractAddress),
data: transaction.data,
value: EtherAmount.zero());
print('gaslimit ====' + gaslimit.toString());
return _tofee(gaslimit, gasprice);
} catch (error) {
print(error.toString());
return 'error' + error.toString();
}
}
(2)發(fā)起合約交易,轉(zhuǎn)賬和兌換
/**
* 發(fā)起合約轉(zhuǎn)賬
* fromaddress 發(fā)送地址
* toaddress 接收地址
* privatekey 私鑰
* value 數(shù)量
*/
Future<String> tokenTransfer(String fromaddress, String toaddress,
String privatekey, String fee, String value) async {
BigInt amount = tokenInt(value, decimals);
EthereumAddress receiver = EthereumAddress.fromHex(toaddress);
return await signContractTransaction(
fromaddress, privatekey, fee, "transfer", [receiver, amount]);
}
/**
* 發(fā)起兌換交易
* fromaddress 發(fā)送地址
* privatekey 私鑰
* value 數(shù)量
*/
Future<void> tokenExchange(
String fromaddress, String privatekey, String fee, String value) async {
BigInt amount = tokenInt(value, decimals);
await signContractTransaction(
fromaddress, privatekey, fee, "exchange", [amount]);
}
/*
* 發(fā)起合約交易
* fromaddress 發(fā)送地址
* privatekey 私鑰
* functionname 合約調(diào)用用方法
* parameters 合約參數(shù)
*/
Future<String> signContractTransaction(String from, String privatekey,
String fee, String functionname, List<dynamic> parameters) async {
try {
EthereumAddress fromaddress = EthereumAddress.fromHex(from);
final credentials = EthPrivateKey.fromHex(privatekey);
final networkId = await client.getNetworkId();
final gasprice = await client.getGasPrice();
BigInt gaslimit = BigInt.from(double.parse(fee) * pow(10, 9));
print("gaslimit ====" + gaslimit.toString());
var transaction = Transaction.callContract(
contract: contract,
function: contract.function(functionname),
parameters: parameters,
from: fromaddress,
gasPrice: gasprice,
maxGas: gaslimit.toInt());
print("開(kāi)始交易");
var txHash = await client.sendTransaction(
credentials,
transaction,
chainId: networkId,
);
print('hash====' + txHash);
await client.dispose();
return txHash;
} catch (error) {
print(error);
return error;
}
}
/**
* 獲取交易狀態(tài)
* txHash 交易hash
*/
Future<bool> getTranferstate(String txHash) async {
try {
var transactionReceipt = await client.getTransactionReceipt(txHash);
if (transactionReceipt != null) {
print("交易狀態(tài): " + transactionReceipt.status.toString());
await client.dispose();
return transactionReceipt.status;
}
return false;
} catch (error) {
print("狀態(tài)error: " + error.toString());
return false;
}
}