Skip to content

Commit

Permalink
Merge pull request #14 from LtbLightning/upgrade-v0.18
Browse files Browse the repository at this point in the history
Upgrade v0.18
  • Loading branch information
BitcoinZavior authored Jul 19, 2024
2 parents 21c5e10 + 546c71b commit 8e51e90
Show file tree
Hide file tree
Showing 47 changed files with 13,283 additions and 12,031 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/precompile_binaries.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
on:
push:
branches: [v0.13, main]
branches: [upgrade-v0.18, main]

name: Precompile Binaries

Expand Down
90 changes: 46 additions & 44 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,47 +1,49 @@
## [0.13.0-dev.2]

### Fixed

- Fix `assumeInteractiveReceiver` return type

### Refactor

- Separate receiver and sender logic in example app.

## [0.13.0-dev.1]

## [0.18.0]
Updated `flutter_rust_bridge` to `2.0.0`.
#### APIs added
- Exposed `PjUriBuilder` and `PjUri`.
- Exposed `pjUrlBuilder()` in `ActiveSession`.
- Exposed `checkPjSupported()` in `PjUri`.
- Exposed `fetchOhttpKeys()` to fetch the `ohttp` keys from the specified `payjoin` directory.
#### APIs changed
- Upgrade `receive/v2` type state machine to resume multiple `payjoins` simultaneously ([#283](https://github.com/payjoin/rust-payjoin/pull/283))
- Refactor output substitution with new fallable `try_substitute_outputs` ([#277](https://github.com/payjoin/rust-payjoin/pull/277))
- `Enroller` became `SessionInitializer`.
- `Enrolled` became `ActiveSession`.
- `fallbackTarget()` became `pjUrl()`.

#### Fixed
- Handle OHTTP encapsulated response status ([#284](https://github.com/payjoin/rust-payjoin/pull/284))

## [0.13.0]
### Features & Modules

#### Send module

- ##### V1
- `RequestBuilder` exposes `fromPsbtAndUri`, `buildWithAdditionalFee`, `buildRecommended`, `buildNonIncentivizing`, `alwaysDisableOutputSubstitution`.
- `RequestContext` exposes `extractContextV1` & `extractContextV2`.
- `ContextV1` exposes `processResponse`.
- ##### V2
- `ContextV2` exposes `processResponse`.

- ##### V1
- `RequestBuilder` exposes `fromPsbtAndUri`, `buildWithAdditionalFee`, `buildRecommended`, `buildNonIncentivizing`, `alwaysDisableOutputSubstitution`.
- `RequestContext` exposes `extractContextV1` & `extractContextV2`.
- `ContextV1` exposes `processResponse`.
- ##### V2
- `ContextV2` exposes `processResponse`.
#### Receive module

- ##### V1
- `UncheckedProposal` exposes `fromRequest`, `extractTxToScheduleBroadcast`, `checkBroadcastSuitability`, `buildNonIncentivizing`,
`assumeInteractiveReceiver` &`alwaysDisableOutputSubstitution`.
- `MaybeInputsOwned` exposes `checkInputsNotOwned`.
- `MaybeMixedInputScripts` exposes `checkNoMixedInputScripts`.
- `MaybeInputsSeen` exposes `checkNoInputsSeenBefore`.
- `OutputsUnknown` exposes `identifyReceiverOutputs`.
- `ProvisionalProposal` exposes `substituteOutputAddress`, `contributeNonWitnessInput`, `contributeWitnessInput`, `tryPreservingPrivacy` &
`finalizeProposal`.
- `PayjoinProposal` exposes `isOutputSubstitutionDisabled`, `ownedVouts`, `psbt` & `utxosToBeLocked`.
- ##### V2
- `Enroller` exposes `fromDirectoryConfig`, `processResponse` & `extractRequest`.
- `Enrolled` exposes `extractRequest`, `processResponse` & `fallbackTarget`.
- `UncheckedProposal` exposes `extractTxToScheduleBroadcast`, `checkBroadcastSuitability` & `assumeInteractiveReceiver`.
- `MaybeInputsOwned` exposes `checkInputsNotOwned`.
- `MaybeMixedInputScripts` exposes `checkNoMixedInputScripts`.
- `MaybeInputsSeen` exposes `checkNoInputsSeenBefore`.
- `OutputsUnknown` exposes `identifyReceiverOutputs`.
- `ProvisionalProposal` exposes `substituteOutputAddress`, `contributeNonWitnessInput`, `contributeWitnessInput`, `tryPreservingPrivacy` &
`finalizeProposal`.
- `PayjoinProposal` exposes `deserializeRes`, `extractV1Req`, `extractV2Request`, `isOutputSubstitutionDisabled`, `ownedVouts`, `psbt` &
`utxosToBeLocked`.
- ##### V1
- `UncheckedProposal` exposes `fromRequest`, `extractTxToScheduleBroadcast`, `checkBroadcastSuitability`, `buildNonIncentivizing`,
`assumeInteractiveReceiver` &`alwaysDisableOutputSubstitution`.
- `MaybeInputsOwned` exposes `checkInputsNotOwned`.
- `MaybeMixedInputScripts` exposes `checkNoMixedInputScripts`.
- `MaybeInputsSeen` exposes `checkNoInputsSeenBefore`.
- `OutputsUnknown` exposes `identifyReceiverOutputs`.
- `ProvisionalProposal` exposes `substituteOutputAddress`, `contributeNonWitnessInput`, `contributeWitnessInput`, `tryPreservingPrivacy` &
`finalizeProposal`.
- `PayjoinProposal` exposes `isOutputSubstitutionDisabled`, `ownedVouts`, `psbt` & `utxosToBeLocked`.
- ##### V2
- `Enroller` exposes `fromDirectoryConfig`, `processResponse` & `extractRequest`.
- `Enrolled` exposes `extractRequest`, `processResponse` & `fallbackTarget`.
- `UncheckedProposal` exposes `extractTxToScheduleBroadcast`, `checkBroadcastSuitability` & `assumeInteractiveReceiver`.
- `MaybeInputsOwned` exposes `checkInputsNotOwned`.
- `MaybeMixedInputScripts` exposes `checkNoMixedInputScripts`.
- `MaybeInputsSeen` exposes `checkNoInputsSeenBefore`.
- `OutputsUnknown` exposes `identifyReceiverOutputs`.
- `ProvisionalProposal` exposes `substituteOutputAddress`, `contributeNonWitnessInput`, `contributeWitnessInput`, `tryPreservingPrivacy` &
`finalizeProposal`.
- `PayjoinProposal` exposes `deserializeRes`, `extractV1Req`, `extractV2Request`, `isOutputSubstitutionDisabled`, `ownedVouts`, `psbt` &
`utxosToBeLocked`.
6 changes: 1 addition & 5 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -1,5 +1 @@
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
TODO: Add your license here.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ To use the `payjoin_flutter` package in your project, add it as a dependency in

```dart
dependencies:
payjoin_flutter: 0.13.0
payjoin_flutter: 0.18.0
```
### Requirements

Expand Down
52 changes: 25 additions & 27 deletions example/integration_test/bdk_full_cycle_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -20,48 +20,48 @@ void main() {
final btcClient = BtcClient("sender");
await btcClient.loadWallet();
final sender = BdkClient(
"wpkh(tprv8ZgxMBicQKsPfNH1PykMg16TAvrZgoxDnxr3eorcbhvZxyZzStwFkvqCJegr8Gbwj3GQum8QpXQPh7DGkoobpTB7YbcnUeUSKRDyX2cNN9h/84'/1'/0'/0/*)#ey7hlgpn");
"wpkh(tprv8ZgxMBicQKsPfNH1PykMg16TAvrZgoxDnxr3eorcbhvZxyZzStwFkvqCJegr8Gbwj3GQum8QpXQPh7DGkoobpTB7YbcnUeUSKRDyX2cNN9h/84'/1'/0'/0/*)#ey7hlgpn",
Network.regtest);
final receiver = BdkClient(
"wpkh(tprv8ZgxMBicQKsPczV7D2zfMr7oUzHDhNPEuBUgrwRoWM3ijLRvhG87xYiqh9JFLPqojuhmqwMdo1oJzbe5GUpxCbDHnqyGhQa5Jg1Wt6rc9di/84'/1'/0'/0/*)#kdnuw5lq");
"wpkh(tprv8ZgxMBicQKsPczV7D2zfMr7oUzHDhNPEuBUgrwRoWM3ijLRvhG87xYiqh9JFLPqojuhmqwMdo1oJzbe5GUpxCbDHnqyGhQa5Jg1Wt6rc9di/84'/1'/0'/0/*)#kdnuw5lq",
Network.regtest);
await sender.restoreWallet();
await receiver.restoreWallet();
// Receiver creates the payjoin URI
final pjReceiverAddress = (await receiver.getNewAddress()).address;
final pjSenderAddress = (await sender.getNewAddress()).address;
await btcClient.sendToAddress(await pjSenderAddress.asString(), 1);
await btcClient.sendToAddress(await pjReceiverAddress.asString(), 1);
await btcClient.generate(11, await pjSenderAddress.asString());
final pjReceiverAddress = receiver.getNewAddress().address;
final pjSenderAddress = sender.getNewAddress().address;
await btcClient.sendToAddress(pjSenderAddress.toString(), 1);
await btcClient.sendToAddress(pjReceiverAddress.toString(), 1);
await btcClient.generate(11, pjSenderAddress.toString());
await receiver.syncWallet();
await sender.syncWallet();
// Sender create a funded PSBT (not broadcast) to address with amount given in the pjUri
debugPrint("Sender Balance: ${(await sender.getBalance()).toString()}");
debugPrint("Sender Balance: ${sender.getBalance().toString()}");
final uri = await pay_join_uri.Uri.fromString(
"${await pjReceiverAddress.toQrUri()}?amount=${0.0083285}&pj=https://example.com");
final address = await uri.address();
int amount = (((await uri.amount()) ?? 0) * 100000000).toInt();
"${pjReceiverAddress.toQrUri()}?amount=${0.0083285}&pj=https://example.com");
final address = uri.address();
int amount = (((uri.amount()) ?? 0) * 100000000).toInt();

final senderPsbt = (await sender.createPsbt(address, amount, 2000));
final senderPsbtBase64 = await senderPsbt.serialize();
final senderPsbtBase64 = senderPsbt.toString();
debugPrint(
"\nOriginal sender psbt: $senderPsbtBase64",
);

// Receiver part
final (req, ctx) = await (await (await send.RequestBuilder.fromPsbtAndUri(
psbtBase64: senderPsbtBase64, uri: uri))
psbtBase64: senderPsbtBase64, pjUri: uri.checkPjSupported()))
.buildWithAdditionalFee(
maxFeeContribution: 10000,
minFeeRate: 0,
maxFeeContribution: BigInt.from(10000),
minFeeRate: BigInt.zero,
clampFeeContribution: false))
.extractContextV1();
final headers = common.Headers(map: {
'content-type': 'text/plain',
'content-length': req.body.length.toString(),
});
final uncheckedProposal = await v1.UncheckedProposal.fromRequest(
body: req.body.toList(),
query: (await req.url.query())!,
headers: headers);
body: req.body.toList(), query: (req.url.query())!, headers: headers);
// 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(
Expand All @@ -71,7 +71,7 @@ void main() {
// Receive Check 2: receiver can't sign for proposal inputs
final mixedInputScripts =
await inputsOwned.checkInputsNotOwned(isOwned: (e) async {
return await receiver.getAddressInfo(ScriptBuf(bytes: e));
return receiver.getAddressInfo(ScriptBuf(bytes: e));
});

// Receive Check 3: receiver can't sign for proposal inputs
Expand All @@ -82,11 +82,11 @@ void main() {
return false;
}))
.identifyReceiverOutputs(isReceiverOutput: (e) async {
return await receiver.getAddressInfo(ScriptBuf(bytes: e));
return receiver.getAddressInfo(ScriptBuf(bytes: e));
});
final unspent = await receiver.listUnspent();
final unspent = receiver.listUnspent();
// Select receiver payjoin inputs.
Map<int, common.OutPoint> candidateInputs = {
Map<BigInt, common.OutPoint> candidateInputs = {
for (var input in unspent)
input.txout.value: common.OutPoint(
txid: input.outpoint.txid.toString(), vout: input.outpoint.vout)
Expand All @@ -109,15 +109,13 @@ void main() {
);
await provisionalProposal.contributeWitnessInput(
txo: txoToContribute, outpoint: outpointToContribute);
final receiverAddress = (await receiver.getNewAddress()).address;
await provisionalProposal.substituteOutputAddress(
address: await receiverAddress.asString());

final payJoinProposal =
await provisionalProposal.finalizeProposal(processPsbt: (e) async {
debugPrint("\n Original receiver unsigned psbt: $e");
return await (await receiver
return (await receiver
.signPsbt(await PartiallySignedTransaction.fromString(e)))
.serialize();
.toString();
});
final receiverPsbt = await payJoinProposal.psbt();
debugPrint("\n Original receiver psbt: $receiverPsbt");
Expand Down
19 changes: 6 additions & 13 deletions example/integration_test/bitcoin_core_full_cycle_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import 'package:flutter/cupertino.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import 'package:payjoin_flutter/common.dart' as common;
import 'package:payjoin_flutter/send.dart';
import 'package:payjoin_flutter/uri.dart' as pay_join_uri;
import 'package:payjoin_flutter_example/btc_client.dart';
import 'package:payjoin_flutter_example/payjoin_library.dart';
Expand Down Expand Up @@ -36,15 +35,11 @@ void main() {
final amount = await uri.amount();
final senderPsbt =
(await sender.walletCreateFundedPsbt(amount, address, 2000))["psbt"];
final requestContext = await (await RequestBuilder.fromPsbtAndUri(
psbtBase64: senderPsbt, uri: uri))
.buildRecommended(minFeeRate: 0);
final (_, ctx) = await requestContext.extractContextV1();
debugPrint(
"\nOriginal sender psbt: $senderPsbt",
);
final provisionalProposal =
await payJoinLib.handlePjRequest(senderPsbt, (e) async {
final (provisionalProposal, ctx) =
await payJoinLib.handlePjRequest(senderPsbt, pjUri, (e) async {
final script = ScriptBuf(bytes: e);
final address = await (await Address.fromScript(
script: script, network: Network.regtest))
Expand All @@ -53,9 +48,9 @@ void main() {
});
final availableInputs = await receiver.listUnspent([]);
// Select receiver payjoin inputs.
Map<int, common.OutPoint> candidateInputs = {};
Map<BigInt, common.OutPoint> candidateInputs = {};
for (var e in availableInputs) {
int amount = (e["amount"] * 100000000).toInt();
var amount = BigInt.from(e["amount"] * 100000000);
candidateInputs[amount] =
common.OutPoint(txid: e["txid"], vout: e["vout"]);
}
Expand All @@ -67,7 +62,8 @@ void main() {
(e["vout"] == selectedOutpoint.vout));
final selectedUtxoScriptPubKey =
await ScriptBuf.fromHex(selectedUtxo["scriptPubKey"]);
int selectedUtxoAmount = (selectedUtxo["amount"] * 100000000).toInt();
final selectedUtxoAmount =
BigInt.from(selectedUtxo["amount"] * 100000000);
final txoutToContribute = common.TxOut(
scriptPubkey: selectedUtxoScriptPubKey.bytes,
value: selectedUtxoAmount,
Expand All @@ -76,9 +72,6 @@ void main() {
txid: selectedUtxo["txid"], vout: selectedUtxo["vout"]);
await provisionalProposal.contributeWitnessInput(
txo: txoutToContribute, outpoint: outputToContribute);
final newReceiverAddress = await receiver.getNewAddress();
await provisionalProposal.substituteOutputAddress(
address: newReceiverAddress);
final payJoinProposal =
await provisionalProposal.finalizeProposal(processPsbt: (e) async {
return (await receiver.walletProcessPsbt(e))["psbt"];
Expand Down
8 changes: 4 additions & 4 deletions example/ios/Podfile.lock
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
PODS:
- bdk_flutter (0.31.2-dev.1):
- bdk_flutter (0.31.2):
- Flutter
- Flutter (1.0.0)
- integration_test (0.0.1):
- Flutter
- path_provider_foundation (0.0.1):
- Flutter
- FlutterMacOS
- payjoin_flutter (0.0.1)
- payjoin_flutter (0.18.0)

DEPENDENCIES:
- bdk_flutter (from `.symlinks/plugins/bdk_flutter/ios`)
Expand All @@ -29,11 +29,11 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/payjoin_flutter/ios"

SPEC CHECKSUMS:
bdk_flutter: 1d889a00393def5bcd2be9cad91fa0c2a34fff7f
bdk_flutter: fb57a7400a7f3f181c5977bcdc2a5ef347ae4e7f
Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7
integration_test: ce0a3ffa1de96d1a89ca0ac26fca7ea18a749ef4
path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46
payjoin_flutter: 9011d8ef87f28bd66bcf80a21fdef14951b8a2aa
payjoin_flutter: 845f79d3e51d45e67842ee5df33ab492a1fd03cb

PODFILE CHECKSUM: a57f30d18f102dd3ce366b1d62a55ecbef2158e5

Expand Down
Loading

0 comments on commit 8e51e90

Please sign in to comment.