transfer method

Future<WalletTransferResult> transfer({
  1. required String sourceWalletId,
  2. required String destinationWalletId,
  3. int? amountMsat,
  4. Duration? timeout,
})

Transfers funds directly between two configured wallets.

BOLT11-capable wallets exchange a fresh invoice. A BOLT12-only receiver exposes its reusable offer and requires a BIP-321-capable sender.

Implementation

Future<WalletTransferResult> transfer({
  required String sourceWalletId,
  required String destinationWalletId,
  int? amountMsat,
  Duration? timeout,
}) async {
  await _initializationFuture;
  final source = await _getWalletForOperation(sourceWalletId);
  final destination = await _getWalletForOperation(destinationWalletId);
  final protocol = compatibleTransferProtocol(
    source: source,
    destination: destination,
  );
  if (protocol == null) {
    throw UnsupportedError(
      'The selected wallets have no compatible payment protocol',
    );
  }
  if (amountMsat != null && amountMsat <= 0) {
    throw ArgumentError.value(
      amountMsat,
      'amountMsat',
      'Transfer amount must be positive',
    );
  }
  if (protocol == WalletPaymentProtocol.bolt11 &&
      (amountMsat == null || amountMsat % 1000 != 0)) {
    throw ArgumentError.value(
      amountMsat,
      'amountMsat',
      'BOLT11 wallet transfers require a positive whole-satoshi amount',
    );
  }

  ReceiveResponse? receiveResponse;
  late final String payment;
  if (destination.supportsBip321Receive) {
    receiveResponse = await receiveBip321(
      walletId: destination.id,
      amountMsat: amountMsat,
      timeout: timeout,
    );
    payment = receiveResponse.bip321;
  } else {
    final invoice = await receive(
      walletId: destination.id,
      amountSats: amountMsat! ~/ 1000,
    );
    payment = Bip321.fromBolt11(invoice);
  }

  if (source.supportsBip321Pay) {
    final payResponse = await payBip321(
      walletId: source.id,
      payment: payment,
      amountMsat: amountMsat,
      timeout: timeout,
    );
    if (payResponse.errorCode != null || payResponse.state == 'failed') {
      throw StateError(
        payResponse.errorMessage ??
            payResponse.failureReason ??
            'Wallet transfer failed',
      );
    }
    final selectedProtocol = payResponse.instructionType == 'bolt12'
        ? WalletPaymentProtocol.bolt12
        : WalletPaymentProtocol.bolt11;
    await _refreshTransferredWalletData(source.id, destination.id);
    return WalletTransferResult(
      sourceWalletId: source.id,
      destinationWalletId: destination.id,
      protocol: selectedProtocol,
      payment: payment,
      receiveResponse: receiveResponse,
      payResponse: payResponse,
    );
  }

  final invoice = Bip321.getBolt11(payment);
  final payInvoiceResponse = await send(
    walletId: source.id,
    invoice: invoice,
    timeout: timeout,
  );
  if (payInvoiceResponse.errorCode != null) {
    throw StateError(
      payInvoiceResponse.errorMessage ?? 'Wallet transfer failed',
    );
  }
  await _refreshTransferredWalletData(source.id, destination.id);
  return WalletTransferResult(
    sourceWalletId: source.id,
    destinationWalletId: destination.id,
    protocol: WalletPaymentProtocol.bolt11,
    payment: payment,
    receiveResponse: receiveResponse,
    payInvoiceResponse: payInvoiceResponse,
  );
}