小言_互联网的博客

Flutter调用以太坊区块链智能合约 (私链)

385人阅读  评论(0)

该案例适用于Flutter调用以太坊solidity智能合约

文章目录


前言


一、需要使用哪些开发工具?

  1. Remix IDE
  2. android studio
  3. ubuntu
  4. truffle

二、操作步骤(如果出现问题看最后的总结)

1.搭建Flutter Project

 首先打开Android studio开发工具,按照如下步骤进行新建项目

 

 然后会自动生成一个Flutter项目的demo,点击如下配置文件,该文件右上角会出现 Pub get

 然后可以运行该demo了。


2.集成Truffle框架

   1、首先确保你的truffle已经安装,在Terminal控制台进行 truffle version

2、接着truffle init 会生成几个文件夹

 3、在contract编写自己的智能合约并部署,注意修改truffle-config.js文件的配置


 3.Copy代码

   首先在lib文件夹下面新建如下文件夹并进行下面的dart代码复制

  1. main.dart
    
        
    1. import 'package:flutter/material.dart';
    2. import 'package:flutter_basic_dapp/pages/home_page.dart';
    3. import 'package:flutter_dotenv/flutter_dotenv.dart';
    4. Future main() async {
    5. await dotenv.load(fileName: ".env");
    6. runApp(MyApp());
    7. }
    8. class MyApp extends StatelessWidget {
    9. const MyApp({Key? key}) : super(key: key);
    10. @override
    11. Widget build(BuildContext context) {
    12. return MaterialApp(
    13. debugShowCheckedModeBanner: false,
    14. home: HomePage(),
    15. );
    16. }
    17. }
  2.  ethereum_utils.dart

    
        
    1. import 'dart:convert';
    2. import 'package:flutter/services.dart';
    3. import 'package:flutter_dotenv/flutter_dotenv.dart';
    4. import 'package:http/http.dart';
    5. import 'package:web3dart/web3dart.dart';
    6. var apiUrl = "http://192.168.1.161:8545"; //Replace with your API
    7. var httpClient = Client();
    8. var web3client = Web3Client(apiUrl, httpClient);
    9. class EthereumUtils {
    10. final contractAddress = dotenv.env[ 'CONTRACT_ADDRESS'];
    11. Future getBalance() async {
    12. final contract = await getDeployedContract();
    13. final etherFunction = contract.function( "getBalance");
    14. final result = await web3client.call(contract: contract, function: etherFunction, params: []);
    15. List< dynamic> res = result;
    16. return res[ 0];
    17. }
    18. Future< String> sendBalance( int amount) async {
    19. var bigAmount = BigInt.from(amount);
    20. EthPrivateKey privateKeyCred = EthPrivateKey.fromHex(dotenv.env[ 'METAMASK_PRIVATE_KEY']!);
    21. DeployedContract contract = await getDeployedContract();
    22. final etherFunction = contract.function( "sendBalance");
    23. final result = await web3client.sendTransaction(
    24. privateKeyCred,
    25. Transaction.callContract(
    26. contract: contract,
    27. function: etherFunction,
    28. parameters: [bigAmount],
    29. maxGas: 100000,
    30. ),chainId: 20220824,
    31. fetchChainIdFromNetworkId: false);
    32. return result;
    33. }
    34. Future< String> withDrawBalance( int amount) async {
    35. var bigAmount = BigInt.from(amount);
    36. EthPrivateKey privateKeyCred = EthPrivateKey.fromHex(dotenv.env[ 'METAMASK_PRIVATE_KEY']!);
    37. DeployedContract contract = await getDeployedContract();
    38. final etherFunction = contract.function( "withDrawBalance");
    39. final result = await web3client.sendTransaction(
    40. privateKeyCred,
    41. Transaction.callContract(
    42. contract: contract,
    43. function: etherFunction,
    44. parameters: [bigAmount],
    45. maxGas: 100000,
    46. ),chainId: 20220824,
    47. fetchChainIdFromNetworkId: false);
    48. return result;
    49. }
    50. Future<DeployedContract> getDeployedContract() async {
    51. String abiStringFile = await rootBundle.loadString( "assets/artifacts/BasicDapp.json");
    52. var jsonAbi = jsonDecode(abiStringFile);
    53. final contract = DeployedContract(ContractAbi.fromJson(jsonEncode(jsonAbi[ "abi"]), "BasicDapp"), EthereumAddress.fromHex(contractAddress!));
    54. return contract;
    55. }
    56. }
  3.  home_page.dart

    
        
    1. import 'package:flutter/material.dart';
    2. import 'package:flutter_basic_dapp/models/ethereum_utils.dart';
    3. import 'package:flutter_basic_dapp/widgets/button_container_widget.dart';
    4. import 'package:syncfusion_flutter_sliders/sliders.dart';
    5. class HomePage extends StatefulWidget {
    6. const HomePage({Key? key}) : super(key: key);
    7. @override
    8. State<HomePage> createState() => _HomePageState();
    9. }
    10. class _HomePageState extends State<HomePage> {
    11. EthereumUtils ethUtils = EthereumUtils();
    12. double? _value = 0.0;
    13. var _data;
    14. @override
    15. void initState() {
    16. ethUtils.getBalance().then((value) {
    17. _data = value;
    18. setState(() {
    19. });
    20. });
    21. super.initState();
    22. }
    23. @override
    24. Widget build(BuildContext context) {
    25. return Scaffold(
    26. backgroundColor: Colors.deepPurple.withOpacity( .9),
    27. appBar: AppBar(
    28. title: Text( " "),
    29. ),
    30. body: Container(
    31. margin: EdgeInsets.symmetric(horizontal: 20, vertical: 30),
    32. // child: SingleChildScrollView(
    33. child: Column(
    34. mainAxisAlignment: MainAxisAlignment.spaceAround,
    35. children: [
    36. Container(
    37. width: MediaQuery.of(context).size.width,
    38. height: MediaQuery.of(context).size.height * 0.13,
    39. decoration: BoxDecoration(
    40. color: Colors.deepPurple..withOpacity( .4),
    41. borderRadius: BorderRadius.circular( 10),
    42. ),
    43. child: Center(
    44. child: Padding(
    45. padding: EdgeInsets.symmetric(horizontal: 10, vertical: 10),
    46. child: Column(
    47. children: [
    48. Text( "Current Balance", style: TextStyle(fontSize: 30, fontWeight: FontWeight.bold, color: Colors.white),),
    49. SizedBox(height: 12,),
    50. _data == null ? CircularProgressIndicator() : Text( "${_data}", style: TextStyle(fontWeight: FontWeight.bold, fontSize: 30, color: Colors.white),)
    51. ],
    52. ),
    53. ),
    54. ),
    55. ),
    56. SizedBox(height: 40,),
    57. SfSlider(
    58. value: _value,
    59. onChanged: (value) {
    60. setState(() {
    61. _value = value;
    62. });
    63. } ,
    64. interval: 1,
    65. activeColor: Colors.white,
    66. enableTooltip: true,
    67. stepSize: 1.0,
    68. showLabels: true,
    69. min: 0.0,
    70. max: 10.0,
    71. ),
    72. SizedBox(height: 40,),
    73. CustomContainerButtonWidget(title: "Get Balance", color: Colors.green, onTap: () {
    74. ethUtils.getBalance().then((value) {
    75. _data = value;
    76. setState(() {
    77. });
    78. });
    79. }),
    80. SizedBox(height: 40,),
    81. CustomContainerButtonWidget(title: "Send Balance", color: Colors.deepPurpleAccent,
    82. onTap: () async {
    83. await ethUtils.sendBalance(_value!.toInt());
    84. if (_value == 0) {
    85. incorrectValueDialogBox(context);
    86. } else {
    87. sendDialogBox(context);
    88. }
    89. }),
    90. SizedBox(height: 40,),
    91. CustomContainerButtonWidget(title: "WithDraw", color: Colors.deepOrange,
    92. onTap: () async {
    93. await ethUtils.withDrawBalance(_value!.toInt());
    94. if (_value == 0) {
    95. incorrectValueDialogBox(context);
    96. } else {
    97. withDrawDialogBox(context);
    98. }
    99. }),
    100. ],
    101. ),
    102. // ),
    103. ),
    104. );
    105. }
    106. incorrectValueDialogBox(BuildContext context) {
    107. return showDialog(
    108. context: context,
    109. builder: (BuildContext context) {
    110. return AlertDialog(
    111. title: Text(
    112. 'Invalid Value',
    113. textAlign: TextAlign.center,
    114. style: TextStyle(
    115. fontSize: 18.0,
    116. ),
    117. ),
    118. content: const Text( 'Please put a value greater then 0.',
    119. textAlign: TextAlign.center,
    120. style: TextStyle(
    121. color: Colors.black87,
    122. )),
    123. actions: [
    124. ElevatedButton(
    125. child: Text( 'OK'),
    126. onPressed: () {
    127. Navigator.of(context).pop();
    128. },
    129. ),
    130. ],
    131. );
    132. });
    133. }
    134. sendDialogBox(BuildContext context) {
    135. return showDialog(
    136. context: context,
    137. builder: (BuildContext context) {
    138. return AlertDialog(
    139. title: Padding(
    140. padding: const EdgeInsets.all( 10.0),
    141. child: Text(
    142. "Thanks for your Transaction",
    143. textAlign: TextAlign.center,
    144. style: TextStyle(
    145. fontSize: 20.0,
    146. ),
    147. ),
    148. ),
    149. actions: [
    150. ElevatedButton(
    151. child: Text( 'Cancel'),
    152. onPressed: () {
    153. Navigator.of(context).pop();
    154. },
    155. ),
    156. ],
    157. );
    158. });
    159. }
    160. withDrawDialogBox(BuildContext context) {
    161. return showDialog(
    162. context: context,
    163. builder: (BuildContext context) {
    164. return AlertDialog(
    165. title: Padding(
    166. padding: const EdgeInsets.all( 10.0),
    167. child: Text(
    168. "Thanks for your Withdrawal",
    169. textAlign: TextAlign.center,
    170. style: TextStyle(
    171. fontSize: 20.0,
    172. ),
    173. ),
    174. ),
    175. actions: [
    176. ElevatedButton(
    177. child: Text( 'Cancel'),
    178. onPressed: () {
    179. Navigator.of(context).pop();
    180. },
    181. ),
    182. ],
    183. );
    184. });
    185. }
    186. }
  4. button_container_widget.dart

    
        
    1. import 'package:flutter/material.dart';
    2. class CustomContainerButtonWidget extends StatelessWidget {
    3. final String title;
    4. final Color color;
    5. final VoidCallback onTap;
    6. final int? value;
    7. const CustomContainerButtonWidget({Key? key, required this.title, required this.color, required this.onTap, this.value}) : super(key: key);
    8. @override
    9. Widget build(BuildContext context) {
    10. return InkWell(
    11. onTap: onTap,
    12. child: Container(
    13. height: 60,
    14. width: MediaQuery.of(context).size.width * 0.6,
    15. decoration: BoxDecoration(
    16. color: color,
    17. ),
    18. child: Center(
    19. child: Text(
    20. title, textAlign: TextAlign.left,
    21. style: TextStyle(
    22. fontSize: 20,
    23. fontWeight: FontWeight.bold,
    24. color: Colors.white
    25. ),
    26. ),
    27. ),
    28. ),
    29. );
    30. }
    31. }
  5. pubspec.yaml

    
        
    1. name: flutter_basic_dapp
    2. description: A new Flutter project.
    3. # The following line prevents the package from being accidentally published to
    4. # pub.dev using `flutter pub publish`. This is preferred for private packages.
    5. publish_to: 'none' # Remove this line if you wish to publish to pub.dev
    6. # The following defines the version and build number for your application.
    7. # A version number is three numbers separated by dots, like 1.2 .43
    8. # followed by an optional build number separated by a +.
    9. # Both the version and the builder number may be overridden in flutter
    10. # build by specifying --build-name and --build-number, respectively.
    11. # In Android, build-name is used as versionName while build-number used as versionCode.
    12. # Read more about Android versioning at https: //developer.android.com/studio/publish/versioning
    13. # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion.
    14. # Read more about iOS versioning at
    15. # https: //developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
    16. version: 1.0 .0+ 1
    17. environment:
    18. sdk: ">=2.16.1 <3.0.0"
    19. # Dependencies specify other packages that your package needs in order to work.
    20. # To automatically upgrade your package dependencies to the latest versions
    21. # consider running `flutter pub upgrade --major-versions`. Alternatively,
    22. # dependencies can be manually updated by changing the version numbers below to
    23. # the latest version available on pub.dev. To see which dependencies have newer
    24. # versions available, run `flutter pub outdated`.
    25. dependencies:
    26. flutter:
    27. sdk: flutter
    28. flutter_dotenv: ^ 5.0 .2
    29. http: ^ 0.13 .4
    30. web3dart: ^ 2.3 .5
    31. syncfusion_flutter_sliders: ^ 19.4 .56
    32. # The following adds the Cupertino Icons font to your application.
    33. # Use with the CupertinoIcons class for iOS style icons.
    34. cupertino_icons: ^1.0.2
    35. dev_dependencies:
    36. flutter_test:
    37. sdk: flutter
    38. # The "flutter_lints" package below contains a set of recommended lints to
    39. # encourage good coding practices. The lint set provided by the package is
    40. # activated in the `analysis_options.yaml` file located at the root of your
    41. # package. See that file for information about deactivating specific lint
    42. # rules and activating additional ones.
    43. flutter_lints: ^1.0.0
    44. # For information on the generic Dart part of this file, see the
    45. # following page: https://dart.dev/tools/pub/pubspec
    46. # The following section is specific to Flutter.
    47. flutter:
    48. # The following line ensures that the Material Icons font is
    49. # included with your application, so that you can use the icons in
    50. # the material Icons class.
    51. uses-material-design: true
    52. # To add assets to your application, add an assets section, like this:
    53. assets:
    54. - .env
    55. - assets/artifacts/.
    56. # An image asset can refer to one or more resolution-specific "variants", see
    57. # https://flutter.dev/assets-and-images/#resolution-aware.
    58. # For details regarding adding assets from package dependencies, see
    59. # https://flutter.dev/assets-and-images/#from-packages
    60. # To add custom fonts to your application, add a fonts section here,
    61. # in this "flutter" section. Each entry in this list should have a
    62. # "family" key with the font family name, and a "fonts" key with a
    63. # list giving the asset and other descriptors for the font. For
    64. # example:
    65. # fonts:
    66. # - family: Schyler
    67. # fonts:
    68. # - asset: fonts/Schyler-Regular.ttf
    69. # - asset: fonts/Schyler-Italic.ttf
    70. # style: italic
    71. # - family: Trajan Pro
    72. # fonts:
    73. # - asset: fonts/TrajanPro.ttf
    74. # - asset: fonts/TrajanPro_Bold.ttf
    75. # weight: 700
    76. #
    77. # For details regarding fonts from package dependencies,
    78. # see https://flutter.dev/custom-fonts/#from-packages

  6. 新建一个 .env文件

    
        
    1. METAMASK_WALLET_ADDRESS = 0x94B6D5dC903c96299C16bdBe45652A61a2334424
    2. METAMASK_PRIVATE_KEY = ee4923c9c3154ccc71697c048ad079c600e09b8a730f1c80b8931ca0c519dc3f
    3. CONTRACT_ADDRESS = 0x0585c0f265D6073d7D46ed339Eaf2b8035982655
    METAMASK_WALLET_ADDRESS是钱包地址
    METAMASK_PRIVATE_KEY是账户私钥
    CONTRACT_ADDRESS是智能合约地址(在Remix中可以获取,truffle框架进行编译也可以进行获取)

 智能合约


  
  1. // SPDX-License-Identifier: MIT
  2. pragma solidity >= 0.7 .0 < 0.9 .0;
  3. contract BasicDapp {
  4. uint balance;
  5. constructor() {
  6. balance = 0;
  7. }
  8. function sendBalance(uint amount) public {
  9. balance += amount;
  10. }
  11. function withDrawBalance(uint amount) public {
  12. require(balance > amount , "Not Enough Balance");
  13. balance -= amount;
  14. }
  15. function getBalance() public view returns (uint){
  16. return balance;
  17. }
  18. }

 运行截图:

总结

特别注意的地方:

1、新建一个 .env文件(有一个点),在flutter项目目录下。里面的配置需要按照自己私链的配置及metamask连上私链配置

2、在models文件夹下的etherum_utils.dart中,这个需要修改为自己私链的ip加端口。

 3、分别代表私钥和智能合约函数名

 4、这个需要修改为链的chainid

 5、这个是truffle编译成的json文件所在目录

 


转载:https://blog.csdn.net/weixin_46085718/article/details/127427616
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场