引用的依赖
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/'; //默认rpc节点,这个需要自己更改,当前为以太坊主网
const int gcdecimals = 18;
首先初始化web3,创建client
static Wbe3Api wbe3api;
static Web3Client client;
static DeployedContract contract;
static String _contractAddress;
static int decimals;
//使用单例模式,
Future getInstances() async {
try {
if (wbe3api == null) {
wbe3api = Wbe3Api();
}
if (client == null) {
client = new Web3Client(rpcUrl, Client());
}
return wbe3api;
} catch (error) {
return null;
}
}
主链币种操作:
1.获取主链的余额,这里面要用到主链的精度,也就是小数位
//获取主链余额
Future 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(' 余额错误: ${err.toString()}');
return formatFour('0.00');
}
}
//格式化小数点
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.主链的交易
首先获取矿工费
//获取主链矿工费,如果矿工费给的不够高,那就无法交易
Future getdefaultEthfee() async {
EtherAmount gasprice = await client.getGasPrice();
print("==" + _tofee(BigInt.from(21000), gasprice));
return _tofee(BigInt.from(21000), gasprice);
}
/**
* 获取手续费
* gaslimit :最小gas,合约需要算出来,主链币则默认为21000
* gasprice:gas价格
*/
String _tofee(BigInt gaslimit, EtherAmount gasprice) {
var fee = gaslimit * gasprice.getInWei;
var result = fee / BigInt.from(pow(10, gcdecimals));
return result.toString();
}
之后发起交易
//判断以太坊地址是否正确
Future getIsGCAddress(String maddress) async {
try {
EthereumAddress address = EthereumAddress.fromHex(maddress);
return true;
} catch (e) {
return false;
}
}
/**
* 发起普通交易
* fromaddress 发送地址
* toaddress 接收地址
* privatekey 私钥
* fee 手续费
* value 数量
*/
Future 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;
}
}
/**
* 通过精度格式化 传入的数量
* value 数量
* decimals 精度(保留小数位)
*/
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));
}
合约查询和操作:
1.判断合约地址
/**
* 判断是否合约地址
* contractaddress 合约地址
*/
Future 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
/**
* 设置全局合约,读取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 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.获取合约基本参数
/**
* 读取合约基本信息decimals和symbol
*/
Future
4.获取合约余额,切记只能执行abi里面的方法
//获取合约余额
Future 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)矿工费,合约的任何交易都要手续费
//转出手续费
Future 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]);
}
//兑换手续费
Future getexchangeFee(
String fromaddress, String toaddress, String value) async {
BigInt amount = tokenInt(value, decimals);
await getCommonFee(fromaddress, "exchange", [amount]);
}
/*
* 获取合约手续费通用方法
* fromaddress 发送地址
* functionname 方法名
* parameters 合约参数
*/
Future getCommonFee(
String from, String functionname, List 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('检测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)发起合约交易,转账和兑换
/**
* 发起合约转账
* fromaddress 发送地址
* toaddress 接收地址
* privatekey 私钥
* value 数量
*/
Future 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]);
}
/**
* 发起兑换交易
* fromaddress 发送地址
* privatekey 私钥
* value 数量
*/
Future tokenExchange(
String fromaddress, String privatekey, String fee, String value) async {
BigInt amount = tokenInt(value, decimals);
await signContractTransaction(
fromaddress, privatekey, fee, "exchange", [amount]);
}
/*
* 发起合约交易
* fromaddress 发送地址
* privatekey 私钥
* functionname 合約调用用方法
* parameters 合約参數
*/
Future signContractTransaction(String from, String privatekey,
String fee, String functionname, List 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("开始交易");
var txHash = await client.sendTransaction(
credentials,
transaction,
chainId: networkId,
);
print('hash====' + txHash);
await client.dispose();
return txHash;
} catch (error) {
print(error);
return error;
}
}
/**
* 获取交易状态
* txHash 交易hash
*/
Future getTranferstate(String txHash) async {
try {
var transactionReceipt = await client.getTransactionReceipt(txHash);
if (transactionReceipt != null) {
print("交易状态: " + transactionReceipt.status.toString());
await client.dispose();
return transactionReceipt.status;
}
return false;
} catch (error) {
print("状态error: " + error.toString());
return false;
}
}