-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #7 from LtbLightning/Updates-v13
Updates for v13
- Loading branch information
Showing
51 changed files
with
4,947 additions
and
4,940 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,46 @@ | ||
# payjoin | ||
# Payjoin Flutter | ||
|
||
A Flutter library for the [Payjoin Dev Kit](https://payjoindevkit.org/). | ||
|
||
### How to Use | ||
|
||
To use the `payjoin_flutter` package in your project, add it as a dependency in your project's pubspec.yaml: | ||
|
||
```dart | ||
dependencies: | ||
payjoin_flutter: 0.13.0 | ||
``` | ||
### Requirements | ||
|
||
- Flutter : 3.0 or higher | ||
- Android minSdkVersion. : API 23 or higher. | ||
- Deployment target : iOS 12.0 or greater. | ||
|
||
### Build and run code | ||
|
||
Before building the code, we need to set up the Bitcoin core properly in the regtest network. If you "don't" | ||
have Bitcoin Core locally, please refer to this [page](https://learn.saylor.org/mod/page/view.php?id=36347). Or you can | ||
install `Nigiri Bitcoin`, which is a tool designed to simplify the process of running local instances of Bitcoin and | ||
Liquid networks for development and testing purposes. You can refer to | ||
this [link](https://github.com/vulpemventures/nigiri), to install it on your local machine. | ||
|
||
NB: The default credentials would be the following | ||
``` | ||
rpc_user = "admin1" | ||
rpc_password = "123" | ||
rpc_host = "localhost" | ||
rpc_port = "18443" | ||
``` | ||
## Running the integration tests | ||
Once we have set up the Bitcoin core properly in the `Regtest` network, | ||
|
||
```shell | ||
git clone https://github.com/LtbLightning/payjoin-flutter.git | ||
cd payjoin-flutter | ||
git checkout v0.13 | ||
|
||
cd example | ||
#Run integration tests with bitcoin_core and bdk_flutter | ||
flutter test integration_test | ||
``` | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -44,7 +44,7 @@ android { | |
} | ||
|
||
defaultConfig { | ||
minSdkVersion 19 | ||
minSdkVersion 23 | ||
} | ||
} | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
import 'dart:convert'; | ||
|
||
import 'package:bdk_flutter/bdk_flutter.dart'; | ||
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/uri.dart' as pay_join_uri; | ||
import 'package:payjoin_flutter_example/bdk_client.dart'; | ||
import 'package:payjoin_flutter_example/btc_client.dart'; | ||
import 'package:payjoin_flutter_example/payjoin_library.dart'; | ||
|
||
void main() { | ||
IntegrationTestWidgetsFlutterBinding.ensureInitialized(); | ||
|
||
group('v1_to_v1', () { | ||
setUp(() async {}); | ||
testWidgets('full_cycle', (WidgetTester tester) async { | ||
final payJoinLib = PayJoinLibrary(); | ||
final btcClient = BtcClient("sender"); | ||
await btcClient.loadWallet(); | ||
final sender = BdkClient( | ||
"puppy interest whip tonight dad never sudden response push zone pig patch"); | ||
final receiver = BdkClient( | ||
"cart super leaf clinic pistol plug replace close super tooth wealth usage"); | ||
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(), 10); | ||
await btcClient.sendToAddress(await pjReceiverAddress.asString(), 2); | ||
await btcClient.generate(11, await pjSenderAddress.asString()); | ||
await receiver.syncWallet(); | ||
await sender.syncWallet(); | ||
final pjUri = await payJoinLib.buildPjUri( | ||
0.0083285, await pjReceiverAddress.asString()); | ||
// Sender create a funded PSBT (not broadcast) to address with amount given in the pjUri | ||
debugPrint("Sender Balance: ${(await sender.getBalance()).toString()}"); | ||
final uri = await pay_join_uri.Uri.fromString(pjUri); | ||
final address = await uri.address(); | ||
int amount = (((await uri.amount()) ?? 0) * 100000000).toInt(); | ||
final senderPsbt = (await sender.createPsbt(address, amount, 2000)); | ||
final senderPsbtBase64 = await senderPsbt.serialize(); | ||
debugPrint( | ||
"\nOriginal sender psbt: $senderPsbtBase64", | ||
); | ||
// Receiver part | ||
final (provisionalProposal, ctx) = | ||
await payJoinLib.handlePjRequest(senderPsbtBase64, pjUri, (e) async { | ||
final script = ScriptBuf(bytes: e); | ||
return (await receiver.getAddressInfo(script)); | ||
}); | ||
final availableInputs = await receiver.listUnspent(); | ||
// Select receiver payjoin inputs. | ||
Map<int, common.OutPoint> candidateInputs = { | ||
for (var input in availableInputs) | ||
input.txout.value: common.OutPoint( | ||
txid: input.outpoint.txid.toString(), vout: input.outpoint.vout) | ||
}; | ||
final selectedOutpoint = await provisionalProposal.tryPreservingPrivacy( | ||
candidateInputs: candidateInputs); | ||
var selectedUtxo = availableInputs.firstWhere( | ||
(i) => | ||
i.outpoint.txid.toString() == selectedOutpoint.txid && | ||
i.outpoint.vout == selectedOutpoint.vout, | ||
orElse: () => throw Exception('UTXO not found')); | ||
var txoToContribute = common.TxOut( | ||
value: selectedUtxo.txout.value, | ||
scriptPubkey: selectedUtxo.txout.scriptPubkey.bytes, | ||
); | ||
|
||
var outpointToContribute = common.OutPoint( | ||
txid: selectedUtxo.outpoint.txid.toString(), | ||
vout: selectedUtxo.outpoint.vout, | ||
); | ||
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 { | ||
return await (await receiver | ||
.signPsbt(await PartiallySignedTransaction.fromString(e))) | ||
.serialize(); | ||
}); | ||
final receiverPsbt = await payJoinProposal.psbt(); | ||
debugPrint("\n Original receiver psbt: $receiverPsbt"); | ||
final receiverProcessedPsbt = | ||
await ctx.processResponse(response: utf8.encode(receiverPsbt)); | ||
final senderProcessedPsbt = (await sender.signPsbt( | ||
await PartiallySignedTransaction.fromString(receiverProcessedPsbt))); | ||
|
||
final txid = await sender.broadcastPsbt(senderProcessedPsbt); | ||
debugPrint("Broadcast success: $txid"); | ||
}); | ||
}); | ||
} |
93 changes: 93 additions & 0 deletions
93
example/integration_test/bitcoin_core_full_cycle_test.dart
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
import 'dart:convert'; | ||
|
||
import 'package:bdk_flutter/bdk_flutter.dart'; | ||
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/uri.dart' as pay_join_uri; | ||
import 'package:payjoin_flutter_example/btc_client.dart'; | ||
import 'package:payjoin_flutter_example/payjoin_library.dart'; | ||
|
||
void main() { | ||
IntegrationTestWidgetsFlutterBinding.ensureInitialized(); | ||
|
||
group('v1_to_v1', () { | ||
setUp(() async {}); | ||
testWidgets('full_cycle', (WidgetTester tester) async { | ||
final payJoinLib = PayJoinLibrary(); | ||
final sender = BtcClient("receiver"); | ||
final client = BtcClient(""); | ||
final receiver = BtcClient("sender"); | ||
// Receiver creates the payjoin URI | ||
final pjReceiverAddress = await receiver.getNewAddress(); | ||
final pjSenderAddress = await sender.getNewAddress(); | ||
//Generate blocks to receiver and sender | ||
await client.sendToAddress(pjSenderAddress, 10); | ||
await client.sendToAddress(pjReceiverAddress, 1); | ||
await sender.generate(11, pjSenderAddress); | ||
await receiver.generate(1, pjReceiverAddress); | ||
final pjUri = await payJoinLib.buildPjUri(0.0083285, pjReceiverAddress); | ||
// Sender create a funded PSBT (not broadcast) to address with amount given in the pjUri | ||
debugPrint("Sender Balance: ${(await sender.getBalance()).toString()}"); | ||
final uri = await pay_join_uri.Uri.fromString(pjUri); | ||
final address = await uri.address(); | ||
final amount = await uri.amount(); | ||
final senderPsbt = | ||
(await sender.walletCreateFundedPsbt(amount, address, 2000))["psbt"]; | ||
debugPrint( | ||
"\nOriginal sender psbt: $senderPsbt", | ||
); | ||
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)) | ||
.asString(); | ||
return (await receiver.getAddressInfo(address))["ismine"]; | ||
}); | ||
final availableInputs = await receiver.listUnspent([]); | ||
// Select receiver payjoin inputs. | ||
Map<int, common.OutPoint> candidateInputs = {}; | ||
for (var e in availableInputs) { | ||
int amount = (e["amount"] * 100000000).toInt(); | ||
candidateInputs[amount] = | ||
common.OutPoint(txid: e["txid"], vout: e["vout"]); | ||
} | ||
final selectedOutpoint = await provisionalProposal.tryPreservingPrivacy( | ||
candidateInputs: candidateInputs); | ||
|
||
final selectedUtxo = availableInputs.firstWhere((e) => | ||
(e["txid"] == selectedOutpoint.txid) && | ||
(e["vout"] == selectedOutpoint.vout)); | ||
final selectedUtxoScriptPubKey = | ||
await ScriptBuf.fromHex(selectedUtxo["scriptPubKey"]); | ||
int selectedUtxoAmount = (selectedUtxo["amount"] * 100000000).toInt(); | ||
final txoutToContribute = common.TxOut( | ||
scriptPubkey: selectedUtxoScriptPubKey.bytes, | ||
value: selectedUtxoAmount, | ||
); | ||
final outputToContribute = common.OutPoint( | ||
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"]; | ||
}); | ||
final receiverPsbt = await payJoinProposal.psbt(); | ||
debugPrint("\n Original receiver psbt: $receiverPsbt"); | ||
final receiverProcessedPsbt = | ||
await ctx.processResponse(response: utf8.encode(receiverPsbt)); | ||
final senderProcessedPsbt = | ||
(await sender.walletProcessPsbt(receiverProcessedPsbt))["psbt"]; | ||
final senderFinalizedPsbt = | ||
(await sender.finalizePsbt(senderProcessedPsbt)); | ||
final res = await sender.sendRawTransaction(senderFinalizedPsbt["hex"]); | ||
debugPrint("Broadcast success: $res"); | ||
}); | ||
}); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.