flutter web3主鏈,合約操作

引用的依賴

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<Wbe3Api> getInstances() async {
    try {
      if (wbe3api == null) {
        wbe3api = Wbe3Api();
      }
      if (client == null) {
        client = new Web3Client(rpcUrl, Client());
      }
      return wbe3api;
    } catch (error) {
      return null;
    }
  }

主鏈幣種操作:

1.獲取主鏈的余額,這里面要用到主鏈的精度,也就是小數位

 //獲取主鏈余額
  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(' 余額錯誤: ${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<String> 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<bool> getIsGCAddress(String maddress) async {
    try {
      EthereumAddress address = EthereumAddress.fromHex(maddress);
      return true;
    } catch (e) {
      return false;
    }
  }

  /**
   * 發起普通交易
   * fromaddress 發送地址
   * toaddress  接收地址
   * privatekey 私鑰
   * fee  手續費
   * value  數量
   */
  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;
    }
  }

 /**
   * 通過精度格式化 傳入的數量
   * 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<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

 /**
   * 設置全局合約,讀取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.獲取合約基本參數

 /**
   * 讀取合約基本信息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:合約精度,小數位
   * 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.獲取合約余額,切記只能執行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)礦工費,合約的任何交易都要手續費

 //轉出手續費
  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]);
  }

  //兌換手續費
  Future<void> getexchangeFee(
      String fromaddress, String toaddress, String value) async {
    BigInt amount = tokenInt(value, decimals);
    await getCommonFee(fromaddress, "exchange", [amount]);
  }

/*
   * 獲取合約手續費通用方法
   * fromaddress 發送地址
   * functionname 方法名
   * parameters  合約參數
   */
  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('檢測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<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]);
  }

  /**
   * 發起兌換交易
   * fromaddress 發送地址
   * privatekey 私鑰
   * value  數量
   */
  Future<void> 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<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("開始交易");
      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<bool> 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;
    }
  }
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容