flutter web3主鏈,合約操作

引用的依賴(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;
    }
  }
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末爽雄,一起剝皮案震驚了整個(gè)濱河市蝠检,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌挚瘟,老刑警劉巖叹谁,帶你破解...
    沈念sama閱讀 206,968評(píng)論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異乘盖,居然都是意外死亡焰檩,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門(mén)订框,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)析苫,“玉大人,你說(shuō)我怎么就攤上這事穿扳√傥ィ” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 153,220評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵纵揍,是天一觀的道長(zhǎng)顿乒。 經(jīng)常有香客問(wèn)我,道長(zhǎng)泽谨,這世上最難降的妖魔是什么璧榄? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,416評(píng)論 1 279
  • 正文 為了忘掉前任特漩,我火速辦了婚禮,結(jié)果婚禮上骨杂,老公的妹妹穿的比我還像新娘涂身。我一直安慰自己,他們只是感情好搓蚪,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,425評(píng)論 5 374
  • 文/花漫 我一把揭開(kāi)白布蛤售。 她就那樣靜靜地躺著,像睡著了一般妒潭。 火紅的嫁衣襯著肌膚如雪悴能。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 49,144評(píng)論 1 285
  • 那天雳灾,我揣著相機(jī)與錄音漠酿,去河邊找鬼。 笑死谎亩,一個(gè)胖子當(dāng)著我的面吹牛炒嘲,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播匈庭,決...
    沈念sama閱讀 38,432評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼夫凸,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了阱持?” 一聲冷哼從身側(cè)響起夭拌,我...
    開(kāi)封第一講書(shū)人閱讀 37,088評(píng)論 0 261
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎紊选,沒(méi)想到半個(gè)月后啼止,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,586評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡兵罢,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,028評(píng)論 2 325
  • 正文 我和宋清朗相戀三年献烦,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片卖词。...
    茶點(diǎn)故事閱讀 38,137評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡巩那,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出此蜈,到底是詐尸還是另有隱情即横,我是刑警寧澤,帶...
    沈念sama閱讀 33,783評(píng)論 4 324
  • 正文 年R本政府宣布裆赵,位于F島的核電站东囚,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏战授。R本人自食惡果不足惜页藻,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,343評(píng)論 3 307
  • 文/蒙蒙 一桨嫁、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧份帐,春花似錦璃吧、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,333評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至噩凹,卻和暖如春巴元,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背栓始。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,559評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工务冕, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留血当,地道東北人幻赚。 一個(gè)月前我還...
    沈念sama閱讀 45,595評(píng)論 2 355
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像臊旭,于是被迫代替她去往敵國(guó)和親落恼。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,901評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容