From 3277aceb9df060276044065429ccb216d8cdb52d Mon Sep 17 00:00:00 2001 From: BitcoinZavior Date: Wed, 17 Jul 2024 23:59:00 -0400 Subject: [PATCH 1/5] dependency upgraded --- Cargo.lock | 683 ++++++++++++++++++++++++++++++++++++++++------ Cargo.toml | 15 +- README.md | 2 +- python/README.md | 36 +-- src/error.rs | 11 +- src/io.rs | 25 ++ src/lib.rs | 8 +- src/receive/v1.rs | 46 ++-- src/receive/v2.rs | 222 ++++++++++----- src/send/v1.rs | 15 +- src/uri.rs | 148 +++++----- 11 files changed, 931 insertions(+), 280 deletions(-) create mode 100644 src/io.rs diff --git a/Cargo.lock b/Cargo.lock index 7f985c9..fb96797 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -123,7 +123,7 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b" dependencies = [ - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -133,7 +133,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "58f54d10c6dfa51283a066ceab3ec1ab78d13fae00aa49243a45e4571fb79dfd" dependencies = [ "anstyle", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -142,6 +142,12 @@ version = "1.0.75" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" +[[package]] +name = "arrayvec" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" + [[package]] name = "askama" version = "0.12.0" @@ -206,6 +212,16 @@ dependencies = [ "rustc-demangle", ] +[[package]] +name = "base58ck" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c8d66485a3a2ea485c1913c4572ce0256067a5377ac8c75c4960e1cda98605f" +dependencies = [ + "bitcoin-internals 0.3.0", + "bitcoin_hashes 0.14.0", +] + [[package]] name = "base64" version = "0.13.1" @@ -275,9 +291,9 @@ checksum = "d86b93f97252c47b41663388e6d155714a9d0c398b99f1005cbc5f978b29f445" [[package]] name = "bech32" -version = "0.10.0-beta" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98f7eed2b2781a6f0b5c903471d48e15f56fb4e1165df8a9a2337fd1a59d45ea" +checksum = "d965446196e3b7decd44aa7ee49e31d630118f90ef12f97900f262eb915c951d" [[package]] name = "bhttp" @@ -335,16 +351,19 @@ dependencies = [ [[package]] name = "bitcoin" -version = "0.31.2" +version = "0.32.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c85783c2fe40083ea54a33aa2f0ba58831d90fcd190f5bdc47e74e84d2a96ae" +checksum = "ea507acc1cd80fc084ace38544bbcf7ced7c2aa65b653b102de0ce718df668f6" dependencies = [ - "bech32 0.10.0-beta", - "bitcoin-internals 0.2.0", - "bitcoin_hashes 0.13.0", + "base58ck", + "bech32 0.11.0", + "bitcoin-internals 0.3.0", + "bitcoin-io", + "bitcoin-units", + "bitcoin_hashes 0.14.0", "hex-conservative", "hex_lit", - "secp256k1 0.28.2", + "secp256k1 0.29.0", "serde", ] @@ -356,19 +375,35 @@ checksum = "1f9997f8650dd818369931b5672a18dbef95324d0513aa99aae758de8ce86e5b" [[package]] name = "bitcoin-internals" -version = "0.2.0" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9425c3bf7089c983facbae04de54513cce73b41c7f9ff8c845b54e7bc64ebbfb" +checksum = "30bdbe14aa07b06e6cfeffc529a1f099e5fbe249524f8125358604df99a4bed2" dependencies = [ "serde", ] +[[package]] +name = "bitcoin-io" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "340e09e8399c7bd8912f495af6aa58bea0c9214773417ffaa8f6460f93aaee56" + [[package]] name = "bitcoin-private" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "73290177011694f38ec25e165d0387ab7ea749a4b81cd4c80dae5988229f7a57" +[[package]] +name = "bitcoin-units" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5285c8bcaa25876d07f37e3d30c303f2609179716e11d688f51e8f1fe70063e2" +dependencies = [ + "bitcoin-internals 0.3.0", + "serde", +] + [[package]] name = "bitcoin_hashes" version = "0.11.0" @@ -387,20 +422,20 @@ dependencies = [ [[package]] name = "bitcoin_hashes" -version = "0.13.0" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1930a4dabfebb8d7d9992db18ebe3ae2876f0a305fab206fd168df931ede293b" +checksum = "bb18c03d0db0247e147a21a6faafd5a7eb851c743db062de72018b6b7e8e4d16" dependencies = [ - "bitcoin-internals 0.2.0", + "bitcoin-io", "hex-conservative", "serde", ] [[package]] name = "bitcoincore-rpc" -version = "0.18.0" +version = "0.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8eb70725a621848c83b3809913d5314c0d20ca84877d99dd909504b564edab00" +checksum = "aedd23ae0fd321affb4bbbc36126c6f49a32818dc6b979395d24da8c9d4e80ee" dependencies = [ "bitcoincore-rpc-json", "jsonrpc", @@ -411,11 +446,11 @@ dependencies = [ [[package]] name = "bitcoincore-rpc-json" -version = "0.18.0" +version = "0.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "856ffbee2e492c23bca715d72ea34aae80d58400f2bda26a82015d6bc2ec3662" +checksum = "d8909583c5fab98508e80ef73e5592a651c954993dc6b7739963257d19f0e71a" dependencies = [ - "bitcoin 0.31.2", + "bitcoin 0.32.2", "serde", "serde_json", ] @@ -608,7 +643,7 @@ version = "4.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c9fd1a5729c4548118d7d70ff234a44868d00489a4b6597b0b020918a0e91a1a" dependencies = [ - "heck", + "heck 0.4.1", "proc-macro2", "quote", "syn 2.0.48", @@ -751,7 +786,7 @@ dependencies = [ "byteorder", "libc", "log", - "rustls", + "rustls 0.21.7", "serde", "serde_json", "webpki", @@ -782,6 +817,12 @@ dependencies = [ "miniz_oxide", ] +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + [[package]] name = "form_urlencoded" version = "1.2.1" @@ -807,6 +848,39 @@ dependencies = [ "winapi", ] +[[package]] +name = "futures-channel" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" +dependencies = [ + "futures-core", +] + +[[package]] +name = "futures-core" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" + +[[package]] +name = "futures-task" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" + +[[package]] +name = "futures-util" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" +dependencies = [ + "futures-core", + "futures-task", + "pin-project-lite", + "pin-utils", +] + [[package]] name = "fxhash" version = "0.2.1" @@ -886,6 +960,12 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + [[package]] name = "hex" version = "0.4.3" @@ -894,9 +974,12 @@ checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" [[package]] name = "hex-conservative" -version = "0.1.2" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "212ab92002354b4819390025006c897e8140934349e8635c9b077f47b4dcbd20" +checksum = "5313b072ce3c597065a808dbf612c4c8e8590bdbf8b579508bf7a762c5eae6cd" +dependencies = [ + "arrayvec", +] [[package]] name = "hex_lit" @@ -963,6 +1046,102 @@ dependencies = [ "zeroize", ] +[[package]] +name = "http" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http-body" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" +dependencies = [ + "bytes", + "http", +] + +[[package]] +name = "http-body-util" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f" +dependencies = [ + "bytes", + "futures-util", + "http", + "http-body", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fcc0b4a115bf80b728eb8ea024ad5bd707b615bfed49e0665b6e0f86fd082d9" + +[[package]] +name = "hyper" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50dfd22e0e76d0f662d429a5f80fcaf3855009297eab6a0a9f8543834744ba05" +dependencies = [ + "bytes", + "futures-channel", + "futures-util", + "http", + "http-body", + "httparse", + "itoa", + "pin-project-lite", + "smallvec", + "tokio", + "want", +] + +[[package]] +name = "hyper-rustls" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0bea761b46ae2b24eb4aef630d8d1c398157b6fc29e6350ecf090a0b70c952c" +dependencies = [ + "futures-util", + "http", + "hyper", + "hyper-util", + "rustls 0.22.4", + "rustls-pki-types", + "tokio", + "tokio-rustls", + "tower-service", +] + +[[package]] +name = "hyper-util" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ab92f4f49ee4fb4f997c784b7a2e0fa70050211e0b6a287f898c3c9785ca956" +dependencies = [ + "bytes", + "futures-channel", + "futures-util", + "http", + "http-body", + "hyper", + "pin-project-lite", + "socket2", + "tokio", + "tower", + "tower-service", + "tracing", +] + [[package]] name = "idna" version = "0.5.0" @@ -991,6 +1170,12 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "ipnet" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" + [[package]] name = "itoa" version = "1.0.9" @@ -1008,11 +1193,12 @@ dependencies = [ [[package]] name = "jsonrpc" -version = "0.14.1" +version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8128f36b47411cd3f044be8c1f5cc0c9e24d1d1bfdc45f0a57897b32513053f2" +checksum = "3662a38d341d77efecb73caf01420cfa5aa63c0253fd7bc05289ef9f6616e1bf" dependencies = [ "base64 0.13.1", + "minreq", "serde", "serde_json", ] @@ -1093,6 +1279,28 @@ dependencies = [ "adler", ] +[[package]] +name = "minreq" +version = "2.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fdef521c74c2884a4f3570bcdb6d2a77b3c533feb6b27ac2ae72673cc221c64" +dependencies = [ + "log", + "serde", + "serde_json", +] + +[[package]] +name = "mio" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" +dependencies = [ + "libc", + "wasi", + "windows-sys 0.48.0", +] + [[package]] name = "nom" version = "7.1.3" @@ -1141,12 +1349,6 @@ version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" -[[package]] -name = "oneshot-uniffi" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c548d5c78976f6955d72d0ced18c48ca07030f7a1d4024529fedd7c1c01b29c" - [[package]] name = "opaque-debug" version = "0.3.0" @@ -1186,15 +1388,18 @@ checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" [[package]] name = "payjoin" -version = "0.16.0" -source = "git+https://github.com/payjoin/rust-payjoin?rev=457a0dd5cb212ddd9ea169b7fa3842bfc3d5f373#457a0dd5cb212ddd9ea169b7fa3842bfc3d5f373" +version = "0.18.0" +source = "git+https://github.com/LtbLightning/rust-payjoin?branch=clone-pj-uri-builder#3b5bda95fc8ce63f506538f0ff9daed885810488" dependencies = [ "bhttp", "bip21", "bitcoin 0.30.1", "chacha20poly1305 0.10.1", + "http", "log", "ohttp", + "reqwest", + "rustls 0.22.4", "serde", "serde_json", "url", @@ -1202,7 +1407,7 @@ dependencies = [ [[package]] name = "payjoin_ffi" -version = "0.13.0" +version = "0.18.0" dependencies = [ "base64 0.22.1", "bdk", @@ -1227,12 +1432,38 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3637c05577168127568a64e9dc5a6887da720efef07b3d9472d45f63ab191166" +[[package]] +name = "pin-project" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6bf43b791c5b9e34c3d182969b4abb522f9343702850a2e57f460d00d09b4b3" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.48", +] + [[package]] name = "pin-project-lite" version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + [[package]] name = "plain" version = "0.2.3" @@ -1354,6 +1585,47 @@ dependencies = [ "bitflags", ] +[[package]] +name = "reqwest" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "566cafdd92868e0939d3fb961bd0dc25fcfaaed179291093b3d43e6b3150ea10" +dependencies = [ + "base64 0.22.1", + "bytes", + "futures-core", + "futures-util", + "http", + "http-body", + "http-body-util", + "hyper", + "hyper-rustls", + "hyper-util", + "ipnet", + "js-sys", + "log", + "mime", + "once_cell", + "percent-encoding", + "pin-project-lite", + "rustls 0.22.4", + "rustls-pemfile", + "rustls-pki-types", + "serde", + "serde_json", + "serde_urlencoded", + "sync_wrapper", + "tokio", + "tokio-rustls", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "webpki-roots 0.26.3", + "winreg", +] + [[package]] name = "ring" version = "0.16.20" @@ -1380,7 +1652,7 @@ dependencies = [ "libc", "spin 0.9.8", "untrusted 0.9.0", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -1397,10 +1669,40 @@ checksum = "cd8d6c9f025a446bc4d18ad9632e69aec8f287aa84499ee335599fabd20c3fd8" dependencies = [ "log", "ring 0.16.20", - "rustls-webpki", + "rustls-webpki 0.101.6", "sct", ] +[[package]] +name = "rustls" +version = "0.22.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf4ef73721ac7bcd79b2b315da7779d8fc09718c6b3d2d1b2d94850eb8c18432" +dependencies = [ + "log", + "ring 0.17.7", + "rustls-pki-types", + "rustls-webpki 0.102.5", + "subtle", + "zeroize", +] + +[[package]] +name = "rustls-pemfile" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29993a25686778eb88d4189742cd713c9bce943bc54251a33509dc63cbacf73d" +dependencies = [ + "base64 0.22.1", + "rustls-pki-types", +] + +[[package]] +name = "rustls-pki-types" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "976295e77ce332211c0d24d92c0e83e50f5c5f046d11082cea19f3df13a3562d" + [[package]] name = "rustls-webpki" version = "0.101.6" @@ -1411,6 +1713,17 @@ dependencies = [ "untrusted 0.7.1", ] +[[package]] +name = "rustls-webpki" +version = "0.102.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9a6fccd794a42c2c105b513a2f62bc3fd8f3ba57a4593677ceb0bd035164d78" +dependencies = [ + "ring 0.17.7", + "rustls-pki-types", + "untrusted 0.9.0", +] + [[package]] name = "ryu" version = "1.0.15" @@ -1467,13 +1780,13 @@ dependencies = [ [[package]] name = "secp256k1" -version = "0.28.2" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d24b59d129cdadea20aea4fb2352fa053712e5d713eee47d700cd4b2bc002f10" +checksum = "0e0cc0f1cf93f4969faf3ea1c7d8a9faed25918d96affa959720823dfe86d4f3" dependencies = [ - "bitcoin_hashes 0.12.0", + "bitcoin_hashes 0.14.0", "rand", - "secp256k1-sys 0.9.2", + "secp256k1-sys 0.10.0", "serde", ] @@ -1488,9 +1801,9 @@ dependencies = [ [[package]] name = "secp256k1-sys" -version = "0.9.2" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5d1746aae42c19d583c3c1a8c646bfad910498e2051c551a7f2e3c0c9fbb7eb" +checksum = "1433bd67156263443f14d603720b082dd3121779323fce20cba2aa07b874bc1b" dependencies = [ "cc", ] @@ -1535,6 +1848,18 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + [[package]] name = "sha2" version = "0.9.9" @@ -1593,6 +1918,16 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b7c388c1b5e93756d0c740965c41e8822f866621d41acbdf6336a6a168f8840c" +[[package]] +name = "socket2" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + [[package]] name = "socks" version = "0.3.4" @@ -1656,6 +1991,12 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "sync_wrapper" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" + [[package]] name = "textwrap" version = "0.16.0" @@ -1663,8 +2004,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d" dependencies = [ "smawk", - "unicode-linebreak", - "unicode-width", ] [[package]] @@ -1709,8 +2048,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "61285f6515fa018fb2d1e46eb21223fff441ee8db5d0f1435e8ab4f5cdb80931" dependencies = [ "backtrace", + "bytes", + "libc", + "mio", "pin-project-lite", + "socket2", "tokio-macros", + "windows-sys 0.48.0", ] [[package]] @@ -1724,6 +2068,17 @@ dependencies = [ "syn 2.0.48", ] +[[package]] +name = "tokio-rustls" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "775e0c0f0adb3a2f22a00c4745d728b479985fc15ee7ca6a2608388c5569860f" +dependencies = [ + "rustls 0.22.4", + "rustls-pki-types", + "tokio", +] + [[package]] name = "toml" version = "0.5.11" @@ -1733,6 +2088,58 @@ dependencies = [ "serde", ] +[[package]] +name = "tower" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" +dependencies = [ + "futures-core", + "futures-util", + "pin-project", + "pin-project-lite", + "tokio", + "tower-layer", + "tower-service", +] + +[[package]] +name = "tower-layer" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c20c8dbed6283a09604c3e69b4b7eeb54e298b8a600d4d5ecb5ad39de609f1d0" + +[[package]] +name = "tower-service" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" + +[[package]] +name = "tracing" +version = "0.1.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" +dependencies = [ + "pin-project-lite", + "tracing-core", +] + +[[package]] +name = "tracing-core" +version = "0.1.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" +dependencies = [ + "once_cell", +] + +[[package]] +name = "try-lock" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" + [[package]] name = "typenum" version = "1.17.0" @@ -1760,12 +2167,6 @@ version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c" -[[package]] -name = "unicode-linebreak" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b09c83c3c29d37506a3e260c08c03743a6bb66a9cd432c6934ab501a190571f" - [[package]] name = "unicode-normalization" version = "0.1.22" @@ -1775,17 +2176,11 @@ dependencies = [ "tinyvec", ] -[[package]] -name = "unicode-width" -version = "0.1.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85" - [[package]] name = "uniffi" -version = "0.27.1" +version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5566fae48a5cb017005bf9cd622af5236b2a203a13fb548afde3506d3c68277" +checksum = "f31bff6daf87277a9014bcdefbc2842b0553392919d1096843c5aad899ca4588" dependencies = [ "anyhow", "camino", @@ -1798,19 +2193,18 @@ dependencies = [ [[package]] name = "uniffi_bindgen" -version = "0.27.1" +version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a77bb514bcd4bf27c9bd404d7c3f2a6a8131b957eba9c22cfeb7751c4278e09" +checksum = "96061d7e01b185aa405f7c9b134741ab3e50cc6796a47d6fd8ab9a5364b5feed" dependencies = [ "anyhow", "askama", "camino", "cargo_metadata", - "clap", "fs-err", "glob", "goblin", - "heck", + "heck 0.5.0", "once_cell", "paste", "serde", @@ -1823,9 +2217,9 @@ dependencies = [ [[package]] name = "uniffi_build" -version = "0.27.1" +version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45cba427aeb7b3a8b54830c4c915079a7a3c62608dd03dddba1d867a8a023eb4" +checksum = "9d6b86f9b221046af0c533eafe09ece04e2f1ded04ccdc9bba0ec09aec1c52bd" dependencies = [ "anyhow", "camino", @@ -1834,9 +2228,9 @@ dependencies = [ [[package]] name = "uniffi_checksum_derive" -version = "0.27.1" +version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae7e5a6c33b1dec3f255f57ec0b6af0f0b2bb3021868be1d5eec7a38e2905ebc" +checksum = "2fcfa22f55829d3aaa7acfb1c5150224188fe0f27c59a8a3eddcaa24d1ffbe58" dependencies = [ "quote", "syn 2.0.48", @@ -1844,25 +2238,24 @@ dependencies = [ [[package]] name = "uniffi_core" -version = "0.27.1" +version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ea3eb5474d50fc149b7e4d86b9c5bd4a61dcc167f0683902bf18ae7bbb3deef" +checksum = "3210d57d6ab6065ab47a2898dacdb7c606fd6a4156196831fa3bf82e34ac58a6" dependencies = [ "anyhow", "bytes", "camino", "log", "once_cell", - "oneshot-uniffi", "paste", "static_assertions", ] [[package]] name = "uniffi_macros" -version = "0.27.1" +version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18331d35003f46f0d04047fbe4227291815b83a937a8c32bc057f990962182c4" +checksum = "b58691741080935437dc862122e68d7414432a11824ac1137868de46181a0bd2" dependencies = [ "bincode", "camino", @@ -1878,9 +2271,9 @@ dependencies = [ [[package]] name = "uniffi_meta" -version = "0.27.1" +version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7224422c4cfd181c7ca9fca2154abca4d21db962f926f270f996edd38b0c4b8" +checksum = "7663eacdbd9fbf4a88907ddcfe2e6fa85838eb6dc2418a7d91eebb3786f8e20b" dependencies = [ "anyhow", "bytes", @@ -1890,9 +2283,9 @@ dependencies = [ [[package]] name = "uniffi_testing" -version = "0.27.1" +version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8ce878d0bdfc288b58797044eaaedf748526c56eef3575380bb4d4b19d69eee" +checksum = "f922465f7566f25f8fe766920205fdfa9a3fcdc209c6bfb7557f0b5bf45b04dd" dependencies = [ "anyhow", "camino", @@ -1903,9 +2296,9 @@ dependencies = [ [[package]] name = "uniffi_udl" -version = "0.27.1" +version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c43c9ed40a8d20a5c3eae2d23031092db6b96dc8e571beb449ba9757484cea0" +checksum = "cef408229a3a407fafa4c36dc4f6ece78a6fb258ab28d2b64bddd49c8cb680f6" dependencies = [ "anyhow", "textwrap", @@ -1956,8 +2349,8 @@ dependencies = [ "flate2", "log", "once_cell", - "rustls", - "rustls-webpki", + "rustls 0.21.7", + "rustls-webpki 0.101.6", "serde", "serde_json", "socks", @@ -1974,6 +2367,7 @@ dependencies = [ "form_urlencoded", "idna", "percent-encoding", + "serde", ] [[package]] @@ -1988,6 +2382,15 @@ version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +[[package]] +name = "want" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" +dependencies = [ + "try-lock", +] + [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" @@ -2019,6 +2422,18 @@ dependencies = [ "wasm-bindgen-shared", ] +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c02dbc21516f9f1f04f187958890d7e6026df8d16540b7ad9492bc34a67cea03" +dependencies = [ + "cfg-if", + "js-sys", + "wasm-bindgen", + "web-sys", +] + [[package]] name = "wasm-bindgen-macro" version = "0.2.87" @@ -2083,6 +2498,15 @@ version = "0.25.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "14247bb57be4f377dfb94c72830b8ce8fc6beac03cf4bf7b9732eadd414123fc" +[[package]] +name = "webpki-roots" +version = "0.26.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd7c23921eeb1713a4e851530e9b9756e4fb0e89978582942612524cf09f01cd" +dependencies = [ + "rustls-pki-types", +] + [[package]] name = "weedle2" version = "5.0.0" @@ -2120,7 +2544,16 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" dependencies = [ - "windows-targets", + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.6", ] [[package]] @@ -2129,13 +2562,29 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", ] [[package]] @@ -2144,42 +2593,100 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + [[package]] name = "windows_aarch64_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + [[package]] name = "windows_i686_gnu" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + [[package]] name = "windows_i686_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + [[package]] name = "windows_x86_64_gnu" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + [[package]] name = "windows_x86_64_gnullvm" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + [[package]] name = "windows_x86_64_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "winreg" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a277a57398d4bfa075df44f501a17cfdf8542d224f0d36095a2adc7aee4ef0a5" +dependencies = [ + "cfg-if", + "windows-sys 0.48.0", +] + [[package]] name = "x25519-dalek" version = "2.0.0-pre.1" diff --git a/Cargo.toml b/Cargo.toml index 4c62728..a2bdbb7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "payjoin_ffi" -version = "0.13.0" +version = "0.18.0" license = "MIT OR Apache-2.0" edition = "2021" exclude = ["tests"] @@ -10,16 +10,17 @@ crate-type = ["lib", "staticlib", "cdylib"] name = "payjoin_ffi" [build-dependencies] -uniffi = { version = "0.27.1", features = ["build"] } +uniffi = { version = "0.28.0", features = ["build"] } [dev-dependencies] -uniffi = { version = "0.27.1", features = ["bindgen-tests"] } +uniffi = { version = "0.28.0", features = ["bindgen-tests"] } bdk = { version = "0.29.0", features = ["all-keys", "use-esplora-ureq", "keys-bip39"] } -bitcoincore-rpc = "0.18.0" +bitcoincore-rpc = "0.19.0" [dependencies] -#https://github.com/payjoin/rust-payjoin/commit/457a0dd5cb212ddd9ea169b7fa3842bfc3d5f373 -payjoin = { git= "https://github.com/payjoin/rust-payjoin", rev = "457a0dd5cb212ddd9ea169b7fa3842bfc3d5f373", features = ["send", "receive", "base64", "v2"] } -uniffi = { version = "0.27.1" } + +#payjoin = {version = "=0.18.0", features = ["send", "receive", "base64", "v2", "io", "danger-local-https"] } +payjoin={ git = "https://github.com/LtbLightning/rust-payjoin", branch = "clone-pj-uri-builder", features = ["send", "receive", "base64", "v2", "io", "danger-local-https"]} +uniffi = { version = "0.28.0" } thiserror = "1.0.47" ohttp = { version = "0.5.1" } url = "2.5.0" diff --git a/README.md b/README.md index 7d65e19..59729fe 100644 --- a/README.md +++ b/README.md @@ -57,8 +57,8 @@ rpc_port = "18443" ``` Now, run the integration tests: -The integration tests illustrates and verify integration using bitcoin core and with bitcoin dev kit(bdk). +The integration tests illustrates and verify integration using bitcoin core and with bitcoin dev kit(bdk). ```shell diff --git a/python/README.md b/python/README.md index be1cc22..1a9ae83 100644 --- a/python/README.md +++ b/python/README.md @@ -1,16 +1,17 @@ # Payjoin -The Python language bindings for the [Payjoin Dev Kit](https://payjoindevkit.org/). +Welcome to the Python language bindings for the [Payjoin Dev Kit](https://payjoindevkit.org/)! Let's get you up and running with some smooth transactions and a sprinkle of fun. ## Install from PyPI -Install the latest release using +Grab the latest release with a simple: ```shell pip install payjoin ``` -## Run the unit tests +## Running Unit Tests +Follow these steps to clone the repository and run the unit tests: ```shell @@ -27,34 +28,33 @@ python setup.py bdist_wheel --verbose # Force reinstall payjoin pip install ./dist/payjoin-.whl --force-reinstall -#Run unit tests +# Run unit tests python -m unittest --verbose test/payjoin_unit_test.py + ``` -## Run the integration test +## Running the Integration Test -Before running the integration test, 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. +Before diving into the integration test, you'll need to set up Bitcoin Core on the regtest network. If you don't have Bitcoin Core installed locally, check out [this installation guide](https://learn.saylor.org/mod/page/view.php?id=36347). Alternatively, you can use `Nigiri Bitcoin`, a tool designed to streamline the process of running local instances of Bitcoin and Liquid networks for development and testing. Follow the instructions [here](https://github.com/vulpemventures/nigiri) to install it on your machine. -Once the nigiri bitcoin starts running, please replace following snippet in `payjoin_integration_test.py`, with you -nigiri bitcoin core credentials. +Once Nigiri Bitcoin is up and running, replace the following snippet in `payjoin_integration_test.py` with your `Nigiri Bitcoin` Core credentials: ``` rpc_user = "bitcoin" rpc_password = "bitcoin" + ``` -NB: The default credentials would be the following +By default, these credentials are: ``` rpc_user = "admin1" rpc_password = "123" rpc_host = "localhost" rpc_port = "18443" + ``` +Now, proceed with the integration test: ```shell @@ -71,11 +71,12 @@ python setup.py bdist_wheel --verbose # Force reinstall payjoin pip install ./dist/payjoin-.whl --force-reinstall -#Run the integration test +# Run the integration test python -m unittest --verbose test/payjoin_integration_test.py + ``` -## Build the package +## Building the Package ```shell # Install dependencies @@ -86,4 +87,7 @@ bash ./scripts/generate_macos.sh # Build the wheel python setup.py --verbose bdist_wheel -``` \ No newline at end of file + +``` +We hope everything worked smoothly! Now go forth test, and may your test results be as reliable as the Bitcoin blockchain itself! +₿🔒🤝 diff --git a/src/error.rs b/src/error.rs index 363c89e..8a98ebc 100644 --- a/src/error.rs +++ b/src/error.rs @@ -43,7 +43,7 @@ pub enum PayjoinError { PjParseError { message: String }, #[error("{message}")] - PjNotSupported { message: String }, + PjNotSupported{ message: String }, #[error("Malformed response from receiver: {message}")] ValidationError { message: String }, @@ -59,6 +59,9 @@ pub enum PayjoinError { #[error("{message}")] UrlError { message: String }, + + #[error("{message}")] + IoError { message: String }, } macro_rules! impl_from_error { @@ -99,3 +102,9 @@ impl From for PayjoinError { } } } + +impl From for PayjoinError { + fn from(value: payjoin::io::Error) -> Self { + PayjoinError::IoError { message: value.to_string() } + } +} diff --git a/src/io.rs b/src/io.rs new file mode 100644 index 0000000..7a9be82 --- /dev/null +++ b/src/io.rs @@ -0,0 +1,25 @@ +use crate::error::PayjoinError; +use crate::types::OhttpKeys; +use crate::uri::Url; + +/// Fetch the ohttp keys from the specified payjoin directory via proxy. +/// +/// * `ohttp_relay`: The http CONNNECT method proxy to request the ohttp keys from a payjoin +/// directory. Proxying requests for ohttp keys ensures a client IP address is never revealed to +/// the payjoin directory. +/// +/// * `payjoin_directory`: The payjoin directory from which to fetch the ohttp keys. This +/// directory stores and forwards payjoin client payloads. +/// +/// * `cert_der` (optional): The DER-encoded certificate to use for local HTTPS connections. This +/// parameter is only available when the "danger-local-https" feature is enabled. +pub async fn fetch_ohttp_keys( + ohttp_relay: Url, + payjoin_directory: Url, + cert_der: Vec, +) -> Result { + payjoin::io::fetch_ohttp_keys(ohttp_relay.into(), payjoin_directory.into(), cert_der) + .await + .map(|e| e.into()) + .map_err(|e| e.into()) +} diff --git a/src/lib.rs b/src/lib.rs index f149923..de43581 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,10 +1,12 @@ #![crate_name = "payjoin_ffi"] pub mod error; +pub mod io; pub mod receive; pub mod send; pub mod types; pub mod uri; + use crate::error::PayjoinError; #[cfg(feature = "uniffi")] use crate::receive::v1::{ @@ -17,9 +19,9 @@ use crate::receive::v1::{ }; #[allow(unused_imports)] use crate::receive::v2::{ - ClientResponse, Enrolled, Enroller, RequestResponse, V2MaybeInputsOwned, V2MaybeInputsSeen, - V2MaybeMixedInputScripts, V2OutputsUnknown, V2PayjoinProposal, V2ProvisionalProposal, - V2UncheckedProposal, + ActiveSession, ClientResponse, RequestResponse, SessionInitializer, V2MaybeInputsOwned, + V2MaybeInputsSeen, V2MaybeMixedInputScripts, V2OutputsUnknown, V2PayjoinProposal, + V2ProvisionalProposal, V2UncheckedProposal, }; #[allow(unused_imports)] use crate::send::v1::{ diff --git a/src/receive/v1.rs b/src/receive/v1.rs index fa4cbd6..5904f73 100644 --- a/src/receive/v1.rs +++ b/src/receive/v1.rs @@ -90,7 +90,7 @@ impl UncheckedProposal { |transaction| { can_broadcast .callback(payjoin::bitcoin::consensus::encode::serialize(transaction)) - .map_err(|e| payjoin::receive::Error::Server(e.into())) + .map_err(|e| payjoin::receive::Error::Server(Box::new(e))) }, ) .map(|e| Arc::new(e.into())) @@ -108,7 +108,7 @@ impl UncheckedProposal { min_fee_rate.map(|x| FeeRate::from_sat_per_kwu(x)), |transaction| { can_broadcast(&payjoin::bitcoin::consensus::encode::serialize(transaction)) - .map_err(|e| payjoin::receive::Error::Server(e.into())) + .map_err(|e| payjoin::receive::Error::Server(Box::new(e))) }, ) .map(|e| Arc::new(e.into())) @@ -151,7 +151,7 @@ impl MaybeInputsOwned { .check_inputs_not_owned(|input| { is_owned .callback(input.to_bytes()) - .map_err(|e| payjoin::receive::Error::Server(e.into())) + .map_err(|e| payjoin::receive::Error::Server(Box::new(e))) }) .map_err(|e| e.into()) .map(|e| Arc::new(e.into())) @@ -164,7 +164,7 @@ impl MaybeInputsOwned { self.0 .clone() .check_inputs_not_owned(|input| { - is_owned(&input.to_bytes()).map_err(|e| payjoin::receive::Error::Server(e.into())) + is_owned(&input.to_bytes()).map_err(|e| payjoin::receive::Error::Server(Box::new(e))) }) .map_err(|e| e.into()) .map(|e| Arc::new(e.into())) @@ -222,7 +222,7 @@ impl MaybeInputsSeen { self.0 .clone() .check_no_inputs_seen_before(|outpoint| { - is_known.callback(outpoint.clone().into()).map_err(|e| pdk::Error::Server(e.into())) + is_known.callback(outpoint.clone().into()).map_err(|e| pdk::Error::Server(Box::new(e))) }) .map_err(|e| e.into()) .map(|e| Arc::new(e.into())) @@ -235,7 +235,7 @@ impl MaybeInputsSeen { self.0 .clone() .check_no_inputs_seen_before(|outpoint| { - is_known(&outpoint.clone().into()).map_err(|e| pdk::Error::Server(e.into())) + is_known(&outpoint.clone().into()).map_err(|e| pdk::Error::Server(Box::new(e))) }) .map_err(|e| e.into()) .map(|e| Arc::new(e.into())) @@ -266,7 +266,7 @@ impl OutputsUnknown { .identify_receiver_outputs(|output_script| { is_receiver_output .callback(output_script.to_bytes()) - .map_err(|e| payjoin::receive::Error::Server(e.into())) + .map_err(|e| payjoin::receive::Error::Server(Box::new(e))) }) .map(|e| Arc::new(e.into())) .map_err(|e| e.into()) @@ -275,15 +275,15 @@ impl OutputsUnknown { pub fn identify_receiver_outputs( &self, is_receiver_output: impl Fn(&Vec) -> Result, - ) -> Result, PayjoinError> { + ) -> Result { self.0 .clone() .identify_receiver_outputs(|input| { is_receiver_output(&input.to_bytes()) - .map_err(|e| payjoin::receive::Error::Server(e.into())) + .map_err(|e| payjoin::receive::Error::Server(Box::new(e))) }) .map_err(|e| e.into()) - .map(|e| Arc::new(e.into())) + .map(|e| e.into()) } } @@ -304,13 +304,25 @@ impl ProvisionalProposal { fn mutex_guard(&self) -> MutexGuard<'_, payjoin::receive::ProvisionalProposal> { self.0.lock().unwrap() } - pub fn substitute_output_address( + #[cfg(not(feature = "uniffi"))] + ///If output substitution is enabled, replace the receiver’s output script with a new one. + pub fn try_substitute_receiver_output( + &self, + generate_script: impl Fn() -> Result, PayjoinError>, + ) -> Result<(), PayjoinError> { + self.mutex_guard() + .try_substitute_receiver_output(|| { + generate_script() + .map(|e| payjoin::bitcoin::ScriptBuf::from_bytes(e)) + .map_err(|e| payjoin::Error::Server(Box::new(e))) + }) + .map_err(|e| e.into()) + } + #[cfg(feature = "uniffi")] + pub fn try_substitute_receiver_output( &self, - substitute_address: String, + generate_script: impl Fn() -> Result, PayjoinError>, ) -> Result<(), PayjoinError> { - let address = - payjoin::bitcoin::Address::from_str(substitute_address.as_str())?.assume_checked(); - Ok(self.mutex_guard().substitute_output_address(address)) } pub fn contribute_witness_input( &self, @@ -363,7 +375,7 @@ impl ProvisionalProposal { process_psbt .callback(psbt.to_string()) .map(|e| Psbt::from_str(e.as_str()).expect("Invalid process_psbt ")) - .map_err(|e| pdk::Error::Server(e.into())) + .map_err(|e| pdk::Error::Server(Box::new(e))) }, min_feerate_sat_per_vb.and_then(|x| FeeRate::from_sat_per_vb(x)), ) @@ -382,7 +394,7 @@ impl ProvisionalProposal { |psbt| { process_psbt(psbt.to_string()) .map(|e| Psbt::from_str(e.as_str()).expect("Invalid process_psbt ")) - .map_err(|e| pdk::Error::Server(e.into())) + .map_err(|e| pdk::Error::Server(Box::new(e))) }, min_feerate_sat_per_vb.and_then(|x| FeeRate::from_sat_per_vb(x)), ) diff --git a/src/receive/v2.rs b/src/receive/v2.rs index 21aa52f..0807785 100644 --- a/src/receive/v2.rs +++ b/src/receive/v2.rs @@ -2,6 +2,7 @@ use std::collections::HashMap; use std::io::Cursor; use std::str::FromStr; use std::sync::{Arc, Mutex, MutexGuard}; +use std::time::Duration; use payjoin::bitcoin::psbt::Psbt; use payjoin::bitcoin::FeeRate; @@ -11,6 +12,8 @@ use payjoin::receive as pdk; use crate::receive::v1::{ CanBroadcast, IsOutputKnown, IsScriptOwned, ProcessPartiallySignedTransaction, }; +use crate::types::Network; +use crate::uri::PjUriBuilder; use crate::{OhttpKeys, OutPoint, PayjoinError, Request, TxOut, Url}; pub struct ClientResponse(Mutex>); @@ -33,31 +36,72 @@ pub struct RequestResponse { } #[derive(Clone, Debug)] -pub struct Enroller(pub payjoin::receive::v2::Enroller); -impl From for payjoin::receive::v2::Enroller { - fn from(value: Enroller) -> Self { +pub struct SessionInitializer(pub payjoin::receive::v2::SessionInitializer); +impl From for payjoin::receive::v2::SessionInitializer { + fn from(value: SessionInitializer) -> Self { value.0 } } -impl From for Enroller { - fn from(value: payjoin::receive::v2::Enroller) -> Self { +impl From for SessionInitializer { + fn from(value: payjoin::receive::v2::SessionInitializer) -> Self { Self(value) } } -impl Enroller { - pub fn from_directory_config( +impl SessionInitializer { + /// Creates a new `SessionInitializer` with the provided parameters. + /// + /// # Parameters + /// - `address`: The Bitcoin address for the payjoin session. + /// - `directory`: The URL of the store-and-forward payjoin directory. + /// - `ohttp_keys`: The OHTTP keys used for encrypting and decrypting HTTP requests and responses. + /// - `ohttp_relay`: The URL of the OHTTP relay, used to keep client IP address confidential. + /// - `expire_after`: The duration in seconds after which the session expires. + /// + /// # Returns + /// A new instance of `SessionInitializer`. + /// + /// # References + /// - [BIP 77: Payjoin Version 2: Serverless Payjoin](https://github.com/bitcoin/bips/pull/1483) + #[cfg(feature = "uniffi")] + pub fn new( + address: String, + expire_after: u64, + network: Network, directory: Arc, ohttp_keys: Arc, ohttp_relay: Arc, - ) -> Self { - payjoin::receive::v2::Enroller::from_directory_config( + ) -> Result { + let address = payjoin::bitcoin::Address::from_str(address.as_str())? + .require_network(network.into())?; + Ok(payjoin::receive::v2::SessionInitializer::new( + address, (*directory).clone().into(), (*ohttp_keys).clone().into(), (*ohttp_relay).clone().into(), + Duration::from_secs(expire_after), ) - .into() + .into()) + } + pub fn new( + address: String, + expire_after: u64, + network: Network, + directory: Arc, + ohttp_keys: Arc, + ohttp_relay: Arc, + ) -> Result { + let address = payjoin::bitcoin::Address::from_str(address.as_str())? + .require_network(network.into())?; + Ok(payjoin::receive::v2::SessionInitializer::new( + address, + (*directory).clone().into(), + (*ohttp_keys).clone().into(), + (*ohttp_relay).clone().into(), + Duration::from_secs(expire_after), + ) + .into()) } #[cfg(feature = "uniffi")] @@ -81,10 +125,10 @@ impl Enroller { &self, body: Vec, ctx: ohttp::ClientResponse, - ) -> Result, PayjoinError> { - >::into(self.clone()) + ) -> Result { + >::into(self.clone()) .process_res(Cursor::new(body), ctx) - .map(|e| Arc::new(e.into())) + .map(|e| e.into()) .map_err(|e| e.into()) } #[cfg(feature = "uniffi")] @@ -92,31 +136,28 @@ impl Enroller { &self, body: Vec, ctx: Arc, - ) -> Result, PayjoinError> { - >::into(self.clone()) + ) -> Result, PayjoinError> { + >::into(self.clone()) .process_res(Cursor::new(body), ctx.as_ref().into()) .map(|e| Arc::new(e.into())) .map_err(|e| e.into()) } } #[derive(Clone, Debug)] -pub struct Enrolled(payjoin::receive::v2::Enrolled); +pub struct ActiveSession(payjoin::receive::v2::ActiveSession); -impl From for payjoin::receive::v2::Enrolled { - fn from(value: Enrolled) -> Self { +impl From for payjoin::receive::v2::ActiveSession { + fn from(value: ActiveSession) -> Self { value.0 } } -impl From for Enrolled { - fn from(value: payjoin::receive::v2::Enrolled) -> Self { +impl From for ActiveSession { + fn from(value: payjoin::receive::v2::ActiveSession) -> Self { Self(value) } } -impl Enrolled { - pub fn fallback_target(&self) -> String { - >::into(self.clone()).fallback_target() - } +impl ActiveSession { #[cfg(feature = "uniffi")] pub fn extract_req(&self) -> Result { match self.0.clone().extract_req() { @@ -134,28 +175,48 @@ impl Enrolled { Err(e) => Err(PayjoinError::V2Error { message: e.to_string() }), } } + ///The response can either be an UncheckedProposal or an ACCEPTED message indicating no UncheckedProposal is available yet. #[cfg(feature = "uniffi")] pub fn process_res( &self, body: Vec, context: Arc, ) -> Result>, PayjoinError> { - >::into(self.clone()) + >::into(self.clone()) .process_res(Cursor::new(body), context.as_ref().into()) .map(|e| e.map(|x| Arc::new(x.into()))) .map_err(|e| e.into()) } + ///The response can either be an UncheckedProposal or an ACCEPTED message indicating no UncheckedProposal is available yet. #[cfg(not(feature = "uniffi"))] pub fn process_res( &self, body: Vec, ctx: ohttp::ClientResponse, ) -> Result, PayjoinError> { - >::into(self.clone()) + >::into(self.clone()) .process_res(Cursor::new(body), ctx) .map(|e| e.map(|o| o.into())) .map_err(|e| e.into()) } + pub fn pj_uri_builder(&self) -> PjUriBuilder { + >::into(self.clone()) + .pj_uri_builder() + .into() + } + /// The contents of the `&pj=` query parameter including the base64url-encoded public key receiver subdirectory. + /// This identifies a session at the payjoin directory server. + pub fn pj_url(&self) -> Url { + >::into(self.clone()) + .pj_url() + .into() + } + ///The per-session public key to use as an identifier + pub fn public_key(&self) -> String { + >::into(self.clone()) + .public_key() + .to_string() + } } #[derive(Clone)] @@ -204,7 +265,7 @@ impl V2UncheckedProposal { |tx| { can_broadcast .callback(payjoin::bitcoin::consensus::encode::serialize(tx)) - .map_err(|e| payjoin::receive::Error::Server(e.into())) + .map_err(|e| payjoin::receive::Error::Server(Box::new(e))) }, ) .map(|e| Arc::new(e.into())) @@ -223,7 +284,7 @@ impl V2UncheckedProposal { min_fee_rate.map(|x| FeeRate::from_sat_per_kwu(x)), |transaction| { can_broadcast(&payjoin::bitcoin::consensus::encode::serialize(transaction)) - .map_err(|e| payjoin::receive::Error::Server(e.into())) + .map_err(|e| payjoin::receive::Error::Server(Box::new(e))) }, ) .map(|e| Arc::new(e.into())) @@ -259,7 +320,7 @@ impl V2MaybeInputsOwned { .check_inputs_not_owned(|input| { is_owned .callback(input.to_bytes()) - .map_err(|e| payjoin::receive::Error::Server(e.into())) + .map_err(|e| payjoin::receive::Error::Server(Box::new(e))) }) .map(|e| Arc::new(e.into())) .map_err(|e| e.into()) @@ -272,7 +333,7 @@ impl V2MaybeInputsOwned { self.0 .clone() .check_inputs_not_owned(|input| { - is_owned(&input.to_bytes()).map_err(|e| payjoin::receive::Error::Server(e.into())) + is_owned(&input.to_bytes()).map_err(|e| payjoin::receive::Error::Server(Box::new(e))) }) .map_err(|e| e.into()) .map(|e| Arc::new(e.into())) @@ -321,7 +382,7 @@ impl V2MaybeInputsSeen { self.0 .clone() .check_no_inputs_seen_before(|outpoint| { - is_known.callback(outpoint.clone().into()).map_err(|e| pdk::Error::Server(e.into())) + is_known.callback(outpoint.clone().into()).map_err(|e| pdk::Error::Server(Box::new(e))) }) .map(|e| Arc::new(e.into())) .map_err(|e| e.into()) @@ -334,7 +395,7 @@ impl V2MaybeInputsSeen { self.0 .clone() .check_no_inputs_seen_before(|outpoint| { - is_known(&outpoint.clone().into()).map_err(|e| pdk::Error::Server(e.into())) + is_known(&outpoint.clone().into()).map_err(|e| pdk::Error::Server(Box::new(e))) }) .map_err(|e| e.into()) .map(|e| Arc::new(e.into())) @@ -366,7 +427,7 @@ impl V2OutputsUnknown { .identify_receiver_outputs(|output_script| { is_receiver_output .callback(output_script.to_bytes()) - .map_err(|e| payjoin::receive::Error::Server(e.into())) + .map_err(|e| payjoin::receive::Error::Server(Box::new(e))) }) .map(|e| Arc::new(e.into())) .map_err(|e| e.into()) @@ -375,18 +436,19 @@ impl V2OutputsUnknown { pub fn identify_receiver_outputs( &self, is_receiver_output: impl Fn(&Vec) -> Result, - ) -> Result, PayjoinError> { + ) -> Result { self.0 .clone() .identify_receiver_outputs(|input| { is_receiver_output(&input.to_bytes()) - .map_err(|e| payjoin::receive::Error::Server(e.into())) + .map_err(|e| payjoin::receive::Error::Server(Box::new(e))) }) .map_err(|e| e.into()) - .map(|e| Arc::new(e.into())) + .map(|e| e.into()) } } -pub struct V2ProvisionalProposal(Mutex); + +pub struct V2ProvisionalProposal(pub Mutex); impl From for V2ProvisionalProposal { fn from(value: payjoin::receive::v2::ProvisionalProposal) -> Self { @@ -399,15 +461,7 @@ impl V2ProvisionalProposal { fn mutex_guard(&self) -> MutexGuard<'_, payjoin::receive::v2::ProvisionalProposal> { self.0.lock().unwrap() } - ///Just replace an output address with - pub fn substitute_output_address( - &self, - substitute_address: String, - ) -> Result<(), PayjoinError> { - let address = - payjoin::bitcoin::Address::from_str(substitute_address.as_str())?.assume_checked(); - Ok(self.mutex_guard().substitute_output_address(address)) - } + pub fn contribute_witness_input( &self, txo: TxOut, @@ -451,6 +505,32 @@ impl V2ProvisionalProposal { Err(e) => Err(e.into()), } } + pub fn is_output_substitution_disabled(&self) -> bool { + self.mutex_guard().is_output_substitution_disabled() + } + + #[cfg(not(feature = "uniffi"))] + ///If output substitution is enabled, replace the receiver’s output script with a new one. + pub fn try_substitute_receiver_output( + &self, + generate_script: impl Fn() -> Result, PayjoinError>, + ) -> Result<(), PayjoinError> { + self.mutex_guard() + .try_substitute_receiver_output(|| { + generate_script() + .map(|e| payjoin::bitcoin::ScriptBuf::from_bytes(e)) + .map_err(|e| payjoin::Error::Server(Box::new(e))) + }) + .map_err(|e| e.into()) + } + //TODO; create try_substitute_receiver_output for uniffi build + #[cfg(feature = "uniffi")] + pub fn try_substitute_receiver_output( + &self, + generate_script: impl Fn() -> Result, PayjoinError>, + ) -> Result<(), PayjoinError> { + } + #[cfg(feature = "uniffi")] pub fn finalize_proposal( &self, @@ -460,11 +540,15 @@ impl V2ProvisionalProposal { self.mutex_guard() .clone() .finalize_proposal( - |psbt| { - process_psbt - .callback(psbt.to_string()) - .map(|e| Psbt::from_str(e.as_str()).expect("Invalid process_psbt ")) - .map_err(|e| pdk::Error::Server(e.into())) + |pre_processed| { + let processed = process_psbt + .callback(pre_processed.to_string()) + .map(|e| Psbt::from_str(e.as_str())) + .map_err(|e| pdk::Error::Server(Box::new(e)))?; + match processed { + Ok(e) => Ok(e), + Err(e) => Err(pdk::Error::Server(Box::new(e))), + } }, min_feerate_sat_per_vb.and_then(|x| FeeRate::from_sat_per_vb(x)), ) @@ -480,10 +564,14 @@ impl V2ProvisionalProposal { self.mutex_guard() .clone() .finalize_proposal( - |psbt| { - process_psbt(psbt.to_string()) - .map(|e| Psbt::from_str(e.as_str()).expect("Invalid process_psbt ")) - .map_err(|e| pdk::Error::Server(e.into())) + |pre_processed| { + let processed = process_psbt(pre_processed.to_string()) + .map(|e| Psbt::from_str(e.as_str())) + .map_err(|e| pdk::Error::Server(Box::new(e)))?; + match processed { + Ok(e) => Ok(e), + Err(e) => Err(pdk::Error::Server(Box::new(e))), + } }, min_feerate_sat_per_vb.and_then(|x| FeeRate::from_sat_per_vb(x)), ) @@ -553,25 +641,33 @@ impl V2PayjoinProposal { } } #[cfg(not(feature = "uniffi"))] - pub fn deserialize_res( + ///Processes the response for the final POST message from the receiver client in the v2 Payjoin protocol. + /// + /// This function decapsulates the response using the provided OHTTP context. If the response status is successful, it indicates that the Payjoin proposal has been accepted. Otherwise, it returns an error with the status code. + /// + /// After this function is called, the receiver can either wait for the Payjoin transaction to be broadcast or choose to broadcast the original PSBT. + pub fn process_res( &self, body: Vec, ctx: ohttp::ClientResponse, - ) -> Result, PayjoinError> { + ) -> Result<(), PayjoinError> { >::into(self.clone()) - .deserialize_res(body, ctx) - .map(|e| e.into()) + .process_res(body, ctx) .map_err(|e| e.into()) } #[cfg(feature = "uniffi")] - pub fn deserialize_res( + ///Processes the response for the final POST message from the receiver client in the v2 Payjoin protocol. + /// + /// This function decapsulates the response using the provided OHTTP context. If the response status is successful, it indicates that the Payjoin proposal has been accepted. Otherwise, it returns an error with the status code. + /// + /// After this function is called, the receiver can either wait for the Payjoin transaction to be broadcast or choose to broadcast the original PSBT. + pub fn process_res( &self, res: Vec, ohttp_context: Arc, - ) -> Result, PayjoinError> { + ) -> Result<(), PayjoinError> { >::into(self.clone()) - .deserialize_res(res, ohttp_context.as_ref().into()) - .map(|e| e) + .process_res(res, ohttp_context.as_ref().into()) .map_err(|e| e.into()) } } diff --git a/src/send/v1.rs b/src/send/v1.rs index e390cd7..570a1b5 100644 --- a/src/send/v1.rs +++ b/src/send/v1.rs @@ -7,7 +7,7 @@ pub use payjoin::send as pdk; use crate::error::PayjoinError; use crate::send::v2::ContextV2; use crate::types::Request; -use crate::uri::{Uri, Url}; +use crate::uri::{PjUri, Url}; ///Builder for sender-side payjoin parameters /// @@ -27,7 +27,7 @@ impl RequestBuilder { /// An HTTP client will own the Request data while Context sticks around so /// a `(Request, Context)` tuple is returned from `RequestBuilder::build()` /// to keep them separated. - pub fn from_psbt_and_uri(psbt: String, uri: Arc) -> Result { + pub fn from_psbt_and_uri(psbt: String, uri: Arc) -> Result { let psbt = payjoin::bitcoin::psbt::PartiallySignedTransaction::from_str(psbt.as_str())?; pdk::RequestBuilder::from_psbt_and_uri(psbt, (*uri).clone().into()) .map(|e| e.into()) @@ -94,8 +94,15 @@ impl RequestBuilder { /// /// While it's generally better to offer some contribution some users may wish not to. /// This function disables contribution. - pub fn build_non_incentivizing(&self) -> Result, PayjoinError> { - match self.0.clone().build_non_incentivizing() { + pub fn build_non_incentivizing( + &self, + min_fee_rate: u64, + ) -> Result, PayjoinError> { + match self + .0 + .clone() + .build_non_incentivizing(payjoin::bitcoin::FeeRate::from_sat_per_kwu(min_fee_rate)) + { Ok(e) => Ok(Arc::new(e.into())), Err(e) => Err(e.into()), } diff --git a/src/uri.rs b/src/uri.rs index 0e21089..7de1a2b 100644 --- a/src/uri.rs +++ b/src/uri.rs @@ -1,6 +1,7 @@ use std::str::FromStr; use payjoin::bitcoin::address::NetworkChecked; +use payjoin::UriExt; use crate::error::PayjoinError; #[cfg(not(feature = "uniffi"))] @@ -31,8 +32,18 @@ impl Uri { } ///Gets the amount in satoshis. pub fn amount(&self) -> Option { + self.0.amount.map(|x| x.to_btc()) } + pub fn check_pj_supported(&self) -> Result { + match self.0.clone().check_pj_supported(){ + Ok(e) => Ok(e.into()), + Err(_) => Err(PayjoinError::PjNotSupported{message:"Uri doesn't support payjoin".to_string()}) + } + } + pub fn as_string(&self) -> String { + self.0.clone().to_string() + } } impl From> for PjUri { @@ -46,15 +57,17 @@ impl<'a> From for payjoin::PjUri<'a> { value.0 } } -pub struct PjUri(payjoin::PjUri<'static>); + +#[derive(Clone)] +pub struct PjUri(pub payjoin::PjUri<'static>); impl PjUri { pub fn address(&self) -> String { self.0.clone().address.to_string() } - /// Amount in sats - pub fn amount(&self) -> Option { - self.0.clone().amount.map(|e| e.to_sat()) + /// Number of btc requested as payment + pub fn amount(&self) -> Option { + self.0.clone().amount.map(|e| e.to_btc()) } pub fn as_string(&self) -> String { self.0.clone().to_string() @@ -90,9 +103,16 @@ impl Url { self.0.to_string() } } + +///Build a valid PjUri. +// Payjoin receiver can use this builder to create a payjoin uri to send to the sender. #[cfg(not(feature = "uniffi"))] -pub struct PjUriBuilder { - inner: payjoin::PjUriBuilder, +pub struct PjUriBuilder(pub payjoin::PjUriBuilder); + +impl From for PjUriBuilder { + fn from(value: payjoin::PjUriBuilder) -> Self { + Self(value) + } } #[cfg(not(feature = "uniffi"))] impl PjUriBuilder { @@ -103,94 +123,62 @@ impl PjUriBuilder { ohttp_keys: Option, ) -> Result { let address = payjoin::bitcoin::Address::from_str(&address)?.assume_checked(); - Ok(Self { inner: payjoin::PjUriBuilder::new(address, pj.into(), ohttp_keys.map(|e| e.0)) }) + Ok(payjoin::PjUriBuilder::new(address, pj.into(), ohttp_keys.map(|e| e.0)).into()) } - ///Set the amount in btc you want to receive. - pub fn amount(self, amount: f64) -> Self { - let amount = payjoin::bitcoin::Amount::from_sat((amount * 100_001_890.0) as u64); - Self { inner: self.inner.amount(amount) } + ///Accepts the amount you want to receive in sats and sets it in btc . + pub fn amount(&self, amount: u64) -> Self { + let amount = payjoin::bitcoin::Amount::from_sat(amount); + self.0.clone().amount(amount).into() } - ///Set the message. - pub fn message(self, message: String) -> Self { - Self { inner: self.inner.message(message) } + /// Set the message. + pub fn message(&self, message: String) -> Self { + self.0.clone().message(message).into() } ///Set the label. - pub fn label(self, label: String) -> Self { - Self { inner: self.inner.label(label) } + pub fn label(&self, label: String) -> Self { + self.0.clone().label(label).into() } - ///Set whether or not payjoin output substitution is allowed. - pub fn pjos(self, pjos: bool) -> Self { - Self { inner: self.inner.pjos(pjos) } + ///Set whether payjoin output substitution is allowed. + pub fn pjos(&self, pjos: bool) -> Self { + self.0.clone().pjos(pjos).into() } ///Constructs a Uri with PayjoinParams from the parameters set in the builder. - pub fn build(self) -> PjUri { - self.inner.build().into() + pub fn build(&self) -> PjUri { + self.0.clone().build().into() } } + #[cfg(test)] mod tests { - use std::convert::TryFrom; - - use payjoin::Uri; - - #[test] - fn test_short() { - assert!(Uri::try_from("").is_err()); - assert!(Uri::try_from("bitcoin").is_err()); - assert!(Uri::try_from("bitcoin:").is_err()); - } + use bdk::bitcoin; - #[ignore] + use crate::uri::{PjUriBuilder, Url}; #[test] - fn test_todo_url_encoded() { - let uri = "bitcoin:12c6DSiU4Rq3P4ZxziKxzrL5LmMBrzjrJX?amount=1&pj=https://example.com?ciao"; - assert!(Uri::try_from(uri).is_err(), "pj url should be url encoded"); - } - - #[test] - fn test_valid_url() { - let uri = "bitcoin:12c6DSiU4Rq3P4ZxziKxzrL5LmMBrzjrJX?amount=1&pj=this_is_NOT_a_validURL"; - assert!(Uri::try_from(uri).is_err(), "pj is not a valid url"); - } - - #[test] - fn test_missing_amount() { - let uri = - "bitcoin:12c6DSiU4Rq3P4ZxziKxzrL5LmMBrzjrJX?pj=https://testnet.demo.btcpayserver.org/BTC/pj"; - assert!(Uri::try_from(uri).is_ok(), "missing amount should be ok"); - } - - #[test] - fn test_unencrypted() { - let uri = "bitcoin:12c6DSiU4Rq3P4ZxziKxzrL5LmMBrzjrJX?amount=1&pj=http://example.com"; - assert!(Uri::try_from(uri).is_err(), "unencrypted connection"); - - let uri = "bitcoin:12c6DSiU4Rq3P4ZxziKxzrL5LmMBrzjrJX?amount=1&pj=ftp://foo.onion"; - assert!(Uri::try_from(uri).is_err(), "unencrypted connection"); - } - - #[test] - fn test_valid_uris() { - let https = "https://example.com"; - let onion = "http://vjdpwgybvubne5hda6v4c5iaeeevhge6jvo3w2cl6eocbwwvwxp7b7qd.onion"; - - let base58 = "bitcoin:12c6DSiU4Rq3P4ZxziKxzrL5LmMBrzjrJX"; - let bech32_upper = "BITCOIN:TB1Q6D3A2W975YNY0ASUVD9A67NER4NKS58FF0Q8G4"; - let bech32_lower = "bitcoin:tb1q6d3a2w975yny0asuvd9a67ner4nks58ff0q8g4"; - - for address in [base58, bech32_upper, bech32_lower].iter() { - for pj in [https, onion].iter() { - let uri = format!("{}?amount=1&pj={}", address, pj); - assert!(Uri::try_from(&*uri).is_ok()); + fn test_ffi_builder() { + let https = "https://example.com/"; + let onion = "http://vjdpwgybvubne5hda6v4c5iaeeevhge6jvo3w2cl6eocbwwvwxp7b7qd.onion/"; + let base58 = "12c6DSiU4Rq3P4ZxziKxzrL5LmMBrzjrJX"; + let bech32_upper = "TB1Q6D3A2W975YNY0ASUVD9A67NER4NKS58FF0Q8G4"; + let bech32_lower = "tb1q6d3a2w975yny0asuvd9a67ner4nks58ff0q8g4"; + + for address in vec![base58, bech32_upper, bech32_lower] { + for pj in vec![https, onion] { + let amount = bitcoin::Amount::ONE_BTC; + let builder = PjUriBuilder::new( + address.to_string(), + Url::from_str(pj.to_string()).unwrap(), + None, + ) + .unwrap(); + let uri = builder + .amount(amount.to_sat()) + .message("message".to_string()) + .pjos(true) + .label("label".to_string()) + .build(); + // assert_eq!(uri.amount(), Some(bitcoin::Amount::ONE_BTC.to_btc())); + print!("\n {}", uri.as_string()); } } } - - #[test] - fn test_unsupported() { - assert!(!Uri::try_from("bitcoin:12c6DSiU4Rq3P4ZxziKxzrL5LmMBrzjrJX") - .unwrap() - .extras - .pj_is_supported()); - } } From b005296130ae51d5599ea63269583f03385cd2ad Mon Sep 17 00:00:00 2001 From: BitcoinZavior Date: Thu, 18 Jul 2024 01:37:00 -0400 Subject: [PATCH 2/5] feat(PjUriBuilder): expiry added constructor. --- src/uri.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/uri.rs b/src/uri.rs index 7de1a2b..53f1cda 100644 --- a/src/uri.rs +++ b/src/uri.rs @@ -1,4 +1,5 @@ use std::str::FromStr; +use std::time::{Duration, UNIX_EPOCH}; use payjoin::bitcoin::address::NetworkChecked; use payjoin::UriExt; @@ -117,13 +118,19 @@ impl From for PjUriBuilder { #[cfg(not(feature = "uniffi"))] impl PjUriBuilder { ///Create a new PjUriBuilder with required parameters. + /// Parameters + // address: Represents a bitcoin address. + // origin: Represents either the payjoin endpoint in v1 or the directory in v2. + // ohttp_keys: Optional OHTTP keys for v2 (only available if the "v2" feature is enabled). + // expiry: Optional non-default duration_since epoch expiry for the payjoin session (only available if the "v2" feature is enabled). pub fn new( address: String, pj: Url, ohttp_keys: Option, + expiry: Option, ) -> Result { let address = payjoin::bitcoin::Address::from_str(&address)?.assume_checked(); - Ok(payjoin::PjUriBuilder::new(address, pj.into(), ohttp_keys.map(|e| e.0)).into()) + Ok(payjoin::PjUriBuilder::new(address, pj.into(), ohttp_keys.map(|e| e.0), expiry.map(|e| UNIX_EPOCH + Duration::from_secs(e)),).into()) } ///Accepts the amount you want to receive in sats and sets it in btc . pub fn amount(&self, amount: u64) -> Self { @@ -168,6 +175,7 @@ mod tests { address.to_string(), Url::from_str(pj.to_string()).unwrap(), None, + None ) .unwrap(); let uri = builder From cde43549160494554b82efc1a3171db92e99a7a4 Mon Sep 17 00:00:00 2001 From: BitcoinZavior Date: Thu, 18 Jul 2024 08:22:00 -0400 Subject: [PATCH 3/5] fix(SessionInitializer): made expire_after optional in constructor --- src/receive/v2.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/receive/v2.rs b/src/receive/v2.rs index 0807785..e04dc3d 100644 --- a/src/receive/v2.rs +++ b/src/receive/v2.rs @@ -67,7 +67,7 @@ impl SessionInitializer { #[cfg(feature = "uniffi")] pub fn new( address: String, - expire_after: u64, + expire_after: Option, network: Network, directory: Arc, ohttp_keys: Arc, @@ -80,13 +80,13 @@ impl SessionInitializer { (*directory).clone().into(), (*ohttp_keys).clone().into(), (*ohttp_relay).clone().into(), - Duration::from_secs(expire_after), + expire_after.map(|e| Duration::from_secs(e)), ) .into()) } pub fn new( address: String, - expire_after: u64, + expire_after: Option, network: Network, directory: Arc, ohttp_keys: Arc, @@ -99,7 +99,7 @@ impl SessionInitializer { (*directory).clone().into(), (*ohttp_keys).clone().into(), (*ohttp_relay).clone().into(), - Duration::from_secs(expire_after), + expire_after.map(|e| Duration::from_secs(e)), ) .into()) } From 93ded991bd6e0e0b47aefb7c06be8a35ab95a4e5 Mon Sep 17 00:00:00 2001 From: BitcoinZavior Date: Thu, 18 Jul 2024 11:11:00 -0400 Subject: [PATCH 4/5] code formatted --- src/error.rs | 2 +- src/receive/v1.rs | 7 +++++-- src/receive/v2.rs | 7 +++++-- src/uri.rs | 23 ++++++++++++++++------- 4 files changed, 27 insertions(+), 12 deletions(-) diff --git a/src/error.rs b/src/error.rs index 8a98ebc..a0bb791 100644 --- a/src/error.rs +++ b/src/error.rs @@ -43,7 +43,7 @@ pub enum PayjoinError { PjParseError { message: String }, #[error("{message}")] - PjNotSupported{ message: String }, + PjNotSupported { message: String }, #[error("Malformed response from receiver: {message}")] ValidationError { message: String }, diff --git a/src/receive/v1.rs b/src/receive/v1.rs index 5904f73..54c6a24 100644 --- a/src/receive/v1.rs +++ b/src/receive/v1.rs @@ -164,7 +164,8 @@ impl MaybeInputsOwned { self.0 .clone() .check_inputs_not_owned(|input| { - is_owned(&input.to_bytes()).map_err(|e| payjoin::receive::Error::Server(Box::new(e))) + is_owned(&input.to_bytes()) + .map_err(|e| payjoin::receive::Error::Server(Box::new(e))) }) .map_err(|e| e.into()) .map(|e| Arc::new(e.into())) @@ -222,7 +223,9 @@ impl MaybeInputsSeen { self.0 .clone() .check_no_inputs_seen_before(|outpoint| { - is_known.callback(outpoint.clone().into()).map_err(|e| pdk::Error::Server(Box::new(e))) + is_known + .callback(outpoint.clone().into()) + .map_err(|e| pdk::Error::Server(Box::new(e))) }) .map_err(|e| e.into()) .map(|e| Arc::new(e.into())) diff --git a/src/receive/v2.rs b/src/receive/v2.rs index e04dc3d..aea7b1f 100644 --- a/src/receive/v2.rs +++ b/src/receive/v2.rs @@ -333,7 +333,8 @@ impl V2MaybeInputsOwned { self.0 .clone() .check_inputs_not_owned(|input| { - is_owned(&input.to_bytes()).map_err(|e| payjoin::receive::Error::Server(Box::new(e))) + is_owned(&input.to_bytes()) + .map_err(|e| payjoin::receive::Error::Server(Box::new(e))) }) .map_err(|e| e.into()) .map(|e| Arc::new(e.into())) @@ -382,7 +383,9 @@ impl V2MaybeInputsSeen { self.0 .clone() .check_no_inputs_seen_before(|outpoint| { - is_known.callback(outpoint.clone().into()).map_err(|e| pdk::Error::Server(Box::new(e))) + is_known + .callback(outpoint.clone().into()) + .map_err(|e| pdk::Error::Server(Box::new(e))) }) .map(|e| Arc::new(e.into())) .map_err(|e| e.into()) diff --git a/src/uri.rs b/src/uri.rs index 53f1cda..f144af7 100644 --- a/src/uri.rs +++ b/src/uri.rs @@ -1,5 +1,5 @@ use std::str::FromStr; -use std::time::{Duration, UNIX_EPOCH}; +use std::time::{Duration, UNIX_EPOCH}; use payjoin::bitcoin::address::NetworkChecked; use payjoin::UriExt; @@ -33,13 +33,16 @@ impl Uri { } ///Gets the amount in satoshis. pub fn amount(&self) -> Option { - self.0.amount.map(|x| x.to_btc()) } - pub fn check_pj_supported(&self) -> Result { - match self.0.clone().check_pj_supported(){ + pub fn check_pj_supported(&self) -> Result { + match self.0.clone().check_pj_supported() { Ok(e) => Ok(e.into()), - Err(_) => Err(PayjoinError::PjNotSupported{message:"Uri doesn't support payjoin".to_string()}) + Err(_) => { + Err(PayjoinError::PjNotSupported { + message: "Uri doesn't support payjoin".to_string(), + }) + } } } pub fn as_string(&self) -> String { @@ -130,7 +133,13 @@ impl PjUriBuilder { expiry: Option, ) -> Result { let address = payjoin::bitcoin::Address::from_str(&address)?.assume_checked(); - Ok(payjoin::PjUriBuilder::new(address, pj.into(), ohttp_keys.map(|e| e.0), expiry.map(|e| UNIX_EPOCH + Duration::from_secs(e)),).into()) + Ok(payjoin::PjUriBuilder::new( + address, + pj.into(), + ohttp_keys.map(|e| e.0), + expiry.map(|e| UNIX_EPOCH + Duration::from_secs(e)), + ) + .into()) } ///Accepts the amount you want to receive in sats and sets it in btc . pub fn amount(&self, amount: u64) -> Self { @@ -175,7 +184,7 @@ mod tests { address.to_string(), Url::from_str(pj.to_string()).unwrap(), None, - None + None, ) .unwrap(); let uri = builder From e4201d7cb3e0d1fb364f9484fdd5b92639f1db00 Mon Sep 17 00:00:00 2001 From: BitcoinZavior Date: Thu, 18 Jul 2024 11:14:00 -0400 Subject: [PATCH 5/5] integration tests updated --- tests/bdk_integration_test.rs | 6 +----- tests/bitcoin_core_integration.rs | 8 +++----- 2 files changed, 4 insertions(+), 10 deletions(-) diff --git a/tests/bdk_integration_test.rs b/tests/bdk_integration_test.rs index 2eb4d02..9b199d4 100644 --- a/tests/bdk_integration_test.rs +++ b/tests/bdk_integration_test.rs @@ -278,10 +278,6 @@ fn handle_proposal(proposal: UncheckedProposal, receiver: Wallet) -> Arc Result<(), BoxError> { pj_receiver_address.to_string(), Url::from_str("https://example.com".to_string())?, None, + None, )? - .amount(0.0083285) + .amount(832_850) .build() .as_string(); print!("pj_uri {}", pj_uri_string); @@ -60,7 +61,7 @@ fn v1_to_v1_full_cycle() -> Result<(), BoxError> { .psbt; let psbt_base64 = sender.wallet_process_psbt(&psbt, None, None, None)?.psbt; eprintln!("Original psbt: {:#?}", psbt_base64); - let req_ctx = RequestBuilder::from_psbt_and_uri(psbt_base64, Arc::new(pj_uri))? + let req_ctx = RequestBuilder::from_psbt_and_uri(psbt_base64, Arc::new(pj_uri.check_pj_supported().unwrap()))? .build_with_additional_fee(10000, None, 0, false)? .extract_v1()?; let req = req_ctx.request; @@ -175,9 +176,6 @@ fn handle_pj_proposal(proposal: UncheckedProposal, receiver: Arc) -> Arc .contribute_witness_input(txo_to_contribute, outpoint_to_contribute) .expect("contribute_witness_input error"); - let receiver_substitute_address = - receiver.get_new_address(None, None).unwrap().assume_checked(); - payjoin.substitute_output_address(receiver_substitute_address.to_string()).unwrap(); let payjoin_proposal = payjoin .finalize_proposal( |e| {