Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions Cargo-minimal.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2451,6 +2451,7 @@ dependencies = [
name = "payjoin-ffi"
version = "0.24.0"
dependencies = [
"async-trait",
"bdk",
"bitcoin-ohttp",
"getrandom 0.2.15",
Expand Down Expand Up @@ -4055,7 +4056,7 @@ dependencies = [
[[package]]
name = "uniffi-dart"
version = "0.1.0"
source = "git+https://github.com/Uniffi-Dart/uniffi-dart.git?rev=5bdcc79#5bdcc790c3fc99845e7b4a61d7a4f6e1460896e9"
source = "git+https://github.com/Uniffi-Dart/uniffi-dart.git?rev=f830323#f830323646fb6fbca89f9798dcf425f339f166ca"
dependencies = [
"anyhow",
"camino",
Expand Down Expand Up @@ -4125,7 +4126,7 @@ dependencies = [
[[package]]
name = "uniffi_dart_macro"
version = "0.1.0"
source = "git+https://github.com/Uniffi-Dart/uniffi-dart.git?rev=5bdcc79#5bdcc790c3fc99845e7b4a61d7a4f6e1460896e9"
source = "git+https://github.com/Uniffi-Dart/uniffi-dart.git?rev=f830323#f830323646fb6fbca89f9798dcf425f339f166ca"
dependencies = [
"futures",
"proc-macro2",
Expand Down
5 changes: 3 additions & 2 deletions Cargo-recent.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2451,6 +2451,7 @@ dependencies = [
name = "payjoin-ffi"
version = "0.24.0"
dependencies = [
"async-trait",
"bdk",
"bitcoin-ohttp",
"getrandom 0.2.15",
Expand Down Expand Up @@ -4055,7 +4056,7 @@ dependencies = [
[[package]]
name = "uniffi-dart"
version = "0.1.0"
source = "git+https://github.com/Uniffi-Dart/uniffi-dart.git?rev=5bdcc79#5bdcc790c3fc99845e7b4a61d7a4f6e1460896e9"
source = "git+https://github.com/Uniffi-Dart/uniffi-dart.git?rev=f830323#f830323646fb6fbca89f9798dcf425f339f166ca"
dependencies = [
"anyhow",
"camino",
Expand Down Expand Up @@ -4125,7 +4126,7 @@ dependencies = [
[[package]]
name = "uniffi_dart_macro"
version = "0.1.0"
source = "git+https://github.com/Uniffi-Dart/uniffi-dart.git?rev=5bdcc79#5bdcc790c3fc99845e7b4a61d7a4f6e1460896e9"
source = "git+https://github.com/Uniffi-Dart/uniffi-dart.git?rev=f830323#f830323646fb6fbca89f9798dcf425f339f166ca"
dependencies = [
"futures",
"proc-macro2",
Expand Down
3 changes: 2 additions & 1 deletion payjoin-ffi/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ name = "uniffi-bindgen"
path = "uniffi-bindgen.rs"

[dependencies]
async-trait = "0.1"
getrandom = "0.2"
lazy_static = "1.5.0"
ohttp = { package = "bitcoin-ohttp", version = "0.6.0" }
Expand All @@ -32,7 +33,7 @@ serde_json = "1.0.142"
thiserror = "2.0.14"
tokio = { version = "1.47.1", features = ["full"], optional = true }
uniffi = { version = "0.30.0", features = ["cli"] }
uniffi-dart = { git = "https://github.com/Uniffi-Dart/uniffi-dart.git", rev = "5bdcc79", optional = true }
uniffi-dart = { git = "https://github.com/Uniffi-Dart/uniffi-dart.git", rev = "f830323", optional = true }
url = "2.5.4"

# getrandom is ignored here because it's required by the wasm_js feature
Expand Down
100 changes: 100 additions & 0 deletions payjoin-ffi/dart/test/test_payjoin_unit_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,54 @@ class InMemorySenderPersister implements payjoin.JsonSenderSessionPersister {
}
}

class InMemoryReceiverPersisterAsync
implements payjoin.JsonReceiverSessionPersisterAsync {
final String id;
final List<String> events = [];
bool closed = false;

InMemoryReceiverPersisterAsync(this.id);

@override
Future<void> save(String event) async {
events.add(event);
}

@override
Future<List<String>> load() async {
return events;
}

@override
Future<void> close() async {
closed = true;
}
}

class InMemorySenderPersisterAsync
implements payjoin.JsonSenderSessionPersisterAsync {
final String id;
final List<String> events = [];
bool closed = false;

InMemorySenderPersisterAsync(this.id);

@override
Future<void> save(String event) async {
events.add(event);
}

@override
Future<List<String>> load() async {
return events;
}

@override
Future<void> close() async {
closed = true;
}
}

void main() {
group('Test URIs', () {
test('Test todo url encoded', () {
Expand Down Expand Up @@ -153,4 +201,56 @@ void main() {
);
});
});

group("Test Async Persistence", () {
test("Test receiver async persistence", () async {
var persister = InMemoryReceiverPersisterAsync("1");
await payjoin.ReceiverBuilder(
"tb1q6d3a2w975yny0asuvd9a67ner4nks58ff0q8g4",
"https://example.com",
payjoin.OhttpKeys.decode(
Uint8List.fromList(
hex.decode(
"01001604ba48c49c3d4a92a3ad00ecc63a024da10ced02180c73ec12d8a7ad2cc91bb483824fe2bee8d28bfe2eb2fc6453bc4d31cd851e8a6540e86c5382af588d370957000400010003",
),
),
),
).build().saveAsync(persister);
final result = await payjoin.replayReceiverEventLogAsync(persister);
expect(
result,
isA<payjoin.ReplayResult>(),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it possible to assert a specific state like we do in the other tests?

reason: "persistence should return a replay result",
);
});

test("Test sender async persistence", () async {
var receiver_persister = InMemoryReceiverPersisterAsync("1");
var receiver = await payjoin.ReceiverBuilder(
"2MuyMrZHkbHbfjudmKUy45dU4P17pjG2szK",
"https://example.com",
payjoin.OhttpKeys.decode(
Uint8List.fromList(
hex.decode(
"01001604ba48c49c3d4a92a3ad00ecc63a024da10ced02180c73ec12d8a7ad2cc91bb483824fe2bee8d28bfe2eb2fc6453bc4d31cd851e8a6540e86c5382af588d370957000400010003",
),
),
),
).build().saveAsync(receiver_persister);
var uri = receiver.pjUri();

var sender_persister = InMemorySenderPersisterAsync("1");
var psbt =
"cHNidP8BAHMCAAAAAY8nutGgJdyYGXWiBEb45Hoe9lWGbkxh/6bNiOJdCDuDAAAAAAD+////AtyVuAUAAAAAF6kUHehJ8GnSdBUOOv6ujXLrWmsJRDCHgIQeAAAAAAAXqRR3QJbbz0hnQ8IvQ0fptGn+votneofTAAAAAAEBIKgb1wUAAAAAF6kU3k4ekGHKWRNbA1rV5tR5kEVDVNCHAQcXFgAUx4pFclNVgo1WWAdN1SYNX8tphTABCGsCRzBEAiB8Q+A6dep+Rz92vhy26lT0AjZn4PRLi8Bf9qoB/CMk0wIgP/Rj2PWZ3gEjUkTlhDRNAQ0gXwTO7t9n+V14pZ6oljUBIQMVmsAaoNWHVMS02LfTSe0e388LNitPa1UQZyOihY+FFgABABYAFEb2Giu6c4KO5YW0pfw3lGp9jMUUAAA=";
final result = await payjoin.SenderBuilder(
psbt,
uri,
).buildRecommended(1000).saveAsync(sender_persister);
expect(
result,
isA<payjoin.WithReplyKey>(),
reason: "persistence should return a reply key",
);
});
});
}
2 changes: 1 addition & 1 deletion payjoin-ffi/javascript/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

118 changes: 118 additions & 0 deletions payjoin-ffi/javascript/test/unit.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,54 @@ class InMemorySenderPersister {
}
}

class InMemoryReceiverPersisterAsync {
id: number;
events: any[];
closed: boolean;

constructor(id: number) {
this.id = id;
this.events = [];
this.closed = false;
}

async save(event: any): Promise<void> {
this.events.push(event);
}

async load(): Promise<any[]> {
return this.events;
}

async close(): Promise<void> {
this.closed = true;
}
}

class InMemorySenderPersisterAsync {
id: number;
events: any[];
closed: boolean;

constructor(id: number) {
this.id = id;
this.events = [];
this.closed = false;
}

async save(event: any): Promise<void> {
this.events.push(event);
}

async load(): Promise<any[]> {
return this.events;
}

async close(): Promise<void> {
this.closed = true;
}
}

describe("URI tests", () => {
test("URL encoded payjoin parameter", () => {
const uri =
Expand Down Expand Up @@ -172,6 +220,76 @@ describe("Persistence tests", () => {
});
});

describe("Async Persistence tests", () => {
test("receiver async persistence", async () => {
const persister = new InMemoryReceiverPersisterAsync(1);
const address = "tb1q6d3a2w975yny0asuvd9a67ner4nks58ff0q8g4";
const ohttpKeys = payjoin.OhttpKeys.decode(
new Uint8Array([
0x01, 0x00, 0x16, 0x04, 0xba, 0x48, 0xc4, 0x9c, 0x3d, 0x4a,
0x92, 0xa3, 0xad, 0x00, 0xec, 0xc6, 0x3a, 0x02, 0x4d, 0xa1,
0x0c, 0xed, 0x02, 0x18, 0x0c, 0x73, 0xec, 0x12, 0xd8, 0xa7,
0xad, 0x2c, 0xc9, 0x1b, 0xb4, 0x83, 0x82, 0x4f, 0xe2, 0xbe,
0xe8, 0xd2, 0x8b, 0xfe, 0x2e, 0xb2, 0xfc, 0x64, 0x53, 0xbc,
0x4d, 0x31, 0xcd, 0x85, 0x1e, 0x8a, 0x65, 0x40, 0xe8, 0x6c,
0x53, 0x82, 0xaf, 0x58, 0x8d, 0x37, 0x09, 0x57, 0x00, 0x04,
0x00, 0x01, 0x00, 0x03,
]).buffer,
);

const builder = new payjoin.ReceiverBuilder(
address,
"https://example.com",
ohttpKeys,
);
await builder.build().saveAsync(persister);

const result = await payjoin.replayReceiverEventLogAsync(persister);
const state = result.state();

assert.strictEqual(
state.tag,
"Initialized",
"State should be Initialized",
);
});

test("sender async persistence", async () => {
const persister = new InMemoryReceiverPersisterAsync(1);
const address = "2MuyMrZHkbHbfjudmKUy45dU4P17pjG2szK";
const ohttpKeys = payjoin.OhttpKeys.decode(
new Uint8Array([
0x01, 0x00, 0x16, 0x04, 0xba, 0x48, 0xc4, 0x9c, 0x3d, 0x4a,
0x92, 0xa3, 0xad, 0x00, 0xec, 0xc6, 0x3a, 0x02, 0x4d, 0xa1,
0x0c, 0xed, 0x02, 0x18, 0x0c, 0x73, 0xec, 0x12, 0xd8, 0xa7,
0xad, 0x2c, 0xc9, 0x1b, 0xb4, 0x83, 0x82, 0x4f, 0xe2, 0xbe,
0xe8, 0xd2, 0x8b, 0xfe, 0x2e, 0xb2, 0xfc, 0x64, 0x53, 0xbc,
0x4d, 0x31, 0xcd, 0x85, 0x1e, 0x8a, 0x65, 0x40, 0xe8, 0x6c,
0x53, 0x82, 0xaf, 0x58, 0x8d, 0x37, 0x09, 0x57, 0x00, 0x04,
0x00, 0x01, 0x00, 0x03,
]).buffer,
);

const receiver = await new payjoin.ReceiverBuilder(
address,
"https://example.com",
ohttpKeys,
)
.build()
.saveAsync(persister);
const uri = receiver.pjUri();

const senderPersister = new InMemorySenderPersisterAsync(1);
const psbt =
"cHNidP8BAHMCAAAAAY8nutGgJdyYGXWiBEb45Hoe9lWGbkxh/6bNiOJdCDuDAAAAAAD+////AtyVuAUAAAAAF6kUHehJ8GnSdBUOOv6ujXLrWmsJRDCHgIQeAAAAAAAXqRR3QJbbz0hnQ8IvQ0fptGn+votneofTAAAAAAEBIKgb1wUAAAAAF6kU3k4ekGHKWRNbA1rV5tR5kEVDVNCHAQcXFgAUx4pFclNVgo1WWAdN1SYNX8tphTABCGsCRzBEAiB8Q+A6dep+Rz92vhy26lT0AjZn4PRLi8Bf9qoB/CMk0wIgP/Rj2PWZ3gEjUkTlhDRNAQ0gXwTO7t9n+V14pZ6oljUBIQMVmsAaoNWHVMS02LfTSe0e388LNitPa1UQZyOihY+FFgABABYAFEb2Giu6c4KO5YW0pfw3lGp9jMUUAAA=";
const withReplyKey = await new payjoin.SenderBuilder(psbt, uri)
.buildRecommended(BigInt(1000))
.saveAsync(senderPersister);

assert.ok(withReplyKey, "Sender should be created successfully");
});
});

describe("Validation", () => {
test("receiver builder rejects bad address", () => {
assert.throws(() => {
Expand Down
Loading
Loading