Skip to content

Commit

Permalink
use assumeInteractiveReceiver + add comments for non-interactive use
Browse files Browse the repository at this point in the history
  • Loading branch information
kumulynja committed Jun 24, 2024
1 parent 14dcc6c commit 2a80763
Showing 1 changed file with 32 additions and 8 deletions.
40 changes: 32 additions & 8 deletions example/lib/payjoin_library.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import 'dart:typed_data';
import 'package:flutter/cupertino.dart';
import 'package:payjoin_flutter/common.dart' as common;
import 'package:payjoin_flutter/receive/v1.dart' as v1;
import 'package:payjoin_flutter/receive/v2.dart';
import 'package:payjoin_flutter/send.dart' as send;
import 'package:payjoin_flutter/uri.dart' as pj_uri;

Expand Down Expand Up @@ -33,19 +34,42 @@ class PayJoinLibrary {
});
final unchecked = await v1.UncheckedProposal.fromRequest(
body: body.toList(), query: '', headers: headers);
final provisionalProposal = await handleUnckedProposal(unchecked, isOwned);
final provisionalProposal =
await handleUncheckedProposal(unchecked, isOwned);
return provisionalProposal;
}

Future<v1.ProvisionalProposal> handleUnckedProposal(
Future<v1.ProvisionalProposal> handleUncheckedProposal(
v1.UncheckedProposal uncheckedProposal,
Future<bool> Function(Uint8List) isOwned) async {
// in a payment processor where the sender could go offline, this is where you schedule to broadcast the original_tx
var _ = await uncheckedProposal.extractTxToScheduleBroadcast();
final inputsOwned = await uncheckedProposal.checkBroadcastSuitability(
canBroadcast: (e) async {
return true;
});
// A consumer wallet has some manual interaction to initiate a payjoin, it
// is not a server that can receive a lot of requests without the user
// being aware of it. Therefore we say a consumer wallet app is an
// interactive receiver and an automatic payment processor is
// non-interactive.
//
// The way to check a proposal for these cases are different:
// - For an interactive receiver, you can just call
// `assumeInteractiveReceiver` as used here in the example code.
// - For a non-interactive receiver, you would extract the original tx
// with `extractTxToScheduleBroadcast` and check if it can be
// broadcasted in `checkBroadcastSuitability`. This way, if the sender
// doesn't complete the payjoin, you can still broadcast the original
// tx and get your funds. This protects against sender maliciousness of
// probing your utxo set amongst other things.

final inputsOwned = await uncheckedProposal.assumeInteractiveReceiver();
/*
// Non-interactive receiver example code:
final originalTx = await uncheckedProposal.extractTxToScheduleBroadcast();
final inputsOwned = await uncheckedProposal.checkBroadcastSuitability(
canBroadcast: (e) async {
// Here you would check if the original tx is a valid tx that pays you
// and that can be broadcasted.
return true;
});
*/

// Receive Check 2: receiver can't sign for proposal inputs
final mixedInputScripts =
await inputsOwned.checkInputsNotOwned(isOwned: isOwned);
Expand Down

0 comments on commit 2a80763

Please sign in to comment.