该案例适用于Flutter调用以太坊solidity智能合约
首先打开Android studio开发工具,按照如下步骤进行新建项目
然后会自动生成一个Flutter项目的demo,点击如下配置文件,该文件右上角会出现 Pub get
然后可以运行该demo了。
1、首先确保你的truffle已经安装,在Terminal控制台进行 truffle version
2、接着truffle init 会生成几个文件夹
3、在contract编写自己的智能合约并部署,注意修改truffle-config.js文件的配置
首先在lib文件夹下面新建如下文件夹并进行下面的dart代码复制
- import 'package:flutter/material.dart';
- import 'package:flutter_basic_dapp/pages/home_page.dart';
- import 'package:flutter_dotenv/flutter_dotenv.dart';
-
- Future main() async {
- await dotenv.load(fileName: ".env");
- runApp(MyApp());
- }
-
- class MyApp extends StatelessWidget {
- const MyApp({Key? key}) : super(key: key);
-
- @override
- Widget build(BuildContext context) {
- return MaterialApp(
- debugShowCheckedModeBanner: false,
- home: HomePage(),
- );
- }
- }
-
-
ethereum_utils.dart
- import 'dart:convert';
-
- import 'package:flutter/services.dart';
- import 'package:flutter_dotenv/flutter_dotenv.dart';
- import 'package:http/http.dart';
- import 'package:web3dart/web3dart.dart';
-
- var apiUrl = "http://192.168.1.161:8545"; //Replace with your API
- var httpClient = Client();
- var web3client = Web3Client(apiUrl, httpClient);
-
- class EthereumUtils {
- final contractAddress = dotenv.env['CONTRACT_ADDRESS'];
-
- Future getBalance() async {
- final contract = await getDeployedContract();
- final etherFunction = contract.function("getBalance");
- final result = await web3client.call(contract: contract, function: etherFunction, params: []);
- List<dynamic> res = result;
- return res[0];
- }
-
- Future<String> sendBalance(int amount) async {
- var bigAmount = BigInt.from(amount);
- EthPrivateKey privateKeyCred = EthPrivateKey.fromHex(dotenv.env['METAMASK_PRIVATE_KEY']!);
- DeployedContract contract = await getDeployedContract();
- final etherFunction = contract.function("sendBalance");
- final result = await web3client.sendTransaction(
- privateKeyCred,
- Transaction.callContract(
- contract: contract,
- function: etherFunction,
- parameters: [bigAmount],
- maxGas: 100000,
- ),chainId: 20220824,
- fetchChainIdFromNetworkId: false);
- return result;
- }
-
- Future<String> withDrawBalance(int amount) async {
- var bigAmount = BigInt.from(amount);
- EthPrivateKey privateKeyCred = EthPrivateKey.fromHex(dotenv.env['METAMASK_PRIVATE_KEY']!);
- DeployedContract contract = await getDeployedContract();
- final etherFunction = contract.function("withDrawBalance");
- final result = await web3client.sendTransaction(
- privateKeyCred,
- Transaction.callContract(
- contract: contract,
- function: etherFunction,
- parameters: [bigAmount],
- maxGas: 100000,
- ),chainId: 20220824,
- fetchChainIdFromNetworkId: false);
- return result;
-
- }
-
- Future
getDeployedContract() async { - String abiStringFile = await rootBundle.loadString("assets/artifacts/BasicDapp.json");
- var jsonAbi = jsonDecode(abiStringFile);
- final contract = DeployedContract(ContractAbi.fromJson(jsonEncode(jsonAbi["abi"]), "BasicDapp"), EthereumAddress.fromHex(contractAddress!));
- return contract;
- }
- }
home_page.dart
- import 'package:flutter/material.dart';
- import 'package:flutter_basic_dapp/models/ethereum_utils.dart';
- import 'package:flutter_basic_dapp/widgets/button_container_widget.dart';
- import 'package:syncfusion_flutter_sliders/sliders.dart';
-
- class HomePage extends StatefulWidget {
- const HomePage({Key? key}) : super(key: key);
-
- @override
- State
createState() => _HomePageState(); - }
-
- class _HomePageState extends State<HomePage> {
-
- EthereumUtils ethUtils = EthereumUtils();
-
- double? _value = 0.0;
-
- var _data;
-
-
- @override
- void initState() {
- ethUtils.getBalance().then((value) {
- _data = value;
- setState(() {
-
- });
- });
- super.initState();
- }
- @override
- Widget build(BuildContext context) {
- return Scaffold(
- backgroundColor: Colors.deepPurple.withOpacity(.9),
- appBar: AppBar(
- title: Text(" "),
- ),
- body: Container(
- margin: EdgeInsets.symmetric(horizontal: 20, vertical: 30),
- // child: SingleChildScrollView(
- child: Column(
- mainAxisAlignment: MainAxisAlignment.spaceAround,
- children: [
- Container(
- width: MediaQuery.of(context).size.width,
- height: MediaQuery.of(context).size.height * 0.13,
- decoration: BoxDecoration(
- color: Colors.deepPurple..withOpacity(.4),
- borderRadius: BorderRadius.circular(10),
- ),
- child: Center(
- child: Padding(
- padding: EdgeInsets.symmetric(horizontal: 10, vertical: 10),
- child: Column(
- children: [
- Text("Current Balance", style: TextStyle(fontSize: 30, fontWeight: FontWeight.bold, color: Colors.white),),
- SizedBox(height: 12,),
- _data == null ? CircularProgressIndicator() : Text("${_data}", style: TextStyle(fontWeight: FontWeight.bold, fontSize: 30, color: Colors.white),)
- ],
- ),
- ),
- ),
- ),
- SizedBox(height: 40,),
- SfSlider(
- value: _value,
- onChanged: (value) {
- setState(() {
- _value = value;
- });
- } ,
- interval: 1,
- activeColor: Colors.white,
- enableTooltip: true,
- stepSize: 1.0,
- showLabels: true,
- min: 0.0,
- max: 10.0,
- ),
- SizedBox(height: 40,),
- CustomContainerButtonWidget(title: "Get Balance", color: Colors.green, onTap: () {
- ethUtils.getBalance().then((value) {
- _data = value;
- setState(() {
-
- });
- });
- }),
- SizedBox(height: 40,),
- CustomContainerButtonWidget(title: "Send Balance", color: Colors.deepPurpleAccent,
- onTap: () async {
- await ethUtils.sendBalance(_value!.toInt());
- if (_value == 0) {
- incorrectValueDialogBox(context);
- } else {
- sendDialogBox(context);
- }
- }),
- SizedBox(height: 40,),
- CustomContainerButtonWidget(title: "WithDraw", color: Colors.deepOrange,
- onTap: () async {
- await ethUtils.withDrawBalance(_value!.toInt());
-
- if (_value == 0) {
- incorrectValueDialogBox(context);
- } else {
- withDrawDialogBox(context);
- }
- }),
- ],
- ),
- // ),
- ),
- );
- }
-
- incorrectValueDialogBox(BuildContext context) {
- return showDialog(
- context: context,
- builder: (BuildContext context) {
- return AlertDialog(
- title: Text(
- 'Invalid Value',
- textAlign: TextAlign.center,
- style: TextStyle(
- fontSize: 18.0,
- ),
- ),
- content: const Text('Please put a value greater then 0.',
- textAlign: TextAlign.center,
- style: TextStyle(
- color: Colors.black87,
- )),
- actions: [
- ElevatedButton(
- child: Text('OK'),
- onPressed: () {
- Navigator.of(context).pop();
- },
- ),
- ],
- );
- });
- }
-
- sendDialogBox(BuildContext context) {
- return showDialog(
- context: context,
- builder: (BuildContext context) {
- return AlertDialog(
- title: Padding(
- padding: const EdgeInsets.all(10.0),
- child: Text(
- "Thanks for your Transaction",
- textAlign: TextAlign.center,
- style: TextStyle(
- fontSize: 20.0,
- ),
- ),
- ),
- actions: [
- ElevatedButton(
- child: Text('Cancel'),
- onPressed: () {
- Navigator.of(context).pop();
- },
- ),
- ],
- );
- });
- }
-
- withDrawDialogBox(BuildContext context) {
- return showDialog(
- context: context,
- builder: (BuildContext context) {
- return AlertDialog(
- title: Padding(
- padding: const EdgeInsets.all(10.0),
- child: Text(
- "Thanks for your Withdrawal",
- textAlign: TextAlign.center,
- style: TextStyle(
-
- fontSize: 20.0,
- ),
- ),
- ),
- actions: [
- ElevatedButton(
- child: Text('Cancel'),
- onPressed: () {
- Navigator.of(context).pop();
- },
- ),
- ],
- );
- });
- }
- }
button_container_widget.dart
-
- import 'package:flutter/material.dart';
-
- class CustomContainerButtonWidget extends StatelessWidget {
- final String title;
- final Color color;
- final VoidCallback onTap;
- final int? value;
- const CustomContainerButtonWidget({Key? key, required this.title, required this.color, required this.onTap, this.value}) : super(key: key);
-
- @override
- Widget build(BuildContext context) {
- return InkWell(
- onTap: onTap,
- child: Container(
- height: 60,
- width: MediaQuery.of(context).size.width * 0.6,
- decoration: BoxDecoration(
- color: color,
- ),
- child: Center(
- child: Text(
- title, textAlign: TextAlign.left,
- style: TextStyle(
- fontSize: 20,
- fontWeight: FontWeight.bold,
- color: Colors.white
- ),
- ),
- ),
- ),
- );
- }
- }
pubspec.yaml
- name: flutter_basic_dapp
- description: A new Flutter project.
-
- # The following line prevents the package from being accidentally published to
- # pub.dev using `flutter pub publish`. This is preferred for private packages.
- publish_to: 'none' # Remove this line if you wish to publish to pub.dev
-
- # The following defines the version and build number for your application.
- # A version number is three numbers separated by dots, like 1.2.43
- # followed by an optional build number separated by a +.
- # Both the version and the builder number may be overridden in flutter
- # build by specifying --build-name and --build-number, respectively.
- # In Android, build-name is used as versionName while build-number used as versionCode.
- # Read more about Android versioning at https://developer.android.com/studio/publish/versioning
- # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion.
- # Read more about iOS versioning at
- # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
- version: 1.0.0+1
-
- environment:
- sdk: ">=2.16.1 <3.0.0"
-
- # Dependencies specify other packages that your package needs in order to work.
- # To automatically upgrade your package dependencies to the latest versions
- # consider running `flutter pub upgrade --major-versions`. Alternatively,
- # dependencies can be manually updated by changing the version numbers below to
- # the latest version available on pub.dev. To see which dependencies have newer
- # versions available, run `flutter pub outdated`.
- dependencies:
- flutter:
- sdk: flutter
- flutter_dotenv: ^5.0.2
- http: ^0.13.4
- web3dart: ^2.3.5
- syncfusion_flutter_sliders: ^19.4.56
-
-
- # The following adds the Cupertino Icons font to your application.
- # Use with the CupertinoIcons class for iOS style icons.
- cupertino_icons: ^1.0.2
- dev_dependencies:
- flutter_test:
- sdk: flutter
- # The "flutter_lints" package below contains a set of recommended lints to
- # encourage good coding practices. The lint set provided by the package is
- # activated in the `analysis_options.yaml` file located at the root of your
- # package. See that file for information about deactivating specific lint
- # rules and activating additional ones.
- flutter_lints: ^1.0.0
- # For information on the generic Dart part of this file, see the
- # following page: https://dart.dev/tools/pub/pubspec
- # The following section is specific to Flutter.
- flutter:
- # The following line ensures that the Material Icons font is
- # included with your application, so that you can use the icons in
- # the material Icons class.
- uses-material-design: true
- # To add assets to your application, add an assets section, like this:
- assets:
- - .env
- - assets/artifacts/.
- # An image asset can refer to one or more resolution-specific "variants", see
- # https://flutter.dev/assets-and-images/#resolution-aware.
- # For details regarding adding assets from package dependencies, see
- # https://flutter.dev/assets-and-images/#from-packages
- # To add custom fonts to your application, add a fonts section here,
- # in this "flutter" section. Each entry in this list should have a
- # "family" key with the font family name, and a "fonts" key with a
- # list giving the asset and other descriptors for the font. For
- # example:
- # fonts:
- # - family: Schyler
- # fonts:
- # - asset: fonts/Schyler-Regular.ttf
- # - asset: fonts/Schyler-Italic.ttf
- # style: italic
- # - family: Trajan Pro
- # fonts:
- # - asset: fonts/TrajanPro.ttf
- # - asset: fonts/TrajanPro_Bold.ttf
- # weight: 700
- #
- # For details regarding fonts from package dependencies,
- # see https://flutter.dev/custom-fonts/#from-packages
新建一个 .env文件
- METAMASK_WALLET_ADDRESS = 0x94B6D5dC903c96299C16bdBe45652A61a2334424
- METAMASK_PRIVATE_KEY = ee4923c9c3154ccc71697c048ad079c600e09b8a730f1c80b8931ca0c519dc3f
- CONTRACT_ADDRESS = 0x0585c0f265D6073d7D46ed339Eaf2b8035982655
METAMASK_WALLET_ADDRESS是钱包地址 METAMASK_PRIVATE_KEY是账户私钥 CONTRACT_ADDRESS是智能合约地址(在Remix中可以获取,truffle框架进行编译也可以进行获取)
- // SPDX-License-Identifier: MIT
- pragma solidity >=0.7.0 < 0.9.0;
-
- contract BasicDapp {
-
- uint balance;
-
- constructor() {
- balance = 0;
- }
-
- function sendBalance(uint amount) public {
- balance += amount;
- }
-
- function withDrawBalance(uint amount) public {
- require(balance > amount ,"Not Enough Balance");
- balance -= amount;
- }
-
- function getBalance() public view returns (uint){
- return balance;
- }
-
- }
运行截图:
特别注意的地方:
1、新建一个 .env文件(有一个点),在flutter项目目录下。里面的配置需要按照自己私链的配置及metamask连上私链配置
2、在models文件夹下的etherum_utils.dart中,这个需要修改为自己私链的ip加端口。
3、分别代表私钥和智能合约函数名
4、这个需要修改为链的chainid
5、这个是truffle编译成的json文件所在目录