You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter DApp中通过Web3钱包签名部署合约的实现方法咨询

问题描述

我开发了一个Flutter DApp,希望部署使用web3dart库创建的HTLC合约。当前部署合约的代码依赖私钥签名,但我不想管理私钥,希望通过MetaMask这类钱包完成交易签名后再发送。目前已通过flutter_web3实现了Web3钱包连接,请问如何修改代码实现钱包签名部署合约?

现有部署合约代码:

import 'dart:convert';
import 'dart:developer';
import 'package:flutter/services.dart';
import 'package:http/http.dart';
import 'package:web3dart/web3dart.dart';

class HTLCEthContract {
  final String apiUrl = 'http://127.0.0.1:7545';

  Future<void> deployHTLC(
    String privateKey,
    String contractAddress,
    String recipientAddress,
    String hash,
    BigInt amount, {
    int lockTime = 720,
    int chainId = 1337,
  }) async {

    final privateKey = ''; // REPLACE WITH WALLET SIGNATURE

    final web3Client = Web3Client(apiUrl, Client());
    final credentials = EthPrivateKey.fromHex(privateKey);

    final abiStringFile =
        await rootBundle.loadString('truffle/build/contracts/HTLC_ETH.json');
    final jsonAbi = jsonDecode(abiStringFile);
    final contract = DeployedContract(
      jsonAbi,
      EthereumAddress.fromHex(contractAddress),
    );

    final transaction = Transaction.callContract(
      contract: contract,
      function: contract.function('constructor'),
      parameters: [
        EthereumAddress.fromHex(recipientAddress),
        EthereumAddress.fromHex(contractAddress),
        EtherAmount.fromBigInt(EtherUnit.ether, amount),
        hash,
        BigInt.from(lockTime),
      ],
    );

    final transactionHash = await web3Client.sendTransaction(
      credentials,
      transaction,
      chainId: chainId,
    );
    final receipt = await web3Client.getTransactionReceipt(transactionHash);

    log('HTLC contract deployed at ${receipt!.contractAddress!.hex}');
  }
}

现有钱包连接代码:

import 'package:flutter/cupertino.dart';
import 'package:flutter_web3/flutter_web3.dart';

class MetaMaskProvider extends ChangeNotifier {
  static const operatingChain = 4;

  String currentAddress = '';

  String account = '';

  int currentChain = -1;

  bool get isEnabled => ethereum != null;

  bool get isInOperatingChain => currentChain == operatingChain;

  bool get isConnected => isEnabled && currentAddress.isNotEmpty;

  late final Web3Provider web3Provider;

  MetaMaskProvider() {
    if (isEnabled) {
      web3Provider = Web3Provider.fromEthereum(ethereum!);
    }
  }

  Future<void> connect() async {
    if (isEnabled) {
      final accs = await ethereum!.requestAccount();
      account = accs[0];

      if (accs.isNotEmpty) currentAddress = accs.first;

      currentChain = await ethereum!.getChainId();

      notifyListeners();
    }
  }

  Future<void> changeChainId(int chainId) async {
    if (isEnabled && isConnected) {
      await ethereum!.walletSwitchChain(chainId);
    }
  }

  void clear() {
    currentAddress = '';
    currentChain = -1;
    notifyListeners();
  }

  void init() {
    if (isEnabled) {
      ethereum!.onAccountsChanged((accounts) {
        clear();
      });
      ethereum!.onChainChanged((chainId) {
        clear();
      });
      ethereum!.onDisconnect((error) {
        clear();
      });
    }
  }
}
解决方案

要实现钱包签名合约部署,核心是通过flutter_web3的Web3Provider直接构造并发送合约创建交易,无需web3dart的私钥签名逻辑。以下是具体修改步骤:

1. 修正核心逻辑错误

你当前代码中用Transaction.callContract调用constructor是错误的——合约部署不是调用已部署合约的方法,而是发送一个无to地址、包含合约字节码+构造参数编码的交易。需要从ABI文件中提取合约字节码。

2. 整合flutter_web3实现签名部署

修改HTLCEthContract类,依赖已连接的MetaMaskProvider完成交易:

import 'dart:convert';
import 'dart:developer';
import 'package:flutter/services.dart';
import 'package:flutter_web3/flutter_web3.dart';
import 'package:web3dart/web3dart.dart';

class HTLCEthContract {
  final MetaMaskProvider metaMaskProvider;

  HTLCEthContract(this.metaMaskProvider);

  Future<void> deployHTLC(
    String recipientAddress,
    String hash,
    BigInt amount, {
    int lockTime = 720,
  }) async {
    // 检查钱包连接状态
    if (!metaMaskProvider.isConnected) {
      throw Exception('请先连接MetaMask钱包');
    }
    if (!metaMaskProvider.isInOperatingChain) {
      throw Exception('请切换到目标链(链ID:${MetaMaskProvider.operatingChain})');
    }

    // 加载合约ABI和字节码
    final abiStringFile = await rootBundle.loadString('truffle/build/contracts/HTLC_ETH.json');
    final jsonAbi = jsonDecode(abiStringFile);
    final contractAbi = jsonAbi['abi'];
    final contractBytecode = jsonAbi['bytecode'];

    // 用web3dart编码构造函数参数
    final web3Contract = DeployedContract(
      ContractAbi.fromJson(jsonEncode(contractAbi), 'HTLC_ETH'),
      EthereumAddress.fromHex('0x0000000000000000000000000000000000000000'),
    );
    final constructor = web3Contract.function('constructor');
    // 注意:请根据你的HTLC合约实际构造函数参数调整顺序和类型
    final encodedParams = constructor.encodeCall([
      EthereumAddress.fromHex(recipientAddress),
      hash,
      amount, // 直接传wei单位的金额,根据合约定义调整
      BigInt.from(lockTime),
    ]);

    // 拼接字节码和编码后的参数
    final transactionData = contractBytecode + encodedParams.replaceFirst('0x', '');

    // 通过MetaMask发送交易(自动触发钱包签名)
    try {
      final txHash = await metaMaskProvider.web3Provider.sendTransaction({
        'from': metaMaskProvider.currentAddress,
        'data': transactionData,
        'value': '0x${amount.toRadixString(16)}', // 如果合约需要接收ETH,填写对应wei的十六进制
      });

      // 等待交易上链,获取合约地址
      final receipt = await metaMaskProvider.web3Provider.getTransactionReceipt(txHash);
      if (receipt != null && receipt.contractAddress != null) {
        log('HTLC合约部署完成,地址:${receipt.contractAddress}');
      } else {
        log('合约部署失败,未获取到合约地址');
      }
    } catch (e) {
      log('交易处理失败:$e');
      rethrow;
    }
  }
}

3. 关键注意事项

  • 构造参数校验:务必对照你的HTLC合约实际构造函数参数调整encodeCall的参数,之前代码中传入contractAddress作为构造参数大概率是错误的。
  • 金额单位:如果合约接收ETH,value字段需要传入wei单位的十六进制字符串,避免单位错误。
  • 异常处理:调用前检查钱包连接状态和链ID,处理用户拒绝签名、交易失败等异常。

4. 调用示例

在UI逻辑中,通过已连接的MetaMaskProvider实例调用部署方法:

// 假设已通过metaMaskProvider.connect()连接钱包
final htlcContract = HTLCEthContract(metaMaskProvider);
try {
  await htlcContract.deployHTLC(
    '0x你的接收方地址',
    '0x哈希值',
    BigInt.from(1000000000000000000), // 1 ETH(wei单位)
  );
} catch (e) {
  // 处理错误,比如弹窗提示用户
}

内容的提问来源于stack exchange,提问作者redDwarf

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.16 17:34:50