How to Integrate with the Ethereum Blockchain with Magic in Flutter

How to Integrate with the Ethereum Blockchain with Magic in Flutter

#Installation

To interact with the Ethereum blockchain, Magic Flutter SDK embeds web3dart as sub dependency. No more extra dependency is needed.

#Initializing Provider

Dart
01import 'package:magic_sdk/magic_sdk.dart';
02
03void main() {
04  runApp(const MyApp());
05
06  Magic.instance = Magic("YOUR_PUBLISHABLE_KEY");
07}
Dart
01import 'package:magic_sdk/magic_sdk.dart';
02import 'package:magic_sdk/modules/web3/magic_credential.dart';
03import 'package:web3dart/web3dart.dart';
04
05class Web3Page extends StatefulWidget {
06  const Web3Page({Key? key}) : super(key: key);
07
08  
09  State<Web3Page> createState() => _Web3PageState();
10}
11
12class _Web3PageState extends State<Web3Page> {
13  final magic = Magic.instance;
14
15  final client = Web3Client.custom(Magic.instance.provider);
16  final credential = MagicCredential(Magic.instance.provider);
17
18  
19  Widget build(BuildContext context) {
20    //Your page
21  }
22}

#Use Different Networks

#Choose Different Testnet

Dart
01import 'package:magic_sdk/magic_sdk.dart';
02import 'package:magic_sdk/modules/web3/eth_network.dart';
03
04void main() {
05  runApp(const MyApp());
06
07  Magic.instance = Magic.eth("YOUR_PUBLISHABLE_KEY", network: EthNetwork.rinkeby);
08}

rpcUrl: 'http://127.0.0.1:7545', // Your own node URL chainId: 1011, // Your own node's chainId

#Configure Custom Nodes

Dart
01import 'package:magic_sdk/magic_sdk.dart';
02
03void main() {
04  runApp(const MyApp());
05
06  Magic.instance = Magic.custom("YOUR_PUBLISHABLE_KEY", rpcUrl: "https://your.own.node", chainId: 1011); // your own node
07}
important

Do not set the custom nodes to local IP address (E.x. "http://127.0.0.1"). Local IP will point to the network environment inside the mobile device / simulator

#Magic Credential

web3dart supports custodial design where the library will ask for user's private key to sign the payloads.

To integrate web3dart in non-custodial, We recommend you to use MagicCredential to optimize security.

Dart
01class MagicCredential {
02
03  Future<EthereumAddress> getAccount()
04  Future<String> personalSign({required Uint8List payload})
05  Future<String> ethSign({required Uint8List payload})
06  Future<String> signTypedDataLegacy({required Map payload})
07  Future<String> signTypedData({required Map payload})
08  Future<String> sendTransaction(Transaction transaction)
09}
important

You will need to call MagicCredential getAccount() before other signing functions to get the public address that will be used from the current authenticated user.

#Get User Info

Dart
01import 'package:flutter/cupertino.dart';
02import 'package:flutter/material.dart';
03import 'package:magic_sdk/magic_sdk.dart';
04import 'package:magic_sdk/modules/web3/magic_credential.dart';
05
06class _Web3PageState extends State<Web3Page> {
07  final magic = Magic.instance;
08
09  final credential = MagicCredential(Magic.instance.provider);
10
11  
12  Widget build(BuildContext context) {
13    return Scaffold(
14        body: Center(
15            child:
16            Column(mainAxisAlignment: MainAxisAlignment.center, children: [
17              /// get account
18              ElevatedButton(
19                onPressed: () async {
20                  var cred = await credential.getAccount();
21                  debugPrint("account, ${cred.hex}");
22                },
23                child: const Text('getAccount'),
24              ),
25            ])));
26  }
27}

#Send Transaction

Dart
01import 'package:flutter/cupertino.dart';
02import 'package:flutter/material.dart';
03import 'package:magic_sdk/magic_sdk.dart';
04import 'package:magic_sdk/modules/web3/magic_credential.dart';
05
06class _Web3PageState extends State<Web3Page> {
07  final magic = Magic.instance;
08
09  final credential = MagicCredential(Magic.instance.provider);
10  final client = Web3Client.custom(Magic.instance.provider);
11
12  
13  Widget build(BuildContext context) {
14    return Scaffold(
15        body: Center(
16            child:
17            Column(mainAxisAlignment: MainAxisAlignment.center, children: [
18
19              /// send Transaction
20                ElevatedButton(
21                  onPressed: () async {
22                    var hash = await client.sendTransaction(
23                      credential,
24                      Transaction(
25                        to: EthereumAddress.fromHex(
26                            '0x01568bf1c1699bb9d58fac67f3a487b28ab4ab2d'),
27                        gasPrice: EtherAmount.inWei(BigInt.two),
28                        maxGas: 100000,
29                        value: EtherAmount.fromUnitAndValue(EtherUnit.gwei, 2),
30                      ),
31                    );
32                    debugPrint("transaction, $hash");
33                  },
34                  child: const Text('sendTransaction'),
35                ),
36            ])));
37  }
38}

#Sign Message

Magic Credential offers non-custodial signing apis

#Eth Sign

Dart
01import 'package:flutter/cupertino.dart';
02import 'package:flutter/material.dart';
03import 'package:magic_sdk/magic_sdk.dart';
04import 'package:magic_sdk/modules/web3/magic_credential.dart';
05
06class _Web3PageState extends State<Web3Page> {
07  final magic = Magic.instance;
08
09  final credential = MagicCredential(Magic.instance.provider);
10
11  
12  Widget build(BuildContext context) {
13    return Scaffold(
14        body: Center(
15            child:
16            Column(mainAxisAlignment: MainAxisAlignment.center, children: [
17
18              /// eth sign
19              ElevatedButton(
20                onPressed: () async {
21                  List<int> list = utf8.encode("hello world");
22                  Uint8List payload = Uint8List.fromList(list);
23                  var signature = await credential.ethSign(payload: payload);
24                  debugPrint(context, "eth_sign signature, $signature");
25                },
26                child: const Text('eth sign'),
27              ),
28            ])));
29  }
30}

#Sign Typed Data Legacy (V1)

Dart
01import 'package:flutter/cupertino.dart';
02import 'package:flutter/material.dart';
03import 'package:magic_sdk/magic_sdk.dart';
04import 'package:magic_sdk/modules/web3/magic_credential.dart';
05
06class _Web3PageState extends State<Web3Page> {
07  final magic = Magic.instance;
08
09  final credential = MagicCredential(Magic.instance.provider);
10
11  
12  Widget build(BuildContext context) {
13    return Scaffold(
14        body: Center(
15            child:
16            Column(mainAxisAlignment: MainAxisAlignment.center, children: [
17
18              /// Sign Typed Data V1
19              ElevatedButton(
20                onPressed: () async {
21                  var payload = {
22                    "type": "string",
23                    "name": "Hello from Magic Labs",
24                    "value": "This message will be assigned by you"
25                  };
26                  var signature = await credential.signTypedDataLegacy(payload: payload);
27                  debugPrint(context, "sign Typed Data V1 signature, $signature");
28                },
29                child: const Text('sign Typed Data V1'),
30              ),
31            ])));
32  }
33}

#Sign Typed Data (EIP 712)

Dart
01import 'package:flutter/cupertino.dart';
02import 'package:flutter/material.dart';
03import 'package:magic_sdk/magic_sdk.dart';
04import 'package:magic_sdk/modules/web3/magic_credential.dart';
05
06class _Web3PageState extends State<Web3Page> {
07  final magic = Magic.instance;
08
09  final credential = MagicCredential(Magic.instance.provider);
10
11  
12  Widget build(BuildContext context) {
13    return Scaffold(
14        body: Center(
15            child:
16            Column(mainAxisAlignment: MainAxisAlignment.center, children: [
17
18              /// Sign Typed Data V3
19              ElevatedButton(
20                onPressed: () async {
21                  var signature =
22                  await credential.signTypedData(payload: signTypedDataV3Payload);
23                  showResult(context, "sign Typed Data V3 signature, ${(signature)}");
24                },
25                child: const Text('sign Typed Data V3'),
26              ),
27            ])));
28  }
29}
30
31var signTypedDataV3Payload = {
32  "types": {
33    "EIP712Domain": [
34      {"name": "name", "type": "string"},
35      {"name": "version", "type": "string"},
36      {"name": "verifyingContract", "type": "address"}
37    ],
38    "Order": [
39      {"name": "makerAddress", "type": "address"},
40      {"name": "takerAddress", "type": "address"},
41      {"name": "feeRecipientAddress", "type": "address"},
42      {"name": "senderAddress", "type": "address"},
43      {"name": "makerAssetAmount", "type": "uint256"},
44      {"name": "takerAssetAmount", "type": "uint256"},
45      {"name": "makerFee", "type": "uint256"},
46      {"name": "takerFee", "type": "uint256"},
47      {"name": "expirationTimeSeconds", "type": "uint256"},
48      {"name": "salt", "type": "uint256"},
49      {"name": "makerAssetData", "type": "bytes"},
50      {"name": "takerAssetData", "type": "bytes"}
51    ]
52  },
53  "domain": {
54    "name": "0x Protocol",
55    "version": "2",
56    "verifyingContract": "0x35dd2932454449b14cee11a94d3674a936d5d7b2"
57  },
58  "message": {
59    "exchangeAddress": "0x35dd2932454449b14cee11a94d3674a936d5d7b2",
60    "senderAddress": "0x0000000000000000000000000000000000000000",
61    "makerAddress": "0x338be8514c1397e8f3806054e088b2daf1071fcd",
62    "takerAddress": "0x0000000000000000000000000000000000000000",
63    "makerFee": "0",
64    "takerFee": "0",
65    "makerAssetAmount": "97500000000000",
66    "takerAssetAmount": "15000000000000000",
67    "makerAssetData":
68    "0xf47261b0000000000000000000000000d0a1e359811322d97991e03f863a0c30c2cf029c",
69    "takerAssetData":
70    "0xf47261b00000000000000000000000006ff6c0ff1d68b964901f986d4c9fa3ac68346570",
71    "salt": "1553722433685",
72    "feeRecipientAddress": "0xa258b39954cef5cb142fd567a46cddb31a670124",
73    "expirationTimeSeconds": "1553808833"
74  },
75  "primaryType": "Order"
76};

#Smart Contract

In this example, we'll be demonstrating how to use Magic with web3dart to interact with Solidity smart contracts. The simple Hello World contract allows anyone to read and write a message to it.

Javascript
01pragma solidity ^0.5.10;
02
03contract HelloWorld {
04
05  string public message;
06
07  constructor(string memory initMessage) public {
08    message = initMessage;
09  }
10
11  function update(string memory newMessage) public {
12    message = newMessage;
13  }
14}
Dart
01class TestContract {
02  static final deployedAddress =
03  EthereumAddress.fromHex("0x8b211dfebf490a648f6de859dfbed61fa22f35e0");
04  static const contractAbi =       '[{"constant":false,"inputs":[{"name":"newMessage","type":"string"}],"name":"update","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"message","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"inputs":[{"name":"initMessage","type":"string"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"}]';
05  static const byteCode =
06      "0x608060405234801561001057600080fd5b5060405161047f38038061047f8339818101604052602081101561003357600080fd5b81019080805164010000000081111561004b57600080fd5b8281019050602081018481111561006157600080fd5b815185600182028301116401000000008211171561007e57600080fd5b5050929190505050806000908051906020019061009c9291906100a3565b5050610148565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106100e457805160ff1916838001178555610112565b82800160010185558215610112579182015b828111156101115782518255916020019190600101906100f6565b5b50905061011f9190610123565b5090565b61014591905b80821115610141576000816000905550600101610129565b5090565b90565b610328806101576000396000f3fe608060405234801561001057600080fd5b5060043610610053576000357c0100000000000000000000000000000000000000000000000000000000900480633d7403a314610058578063e21f37ce14610113575b600080fd5b6101116004803603602081101561006e57600080fd5b810190808035906020019064010000000081111561008b57600080fd5b82018360208201111561009d57600080fd5b803590602001918460018302840111640100000000831117156100bf57600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050509192919290505050610196565b005b61011b6101b0565b6040518080602001828103825283818151815260200191508051906020019080838360005b8381101561015b578082015181840152602081019050610140565b50505050905090810190601f1680156101885780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b80600090805190602001906101ac92919061024e565b5050565b60008054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156102465780601f1061021b57610100808354040283529160200191610246565b820191906000526020600020905b81548152906001019060200180831161022957829003601f168201915b505050505081565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061028f57805160ff19168380011785556102bd565b828001600101855582156102bd579182015b828111156102bc5782518255916020019190600101906102a1565b5b5090506102ca91906102ce565b5090565b6102f091905b808211156102ec5760008160009055506001016102d4565b5090565b9056fea265627a7a7230582003ae1ef5a63bf058bfd2b31398bdee39d3cbfbb7fbf84235f4bc2ec352ee810f64736f6c634300050a0032";
07}

#Deploy Contract

Dart
01final credential = MagicCredential(Magic.instance.provider);
02final client = Web3Client.custom(Magic.instance.provider);
03
04var list = utf8.encode(TestContract.byteCode);
05Uint8List payload = Uint8List.fromList(list);
06final Transaction transaction = Transaction(
07                to: null,
08                from: credential.address,
09                data: payload,
10                maxGas: 2000000);
11final String transactionId =
12                await client.sendTransaction(credential, transaction);

#Read From Contract

Dart
01final credential = MagicCredential(Magic.instance.provider);
02final client = Web3Client.custom(Magic.instance.provider);
03
04final contract = DeployedContract(
05    ContractAbi.fromJson(TestContract.contractAbi, ''),
06    TestContract.deployedAddress);
07final messageFunction = contract.function('message');
08var message = await client.call(
09contract: contract, function: messageFunction, params: []);
10debugPrint("Contract Read Message, $message");
11},

#Write to Contract

Dart
01final credential = MagicCredential(Magic.instance.provider);
02final client = Web3Client.custom(Magic.instance.provider);
03
04final contract = DeployedContract(
05                ContractAbi.fromJson(TestContract.contractAbi, ''),
06                TestContract.deployedAddress);
07final updateFunction = contract.function('update');
08var transactionId = await client.sendTransaction(
09                credential,
10                Transaction.callContract(
11                    contract: contract,
12                    function: updateFunction,
13                    parameters: ["NEW_MESSAGE"]));

Did you find what you were looking for?