dapp_injected_eip155 1.0.0 copy "dapp_injected_eip155: ^1.0.0" to clipboard
dapp_injected_eip155: ^1.0.0 copied to clipboard

Support DApp Injected on Ethereum network - EIP155

example/lib/main.dart

import 'package:eth_sig_util/eth_sig_util.dart';
import 'package:flutter/material.dart';
import 'package:web3dart/crypto.dart';
import 'package:dapp_injected_eip155/dapp_injected_eip155.dart';
// import 'package:flutter_inappwebview/flutter_inappwebview.dart';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await ScriptUtils.initProviderScript();
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        brightness: Brightness.dark,
      ),
      home: const MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key, required this.title});

  final String title;

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  final TextEditingController _urlController =
      TextEditingController(text: 'https://pancakeswap.finance/');

  @override
  void dispose() {
    _urlController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            TextField(
              controller: _urlController,
            ),
            const SizedBox(height: 30),
            ElevatedButton(
              onPressed: () async {
                Navigator.of(context).push(
                  MaterialPageRoute(
                      builder: (c) => ExampleDapp(
                            initialUrl: _urlController.text.trim(),
                          )),
                );
              },
              child: const Text('DApp Injected'),
            ),
          ],
        ),
      ),
    );
  }
}

class ExampleDapp extends StatefulWidget {
  final String initialUrl;
  const ExampleDapp({super.key, required this.initialUrl});

  @override
  State<ExampleDapp> createState() => _ExampleDappState();
}

class _ExampleDappState extends State<ExampleDapp> {
  final List<NetworkSupport> networkLi = [
    NetworkSupport(
      chainId: 1,
      chainName: 'Ethereum',
      nativeCurrency: NativeCurrency(
        name: 'ETH',
        symbol: 'eth',
        decimals: 18,
      ),
      rpcUrls: [
        "https://rpc.ankr.com/eth",
      ],
      blockExplorerUrls: [
        "https://etherscan.io/tx/",
      ],
    ),
  ];
  final List<String> addressLi = [
    '0xB4A9cAB492C74A6e1C2503A3577b51d3856F8a8C',
    '0x1bc9BDF4f77AD6662adD75628c6A65B4062Fd3f3',
  ];
  final String _privateKey = ''; // mock
  late NetworkSupport currentNetwork = networkLi.first;
  late String currentAddress = addressLi.first;

  @override
  Widget build(BuildContext context) {
    return DAppInjectedView(
      actions: [
        _buildAccountSwitcher(context),
      ],
      loadingChild: const Center(
        child: SizedBox(
          height: 32,
          width: 32,
          child: CircularProgressIndicator(),
        ),
      ),
      title: const Text('DApp'),
      initialUrl: widget.initialUrl,
      currentProvider: WalletWeb3Provider(
        address: currentAddress,
        network: currentNetwork,
      ),
      // initialSettings: InAppWebViewSettings(
      //   isInspectable: true, //kDebugMode,
      //   mediaPlaybackRequiresUserGesture: true,
      //   allowsInlineMediaPlayback: true,
      //   iframeAllowFullscreen: true,
      //   javaScriptEnabled: true,
      // ),
      onShare: (url) {
        /// add share action
        debugPrint('SHARE: $url');
      },
      methodCallbacks: MethodCallbacks(
        onSignTransaction: _onSignTransaction,
        onSwitchNetwork: (chainId) async {
          /// need check case chainId not support
          int index = networkLi.indexWhere((e) => e.chainId == chainId);
          if (index == -1) {
            throw const NotFoundChainException();
          }
          return networkLi[index];
        },
        onAddNetwork: (network) async {
          ///user reject
          // throw const UserRejectException();
          networkLi.add(network);
          return; //confirm
        },
        onSignMessage: _onSignMessage,
        onSignPersonalMessage: _onSignPersonalMessage,
        onSignTypeMessage: _onSignTypeMessage,
        // onEcRecover: _onEcRecover,
      ),
    );
  }

  Widget _buildAccountSwitcher(BuildContext context) {
    return IconButton(
      onPressed: () async {
        await showModalBottomSheet(
            context: context,
            builder: (context) {
              return ListView.builder(
                padding: const EdgeInsets.only(top: 25, bottom: 35),
                itemBuilder: (c, index) {
                  bool isActive = currentAddress == addressLi[index];
                  return GestureDetector(
                    onTap: () {
                      Navigator.of(context).pop();
                      if (isActive) return;
                      currentAddress = addressLi[index];
                      setState(() {});
                    },
                    child: Padding(
                      padding: const EdgeInsets.symmetric(
                          horizontal: 12, vertical: 16),
                      child: Text(
                        addressLi[index],
                        style: Theme.of(context).textTheme.bodyLarge?.copyWith(
                              color: isActive
                                  ? Theme.of(context).primaryColor
                                  : null,
                            ),
                      ),
                    ),
                  );
                },
                itemCount: addressLi.length,
              );
            });
      },
      icon: const Icon(Icons.menu),
    );
  }

  Future<bool> _confirmSignMessage(String title, String message) async {
    bool? status = await showModalBottomSheet(
      context: context,
      builder: (c) {
        return Padding(
          padding: const EdgeInsets.symmetric(vertical: 25, horizontal: 16),
          child: Column(
            children: [
              Text(
                title,
                style: Theme.of(context).textTheme.headlineLarge,
              ),
              const SizedBox(height: 25),
              Expanded(
                child: SingleChildScrollView(
                  child: Text(
                    message,
                    style: Theme.of(context).textTheme.bodyLarge,
                  ),
                ),
              ),
              const SizedBox(height: 16),
              Row(
                children: [
                  Expanded(
                    child: ElevatedButton(
                      onPressed: () async {
                        Navigator.of(context).pop(false);
                      },
                      child: const Text('Cancel'),
                    ),
                  ),
                  const SizedBox(width: 12),
                  Expanded(
                    child: ElevatedButton(
                      onPressed: () async {
                        Navigator.of(context).pop(true);
                      },
                      child: const Text('Confirm'),
                    ),
                  ),
                ],
              )
            ],
          ),
        );
      },
    );
    return status ?? false;
  }

  Future<String> _onSignTransaction(
      NetworkSupport network, JsTransaction transaction) async {
    /// if user reject
    throw const UserRejectException();
    // try {
    //   final tx = Transaction(
    //     from: EthereumAddress.fromHex(transaction.from),
    //     data: hexToBytes(transaction.data),
    //     value: EtherAmount.fromBase10String(EtherUnit.wei, transaction.value ?? '0'),
    //     to: EthereumAddress.fromHex(transaction.to),
    //     maxGas: 61931, /// mock or transaction.gas
    //   );
    //   final client = Web3Client(network.rpcUrl, http.Client());
    //   final hash = await client.sendTransaction(
    //     EthPrivateKey.fromHex(_privateKey),
    //     tx,
    //     chainId: network.chainId,
    //   );
    //   return hash;
    // } on RPCError catch(e) {
    //   throw RpcException(e.errorCode, e.message);
    // } catch(e) {
    //   rethrow;
    // }
  }

  Future<String> _onSignMessage(String type, String message) async {
    bool isAccept = await _confirmSignMessage(type, message);
    if (!isAccept) {
      // user reject
      throw const UserRejectException();
    }
    String signature = EthSigUtil.signMessage(
      privateKey: _privateKey,
      message: hexToBytes(message),
    );
    return signature;
  }

  Future<String> _onSignPersonalMessage(String type, String message) async {
    bool isAccept = await _confirmSignMessage(type, message);
    if (!isAccept) {
      // user reject
      throw const UserRejectException();
    }
    String signature = EthSigUtil.signPersonalMessage(
      privateKey: _privateKey,
      message: hexToBytes(message),
    );
    return signature;
  }

  Future<String> _onSignTypeMessage(String type, JsSignTypeData data) async {
    bool isAccept = await _confirmSignMessage(type, data.raw);
    if (!isAccept) {
      // user reject
      throw const UserRejectException();
    }
    TypedDataVersion? version;
    switch (data.version) {
      case 'V1':
        version = TypedDataVersion.V1;
        break;
      case 'V3':
        version = TypedDataVersion.V3;
        break;
      case 'V4':
        version = TypedDataVersion.V4;
        break;
      default:
        break;
    }
    if (version == null) {
      throw const InvalidInputException();
    }
    final String signature = EthSigUtil.signTypedData(
      privateKey: _privateKey,
      jsonData: data.raw,
      version: version,
    );
    return signature;
  }
}
0
likes
0
points
18
downloads

Publisher

unverified uploader

Weekly Downloads

Support DApp Injected on Ethereum network - EIP155

Homepage
Repository (GitHub)
View/report issues

License

unknown (license)

Dependencies

flutter, flutter_inappwebview

More

Packages that depend on dapp_injected_eip155