diff --git a/.sqlx/query-40d91f489356af51ae859a2237fa85cc8f96a63c1dbc237d44a2d18a8a5b365a.json b/.sqlx/query-40d91f489356af51ae859a2237fa85cc8f96a63c1dbc237d44a2d18a8a5b365a.json deleted file mode 100644 index 0c07dcd2..00000000 --- a/.sqlx/query-40d91f489356af51ae859a2237fa85cc8f96a63c1dbc237d44a2d18a8a5b365a.json +++ /dev/null @@ -1,125 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "SELECT\n payout_queue_id, unsigned_psbt, signed_tx, bitcoin_tx_id, s.batch_id,\n s.wallet_id, s.current_keychain_id, s.signing_keychains, total_in_sats,\n total_spent_sats, change_sats, change_address, change_vout, s.total_fee_sats,\n cpfp_fee_sats, cpfp_details, batch_created_ledger_tx_id, batch_broadcast_ledger_tx_id\n FROM bria_batch_wallet_summaries s\n LEFT JOIN bria_batches b ON b.id = s.batch_id\n WHERE s.batch_id = $1 AND b.account_id = $2", - "describe": { - "columns": [ - { - "ordinal": 0, - "name": "payout_queue_id", - "type_info": "Uuid" - }, - { - "ordinal": 1, - "name": "unsigned_psbt", - "type_info": "Bytea" - }, - { - "ordinal": 2, - "name": "signed_tx", - "type_info": "Bytea" - }, - { - "ordinal": 3, - "name": "bitcoin_tx_id", - "type_info": "Bytea" - }, - { - "ordinal": 4, - "name": "batch_id", - "type_info": "Uuid" - }, - { - "ordinal": 5, - "name": "wallet_id", - "type_info": "Uuid" - }, - { - "ordinal": 6, - "name": "current_keychain_id", - "type_info": "Uuid" - }, - { - "ordinal": 7, - "name": "signing_keychains", - "type_info": "UuidArray" - }, - { - "ordinal": 8, - "name": "total_in_sats", - "type_info": "Int8" - }, - { - "ordinal": 9, - "name": "total_spent_sats", - "type_info": "Int8" - }, - { - "ordinal": 10, - "name": "change_sats", - "type_info": "Int8" - }, - { - "ordinal": 11, - "name": "change_address", - "type_info": "Varchar" - }, - { - "ordinal": 12, - "name": "change_vout", - "type_info": "Int4" - }, - { - "ordinal": 13, - "name": "total_fee_sats", - "type_info": "Int8" - }, - { - "ordinal": 14, - "name": "cpfp_fee_sats", - "type_info": "Int8" - }, - { - "ordinal": 15, - "name": "cpfp_details", - "type_info": "Jsonb" - }, - { - "ordinal": 16, - "name": "batch_created_ledger_tx_id", - "type_info": "Uuid" - }, - { - "ordinal": 17, - "name": "batch_broadcast_ledger_tx_id", - "type_info": "Uuid" - } - ], - "parameters": { - "Left": [ - "Uuid", - "Uuid" - ] - }, - "nullable": [ - false, - false, - true, - false, - false, - false, - false, - false, - false, - false, - false, - true, - true, - false, - false, - false, - true, - true - ] - }, - "hash": "40d91f489356af51ae859a2237fa85cc8f96a63c1dbc237d44a2d18a8a5b365a" -} diff --git a/.sqlx/query-83ce7790000ed6abed021305761008d0d5423d191aab8e911e10c99da41458e1.json b/.sqlx/query-83ce7790000ed6abed021305761008d0d5423d191aab8e911e10c99da41458e1.json deleted file mode 100644 index cf325649..00000000 --- a/.sqlx/query-83ce7790000ed6abed021305761008d0d5423d191aab8e911e10c99da41458e1.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "INSERT INTO bria_batches (id, account_id, payout_queue_id, total_fee_sats, bitcoin_tx_id, unsigned_psbt)\n VALUES ($1, $2, $3, $4, $5, $6)", - "describe": { - "columns": [], - "parameters": { - "Left": [ - "Uuid", - "Uuid", - "Uuid", - "Int8", - "Bytea", - "Bytea" - ] - }, - "nullable": [] - }, - "hash": "83ce7790000ed6abed021305761008d0d5423d191aab8e911e10c99da41458e1" -} diff --git a/Cargo.lock b/Cargo.lock index 6818b6af..1b65c3e8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,18 +4,28 @@ version = 3 [[package]] name = "addr2line" -version = "0.21.0" +version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" +checksum = "f5fb1d8e4442bd405fdfd1dacb42792696b0cf9cb15882e5d097b742a676d375" dependencies = [ "gimli", ] [[package]] -name = "adler" -version = "1.0.2" +name = "adler2" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" + +[[package]] +name = "aead" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +checksum = "0b613b8e1e3cf911a086f53f03bf286f52fd7a7258e4fa606f0ef220d39d8877" +dependencies = [ + "generic-array", + "rand_core", +] [[package]] name = "aead" @@ -27,6 +37,32 @@ dependencies = [ "generic-array", ] +[[package]] +name = "aes" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e8b47f52ea9bae42228d07ec09eb676433d7c4ed1ebdf0f1d1c29ed446f1ab8" +dependencies = [ + "cfg-if", + "cipher 0.3.0", + "cpufeatures 0.2.14", + "opaque-debug", +] + +[[package]] +name = "aes-gcm" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc3be92e19a7ef47457b8e6f90707e12b6ac5d20c6f3866584fa3be0787d839f" +dependencies = [ + "aead 0.4.3", + "aes", + "cipher 0.3.0", + "ctr", + "ghash", + "subtle", +] + [[package]] name = "ahash" version = "0.7.8" @@ -53,18 +89,18 @@ dependencies = [ [[package]] name = "aho-corasick" -version = "1.1.2" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" dependencies = [ "memchr", ] [[package]] name = "allocator-api2" -version = "0.2.16" +version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0942ffc6dcaadf03badf6e6a2d0228460359d5e34b57ccdc720b7382dfbd5ec5" +checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f" [[package]] name = "android-tzdata" @@ -83,47 +119,48 @@ dependencies = [ [[package]] name = "anstream" -version = "0.6.13" +version = "0.6.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d96bd03f33fe50a863e394ee9718a706f988b9079b20c3784fb726e7678b62fb" +checksum = "64e15c1ab1f89faffbf04a634d5e1962e9074f2741eef6d97f3c4e322426d526" dependencies = [ "anstyle", "anstyle-parse", "anstyle-query", "anstyle-wincon", "colorchoice", + "is_terminal_polyfill", "utf8parse", ] [[package]] name = "anstyle" -version = "1.0.6" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8901269c6307e8d93993578286ac0edf7f195079ffff5ebdeea6a59ffb7e36bc" +checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1" [[package]] name = "anstyle-parse" -version = "0.2.3" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c75ac65da39e5fe5ab759307499ddad880d724eed2f6ce5b5e8a26f4f387928c" +checksum = "eb47de1e80c2b463c735db5b217a0ddc39d612e7ac9e2e96a5aed1f57616c1cb" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" -version = "1.0.2" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e28923312444cdd728e4738b3f9c9cac739500909bb3d3c94b43551b16517648" +checksum = "6d36fc52c7f6c869915e99412912f22093507da8d9e942ceaf66fe4b7c14422a" dependencies = [ "windows-sys 0.52.0", ] [[package]] name = "anstyle-wincon" -version = "3.0.2" +version = "3.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cd54b81ec8d6180e24654d0b371ad22fc3dd083b6ff8ba325b72e00c87660a7" +checksum = "5bf74e1b6e971609db8ca7a9ce79fd5768ab6ae46441c572e46cf596f59e57f8" dependencies = [ "anstyle", "windows-sys 0.52.0", @@ -131,9 +168,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.82" +version = "1.0.88" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f538837af36e6f6a9be0faa67f9a314f8119e4e4b5867c6ab40ed60360142519" +checksum = "4e1496f8fb1fbf272686b8d37f523dab3e4a7443300055e74cdaa449f3114356" [[package]] name = "anymap2" @@ -143,9 +180,9 @@ checksum = "d301b3b94cb4b2f23d7917810addbbaff90738e0ca2be692bd027e70d7e0330c" [[package]] name = "arrayvec" -version = "0.7.4" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" [[package]] name = "ascii-canvas" @@ -175,18 +212,18 @@ checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.77", ] [[package]] name = "async-trait" -version = "0.1.80" +version = "0.1.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6fa2087f2753a7da8cc1c0dbfcf89579dd57458e36769de5ac750b4671737ca" +checksum = "a27b8a3a6e1a44fa4c8baf1f653e4172e81486d4941f2237e20dc2d0cf4ddff1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.77", ] [[package]] @@ -200,15 +237,15 @@ dependencies = [ [[package]] name = "autocfg" -version = "1.1.0" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" [[package]] name = "autotools" -version = "0.2.6" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aef8da1805e028a172334c3b680f93e71126f2327622faef2ec3d893c0a4ad77" +checksum = "ef941527c41b0fc0dd48511a8154cd5fc7e29200a0ff8b7203c5d777dbc795cf" dependencies = [ "cc", ] @@ -226,7 +263,7 @@ dependencies = [ "futures-util", "http 0.2.12", "http-body 0.4.6", - "hyper 0.14.28", + "hyper 0.14.30", "itoa", "matchit", "memchr", @@ -260,17 +297,27 @@ dependencies = [ [[package]] name = "backtrace" -version = "0.3.69" +version = "0.3.74" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" +checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" dependencies = [ "addr2line", - "cc", "cfg-if", "libc", "miniz_oxide", "object", "rustc-demangle", + "windows-targets 0.52.6", +] + +[[package]] +name = "base58ck" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c8d66485a3a2ea485c1913c4572ce0256067a5377ac8c75c4960e1cda98605f" +dependencies = [ + "bitcoin-internals", + "bitcoin_hashes 0.14.0", ] [[package]] @@ -305,7 +352,7 @@ checksum = "2fc1fc1a92e0943bfbcd6eb7d32c1b2a79f2f1357eb1e2eee9d7f36d6d7ca44a" dependencies = [ "async-trait", "bdk-macros", - "bitcoin", + "bitcoin 0.30.2", "electrum-client", "getrandom", "js-sys", @@ -335,6 +382,31 @@ version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d86b93f97252c47b41663388e6d155714a9d0c398b99f1005cbc5f978b29f445" +[[package]] +name = "bech32" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d965446196e3b7decd44aa7ee49e31d630118f90ef12f97900f262eb915c951d" + +[[package]] +name = "bhttp" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ef06386f8f092c3419e153a657396e53cafbb901de445a5c54d96ab2ff8c7b2" +dependencies = [ + "thiserror", +] + +[[package]] +name = "bip21" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebe7a7f5928d264879d5b65eb18a72ea1890c57f22d62ee2eba93f207a6a020b" +dependencies = [ + "bitcoin 0.32.2", + "percent-encoding-rfc3986", +] + [[package]] name = "bit-set" version = "0.5.3" @@ -357,20 +429,106 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1945a5048598e4189e239d3f809b19bdad4845c4b2ba400d304d2dcf26d2c462" dependencies = [ "base64 0.13.1", - "bech32", + "bech32 0.9.1", "bitcoin-private", - "bitcoin_hashes", + "bitcoin_hashes 0.12.0", "hex_lit", - "secp256k1", + "secp256k1 0.27.0", "serde", ] +[[package]] +name = "bitcoin" +version = "0.32.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea507acc1cd80fc084ace38544bbcf7ced7c2aa65b653b102de0ce718df668f6" +dependencies = [ + "base58ck", + "base64 0.21.7", + "bech32 0.11.0", + "bitcoin-internals", + "bitcoin-io", + "bitcoin-units", + "bitcoin_hashes 0.14.0", + "hex-conservative", + "hex_lit", + "secp256k1 0.29.1", + "serde", +] + +[[package]] +name = "bitcoin-hpke" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d37a54c486727c1d1ae9cc28dcf78b6e6ba20dcb88e8c892f1437d9ce215dc8c" +dependencies = [ + "aead 0.5.2", + "chacha20poly1305 0.10.1", + "digest 0.10.7", + "generic-array", + "hkdf 0.12.4", + "hmac 0.12.1", + "rand_core", + "secp256k1 0.29.1", + "sha2 0.10.8", + "subtle", + "zeroize", +] + +[[package]] +name = "bitcoin-internals" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +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-ohttp" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87a803a4b54e44635206b53329c78c0029d0c70926288ac2f07f4bb1267546cb" +dependencies = [ + "aead 0.4.3", + "aes-gcm", + "bitcoin-hpke", + "byteorder", + "chacha20poly1305 0.8.0", + "hex", + "hkdf 0.11.0", + "lazy_static", + "log", + "rand", + "serde", + "serde_derive", + "sha2 0.9.9", + "thiserror", + "toml", +] + [[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", + "serde", +] + [[package]] name = "bitcoin_hashes" version = "0.12.0" @@ -381,6 +539,17 @@ dependencies = [ "serde", ] +[[package]] +name = "bitcoin_hashes" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb18c03d0db0247e147a21a6faafd5a7eb851c743db062de72018b6b7e8e4d16" +dependencies = [ + "bitcoin-io", + "hex-conservative", + "serde", +] + [[package]] name = "bitcoincore-rpc" version = "0.17.0" @@ -401,7 +570,7 @@ version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d30ce6f40fb0a2e8d98522796219282504b7a4b14e2b4c26139a7bea6aec6586" dependencies = [ - "bitcoin", + "bitcoin 0.30.2", "bitcoin-private", "serde", "serde_json", @@ -415,9 +584,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.4.2" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf" +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" dependencies = [ "serde", ] @@ -434,6 +603,15 @@ dependencies = [ "wyz", ] +[[package]] +name = "block-buffer" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" +dependencies = [ + "generic-array", +] + [[package]] name = "block-buffer" version = "0.10.4" @@ -445,9 +623,9 @@ dependencies = [ [[package]] name = "borsh" -version = "1.3.1" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f58b559fd6448c6e2fd0adb5720cd98a2506594cafa4737ff98c396f3e82f667" +checksum = "a6362ed55def622cddc70a4746a68554d7b687713770de539e59a739b249f8ed" dependencies = [ "borsh-derive", "cfg_aliases", @@ -455,15 +633,15 @@ dependencies = [ [[package]] name = "borsh-derive" -version = "1.3.1" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7aadb5b6ccbd078890f6d7003694e33816e6b784358f18e15e7e6d9f065a57cd" +checksum = "c3ef8005764f53cd4dca619f5bf64cafd4664dada50ece25e4d81de54c80cc0b" dependencies = [ "once_cell", "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.77", "syn_derive", ] @@ -476,7 +654,7 @@ dependencies = [ "base64 0.22.1", "bdk", "bitcoincore-rpc", - "chacha20poly1305", + "chacha20poly1305 0.10.1", "chrono", "clap", "derive_builder", @@ -488,12 +666,13 @@ dependencies = [ "opentelemetry", "opentelemetry-otlp", "opentelemetry_sdk", + "payjoin", "prost", "prost-wkt-types", "protobuf-src", "rand", "regex", - "reqwest 0.12.5", + "reqwest 0.12.7", "reqwest-middleware", "reqwest-retry", "rust_decimal", @@ -523,9 +702,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.15.3" +version = "3.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ea184aa71bb362a1157c896979544cc23974e08fd265f29ea96b59f0b4a555b" +checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" [[package]] name = "bytecheck" @@ -557,22 +736,22 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.5.0" +version = "1.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" +checksum = "8318a53db07bb3f8dca91a600466bdb3f2eaadeedfdbcf02e1accbad9271ba50" [[package]] name = "cached" -version = "0.49.2" +version = "0.49.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f251fd1e72720ca07bf5d8e310f54a193fd053479a1f6342c6663ee4fa01cf96" +checksum = "8e8e463fceca5674287f32d252fb1d94083758b8709c160efae66d263e5f4eba" dependencies = [ "ahash 0.8.11", "async-trait", "cached_proc_macro", "cached_proc_macro_types", "futures", - "hashbrown 0.14.3", + "hashbrown 0.14.5", "instant", "once_cell", "thiserror", @@ -599,9 +778,12 @@ checksum = "ade8366b8bd5ba243f0a58f036cc0ca8a2f069cff1a2351ef1cac6b083e16fc0" [[package]] name = "cc" -version = "1.0.89" +version = "1.1.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0ba8f7aaa012f30d5b2861462f6708eccd49c3c39863fe083a308035f63d723" +checksum = "b62ac837cdb5cb22e10a256099b4fc502b1dfe560cb282963a974d7abd80e476" +dependencies = [ + "shlex", +] [[package]] name = "cfg-if" @@ -611,9 +793,21 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "cfg_aliases" -version = "0.1.1" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" + +[[package]] +name = "chacha20" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fee7ad89dc1128635074c268ee661f90c3f7e83d9fd12910608c36b47d6c3412" +dependencies = [ + "cfg-if", + "cipher 0.3.0", + "cpufeatures 0.1.5", + "zeroize", +] [[package]] name = "chacha20" @@ -622,8 +816,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3613f74bd2eac03dad61bd53dbe620703d4371614fe0bc3b9f04dd36fe4e818" dependencies = [ "cfg-if", - "cipher", - "cpufeatures", + "cipher 0.4.4", + "cpufeatures 0.2.14", +] + +[[package]] +name = "chacha20poly1305" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1580317203210c517b6d44794abfbe600698276db18127e37ad3e69bf5e848e5" +dependencies = [ + "aead 0.4.3", + "chacha20 0.7.1", + "cipher 0.3.0", + "poly1305 0.7.2", + "zeroize", ] [[package]] @@ -632,10 +839,10 @@ version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "10cd79432192d1c0f4e1a0fef9527696cc039165d729fb41b3f4f4f354c2dc35" dependencies = [ - "aead", - "chacha20", - "cipher", - "poly1305", + "aead 0.5.2", + "chacha20 0.9.1", + "cipher 0.4.4", + "poly1305 0.8.0", "zeroize", ] @@ -651,7 +858,16 @@ dependencies = [ "num-traits", "serde", "wasm-bindgen", - "windows-targets 0.52.4", + "windows-targets 0.52.6", +] + +[[package]] +name = "cipher" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ee52072ec15386f770805afd189a01c8841be8696bed250fa2f13c4c0d6dfb7" +dependencies = [ + "generic-array", ] [[package]] @@ -667,9 +883,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.4" +version = "4.5.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90bc066a67923782aa8515dbaea16946c5bcc5addbd668bb80af688e53e548a0" +checksum = "3e5a21b8495e732f1b3c364c9949b201ca7bae518c502c80256c96ad79eaf6ac" dependencies = [ "clap_builder", "clap_derive", @@ -677,39 +893,39 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.2" +version = "4.5.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae129e2e766ae0ec03484e609954119f123cc1fe650337e155d03b022f24f7b4" +checksum = "8cf2dd12af7a047ad9d6da2b6b249759a22a7abc0f474c1dae1777afa4b21a73" dependencies = [ "anstream", "anstyle", "clap_lex", - "strsim 0.11.0", + "strsim 0.11.1", ] [[package]] name = "clap_derive" -version = "4.5.4" +version = "4.5.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "528131438037fd55894f62d6e9f068b8f45ac57ffa77517819645d10aed04f64" +checksum = "501d359d5f3dcaf6ecdeee48833ae73ec6e42723a1e52419c79abf9507eec0a0" dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.77", ] [[package]] name = "clap_lex" -version = "0.7.0" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce" +checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97" [[package]] name = "colorchoice" -version = "1.0.0" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" +checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0" [[package]] name = "const-oid" @@ -729,24 +945,33 @@ dependencies = [ [[package]] name = "core-foundation-sys" -version = "0.8.6" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" [[package]] name = "cpufeatures" -version = "0.2.12" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66c99696f6c9dd7f35d486b9d04d7e6e202aa3e8c40d553f2fdf5e7e0c6a71ef" +dependencies = [ + "libc", +] + +[[package]] +name = "cpufeatures" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" +checksum = "608697df725056feaccfa42cffdaeeec3fccc4ffc38358ecd19b243e716a78e0" dependencies = [ "libc", ] [[package]] name = "crc" -version = "3.0.1" +version = "3.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86ec7a15cbe22e59248fc7eadb1907dab5ba09372595da4d73dd805ed4417dfe" +checksum = "69e6e4d7b33a94f0991c26729976b10ebde1d34c3ee82408fb536164fa10d636" dependencies = [ "crc-catalog", ] @@ -759,9 +984,9 @@ checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5" [[package]] name = "crc32fast" -version = "1.4.0" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3855a8a784b474f333699ef2bbca9db2c4a1f6d9088a90a2d25b1eb53111eaa" +checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" dependencies = [ "cfg-if", ] @@ -786,9 +1011,9 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.19" +version = "0.8.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345" +checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" [[package]] name = "crunchy" @@ -807,6 +1032,25 @@ dependencies = [ "typenum", ] +[[package]] +name = "crypto-mac" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25fab6889090c8133f3deb8f73ba3c65a7f456f66436fc012a1b1e272b1e103e" +dependencies = [ + "generic-array", + "subtle", +] + +[[package]] +name = "ctr" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a232f92a03f37dd7d7dd2adc67166c77e9cd88de5b019b9a9eecfaeaf7bfd481" +dependencies = [ + "cipher 0.3.0", +] + [[package]] name = "darling" version = "0.14.4" @@ -819,12 +1063,12 @@ dependencies = [ [[package]] name = "darling" -version = "0.20.8" +version = "0.20.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54e36fcd13ed84ffdfda6f5be89b31287cbb80c439841fe69e04841435464391" +checksum = "6f63b86c8a8826a49b8c21f08a2d07338eec8d900540f8630dc76284be802989" dependencies = [ - "darling_core 0.20.8", - "darling_macro 0.20.8", + "darling_core 0.20.10", + "darling_macro 0.20.10", ] [[package]] @@ -843,16 +1087,16 @@ dependencies = [ [[package]] name = "darling_core" -version = "0.20.8" +version = "0.20.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c2cf1c23a687a1feeb728783b993c4e1ad83d99f351801977dd809b48d0a70f" +checksum = "95133861a8032aaea082871032f5815eb9e98cef03fa916ab4500513994df9e5" dependencies = [ "fnv", "ident_case", "proc-macro2", "quote", - "strsim 0.10.0", - "syn 2.0.52", + "strsim 0.11.1", + "syn 2.0.77", ] [[package]] @@ -868,20 +1112,20 @@ dependencies = [ [[package]] name = "darling_macro" -version = "0.20.8" +version = "0.20.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a668eda54683121533a393014d8692171709ff57a7d61f187b6e782719f8933f" +checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" dependencies = [ - "darling_core 0.20.8", + "darling_core 0.20.10", "quote", - "syn 2.0.52", + "syn 2.0.77", ] [[package]] name = "der" -version = "0.7.8" +version = "0.7.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fffa369a668c8af7dbf8b5e56c9f744fbd399949ed171606040001947de40b1c" +checksum = "f55bf8e7b65898637379c1b74eb1551107c8294ed26d855ceb9fd1a09cfc9bc0" dependencies = [ "const-oid", "pem-rfc7468", @@ -900,33 +1144,42 @@ dependencies = [ [[package]] name = "derive_builder" -version = "0.20.0" +version = "0.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0350b5cb0331628a5916d6c5c0b72e97393b8b6b03b47a9284f4e7f5a405ffd7" +checksum = "cd33f37ee6a119146a1781d3356a7c26028f83d779b2e04ecd45fdc75c76877b" dependencies = [ "derive_builder_macro", ] [[package]] name = "derive_builder_core" -version = "0.20.0" +version = "0.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d48cda787f839151732d396ac69e3473923d54312c070ee21e9effcaa8ca0b1d" +checksum = "7431fa049613920234f22c47fdc33e6cf3ee83067091ea4277a3f8c4587aae38" dependencies = [ - "darling 0.20.8", + "darling 0.20.10", "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.77", ] [[package]] name = "derive_builder_macro" -version = "0.20.0" +version = "0.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "206868b8242f27cecce124c19fd88157fbd0dd334df2587f36417bafbc85097b" +checksum = "4abae7035bf79b9877b779505d8cf3749285b80c43941eda66604841889451dc" dependencies = [ "derive_builder_core", - "syn 2.0.52", + "syn 2.0.77", +] + +[[package]] +name = "digest" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" +dependencies = [ + "generic-array", ] [[package]] @@ -935,7 +1188,7 @@ version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ - "block-buffer", + "block-buffer 0.10.4", "const-oid", "crypto-common", "subtle", @@ -976,9 +1229,9 @@ checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b" [[package]] name = "either" -version = "1.10.0" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a" +checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" dependencies = [ "serde", ] @@ -989,12 +1242,12 @@ version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6bc133f1c8d829d254f013f946653cbeb2b08674b960146361d1e9b67733ad19" dependencies = [ - "bitcoin", + "bitcoin 0.30.2", "bitcoin-private", "byteorder", "libc", "log", - "rustls 0.21.11", + "rustls 0.21.12", "serde", "serde_json", "webpki", @@ -1004,18 +1257,18 @@ dependencies = [ [[package]] name = "ena" -version = "0.14.2" +version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c533630cf40e9caa44bd91aadc88a75d75a4c3a12b4cfde353cbed41daa1e1f1" +checksum = "3d248bdd43ce613d87415282f69b9bb99d947d290b10962dd6c56233312c2ad5" dependencies = [ "log", ] [[package]] name = "encoding_rs" -version = "0.8.33" +version = "0.8.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7268b386296a025e474d5140678f75d6de9493ae55a5d709eeb9dd08149945e1" +checksum = "b45de904aa0b010bce2ab45264d0631681847fa7b6f2eaa7dab7619943bc4f59" dependencies = [ "cfg-if", ] @@ -1028,18 +1281,19 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "erased-serde" -version = "0.4.3" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "388979d208a049ffdfb22fa33b9c81942215b940910bccfe258caeb25d125cb3" +checksum = "24e2389d65ab4fab27dc2a5de7b191e1f6617d1f1c8855c0dc569c94a4cbb18d" dependencies = [ "serde", + "typeid", ] [[package]] name = "errno" -version = "0.3.8" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" +checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" dependencies = [ "libc", "windows-sys 0.52.0", @@ -1064,9 +1318,9 @@ checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" [[package]] name = "fastrand" -version = "2.0.1" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" +checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6" [[package]] name = "fedimint-tonic-lnd" @@ -1076,10 +1330,10 @@ checksum = "df03ca33b5116de3051c1e233fe341e23b04c4913c7b16042497924559bc2a2e" dependencies = [ "hex", "http-body 0.4.6", - "hyper 0.14.28", + "hyper 0.14.30", "hyper-rustls 0.24.2", "prost", - "rustls 0.21.11", + "rustls 0.21.12", "rustls-pemfile 1.0.4", "tokio", "tokio-stream", @@ -1088,12 +1342,6 @@ dependencies = [ "tower", ] -[[package]] -name = "finl_unicode" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fcfdc7a0362c9f4444381a9e697c79d435fe65b52a37466fc2c1184cee9edc6" - [[package]] name = "fixedbitset" version = "0.4.2" @@ -1108,7 +1356,7 @@ checksum = "55ac459de2512911e4b674ce33cf20befaba382d05b62b008afc1c8b57cbf181" dependencies = [ "futures-core", "futures-sink", - "spin 0.9.8", + "spin", ] [[package]] @@ -1192,7 +1440,7 @@ checksum = "1d930c203dd0b6ff06e0201a4a2fe9149b43c684fd4420555b26d21b1a02956f" dependencies = [ "futures-core", "lock_api", - "parking_lot 0.12.1", + "parking_lot 0.12.3", ] [[package]] @@ -1209,7 +1457,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.77", ] [[package]] @@ -1263,9 +1511,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.12" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ "cfg-if", "js-sys", @@ -1274,11 +1522,21 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "ghash" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1583cc1656d7839fd3732b80cf4f38850336cdb9b8ded1cd399ca62958de3c99" +dependencies = [ + "opaque-debug", + "polyval", +] + [[package]] name = "gimli" -version = "0.28.1" +version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" +checksum = "32085ea23f3234fc7846555e85283ba4de91e21016dc0455a16286d87a292d64" [[package]] name = "glob" @@ -1298,7 +1556,7 @@ dependencies = [ "futures-sink", "futures-util", "http 0.2.12", - "indexmap 2.2.5", + "indexmap 2.5.0", "slab", "tokio", "tokio-util", @@ -1316,9 +1574,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.14.3" +version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" dependencies = [ "ahash 0.8.11", "allocator-api2", @@ -1330,7 +1588,7 @@ version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e8094feaf31ff591f651a2664fb9cfd92bba7a60ce3197265e9482ebe753c8f7" dependencies = [ - "hashbrown 0.14.3", + "hashbrown 0.14.5", ] [[package]] @@ -1360,19 +1618,48 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +[[package]] +name = "hex-conservative" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5313b072ce3c597065a808dbf612c4c8e8590bdbf8b579508bf7a762c5eae6cd" +dependencies = [ + "arrayvec", +] + [[package]] name = "hex_lit" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3011d1213f159867b13cfd6ac92d2cd5f1345762c63be3554e84092d85a50bbd" +[[package]] +name = "hkdf" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01706d578d5c281058480e673ae4086a9f4710d8df1ad80a5b03e39ece5f886b" +dependencies = [ + "digest 0.9.0", + "hmac 0.11.0", +] + [[package]] name = "hkdf" version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7" dependencies = [ - "hmac", + "hmac 0.12.1", +] + +[[package]] +name = "hmac" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a2a2320eb7ec0ebe8da8f744d7812d9fc4cb4d09344ac01898dbcb6a20ae69b" +dependencies = [ + "crypto-mac", + "digest 0.9.0", ] [[package]] @@ -1381,7 +1668,7 @@ version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" dependencies = [ - "digest", + "digest 0.10.7", ] [[package]] @@ -1428,9 +1715,9 @@ dependencies = [ [[package]] name = "http-body" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cac85db508abc24a2e48553ba12a996e87244a0395ce011e62b37158745d643" +checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" dependencies = [ "bytes", "http 1.1.0", @@ -1438,22 +1725,22 @@ dependencies = [ [[package]] name = "http-body-util" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0475f8b2ac86659c21b64320d5d653f9efe42acd2a4e560073ec61a155a34f1d" +checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f" dependencies = [ "bytes", - "futures-core", + "futures-util", "http 1.1.0", - "http-body 1.0.0", + "http-body 1.0.1", "pin-project-lite", ] [[package]] name = "httparse" -version = "1.8.0" +version = "1.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" +checksum = "0fcc0b4a115bf80b728eb8ea024ad5bd707b615bfed49e0665b6e0f86fd082d9" [[package]] name = "httpdate" @@ -1463,9 +1750,9 @@ checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" [[package]] name = "hyper" -version = "0.14.28" +version = "0.14.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf96e135eb83a2a8ddf766e426a841d8ddd7449d5f00d34ea02b41d2f19eef80" +checksum = "a152ddd61dfaec7273fe8419ab357f33aee0d914c5f4efbf0d96fa749eea5ec9" dependencies = [ "bytes", "futures-channel", @@ -1487,15 +1774,15 @@ dependencies = [ [[package]] name = "hyper" -version = "1.2.0" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "186548d73ac615b32a73aafe38fb4f56c0d340e110e5a200bcadbaf2e199263a" +checksum = "50dfd22e0e76d0f662d429a5f80fcaf3855009297eab6a0a9f8543834744ba05" dependencies = [ "bytes", "futures-channel", "futures-util", "http 1.1.0", - "http-body 1.0.0", + "http-body 1.0.1", "httparse", "itoa", "pin-project-lite", @@ -1512,28 +1799,28 @@ checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590" dependencies = [ "futures-util", "http 0.2.12", - "hyper 0.14.28", - "rustls 0.21.11", + "hyper 0.14.30", + "rustls 0.21.12", "tokio", "tokio-rustls 0.24.1", ] [[package]] name = "hyper-rustls" -version = "0.27.2" +version = "0.27.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ee4be2c948921a1a5320b629c4193916ed787a7f7f293fd3f7f5a6c9de74155" +checksum = "08afdbb5c31130e3034af566421053ab03787c640246a446327f550d11bcb333" dependencies = [ "futures-util", "http 1.1.0", - "hyper 1.2.0", + "hyper 1.4.1", "hyper-util", - "rustls 0.23.10", + "rustls 0.23.13", "rustls-pki-types", "tokio", "tokio-rustls 0.26.0", "tower-service", - "webpki-roots 0.26.1", + "webpki-roots 0.26.5", ] [[package]] @@ -1542,7 +1829,7 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbb958482e8c7be4bc3cf272a766a2b0bf1a6755e7a6ae777f017a31d11b13b1" dependencies = [ - "hyper 0.14.28", + "hyper 0.14.30", "pin-project-lite", "tokio", "tokio-io-timeout", @@ -1550,16 +1837,16 @@ dependencies = [ [[package]] name = "hyper-util" -version = "0.1.3" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca38ef113da30126bbff9cd1705f9273e15d45498615d138b0c20279ac7a76aa" +checksum = "da62f120a8a37763efb0cf8fdf264b884c7b8b9ac8660b900c8661030c00e6ba" dependencies = [ "bytes", "futures-channel", "futures-util", "http 1.1.0", - "http-body 1.0.0", - "hyper 1.2.0", + "http-body 1.0.1", + "hyper 1.4.1", "pin-project-lite", "socket2", "tokio", @@ -1620,12 +1907,12 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.2.5" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b0b929d511467233429c45a44ac1dcaa21ba0f5ba11e4879e6ed28ddb4f9df4" +checksum = "68b900aa2f7301e21c36462b170ee99994de34dff39a4a6a528e80e7376d07e5" dependencies = [ "equivalent", - "hashbrown 0.14.3", + "hashbrown 0.14.5", "serde", ] @@ -1640,9 +1927,9 @@ dependencies = [ [[package]] name = "instant" -version = "0.1.12" +version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222" dependencies = [ "cfg-if", "js-sys", @@ -1658,9 +1945,15 @@ checksum = "f958d3d68f4167080a18141e10381e7634563984a537f2a49a30fd8e53ac5767" [[package]] name = "ipnet" -version = "2.9.0" +version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" +checksum = "187674a687eed5fe42285b40c6291f9a01517d415fad1c3cbc6a9f778af7fcd4" + +[[package]] +name = "is_terminal_polyfill" +version = "1.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" [[package]] name = "itertools" @@ -1682,15 +1975,15 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.10" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" +checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" [[package]] name = "js-sys" -version = "0.3.69" +version = "0.3.70" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" +checksum = "1868808506b929d7b0cfa8f75951347aa71bb21144b7791bae35d9bccfcfe37a" dependencies = [ "wasm-bindgen", ] @@ -1720,7 +2013,7 @@ dependencies = [ "petgraph", "pico-args", "regex", - "regex-syntax 0.8.2", + "regex-syntax 0.8.4", "string_cache", "term", "tiny-keccak", @@ -1734,23 +2027,23 @@ version = "0.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "507460a910eb7b32ee961886ff48539633b788a36b65692b95f225b844c82553" dependencies = [ - "regex-automata 0.4.6", + "regex-automata 0.4.7", ] [[package]] name = "lazy_static" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" dependencies = [ - "spin 0.5.2", + "spin", ] [[package]] name = "libc" -version = "0.2.153" +version = "0.2.158" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" +checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439" [[package]] name = "libm" @@ -1760,13 +2053,12 @@ checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" [[package]] name = "libredox" -version = "0.0.1" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85c833ca1e66078851dba29046874e38f08b2c883700aa29a03ddd3b23814ee8" +checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" dependencies = [ - "bitflags 2.4.2", + "bitflags 2.6.0", "libc", - "redox_syscall 0.4.1", ] [[package]] @@ -1782,15 +2074,15 @@ dependencies = [ [[package]] name = "linux-raw-sys" -version = "0.4.13" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" +checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" [[package]] name = "lock_api" -version = "0.4.11" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" +checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" dependencies = [ "autocfg", "scopeguard", @@ -1798,9 +2090,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.21" +version = "0.4.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" [[package]] name = "matchers" @@ -1824,14 +2116,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf" dependencies = [ "cfg-if", - "digest", + "digest 0.10.7", ] [[package]] name = "memchr" -version = "2.7.1" +version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "mime" @@ -1847,46 +2139,47 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] name = "miniscript" -version = "10.0.0" +version = "10.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1eb102b66b2127a872dbcc73095b7b47aeb9d92f7b03c2b2298253ffc82c7594" +checksum = "d371924f9eb7aa860ab395baaaa0bcdfa81a32f330b538c4e2c04617b2722fe3" dependencies = [ - "bitcoin", + "bitcoin 0.30.2", "bitcoin-private", "serde", ] [[package]] name = "miniz_oxide" -version = "0.7.2" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7" +checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1" dependencies = [ - "adler", + "adler2", ] [[package]] name = "mio" -version = "0.8.11" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" +checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec" dependencies = [ + "hermit-abi", "libc", "wasi", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] name = "multimap" -version = "0.8.3" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5ce46fe64a9d73be07dcbe690a38ce1b293be448fd8ce1e6c1b8062c9f72c6a" +checksum = "defc4c55412d89136f966bbb339008b474350e5e6e78d2714439c386b3137a03" [[package]] name = "new_debug_unreachable" -version = "1.0.4" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4a24736216ec316047a1fc4252e27dabb04218aa4a3f37c6e7ddbf1f9782b54" +checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" [[package]] name = "nom" @@ -1942,9 +2235,9 @@ dependencies = [ [[package]] name = "num-iter" -version = "0.1.44" +version = "0.1.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d869c01cc0c455284163fd0092f1f93835385ccab5a98a0dcc497b2f8bf055a9" +checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" dependencies = [ "autocfg", "num-integer", @@ -1953,38 +2246,28 @@ dependencies = [ [[package]] name = "num-traits" -version = "0.2.18" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ "autocfg", "libm", ] -[[package]] -name = "num_cpus" -version = "1.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" -dependencies = [ - "hermit-abi", - "libc", -] - [[package]] name = "object" -version = "0.32.2" +version = "0.36.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" +checksum = "084f1a5821ac4c651660a94a7153d27ac9d8a53736203f58b31945ded098070a" dependencies = [ "memchr", ] [[package]] name = "once_cell" -version = "1.19.0" +version = "1.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +checksum = "33ea5043e58958ee56f3e15a90aee535795cd7dfd319846288d93c5b57d85cbe" [[package]] name = "opaque-debug" @@ -2075,9 +2358,9 @@ dependencies = [ [[package]] name = "ordered-float" -version = "4.2.0" +version = "4.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a76df7075c7d4d01fdcb46c912dd17fba5b60c78ea480b475f2b6ab6f666584e" +checksum = "4a91171844676f8c7990ce64959210cd2eaef32c2612c50f9fae9f8aaa6065a6" dependencies = [ "num-traits", ] @@ -2101,12 +2384,12 @@ dependencies = [ [[package]] name = "parking_lot" -version = "0.12.1" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" dependencies = [ "lock_api", - "parking_lot_core 0.9.9", + "parking_lot_core 0.9.10", ] [[package]] @@ -2125,22 +2408,39 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.9" +version = "0.9.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" +checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" dependencies = [ "cfg-if", "libc", - "redox_syscall 0.4.1", + "redox_syscall 0.5.4", "smallvec", - "windows-targets 0.48.5", + "windows-targets 0.52.6", ] [[package]] name = "paste" -version = "1.0.14" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + +[[package]] +name = "payjoin" +version = "0.20.0" +dependencies = [ + "bhttp", + "bip21", + "bitcoin 0.32.2", + "bitcoin-hpke", + "bitcoin-ohttp", + "http 1.1.0", + "log", + "reqwest 0.12.7", + "serde", + "serde_json", + "url", +] [[package]] name = "pem-rfc7468" @@ -2157,14 +2457,20 @@ version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" +[[package]] +name = "percent-encoding-rfc3986" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3637c05577168127568a64e9dc5a6887da720efef07b3d9472d45f63ab191166" + [[package]] name = "petgraph" -version = "0.6.4" +version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1d3afd2628e69da2be385eb6f2fd57c8ac7977ceeff6dc166ff1657b0e386a9" +checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db" dependencies = [ "fixedbitset", - "indexmap 2.2.5", + "indexmap 2.5.0", ] [[package]] @@ -2199,14 +2505,14 @@ checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.77", ] [[package]] name = "pin-project-lite" -version = "0.2.13" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" +checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" [[package]] name = "pin-utils" @@ -2241,15 +2547,38 @@ version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" +[[package]] +name = "poly1305" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "048aeb476be11a4b6ca432ca569e375810de9294ae78f4774e78ea98a9246ede" +dependencies = [ + "cpufeatures 0.2.14", + "opaque-debug", + "universal-hash 0.4.0", +] + [[package]] name = "poly1305" version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8159bd90725d2df49889a078b54f4f79e87f1f8a8444194cdca81d38f5393abf" dependencies = [ - "cpufeatures", + "cpufeatures 0.2.14", + "opaque-debug", + "universal-hash 0.5.1", +] + +[[package]] +name = "polyval" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8419d2b623c7c0896ff2d5d96e2cb4ede590fed28fcc34934f4c33c036e620a1" +dependencies = [ + "cfg-if", + "cpufeatures 0.2.14", "opaque-debug", - "universal-hash", + "universal-hash 0.4.0", ] [[package]] @@ -2260,9 +2589,12 @@ checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" [[package]] name = "ppv-lite86" -version = "0.2.17" +version = "0.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" +checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" +dependencies = [ + "zerocopy", +] [[package]] name = "precomputed-hash" @@ -2272,19 +2604,19 @@ checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" [[package]] name = "prettyplease" -version = "0.2.16" +version = "0.2.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a41cf62165e97c7f814d2221421dbb9afcbcdb0a88068e5ea206e19951c2cbb5" +checksum = "479cf940fbbb3426c32c5d5176f62ad57549a0bb84773423ba8be9d089f5faba" dependencies = [ "proc-macro2", - "syn 2.0.52", + "syn 2.0.77", ] [[package]] name = "proc-macro-crate" -version = "3.1.0" +version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d37c51ca738a55da99dc0c4a34860fd675453b8b36209178c2249bb13651284" +checksum = "8ecf48c7ca261d60b74ab1a7b20da18bede46776b2e55535cb958eb595c5fa7b" dependencies = [ "toml_edit", ] @@ -2314,9 +2646,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.78" +version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae" +checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" dependencies = [ "unicode-ident", ] @@ -2333,13 +2665,13 @@ dependencies = [ [[package]] name = "prost-build" -version = "0.12.3" +version = "0.12.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c55e02e35260070b6f716a2423c2ff1c3bb1642ddca6f99e1f26d06268a0e2d2" +checksum = "22505a5c94da8e3b7c2996394d1c933236c4d743e81a410bcca4e6989fc066a4" dependencies = [ "bytes", - "heck 0.4.1", - "itertools 0.11.0", + "heck 0.5.0", + "itertools 0.12.1", "log", "multimap", "once_cell", @@ -2348,9 +2680,8 @@ dependencies = [ "prost", "prost-types", "regex", - "syn 2.0.52", + "syn 2.0.77", "tempfile", - "which", ] [[package]] @@ -2363,14 +2694,14 @@ dependencies = [ "itertools 0.12.1", "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.77", ] [[package]] name = "prost-types" -version = "0.12.3" +version = "0.12.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "193898f59edcf43c26227dcd4c8427f00d99d61e95dcde58dabd49fa291d470e" +checksum = "9091c90b0a32608e984ff2fa4091273cbdd755d54935c51d520887f4a1dbd5b0" dependencies = [ "prost", ] @@ -2453,16 +2784,17 @@ dependencies = [ [[package]] name = "quinn" -version = "0.11.2" +version = "0.11.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4ceeeeabace7857413798eb1ffa1e9c905a9946a57d81fb69b4b71c4d8eb3ad" +checksum = "8c7c5fdde3cdae7203427dc4f0a68fe0ed09833edc525a03456b153b79828684" dependencies = [ "bytes", "pin-project-lite", "quinn-proto", "quinn-udp", "rustc-hash", - "rustls 0.23.10", + "rustls 0.23.13", + "socket2", "thiserror", "tokio", "tracing", @@ -2470,15 +2802,15 @@ dependencies = [ [[package]] name = "quinn-proto" -version = "0.11.3" +version = "0.11.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddf517c03a109db8100448a4be38d498df8a210a99fe0e1b9eaf39e78c640efe" +checksum = "fadfaed2cd7f389d0161bb73eeb07b7b78f8691047a6f3e73caaeae55310a4a6" dependencies = [ "bytes", "rand", "ring", "rustc-hash", - "rustls 0.23.10", + "rustls 0.23.13", "slab", "thiserror", "tinyvec", @@ -2487,22 +2819,22 @@ dependencies = [ [[package]] name = "quinn-udp" -version = "0.5.2" +version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9096629c45860fc7fb143e125eb826b5e721e10be3263160c7d60ca832cf8c46" +checksum = "4fe68c2e9e1a1234e218683dbdf9f9dfcb094113c5ac2b938dfcb9bab4c4140b" dependencies = [ "libc", "once_cell", "socket2", "tracing", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] name = "quote" -version = "1.0.35" +version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" dependencies = [ "proc-macro2", ] @@ -2554,18 +2886,18 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.4.1" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" +checksum = "0884ad60e090bf1345b93da0a5de8923c93884cd03f40dfcfddd3b4bee661853" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.6.0", ] [[package]] name = "redox_users" -version = "0.4.4" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a18479200779601e498ada4e8c1e1f50e3ee19deb0259c25825a98b5603b2cb4" +checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" dependencies = [ "getrandom", "libredox", @@ -2574,14 +2906,14 @@ dependencies = [ [[package]] name = "regex" -version = "1.10.4" +version = "1.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c117dbdfde9c8308975b6a18d71f3f385c89461f7b3fb054288ecf2a2058ba4c" +checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619" dependencies = [ "aho-corasick", "memchr", - "regex-automata 0.4.6", - "regex-syntax 0.8.2", + "regex-automata 0.4.7", + "regex-syntax 0.8.4", ] [[package]] @@ -2595,13 +2927,13 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.6" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea" +checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" dependencies = [ "aho-corasick", "memchr", - "regex-syntax 0.8.2", + "regex-syntax 0.8.4", ] [[package]] @@ -2612,9 +2944,9 @@ checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" [[package]] name = "regex-syntax" -version = "0.8.2" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" +checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" [[package]] name = "rend" @@ -2639,7 +2971,7 @@ dependencies = [ "h2", "http 0.2.12", "http-body 0.4.6", - "hyper 0.14.28", + "hyper 0.14.30", "ipnet", "js-sys", "log", @@ -2658,24 +2990,24 @@ dependencies = [ "wasm-bindgen", "wasm-bindgen-futures", "web-sys", - "winreg 0.50.0", + "winreg", ] [[package]] name = "reqwest" -version = "0.12.5" +version = "0.12.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7d6d2a27d57148378eb5e111173f4276ad26340ecc5c49a4a2152167a2d6a37" +checksum = "f8f4955649ef5c38cc7f9e8aa41761d48fb9677197daea9984dc54f56aad5e63" dependencies = [ "base64 0.22.1", "bytes", "futures-core", "futures-util", "http 1.1.0", - "http-body 1.0.0", + "http-body 1.0.1", "http-body-util", - "hyper 1.2.0", - "hyper-rustls 0.27.2", + "hyper 1.4.1", + "hyper-rustls 0.27.3", "hyper-util", "ipnet", "js-sys", @@ -2685,8 +3017,8 @@ dependencies = [ "percent-encoding", "pin-project-lite", "quinn", - "rustls 0.23.10", - "rustls-pemfile 2.1.2", + "rustls 0.23.13", + "rustls-pemfile 2.1.3", "rustls-pki-types", "serde", "serde_json", @@ -2699,20 +3031,20 @@ dependencies = [ "wasm-bindgen", "wasm-bindgen-futures", "web-sys", - "webpki-roots 0.26.1", - "winreg 0.52.0", + "webpki-roots 0.26.5", + "windows-registry", ] [[package]] name = "reqwest-middleware" -version = "0.3.1" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a45d100244a467870f6cb763c4484d010a6bed6bd610b3676e3825d93fb4cfbd" +checksum = "562ceb5a604d3f7c885a792d42c199fd8af239d0a51b2fa6a78aafa092452b04" dependencies = [ "anyhow", "async-trait", "http 1.1.0", - "reqwest 0.12.5", + "reqwest 0.12.7", "serde", "thiserror", "tower-service", @@ -2730,9 +3062,9 @@ dependencies = [ "futures", "getrandom", "http 1.1.0", - "hyper 1.2.0", + "hyper 1.4.1", "parking_lot 0.11.2", - "reqwest 0.12.5", + "reqwest 0.12.7", "reqwest-middleware", "retry-policies", "tokio", @@ -2761,16 +3093,16 @@ dependencies = [ "cfg-if", "getrandom", "libc", - "spin 0.9.8", + "spin", "untrusted", "windows-sys 0.52.0", ] [[package]] name = "rkyv" -version = "0.7.44" +version = "0.7.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cba464629b3394fc4dbc6f940ff8f5b4ff5c7aef40f29166fd4ad12acbc99c0" +checksum = "9008cd6385b9e161d8229e1f6549dd23c3d022f132a2ea37ac3a10ac4935779b" dependencies = [ "bitvec", "bytecheck", @@ -2786,9 +3118,9 @@ dependencies = [ [[package]] name = "rkyv_derive" -version = "0.7.44" +version = "0.7.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7dddfff8de25e6f62b9d64e6e432bf1c6736c57d20323e15ee10435fbda7c65" +checksum = "503d1d27590a2b0a3a4ca4c94755aa2875657196ecbf401a42eff41d7de532c0" dependencies = [ "proc-macro2", "quote", @@ -2802,7 +3134,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5d0e5124fcb30e76a7e79bfee683a2746db83784b86289f6251b54b7950a0dfc" dependencies = [ "const-oid", - "digest", + "digest 0.10.7", "num-bigint-dig", "num-integer", "num-traits", @@ -2817,9 +3149,9 @@ dependencies = [ [[package]] name = "rust_decimal" -version = "1.35.0" +version = "1.36.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1790d1c4c0ca81211399e0e0af16333276f375209e71a37b67698a373db5b47a" +checksum = "b082d80e3e3cc52b2ed634388d436fe1f4de6af5786cc2de9ba9737527bdf555" dependencies = [ "arrayvec", "borsh", @@ -2833,9 +3165,9 @@ dependencies = [ [[package]] name = "rust_decimal_macros" -version = "1.34.2" +version = "1.36.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e418701588729bef95e7a655f2b483ad64bb97c46e8e79fde83efd92aaab6d82" +checksum = "da991f231869f34268415a49724c6578e740ad697ba0999199d6f22b3949332c" dependencies = [ "quote", "rust_decimal", @@ -2843,23 +3175,23 @@ dependencies = [ [[package]] name = "rustc-demangle" -version = "0.1.23" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" +checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" [[package]] name = "rustc-hash" -version = "1.1.0" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" +checksum = "583034fd73374156e66797ed8e5b0d5690409c9226b22d87cb7f19821c05d152" [[package]] name = "rustix" -version = "0.38.31" +version = "0.38.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ea3e1a662af26cd7a3ba09c0297a31af215563ecf42817c98df621387f4e949" +checksum = "8acb788b847c24f28525660c4d7758620a7210875711f79e7f663cc152726811" dependencies = [ - "bitflags 2.4.2", + "bitflags 2.6.0", "errno", "libc", "linux-raw-sys", @@ -2868,9 +3200,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.21.11" +version = "0.21.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fecbfb7b1444f477b345853b1fce097a2c6fb637b2bfb87e6bc5db0f043fae4" +checksum = "3f56a14d1f48b391359b22f731fd4bd7e43c97f3c50eee276f3aa09c94784d3e" dependencies = [ "log", "ring", @@ -2880,14 +3212,14 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.10" +version = "0.23.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05cff451f60db80f490f3c182b77c35260baace73209e9cdbbe526bfe3a4d402" +checksum = "f2dabaac7466917e566adb06783a81ca48944c6898a1b08b9374106dd671f4c8" dependencies = [ "once_cell", "ring", "rustls-pki-types", - "rustls-webpki 0.102.4", + "rustls-webpki 0.102.8", "subtle", "zeroize", ] @@ -2903,9 +3235,9 @@ dependencies = [ [[package]] name = "rustls-pemfile" -version = "2.1.2" +version = "2.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29993a25686778eb88d4189742cd713c9bce943bc54251a33509dc63cbacf73d" +checksum = "196fe16b00e106300d3e45ecfcb764fa292a535d7326a29a5875c579c7417425" dependencies = [ "base64 0.22.1", "rustls-pki-types", @@ -2913,9 +3245,9 @@ dependencies = [ [[package]] name = "rustls-pki-types" -version = "1.7.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "976295e77ce332211c0d24d92c0e83e50f5c5f046d11082cea19f3df13a3562d" +checksum = "fc0a2ce646f8655401bb81e7927b812614bd5d91dbc968696be50603510fcaf0" [[package]] name = "rustls-webpki" @@ -2929,9 +3261,9 @@ dependencies = [ [[package]] name = "rustls-webpki" -version = "0.102.4" +version = "0.102.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff448f7e92e913c4b7d4c6d8e4540a1724b319b4152b8aef6d4cf8339712b33e" +checksum = "64ca1bc8749bd4cf37b5ce386cc146580777b4e8572c7b97baf22c83f444bee9" dependencies = [ "ring", "rustls-pki-types", @@ -2940,9 +3272,9 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.14" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4" +checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6" [[package]] name = "rusty-money" @@ -2956,9 +3288,9 @@ dependencies = [ [[package]] name = "ryu" -version = "1.0.17" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1" +checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" [[package]] name = "same-file" @@ -2971,9 +3303,9 @@ dependencies = [ [[package]] name = "scc" -version = "2.1.0" +version = "2.1.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec96560eea317a9cc4e0bb1f6a2c93c09a19b8c4fc5cb3fcc0ec1c094cd783e2" +checksum = "0c947adb109a8afce5fc9c7bf951f87f146e9147b3a6a58413105628fb1d1e66" dependencies = [ "sdd", ] @@ -2996,9 +3328,9 @@ dependencies = [ [[package]] name = "sdd" -version = "0.2.0" +version = "3.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b84345e4c9bd703274a082fb80caaa99b7612be48dfaa1dd9266577ec412309d" +checksum = "60a7b59a5d9b0099720b417b6325d91a52cbf5b3dcb5041d864be53eefa58abc" [[package]] name = "seahash" @@ -3012,9 +3344,21 @@ version = "0.27.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "25996b82292a7a57ed3508f052cfff8640d38d32018784acd714758b43da9c8f" dependencies = [ - "bitcoin_hashes", + "bitcoin_hashes 0.12.0", "rand", - "secp256k1-sys", + "secp256k1-sys 0.8.1", + "serde", +] + +[[package]] +name = "secp256k1" +version = "0.29.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9465315bc9d4566e1724f0fffcbcc446268cb522e60f9a27bcded6b19c108113" +dependencies = [ + "bitcoin_hashes 0.14.0", + "rand", + "secp256k1-sys 0.10.1", "serde", ] @@ -3027,33 +3371,43 @@ dependencies = [ "cc", ] +[[package]] +name = "secp256k1-sys" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4387882333d3aa8cb20530a17c69a3752e97837832f34f6dccc760e715001d9" +dependencies = [ + "cc", +] + [[package]] name = "serde" -version = "1.0.203" +version = "1.0.210" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7253ab4de971e72fb7be983802300c30b5a7f0c2e56fab8abfc6a214307c0094" +checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.203" +version = "1.0.210" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba" +checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.77", ] [[package]] name = "serde_json" -version = "1.0.117" +version = "1.0.128" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "455182ea6142b14f93f4bc5320a2b31c1f266b66a4a5c858b013302a5d8cbfc3" +checksum = "6ff5456707a1de34e7e37f2a6fd3d3f808c318259cbd01ab6377795054b483d8" dependencies = [ "itoa", + "memchr", "ryu", "serde", ] @@ -3072,15 +3426,15 @@ dependencies = [ [[package]] name = "serde_with" -version = "3.8.1" +version = "3.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ad483d2ab0149d5a5ebcd9972a3852711e0153d863bf5a5d0391d28883c4a20" +checksum = "69cecfa94848272156ea67b2b1a53f20fc7bc638c4a46d2f8abde08f05f4b857" dependencies = [ "base64 0.22.1", "chrono", "hex", "indexmap 1.9.3", - "indexmap 2.2.5", + "indexmap 2.5.0", "serde", "serde_derive", "serde_json", @@ -3090,23 +3444,23 @@ dependencies = [ [[package]] name = "serde_with_macros" -version = "3.8.1" +version = "3.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65569b702f41443e8bc8bbb1c5779bd0450bbe723b56198980e80ec45780bce2" +checksum = "a8fee4991ef4f274617a51ad4af30519438dacb2f56ac773b08a1922ff743350" dependencies = [ - "darling 0.20.8", + "darling 0.20.10", "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.77", ] [[package]] name = "serde_yaml" -version = "0.9.32" +version = "0.9.34+deprecated" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fd075d994154d4a774f95b51fb96bdc2832b0ea48425c92546073816cda1f2f" +checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" dependencies = [ - "indexmap 2.2.5", + "indexmap 2.5.0", "itoa", "ryu", "serde", @@ -3122,7 +3476,7 @@ dependencies = [ "futures", "log", "once_cell", - "parking_lot 0.12.1", + "parking_lot 0.12.3", "scc", "serial_test_derive", ] @@ -3135,7 +3489,7 @@ checksum = "82fe9db325bcef1fbcde82e078a5cc4efdf787e96b3b9cf45b50b529f2083d67" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.77", ] [[package]] @@ -3145,8 +3499,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" dependencies = [ "cfg-if", - "cpufeatures", - "digest", + "cpufeatures 0.2.14", + "digest 0.10.7", +] + +[[package]] +name = "sha2" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" +dependencies = [ + "block-buffer 0.9.0", + "cfg-if", + "cpufeatures 0.2.14", + "digest 0.9.0", + "opaque-debug", ] [[package]] @@ -3156,8 +3523,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" dependencies = [ "cfg-if", - "cpufeatures", - "digest", + "cpufeatures 0.2.14", + "digest 0.10.7", ] [[package]] @@ -3169,11 +3536,17 @@ dependencies = [ "lazy_static", ] +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + [[package]] name = "signal-hook-registry" -version = "1.4.1" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1" +checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" dependencies = [ "libc", ] @@ -3184,7 +3557,7 @@ version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" dependencies = [ - "digest", + "digest 0.10.7", "rand_core", ] @@ -3227,26 +3600,20 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.13.1" +version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6ecd384b10a64542d77071bd64bd7b231f4ed5940fba55e98c3de13824cf3d7" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" [[package]] name = "socket2" -version = "0.5.6" +version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05ffd9c0a93b7543e062e759284fcf5f5e3b098501104bfbdde4d404db792871" +checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" dependencies = [ "libc", "windows-sys 0.52.0", ] -[[package]] -name = "spin" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" - [[package]] name = "spin" version = "0.9.8" @@ -3268,11 +3635,10 @@ dependencies = [ [[package]] name = "sqlformat" -version = "0.2.3" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce81b7bd7c4493975347ef60d8c7e8b742d4694f4c49f93e0a12ea263938176c" +checksum = "7bba3a93db0cc4f7bdece8bb09e77e2e785c20bfebf79eb8340ed80708048790" dependencies = [ - "itertools 0.12.1", "nom", "unicode_categories", ] @@ -3312,18 +3678,18 @@ dependencies = [ "futures-util", "hashlink", "hex", - "indexmap 2.2.5", + "indexmap 2.5.0", "log", "memchr", "once_cell", "paste", "percent-encoding", "rust_decimal", - "rustls 0.21.11", + "rustls 0.21.12", "rustls-pemfile 1.0.4", "serde", "serde_json", - "sha2", + "sha2 0.10.8", "smallvec", "sqlformat", "thiserror", @@ -3411,7 +3777,7 @@ dependencies = [ "quote", "serde", "serde_json", - "sha2", + "sha2 0.10.8", "sqlx-core", "sqlx-mysql", "sqlx-postgres", @@ -3430,12 +3796,12 @@ checksum = "1ed31390216d20e538e447a7a9b959e06ed9fc51c37b514b46eb758016ecd418" dependencies = [ "atoi", "base64 0.21.7", - "bitflags 2.4.2", + "bitflags 2.6.0", "byteorder", "bytes", "chrono", "crc", - "digest", + "digest 0.10.7", "dotenvy", "either", "futures-channel", @@ -3444,8 +3810,8 @@ dependencies = [ "futures-util", "generic-array", "hex", - "hkdf", - "hmac", + "hkdf 0.12.4", + "hmac 0.12.1", "itoa", "log", "md-5", @@ -3457,7 +3823,7 @@ dependencies = [ "rust_decimal", "serde", "sha1", - "sha2", + "sha2 0.10.8", "smallvec", "sqlx-core", "stringprep", @@ -3475,7 +3841,7 @@ checksum = "7c824eb80b894f926f89a0b9da0c7f435d27cdd35b8c655b114e58223918577e" dependencies = [ "atoi", "base64 0.21.7", - "bitflags 2.4.2", + "bitflags 2.6.0", "byteorder", "chrono", "crc", @@ -3486,8 +3852,8 @@ dependencies = [ "futures-io", "futures-util", "hex", - "hkdf", - "hmac", + "hkdf 0.12.4", + "hmac 0.12.1", "home", "itoa", "log", @@ -3498,7 +3864,7 @@ dependencies = [ "rust_decimal", "serde", "serde_json", - "sha2", + "sha2 0.10.8", "smallvec", "sqlx-core", "stringprep", @@ -3570,20 +3936,20 @@ checksum = "f91138e76242f575eb1d3b38b4f1362f10d3a43f47d182a5b359af488a02293b" dependencies = [ "new_debug_unreachable", "once_cell", - "parking_lot 0.12.1", + "parking_lot 0.12.3", "phf_shared", "precomputed-hash", ] [[package]] name = "stringprep" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb41d74e231a107a1b4ee36bd1214b11285b77768d2e3824aedafa988fd36ee6" +checksum = "7b4df3d392d81bd458a8a621b8bffbd2302a12ffe288a9d931670948749463b1" dependencies = [ - "finl_unicode", "unicode-bidi", "unicode-normalization", + "unicode-properties", ] [[package]] @@ -3594,15 +3960,15 @@ checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" [[package]] name = "strsim" -version = "0.11.0" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ee073c9e4cd00e28217186dbe12796d692868f432bf2e97ee73bed0c56dfa01" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "subtle" -version = "2.5.0" +version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "syn" @@ -3617,9 +3983,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.52" +version = "2.0.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b699d15b36d1f02c3e7c69f8ffef53de37aefae075d8488d4ba1a7788d574a07" +checksum = "9f35bcdf61fd8e7be6caf75f429fdca8beb3ed76584befb503b1569faee373ed" dependencies = [ "proc-macro2", "quote", @@ -3635,7 +4001,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.77", ] [[package]] @@ -3649,6 +4015,9 @@ name = "sync_wrapper" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a7065abeca94b6a8a577f9bd45aa0867a2238b74e8eb67cf10d492bc39351394" +dependencies = [ + "futures-core", +] [[package]] name = "system-configuration" @@ -3679,14 +4048,15 @@ checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" [[package]] name = "tempfile" -version = "3.10.1" +version = "3.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1" +checksum = "04cbcdd0c794ebb0d4cf35e88edd2f7d2c4c3e9a5a6dab322839b321c6a87a64" dependencies = [ "cfg-if", "fastrand", + "once_cell", "rustix", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -3702,22 +4072,22 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.61" +version = "1.0.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c546c80d6be4bc6a00c0f01730c08df82eaa7a7a61f11d656526506112cc1709" +checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.61" +version = "1.0.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533" +checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.77", ] [[package]] @@ -3732,9 +4102,9 @@ dependencies = [ [[package]] name = "time" -version = "0.3.34" +version = "0.3.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8248b6521bb14bc45b4067159b9b6ad792e2d6d754d6c41fb50e29fefe38749" +checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" dependencies = [ "deranged", "itoa", @@ -3753,9 +4123,9 @@ checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" [[package]] name = "time-macros" -version = "0.2.17" +version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ba3a3ef41e6672a2f0f001392bb5dcd3ff0a9992d618ca761a11c3121547774" +checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf" dependencies = [ "num-conv", "time-core", @@ -3772,9 +4142,9 @@ dependencies = [ [[package]] name = "tinyvec" -version = "1.6.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +checksum = "445e881f4f6d382d5f27c034e25eb92edd7c784ceab92a0937db7f2e9471b938" dependencies = [ "tinyvec_macros", ] @@ -3787,21 +4157,20 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.37.0" +version = "1.40.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1adbebffeca75fcfd058afa480fb6c0b81e165a0323f9c9d39c9697e37c46787" +checksum = "e2b070231665d27ad9ec9b8df639893f46727666c6767db40317fbe920a5d998" dependencies = [ "backtrace", "bytes", "libc", "mio", - "num_cpus", - "parking_lot 0.12.1", + "parking_lot 0.12.3", "pin-project-lite", "signal-hook-registry", "socket2", "tokio-macros", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] @@ -3816,13 +4185,13 @@ dependencies = [ [[package]] name = "tokio-macros" -version = "2.2.0" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" +checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.77", ] [[package]] @@ -3831,7 +4200,7 @@ version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" dependencies = [ - "rustls 0.21.11", + "rustls 0.21.12", "tokio", ] @@ -3841,16 +4210,16 @@ version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4" dependencies = [ - "rustls 0.23.10", + "rustls 0.23.13", "rustls-pki-types", "tokio", ] [[package]] name = "tokio-stream" -version = "0.1.15" +version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "267ac89e0bec6e691e5813911606935d77c476ff49024f98abcea3e7b15e37af" +checksum = "4f4e6ce100d0eb49a2734f8c0812bcd324cf357d21810932c5df6b96ef2b86f1" dependencies = [ "futures-core", "pin-project-lite", @@ -3860,31 +4229,39 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.10" +version = "0.7.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5419f34732d9eb6ee4c3578b7989078579b7f039cbbb9ca2c4da015749371e15" +checksum = "61e7c3654c13bcd040d4a03abee2c75b1d14a37b423cf5a813ceae1cc903ec6a" dependencies = [ "bytes", "futures-core", "futures-sink", "pin-project-lite", "tokio", - "tracing", +] + +[[package]] +name = "toml" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" +dependencies = [ + "serde", ] [[package]] name = "toml_datetime" -version = "0.6.5" +version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1" +checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" [[package]] name = "toml_edit" -version = "0.21.1" +version = "0.22.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a8534fd7f78b5405e860340ad6575217ce99f38d4d5c8f2442cb5ecb50090e1" +checksum = "583c44c02ad26b0c3f3066fe629275e50627026c51ac2e595cca4c230ce1ce1d" dependencies = [ - "indexmap 2.2.5", + "indexmap 2.5.0", "toml_datetime", "winnow", ] @@ -3903,12 +4280,12 @@ dependencies = [ "h2", "http 0.2.12", "http-body 0.4.6", - "hyper 0.14.28", + "hyper 0.14.30", "hyper-timeout", "percent-encoding", "pin-project", "prost", - "rustls 0.21.11", + "rustls 0.21.12", "rustls-pemfile 1.0.4", "tokio", "tokio-rustls 0.24.1", @@ -3933,7 +4310,7 @@ dependencies = [ "h2", "http 0.2.12", "http-body 0.4.6", - "hyper 0.14.28", + "hyper 0.14.30", "hyper-timeout", "percent-encoding", "pin-project", @@ -3956,7 +4333,7 @@ dependencies = [ "proc-macro2", "prost-build", "quote", - "syn 2.0.52", + "syn 2.0.77", ] [[package]] @@ -3969,7 +4346,7 @@ dependencies = [ "proc-macro2", "prost-build", "quote", - "syn 2.0.52", + "syn 2.0.77", ] [[package]] @@ -4007,15 +4384,15 @@ dependencies = [ [[package]] name = "tower-layer" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c20c8dbed6283a09604c3e69b4b7eeb54e298b8a600d4d5ecb5ad39de609f1d0" +checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" [[package]] name = "tower-service" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" +checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" [[package]] name = "tracing" @@ -4037,7 +4414,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.77", ] [[package]] @@ -4116,6 +4493,12 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" +[[package]] +name = "typeid" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e13db2e0ccd5e14a544e8a246ba2312cd25223f616442d7f2cb0e3db614236e" + [[package]] name = "typenum" version = "1.17.0" @@ -4124,9 +4507,9 @@ checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" [[package]] name = "typetag" -version = "0.2.16" +version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "661d18414ec032a49ece2d56eee03636e43c4e8d577047ab334c0ba892e29aaf" +checksum = "52ba3b6e86ffe0054b2c44f2d86407388b933b16cb0a70eea3929420db1d9bbe" dependencies = [ "erased-serde", "inventory", @@ -4137,13 +4520,13 @@ dependencies = [ [[package]] name = "typetag-impl" -version = "0.2.16" +version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac73887f47b9312552aa90ef477927ff014d63d1920ca8037c6c1951eab64bb1" +checksum = "70b20a22c42c8f1cd23ce5e34f165d4d37038f5b663ad20fb6adbdf029172483" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.77", ] [[package]] @@ -4154,9 +4537,9 @@ checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" [[package]] name = "unicode-ident" -version = "1.0.12" +version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" [[package]] name = "unicode-normalization" @@ -4167,17 +4550,23 @@ dependencies = [ "tinyvec", ] +[[package]] +name = "unicode-properties" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52ea75f83c0137a9b98608359a5f1af8144876eb67bcb1ce837368e906a9f524" + [[package]] name = "unicode-segmentation" -version = "1.11.0" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" +checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" [[package]] name = "unicode-xid" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" +checksum = "229730647fbc343e3a80e463c1db7f78f3855d3f3739bee0dda773c9a037c90a" [[package]] name = "unicode_categories" @@ -4185,6 +4574,16 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e" +[[package]] +name = "universal-hash" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8326b2c654932e3e4f9196e69d08fdf7cfd718e1dc6f66b347e6024a0c961402" +dependencies = [ + "generic-array", + "subtle", +] + [[package]] name = "universal-hash" version = "0.5.1" @@ -4197,9 +4596,9 @@ dependencies = [ [[package]] name = "unsafe-libyaml" -version = "0.2.10" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab4c90930b95a82d00dc9e9ac071b4991924390d46cbd0dfe566148667605e4b" +checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861" [[package]] name = "untrusted" @@ -4216,6 +4615,7 @@ dependencies = [ "form_urlencoded", "idna", "percent-encoding", + "serde", ] [[package]] @@ -4226,15 +4626,15 @@ checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da" [[package]] name = "utf8parse" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "uuid" -version = "1.8.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a183cf7feeba97b4dd1c0d46788634f6221d87fa961b305bed08c851829efcc0" +checksum = "81dfa00651efa65069b0b6b651f4aaa31ba9e3c3ce0137aaad053604ee7e0314" dependencies = [ "getrandom", "serde", @@ -4254,9 +4654,9 @@ checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" [[package]] name = "version_check" -version = "0.9.4" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" [[package]] name = "walkdir" @@ -4291,34 +4691,35 @@ checksum = "b8dad83b4f25e74f184f64c43b150b91efe7647395b42289f38e50566d82855b" [[package]] name = "wasm-bindgen" -version = "0.2.92" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" +checksum = "a82edfc16a6c469f5f44dc7b571814045d60404b55a0ee849f9bcfa2e63dd9b5" dependencies = [ "cfg-if", + "once_cell", "wasm-bindgen-macro", ] [[package]] name = "wasm-bindgen-backend" -version = "0.2.92" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" +checksum = "9de396da306523044d3302746f1208fa71d7532227f15e347e2d93e4145dd77b" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.77", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.42" +version = "0.4.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76bc14366121efc8dbb487ab05bcc9d346b3b5ec0eaa76e46594cabbe51762c0" +checksum = "61e9300f63a621e96ed275155c108eb6f843b6a26d053f122ab69724559dc8ed" dependencies = [ "cfg-if", "js-sys", @@ -4328,9 +4729,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.92" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" +checksum = "585c4c91a46b072c92e908d99cb1dcdf95c5218eeb6f3bf1efa991ee7a68cccf" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -4338,22 +4739,22 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.92" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" +checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.77", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.92" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" +checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484" [[package]] name = "wasm-timer" @@ -4372,9 +4773,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.69" +version = "0.3.70" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef" +checksum = "26fdeaafd9bd129f65e7c031593c24d62186301e0c72c8978fa1678be7d532c0" dependencies = [ "js-sys", "wasm-bindgen", @@ -4417,32 +4818,20 @@ checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1" [[package]] name = "webpki-roots" -version = "0.26.1" +version = "0.26.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3de34ae270483955a94f4b21bdaaeb83d508bb84a01435f393818edb0012009" +checksum = "0bd24728e5af82c6c4ec1b66ac4844bdf8156257fccda846ec58b42cd0cdbe6a" dependencies = [ "rustls-pki-types", ] -[[package]] -name = "which" -version = "4.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7" -dependencies = [ - "either", - "home", - "once_cell", - "rustix", -] - [[package]] name = "whoami" -version = "1.5.0" +version = "1.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fec781d48b41f8163426ed18e8fc2864c12937df9ce54c88ede7bd47270893e" +checksum = "372d5b87f58ec45c384ba03563b03544dc5fadc3983e434b286913f5b4a9bb6d" dependencies = [ - "redox_syscall 0.4.1", + "redox_syscall 0.5.4", "wasite", ] @@ -4464,11 +4853,11 @@ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" -version = "0.1.6" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596" +checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" dependencies = [ - "winapi", + "windows-sys 0.59.0", ] [[package]] @@ -4483,7 +4872,37 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" dependencies = [ - "windows-targets 0.52.4", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-registry" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e400001bb720a623c1c69032f8e3e4cf09984deec740f007dd2b03ec864804b0" +dependencies = [ + "windows-result", + "windows-strings", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-result" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-strings" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10" +dependencies = [ + "windows-result", + "windows-targets 0.52.6", ] [[package]] @@ -4501,7 +4920,16 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets 0.52.4", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets 0.52.6", ] [[package]] @@ -4521,17 +4949,18 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.52.4" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7dd37b7e5ab9018759f893a1952c9420d060016fc19a472b4bb20d1bdd694d1b" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ - "windows_aarch64_gnullvm 0.52.4", - "windows_aarch64_msvc 0.52.4", - "windows_i686_gnu 0.52.4", - "windows_i686_msvc 0.52.4", - "windows_x86_64_gnu 0.52.4", - "windows_x86_64_gnullvm 0.52.4", - "windows_x86_64_msvc 0.52.4", + "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]] @@ -4542,9 +4971,9 @@ checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] name = "windows_aarch64_gnullvm" -version = "0.52.4" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcf46cf4c365c6f2d1cc93ce535f2c8b244591df96ceee75d8e83deb70a9cac9" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" [[package]] name = "windows_aarch64_msvc" @@ -4554,9 +4983,9 @@ checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_aarch64_msvc" -version = "0.52.4" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da9f259dd3bcf6990b55bffd094c4f7235817ba4ceebde8e6d11cd0c5633b675" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" [[package]] name = "windows_i686_gnu" @@ -4566,9 +4995,15 @@ checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_gnu" -version = "0.52.4" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b474d8268f99e0995f25b9f095bc7434632601028cf86590aea5c8a5cb7801d3" +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" @@ -4578,9 +5013,9 @@ checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_i686_msvc" -version = "0.52.4" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1515e9a29e5bed743cb4415a9ecf5dfca648ce85ee42e15873c3cd8610ff8e02" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" [[package]] name = "windows_x86_64_gnu" @@ -4590,9 +5025,9 @@ checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnu" -version = "0.52.4" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5eee091590e89cc02ad514ffe3ead9eb6b660aedca2183455434b93546371a03" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" [[package]] name = "windows_x86_64_gnullvm" @@ -4602,9 +5037,9 @@ checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] name = "windows_x86_64_gnullvm" -version = "0.52.4" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77ca79f2451b49fa9e2af39f0747fe999fcda4f5e241b2898624dca97a1f2177" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" [[package]] name = "windows_x86_64_msvc" @@ -4614,15 +5049,15 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "windows_x86_64_msvc" -version = "0.52.4" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "winnow" -version = "0.5.40" +version = "0.6.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" +checksum = "68a9bda4691f099d435ad181000724da8e5899daa10713c2d432552b9ccd3a6f" dependencies = [ "memchr", ] @@ -4637,16 +5072,6 @@ dependencies = [ "windows-sys 0.48.0", ] -[[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 = "wyz" version = "0.5.1" @@ -4658,26 +5083,41 @@ dependencies = [ [[package]] name = "zerocopy" -version = "0.7.32" +version = "0.7.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74d4d3961e53fa4c9a25a8637fc2bfaf2595b3d3ae34875568a5cf64787716be" +checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" dependencies = [ + "byteorder", "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.7.32" +version = "0.7.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" +checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.77", ] [[package]] name = "zeroize" -version = "1.7.0" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d" +checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" +dependencies = [ + "zeroize_derive", +] + +[[package]] +name = "zeroize_derive" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.77", +] diff --git a/Cargo.toml b/Cargo.toml index 734ff265..151275ea 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -42,6 +42,7 @@ tracing = "0.1.40" tracing-opentelemetry = "0.24.0" tracing-subscriber = { version = "0.3.18", features = ["env-filter", "json"] } serde_with = "3.8.1" +payjoin = { version = "0.20.0", features = ["base64", "send", "receive", "v2", "io", "serde"] } electrum-client = "0.18.0" reqwest = { version = "0.12.5", default-features = false, features = ["json", "rustls-tls"] } async-trait = "0.1.80" @@ -57,7 +58,12 @@ tonic_lnd = { version = "0.2.0", package="fedimint-tonic-lnd", features = ["ligh [dev-dependencies] serial_test = "*" +payjoin = { version = "0.20.0", features = ["base64", "send", "receive", "v2", "io", "serde", "test-util"] } [build-dependencies] protobuf-src = { version = "1.1.0" } tonic-build = { version = "0.11.0", features = ["prost"] } + + +[patch.crates-io.payjoin] +path = "../payjoin/payjoin" diff --git a/dev/payjoin-cli/config.toml b/dev/payjoin-cli/config.toml new file mode 100644 index 00000000..8006c8ed --- /dev/null +++ b/dev/payjoin-cli/config.toml @@ -0,0 +1,5 @@ +bitcoind_rpcuser = "rpcuser" +bitcoind_rpcpass = "rpcpassword" +bitcoind_rpchost = "http://bitcoind:18443/wallet/payjoin" +pj_endpoint = "https://payjo.in" +ohttp_relay = "https://pj.bobspacebkk.com" \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index 04e70d5f..264ee67b 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -10,6 +10,7 @@ services: - otel-agent - fulcrum - mempool + - payjoin-cli postgres: image: postgres:14.1 environment: @@ -85,6 +86,15 @@ services: command: - | bitcoind -connect=bitcoind:18444 + payjoin-cli: + image: dangould/payjoin-cli:latest + volumes: + - ${HOST_PROJECT_PATH:-.}/dev/payjoin-cli/config.toml:/config.toml + depends_on: [ bitcoind ] + entrypoint: [ "/bin/sh", "-c" ] + command: + - | + tail -f /dev/null lnd: image: lightninglabs/lnd:v0.15.4-beta volumes: diff --git a/migrations/20240927160211_add_new_field_to_bria_batches.down.sql b/migrations/20240927160211_add_new_field_to_bria_batches.down.sql new file mode 100644 index 00000000..57e19e96 --- /dev/null +++ b/migrations/20240927160211_add_new_field_to_bria_batches.down.sql @@ -0,0 +1,2 @@ +-- Add down migration script here +ALTER TABLE bria_batches DROP COLUMN payjoin_proposal; \ No newline at end of file diff --git a/migrations/20240927160211_add_new_field_to_bria_batches.up.sql b/migrations/20240927160211_add_new_field_to_bria_batches.up.sql new file mode 100644 index 00000000..36a4a37d --- /dev/null +++ b/migrations/20240927160211_add_new_field_to_bria_batches.up.sql @@ -0,0 +1,2 @@ +-- Add up migration script here +ALTER TABLE bria_batches ADD COLUMN payjoin_proposal JSONB; \ No newline at end of file diff --git a/proto/api/bria.proto b/proto/api/bria.proto index 0317a145..07516e06 100644 --- a/proto/api/bria.proto +++ b/proto/api/bria.proto @@ -23,6 +23,7 @@ service BriaService { rpc GetWalletBalanceSummary (GetWalletBalanceSummaryRequest) returns (GetWalletBalanceSummaryResponse) {} rpc NewAddress (NewAddressRequest) returns (NewAddressResponse) {} + rpc NewUri (NewAddressRequest) returns (NewUriResponse) {} rpc UpdateAddress (UpdateAddressRequest) returns (UpdateAddressResponse) {} rpc ListAddresses (ListAddressesRequest) returns (ListAddressesResponse) {} rpc GetAddress (GetAddressRequest) returns (GetAddressResponse) {} @@ -186,6 +187,10 @@ message NewAddressResponse { string address = 1; } +message NewUriResponse { + string uri = 1; +} + message UpdateAddressRequest { string address = 2; optional string new_external_id = 3; diff --git a/src/address/repo.rs b/src/address/repo.rs index fb23fabd..ef904971 100644 --- a/src/address/repo.rs +++ b/src/address/repo.rs @@ -149,6 +149,7 @@ impl Addresses { account_id: AccountId, address: String, ) -> Result { + println!("find address: {:?}", address); let rows = sqlx::query!( r#" SELECT b.id, e.sequence, e.event @@ -161,7 +162,7 @@ impl Addresses { ) .fetch_all(&self.pool) .await?; - + println!("found smth?"); if rows.is_empty() { return Err(AddressError::AddressNotFound(address)); } @@ -170,6 +171,7 @@ impl Addresses { for row in rows { events.load_event(row.sequence as usize, row.event)?; } + println!("event loaded"); Ok(WalletAddress::try_from(events)?) } diff --git a/src/api/server/convert.rs b/src/api/server/convert.rs index 2b900633..b0e9c0fa 100644 --- a/src/api/server/convert.rs +++ b/src/api/server/convert.rs @@ -243,6 +243,7 @@ impl From for proto::PayoutQueue { consolidate_deprecated_keychains: payout_queue.config.consolidate_deprecated_keychains, cpfp_payouts_after_mins: payout_queue.config.cpfp_payouts_after_mins, cpfp_payouts_after_blocks: payout_queue.config.cpfp_payouts_after_blocks, + //can_payjoin_preempt: payout_queue.config.can_payjoin_preempt, force_min_change_sats: payout_queue.config.force_min_change_sats.map(u64::from), }); proto::PayoutQueue { diff --git a/src/api/server/mod.rs b/src/api/server/mod.rs index ae813db1..3828684e 100644 --- a/src/api/server/mod.rs +++ b/src/api/server/mod.rs @@ -368,6 +368,42 @@ impl BriaService for Bria { .await } + async fn new_uri( + &self, + request: Request, + ) -> Result, Status> { + crate::tracing::record_error(|| async move { + extract_tracing(&request); + dbg!("REQ"); + + let key = extract_api_token(&request)?; + let profile = self.app.authenticate(key).await?; + let request = request.into_inner(); + let NewAddressRequest { + wallet_name, + external_id, + metadata, + } = request; + + let (_, uri) = self + .app + .new_uri( + &profile, + wallet_name, + external_id, + metadata + .map(serde_json::to_value) + .transpose() + .map_err(ApplicationError::CouldNotParseIncomingMetadata)?, + ) + .await?; + Ok(Response::new(NewUriResponse { + uri: uri.to_string(), + })) + }) + .await + } + #[instrument(name = "bria.update_address", skip_all, fields(error, error.level, error.message), err)] async fn update_address( &self, diff --git a/src/app/error.rs b/src/app/error.rs index bad3851b..91d83d7d 100644 --- a/src/app/error.rs +++ b/src/app/error.rs @@ -81,6 +81,8 @@ pub enum ApplicationError { CouldNotDecryptKey(chacha20poly1305::Error), #[error("AddressError - Could not parse the address: {0}")] CouldNotParseAddress(#[from] bitcoin::AddressError), + #[error("PayjoinSession")] + PayjoinSession(#[from] anyhow::Error), } impl From for ApplicationError { diff --git a/src/app/mod.rs b/src/app/mod.rs index 6c622aa6..56148d54 100644 --- a/src/app/mod.rs +++ b/src/app/mod.rs @@ -1,10 +1,13 @@ mod config; pub mod error; +use bdk::bitcoin::{address::NetworkChecked, Amount}; +use payjoin::receive::v2::SessionInitializer; use sqlxmq::JobRunnerHandle; use tracing::instrument; +use url::Url; -use std::collections::HashMap; +use std::{collections::HashMap, str::FromStr}; pub use config::*; use error::*; @@ -12,6 +15,7 @@ use error::*; use crate::{ account::balance::AccountBalanceSummary, address::*, + api::proto::payout, batch::*, batch_inclusion::*, descriptor::*, @@ -19,6 +23,7 @@ use crate::{ job, ledger::*, outbox::*, + payjoin::{config::PayjoinConfig, *}, payout::*, payout_queue::*, primitives::*, @@ -40,6 +45,7 @@ pub struct App { payout_queues: PayoutQueues, payouts: Payouts, batches: Batches, + // payjoin_sessions: PayjoinSessions, signing_sessions: SigningSessions, ledger: Ledger, utxos: Utxos, @@ -48,6 +54,7 @@ pub struct App { batch_inclusion: BatchInclusion, pool: sqlx::PgPool, config: AppConfig, + pj: crate::payjoin::PayjoinReceiver, } impl App { @@ -97,6 +104,15 @@ impl App { config.jobs.respawn_all_outbox_handlers_delay, ) .await?; + let pj = PayjoinReceiver::new( + pool.clone(), + payout_queues.clone(), + PayjoinConfig { listen_port: 8088 }, + addresses.clone(), + utxos.clone(), + wallets.clone(), + config.blockchain.network, + ); let app = Self { outbox, profiles: Profiles::new(&pool), @@ -114,6 +130,7 @@ impl App { fees_client, batch_inclusion, config, + pj, _runner: runner, }; crate::profile::migration::profile_event_migration(&app.pool).await?; @@ -516,6 +533,57 @@ impl App { Ok((wallet.id, address)) } + #[instrument(name = "app.new_uri", skip(self), err)] + pub async fn new_uri( + &self, + profile: &Profile, + wallet_name: String, + external_id: Option, + metadata: Option, + ) -> Result<(WalletId, String), ApplicationError> { + let wallet = self + .wallets + .find_by_name(profile.account_id, wallet_name) + .await?; + let keychain_wallet = wallet.current_keychain_wallet(&self.pool); + let addr = keychain_wallet.new_external_address().await?; + let address = Address::from(addr.address.clone()); + dbg!("got address: {:?}", addr.address); + let mut builder = NewAddress::builder(); + builder + .address(address.clone()) + .account_id(profile.account_id) + .wallet_id(wallet.id) + .profile_id(profile.id) + .keychain_id(keychain_wallet.keychain_id) + .kind(bitcoin::KeychainKind::External) + .address_idx(addr.index) + .metadata(metadata); + if let Some(external_id) = external_id { + builder.external_id(external_id); + } + let new_address = builder.build().expect("Couldn't build NewUri"); + self.addresses.persist_new_address(new_address).await?; + dbg!("init payjoin"); + let (session, _ohttp_keys) = self + .pj + .init_payjoin_session( + &profile.account_id, + payjoin::bitcoin::Address::from_str(&address.to_string()) + .unwrap() + .assume_checked(), + ) + .await?; + dbg!("init'd payjoin"); + let uri = session + .session + .pj_uri_builder() + .amount(payjoin::bitcoin::Amount::from_sat(600_000)) + .build() + .to_string(); + Ok((wallet.id, uri)) + } + #[instrument(name = "app.update_address", skip(self), err)] pub async fn update_address( &self, diff --git a/src/batch/entity.rs b/src/batch/entity.rs index 358b377e..e931191f 100644 --- a/src/batch/entity.rs +++ b/src/batch/entity.rs @@ -12,6 +12,7 @@ pub struct Batch { pub wallet_summaries: HashMap, pub unsigned_psbt: bitcoin::psbt::PartiallySignedTransaction, pub signed_tx: Option, + pub provisional_proposal: Option, } impl Batch { @@ -31,6 +32,7 @@ pub struct NewBatch { pub(super) total_fee_sats: Satoshis, pub(super) unsigned_psbt: bitcoin::psbt::PartiallySignedTransaction, pub(super) wallet_summaries: HashMap, + pub(super) provisional_proposal: Option, } impl NewBatch { diff --git a/src/batch/repo.rs b/src/batch/repo.rs index 9c6b6d34..86698dd9 100644 --- a/src/batch/repo.rs +++ b/src/batch/repo.rs @@ -31,14 +31,15 @@ impl Batches { ) -> Result { let serializied_psbt = batch.unsigned_psbt.serialize(); sqlx::query!( - r#"INSERT INTO bria_batches (id, account_id, payout_queue_id, total_fee_sats, bitcoin_tx_id, unsigned_psbt) - VALUES ($1, $2, $3, $4, $5, $6)"#, + r#"INSERT INTO bria_batches (id, account_id, payout_queue_id, total_fee_sats, bitcoin_tx_id, unsigned_psbt, payjoin_proposal) + VALUES ($1, $2, $3, $4, $5, $6, $7)"#, batch.id as BatchId, batch.account_id as AccountId, batch.payout_queue_id as PayoutQueueId, i64::from(batch.total_fee_sats), batch.tx_id.as_ref() as &[u8], serializied_psbt.as_slice() as &[u8], + serde_json::to_value(batch.provisional_proposal).unwrap(), ).execute(&mut **tx).await?; let mut query_builder: QueryBuilder = QueryBuilder::new( @@ -90,7 +91,8 @@ impl Batches { payout_queue_id, unsigned_psbt, signed_tx, bitcoin_tx_id, s.batch_id, s.wallet_id, s.current_keychain_id, s.signing_keychains, total_in_sats, total_spent_sats, change_sats, change_address, change_vout, s.total_fee_sats, - cpfp_fee_sats, cpfp_details, batch_created_ledger_tx_id, batch_broadcast_ledger_tx_id + cpfp_fee_sats, cpfp_details, batch_created_ledger_tx_id, batch_broadcast_ledger_tx_id, + payjoin_proposal FROM bria_batch_wallet_summaries s LEFT JOIN bria_batches b ON b.id = s.batch_id WHERE s.batch_id = $1 AND b.account_id = $2"#, @@ -114,6 +116,10 @@ impl Batches { .map(|tx| bitcoin::consensus::deserialize(tx)) .transpose()?; let payout_queue_id = PayoutQueueId::from(rows[0].payout_queue_id); + let provisional_proposal = as Clone>::clone( + &rows[0].payjoin_proposal, + ) + .map(|p| serde_json::from_value(p).unwrap()); for row in rows.into_iter() { let wallet_id = WalletId::from(row.wallet_id); @@ -160,6 +166,7 @@ impl Batches { unsigned_psbt, signed_tx, wallet_summaries, + provisional_proposal, }) } diff --git a/src/cli/api_client.rs b/src/cli/api_client.rs index 80c70a89..38500d11 100644 --- a/src/cli/api_client.rs +++ b/src/cli/api_client.rs @@ -267,6 +267,25 @@ impl ApiClient { output_json(response) } + pub async fn new_uri( + &self, + wallet: String, + external_id: Option, + metadata: Option, + ) -> anyhow::Result<()> { + let request = tonic::Request::new(proto::NewAddressRequest { + wallet_name: wallet, + external_id, + metadata: metadata.map(serde_json::from_value).transpose()?, + }); + let response = self + .connect() + .await? + .new_uri(self.inject_auth_token(request)?) + .await?; + output_json(response) + } + pub async fn update_address( &self, address: String, diff --git a/src/cli/mod.rs b/src/cli/mod.rs index 6d926acb..a4e5b471 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -276,6 +276,25 @@ enum Command { #[clap(short, long, value_parser = parse_json)] metadata: Option, }, + // Get a new BIP21 URI for a wallet + NewUri { + #[clap( + short, + long, + value_parser, + default_value = "http://localhost:2742", + env = "BRIA_API_URL" + )] + url: Option, + #[clap(env = "BRIA_API_KEY", default_value = "")] + api_key: String, + #[clap(short, long)] + wallet: String, + #[clap(short, long)] + external_id: Option, + #[clap(short, long, value_parser = parse_json)] + metadata: Option, + }, /// Update address information UpdateAddress { #[clap( @@ -855,6 +874,16 @@ pub async fn run() -> anyhow::Result<()> { let client = api_client(cli.bria_home, url, api_key); client.new_address(wallet, external_id, metadata).await?; } + Command::NewUri { + url, + api_key, + wallet, + external_id, + metadata, + } => { + let client = api_client(cli.bria_home, url, api_key); + client.new_uri(wallet, external_id, metadata).await?; + } Command::UpdateAddress { url, api_key, diff --git a/src/job/batch_signing.rs b/src/job/batch_signing.rs index 0af00a7e..d8901d0b 100644 --- a/src/job/batch_signing.rs +++ b/src/job/batch_signing.rs @@ -8,6 +8,9 @@ use crate::{ app::BlockchainConfig, batch::*, primitives::*, signing_session::*, wallet::*, xpub::*, }; +use bdk::bitcoin::psbt::PartiallySignedTransaction as BdkPsbt; +use payjoin::bitcoin::psbt::Psbt as PayjoinPsbt; + #[derive(Debug, Clone, Serialize, Deserialize)] pub struct BatchSigningData { pub(super) account_id: AccountId, @@ -44,6 +47,51 @@ pub async fn execute( let mut stalled = false; let mut last_err = None; let mut current_keychain = None; + // get provisional proposal psbt to replace batch.unsigned_psbt out with an mpsc channel, sign it, and replace it with the result with a channel back into the finalize_psbt wallet_process_psbt closure + + let batch = batches.find_by_id(data.account_id, data.batch_id).await?; + let (unsigned_tx, unsigned_rx) = std::sync::mpsc::channel(); + let (signed_tx, signed_rx) = std::sync::mpsc::channel::(); + let (payjoin_tx, payjoin_rx) = std::sync::mpsc::channel(); + // TODO get rt from PayjoinReceiver? + let pj_psbt = if let Some(proposal) = batch.provisional_proposal { + use std::str::FromStr; + //let proposal = proposals.find_by_id(provisional_proposal_id).await?; FIXME lookup proposal by id + tokio::spawn(async move { + let mut payjoin = proposal + .finalize_proposal( + |psbt| { + let _ = unsigned_tx.send(psbt.clone()); + let signed_psbt = + PayjoinPsbt::from_str(&signed_rx.recv().unwrap().to_string()).unwrap(); + Ok(signed_psbt) + }, + None, + payjoin::bitcoin::FeeRate::from_sat_per_vb_unchecked(100), + ) + .expect("payjoin failed"); // FIXME feerates + // Do HTTP for payjoin response, otherwise timeout and return original_psbt tx to broadcast + let (req, ohttp_ctx) = payjoin.extract_v2_req().expect("v2 req extraction failed"); + println!("Got a request from the sender. Responding with a Payjoin proposal."); + let http = reqwest::Client::new(); + let res = http + .post(req.url) + .header("Content-Type", req.content_type) + .body(req.body) + .send() + .await + .expect("payjoin request failed"); + payjoin + .process_res(res.bytes().await.unwrap().to_vec(), ohttp_ctx) + .expect("Failed to deserialize response"); + payjoin_tx.send(BdkPsbt::from_str(&payjoin.psbt().to_string()).unwrap()); + }); + let unsigned_payjoin_psbt = unsigned_rx.recv().unwrap(); + Some(BdkPsbt::from_str(&unsigned_payjoin_psbt.to_string()).unwrap()) + } else { + None + }; + let (mut sessions, mut account_xpub_cache) = if let Some(batch_session) = signing_sessions .list_for_batch(data.account_id, data.batch_id) .await? @@ -55,6 +103,9 @@ pub async fn execute( let batch = batches.find_by_id(data.account_id, data.batch_id).await?; span.record("tx_id", &tracing::field::display(batch.bitcoin_tx_id)); let unsigned_psbt = batch.unsigned_psbt; + if let Some(ref pj_psbt) = pj_psbt { + assert_eq!(&unsigned_psbt, pj_psbt); + } for (wallet_id, summary) in batch.wallet_summaries { let wallet = wallets.find_by_id(wallet_id).await?; if current_keychain.is_none() { @@ -112,6 +163,7 @@ pub async fn execute( continue; } }; + // switch session.unsigned_psbt to provisional_proposal.finalize_psbt(|psbt|) match client.sign_psbt(&session.unsigned_psbt).await { Ok(psbt) => { session.remote_signing_complete(psbt); @@ -146,14 +198,23 @@ pub async fn execute( let wallet = wallets.find_by_id(wallet_id).await?; current_keychain = Some(wallet.current_keychain_wallet(&pool)); } - match ( + let psbt = if let Some(pj_psbt) = pj_psbt { + assert_eq!(&first_signed_psbt, &pj_psbt); + signed_tx.send(first_signed_psbt).unwrap(); + match payjoin_rx.recv() { + Ok(psbt) => Ok(Some(psbt)), + Err(_) => Err(JobError::Payjoin), + } + } else { current_keychain .expect("keychain should always exist") .finalize_psbt(first_signed_psbt) - .await, - last_err, - ) { + .await + .map_err(Into::into) + }; + match (psbt, last_err) { (Ok(Some(finalized_psbt)), _) => { + // TODO we may need an "awaiting payjoin" status here span.record("finalization_status", "complete"); let tx = finalized_psbt.extract_tx(); batches.set_signed_tx(data.batch_id, tx).await?; @@ -173,7 +234,7 @@ pub async fn execute( } (Err(err), _) => { span.record("finalization_status", "errored"); - Err(err.into()) + Err(err) } } } else if let Some(err) = last_err { diff --git a/src/job/error.rs b/src/job/error.rs index d1a562a6..ae998421 100644 --- a/src/job/error.rs +++ b/src/job/error.rs @@ -57,6 +57,8 @@ pub enum JobError { PsbtMissingInSigningSessions, #[error("JobError - psbt::Error: {0}")] PsbtError(#[from] psbt::Error), + #[error("JobError - Payjoin")] + Payjoin, } impl JobExecutionError for JobError {} diff --git a/src/job/mod.rs b/src/job/mod.rs index e563459e..9f76101a 100644 --- a/src/job/mod.rs +++ b/src/job/mod.rs @@ -660,6 +660,27 @@ impl From<(AccountId, PayoutQueueId)> for ProcessPayoutQueueData { payout_queue_id, account_id, batch_id: BatchId::new(), + payjoin_session: None, + tracing_data: crate::tracing::extract_tracing_data(), + } + } +} + +impl From<(AccountId, PayoutQueueId, payjoin::receive::v2::WantsOutputs)> + for ProcessPayoutQueueData +{ + fn from( + (account_id, payout_queue_id, session): ( + AccountId, + PayoutQueueId, + payjoin::receive::v2::WantsOutputs, + ), + ) -> Self { + Self { + payout_queue_id, + account_id, + batch_id: BatchId::new(), + payjoin_session: Some(session), tracing_data: crate::tracing::extract_tracing_data(), } } diff --git a/src/job/process_payout_queue.rs b/src/job/process_payout_queue.rs index ca1e4507..92cf58ab 100644 --- a/src/job/process_payout_queue.rs +++ b/src/job/process_payout_queue.rs @@ -1,5 +1,6 @@ +use payjoin::receive::v2::{ActiveSession, ProvisionalProposal, UncheckedProposal, WantsOutputs}; use serde::{Deserialize, Serialize}; -use std::collections::HashMap; +use std::{collections::HashMap, str::FromStr}; use tracing::instrument; use super::error::JobError; @@ -12,6 +13,7 @@ pub struct ProcessPayoutQueueData { pub(super) payout_queue_id: PayoutQueueId, pub(super) account_id: AccountId, pub(super) batch_id: BatchId, + pub(super) payjoin_session: Option, // find by id? #[serde(flatten)] pub(super) tracing_data: HashMap, } @@ -61,6 +63,10 @@ pub(super) async fn execute<'a>( let fee_rate = fees_client .fee_rate(payout_queue.config.tx_priority) .await?; + + // simplification: only payjoin when there is just one wallet + let is_payjoin_eligible = + data.payjoin_session.is_some() && unbatched_payouts.wallet_ids().len() == 1; let FinishedPsbtBuild { psbt, included_payouts, @@ -68,18 +74,35 @@ pub(super) async fn execute<'a>( wallet_totals, tx_id, fee_satoshis, + provisional_proposal, .. - } = construct_psbt( - &pool, - &mut tx, - &unbatched_payouts, - &utxos, - &wallets, - payout_queue, - fee_rate, - false, - ) - .await?; + } = if is_payjoin_eligible { + let wants_outputs = data.payjoin_session.clone().unwrap(); + construct_payjoin_psbt( + &pool, + &mut tx, + &unbatched_payouts, + &utxos, + &wallets, + payout_queue, + fee_rate, + false, + wants_outputs, + ) + .await? + } else { + construct_psbt( + &pool, + &mut tx, + &unbatched_payouts, + &utxos, + &wallets, + payout_queue, + fee_rate, + false, + ) + .await? + }; let span = tracing::Span::current(); if let (Some(tx_id), Some(psbt)) = (tx_id, psbt) { @@ -112,6 +135,7 @@ pub(super) async fn execute<'a>( .tx_id(tx_id) .unsigned_psbt(psbt) .total_fee_sats(fee_satoshis) + .provisional_proposal(provisional_proposal) .wallet_summaries( wallet_totals .into_iter() @@ -242,6 +266,82 @@ pub async fn construct_psbt( .await?) } +#[allow(clippy::too_many_arguments)] +pub async fn construct_payjoin_psbt( + pool: &sqlx::Pool, + tx: &mut sqlx::Transaction<'_, sqlx::Postgres>, + unbatched_payouts: &UnbatchedPayouts, + utxos: &Utxos, + wallets: &Wallets, // FIXME invariant where unbatched_payouts.wallet_ids().len() == 1 + payout_queue: PayoutQueue, + fee_rate: bitcoin::FeeRate, + for_estimation: bool, + wants_outputs: WantsOutputs, +) -> Result { + let span = tracing::Span::current(); + let PayoutQueue { + id: queue_id, + config: queue_cfg, + name: queue_name, + .. + } = payout_queue; + span.record("payout_queue_name", queue_name); + span.record("payout_queue_id", &tracing::field::display(queue_id)); + span.record("n_unbatched_payouts", unbatched_payouts.n_payouts()); + + let wallets = wallets.find_by_ids(unbatched_payouts.wallet_ids()).await?; + // inputs + let reserved_utxos = { + let keychain_ids = wallets.values().flat_map(|w| w.keychain_ids()); + utxos + .outpoints_bdk_should_not_select(tx, keychain_ids) + .await? + }; + span.record( + "n_reserved_utxos", + reserved_utxos.values().fold(0, |acc, v| acc + v.len()), + ); + + span.record("n_cpfp_utxos", 0); + + let mut cfg = PsbtBuilderConfig::builder() + .consolidate_deprecated_keychains(queue_cfg.consolidate_deprecated_keychains) + .fee_rate(fee_rate) + .reserved_utxos(reserved_utxos) + .force_min_change_output(queue_cfg.force_min_change_sats); + if !for_estimation && queue_cfg.should_cpfp() { + let keychain_ids = wallets.values().flat_map(|w| w.keychain_ids()); + let utxos = utxos + .find_cpfp_utxos( + tx, + keychain_ids, + queue_id, + queue_cfg.cpfp_payouts_detected_before(), + queue_cfg + .cpfp_payouts_detected_before_block(crate::bdk::last_sync_time(pool).await?), + ) + .await?; + span.record( + "n_cpfp_utxos", + utxos.values().fold(0, |acc, v| acc + v.len()), + ); + cfg = cfg.cpfp_utxos(utxos); + } + + let tx_payouts = unbatched_payouts.into_tx_payouts(); + // TODO add proposal tx_payouts + Ok(PsbtBuilder::construct_psbt( + pool, + cfg.for_estimation(for_estimation) + .wants_outputs(Some(wants_outputs)) + .build() + .expect("Couldn't build PsbtBuilderConfig"), + tx_payouts, + wallets, + ) + .await?) +} + #[instrument(name = "job.queue_drain_error", fields(error = true, error.level, error.message))] fn queue_drain_error(n_not_batched: usize) { let span = tracing::Span::current(); diff --git a/src/job/process_payout_queue_payjoin-notes.md b/src/job/process_payout_queue_payjoin-notes.md new file mode 100644 index 00000000..21b9857f --- /dev/null +++ b/src/job/process_payout_queue_payjoin-notes.md @@ -0,0 +1,280 @@ +```rs + //-- THIS IS THE old process_payout_queue payjoin code + //let wallet_id = unbatched_payouts.wallet_ids().into_iter()..first().unwrap(); // we know the length is one from the is_payjoin_eligible check + // DEFINE OUTPUTS ------- + // ---------------------- + use rust_decimal::prelude::ToPrimitive; + let replacement_outputs: Vec = unbatched_payouts + .into_iter() + .flat_map(|(_wallet_id, payouts)| payouts.into_iter()) + .map(|(_, address, sats)| { + payjoin::bitcoin::TxOut { + value: payjoin::bitcoin::Amount::from_btc(sats.to_btc().to_f64().unwrap()).unwrap(), + script_pubkey: payjoin::bitcoin::ScriptBuf::from_bytes(address.script_pubkey().to_bytes()), + } + }) + .collect(); + + // FIXME STUPID SIMPLIFICATION: pick first availabledrain address + // FIXME bria can have multiple drain scripts since a queue 'receiver' is actually multiple wallets + let drain_script = replacement_outputs.first().expect("no outputs to replace with").script_pubkey; + let wants_inputs = wants_outputs.replace_receiver_outputs(replacement_outputs, &drain_script).unwrap().commit_outputs(); + + // CONTRIBUTE INPUTS ------- + // ------------------------- + // payout queue config, batch signing job + println!("contribute"); + // Don't throw an error. Continue optimistic process even if we can't contribute inputs. + + let available_wallets = wallets + .list_by_account_id(data.account_id) + .await + .expect("Failed to list wallets"); + let keychain_ids = available_wallets + .iter() + .flat_map(|wallet| wallet.keychain_ids()); + let mut keychain_utxos = utxos.find_keychain_utxos(keychain_ids).await.expect("failed to find keychain utxos"); + let keychain_utxos = keychain_utxos + .drain() + .map(|(_, keychain_utxos)| keychain_utxos) + .collect::>(); + + let mut available_inputs = keychain_utxos + .iter() + .flat_map(|keychain_utxos| keychain_utxos.utxos.iter()); + + let candidate_inputs: HashMap = available_inputs + .clone() + // Why is a utxo output value NOT saved in bitcoin::Amount? How can it be partial satoshis? + .map(|i| { + let txid = payjoin::bitcoin::Txid::from_str(&i.outpoint.txid.to_string()).unwrap(); + ( + payjoin::bitcoin::Amount::from_sat(i.value.into()), + payjoin::bitcoin::OutPoint::new(txid, i.outpoint.vout), + ) + }) + .collect(); + let selected_outpoint = wants_inputs + .try_preserving_privacy(candidate_inputs) + .expect("no privacy preserving utxo found"); + let selected_utxo = available_inputs + .find(|i| { + let txid = payjoin::bitcoin::Txid::from_str(&i.outpoint.txid.to_string()).unwrap(); + payjoin::bitcoin::OutPoint::new(txid, i.outpoint.vout) == selected_outpoint + }) + .expect("This shouldn't happen. Failed to retrieve the privacy preserving utxo from those we provided to the seclector."); + + let txo_to_contribute = payjoin::bitcoin::TxOut { + value: payjoin::bitcoin::Amount::from_sat(selected_utxo.value.into()), + script_pubkey: payjoin::bitcoin::ScriptBuf::from_bytes(selected_utxo + .address + .clone() + .expect("selected_utxo missing script") + .script_pubkey().to_bytes()), + }; + let provisional_proposal = wants_inputs.contribute_witness_inputs(vec![(selected_outpoint, txo_to_contribute)]).expect("failed to contribute inputs").commit_inputs(); + // -- +``` + +```rs +use std::sync::{Arc, Mutex}; + use std::sync::mpsc::{self, Sender, Receiver}; + use std::thread; + use std::time::Duration; + use crate::payjoin::ProcessPsbtControl; + + let (tx, rx): (Sender, Receiver) = mpsc::channel(); + provisional_proposal.finalize_proposal(|psbt| { + let psbt = crate::payjoin::wallet_process_psbt(psbt.clone()).unwrap(); + Ok(psbt.clone()) + }, None, payjoin::bitcoin::FeeRate::from_sat_per_vb(100).unwrap()); + // TODO + // TODO + // TODO + + + ``` + ```rs + + #[instrument(name = "psbt_builder.construct_payjoin_psbt", skip_all)] + pub async fn construct_payjoin_psbt( + pool: &sqlx::PgPool, + cfg: PsbtBuilderConfig, + wants_outputs: payjoin::receive::v2::WantsOutputs, + unbatched_payouts: HashMap>, + mut wallets: HashMap, // FIXME invariant where unbatched_payouts.wallet_ids().len() == 1 + ) -> Result { + let mut outer_builder: PsbtBuilder = PsbtBuilder::new(cfg); + + let wallet_id = unbatched_payouts.keys().next().expect("unbatched_payouts must be non-empty"); + let payouts = unbatched_payouts.values().next().expect("unbatched_payouts must be non-empty"); + let wallet = wallets.remove(&wallet_id.clone()).expect("Wallet not found"); + + let mut builder = outer_builder.wallet_payouts(*wallet_id, payouts.to_vec()); + for keychain in wallet.deprecated_keychain_wallets(pool.clone()) { + builder = keychain.dispatch_bdk_wallet(builder).await?; + } + // include inputs and outputs: + outer_builder = wallet + .current_keychain_wallet(pool) + .dispatch_bdk_wallet(builder.accept_current_keychain()) + .await? + .next_wallet(); + + //-- + //let wallet_id = unbatched_payouts.wallet_ids().into_iter()..first().unwrap(); // we know the length is one from the is_payjoin_eligible check + // DEFINE OUTPUTS ------- + // ---------------------- + use rust_decimal::prelude::ToPrimitive; + let replacement_outputs: Vec = unbatched_payouts + .into_iter() + .flat_map(|(_wallet_id, payouts)| payouts.into_iter()) + .map(|(_, address, sats)| { + payjoin::bitcoin::TxOut { + value: payjoin::bitcoin::Amount::from_btc(sats.to_btc().to_f64().unwrap()).unwrap(), + script_pubkey: payjoin::bitcoin::ScriptBuf::from_bytes(address.script_pubkey().to_bytes()), + } + }) + .collect(); + + // FIXME STUPID SIMPLIFICATION: pick first availabledrain address + // FIXME bria can have multiple drain scripts since a queue 'receiver' is actually multiple wallets + let drain_script = replacement_outputs.first().expect("no outputs to replace with").script_pubkey; + let wants_inputs = wants_outputs.replace_receiver_outputs(replacement_outputs, &drain_script).unwrap().commit_outputs(); + + // CONTRIBUTE INPUTS ------- + // ------------------------- + // payout queue config, batch signing job + println!("contribute"); + // Don't throw an error. Continue optimistic process even if we can't contribute inputs. + + let available_wallets = wallets + .list_by_account_id(data.account_id) + .await + .expect("Failed to list wallets"); + let keychain_ids = available_wallets + .iter() + .flat_map(|wallet| wallet.keychain_ids()); + let mut keychain_utxos = utxos.find_keychain_utxos(keychain_ids).await.expect("failed to find keychain utxos"); + let keychain_utxos = keychain_utxos + .drain() + .map(|(_, keychain_utxos)| keychain_utxos) + .collect::>(); + + let mut available_inputs = keychain_utxos + .iter() + .flat_map(|keychain_utxos| keychain_utxos.utxos.iter()); + + let candidate_inputs: HashMap = available_inputs + .clone() + // Why is a utxo output value NOT saved in bitcoin::Amount? How can it be partial satoshis? + .map(|i| { + let txid = payjoin::bitcoin::Txid::from_str(&i.outpoint.txid.to_string()).unwrap(); + ( + payjoin::bitcoin::Amount::from_sat(i.value.into()), + payjoin::bitcoin::OutPoint::new(txid, i.outpoint.vout), + ) + }) + .collect(); + let selected_outpoint = wants_inputs + .try_preserving_privacy(candidate_inputs) + .expect("no privacy preserving utxo found"); + let selected_utxo = available_inputs + .find(|i| { + let txid = payjoin::bitcoin::Txid::from_str(&i.outpoint.txid.to_string()).unwrap(); + payjoin::bitcoin::OutPoint::new(txid, i.outpoint.vout) == selected_outpoint + }) + .expect("This shouldn't happen. Failed to retrieve the privacy preserving utxo from those we provided to the seclector."); + + let txo_to_contribute = payjoin::bitcoin::TxOut { + value: payjoin::bitcoin::Amount::from_sat(selected_utxo.value.into()), + script_pubkey: payjoin::bitcoin::ScriptBuf::from_bytes(selected_utxo + .address + .clone() + .expect("selected_utxo missing script") + .script_pubkey().to_bytes()), + }; + let provisional_proposal = wants_inputs.contribute_witness_inputs(vec![(selected_outpoint, txo_to_contribute)]).expect("failed to contribute inputs").commit_inputs(); + // -- + Ok(outer_builder.finish()) + } +``` + +```rs + +#[allow(clippy::too_many_arguments)] +pub async fn construct_payjoin_psbt( + pool: &sqlx::Pool, + tx: &mut sqlx::Transaction<'_, sqlx::Postgres>, + unbatched_payouts: &UnbatchedPayouts, + utxos: &Utxos, + wallets: &Wallets, // FIXME invariant where unbatched_payouts.wallet_ids().len() == 1 + payout_queue: PayoutQueue, + fee_rate: bitcoin::FeeRate, + for_estimation: bool, + wants_outputs: WantsOutputs, +) -> Result { + let span = tracing::Span::current(); + let PayoutQueue { + id: queue_id, + config: queue_cfg, + name: queue_name, + .. + } = payout_queue; + span.record("payout_queue_name", queue_name); + span.record("payout_queue_id", &tracing::field::display(queue_id)); + span.record("n_unbatched_payouts", unbatched_payouts.n_payouts()); + + let wallets = wallets.find_by_ids(unbatched_payouts.wallet_ids()).await?; + // inputs + let reserved_utxos = { + let keychain_ids = wallets.values().flat_map(|w| w.keychain_ids()); + utxos + .outpoints_bdk_should_not_select(tx, keychain_ids) + .await? + }; + span.record( + "n_reserved_utxos", + reserved_utxos.values().fold(0, |acc, v| acc + v.len()), + ); + + span.record("n_cpfp_utxos", 0); + + let mut cfg = PsbtBuilderConfig::builder() + .consolidate_deprecated_keychains(queue_cfg.consolidate_deprecated_keychains) + .fee_rate(fee_rate) + .reserved_utxos(reserved_utxos) + .force_min_change_output(queue_cfg.force_min_change_sats); + if !for_estimation && queue_cfg.should_cpfp() { + let keychain_ids = wallets.values().flat_map(|w| w.keychain_ids()); + let utxos = utxos + .find_cpfp_utxos( + tx, + keychain_ids, + queue_id, + queue_cfg.cpfp_payouts_detected_before(), + queue_cfg + .cpfp_payouts_detected_before_block(crate::bdk::last_sync_time(pool).await?), + ) + .await?; + span.record( + "n_cpfp_utxos", + utxos.values().fold(0, |acc, v| acc + v.len()), + ); + cfg = cfg.cpfp_utxos(utxos); + } + + let tx_payouts = unbatched_payouts.into_tx_payouts(); + // TODO add proposal tx_payouts + Ok(PsbtBuilder::construct_psbt( + pool, + cfg.for_estimation(for_estimation) + .wants_outputs(Some(wants_outputs)) + .build() + .expect("Couldn't build PsbtBuilderConfig"), + tx_payouts, + wallets, + ) + .await?) +} +``` \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index e7c95bf9..81e295de 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -17,6 +17,7 @@ pub mod fees; mod job; pub mod ledger; mod outbox; +pub mod payjoin; pub mod payout; pub mod payout_queue; pub mod primitives; diff --git a/src/payjoin/config.rs b/src/payjoin/config.rs new file mode 100644 index 00000000..2333ae5f --- /dev/null +++ b/src/payjoin/config.rs @@ -0,0 +1,18 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Clone, Debug, Deserialize, Serialize)] +pub struct PayjoinConfig { + #[serde(default = "default_port")] + pub listen_port: u16, +} +impl Default for PayjoinConfig { + fn default() -> Self { + Self { + listen_port: default_port(), + } + } +} + +fn default_port() -> u16 { + 8088 +} diff --git a/src/payjoin/error.rs b/src/payjoin/error.rs new file mode 100644 index 00000000..39c4118b --- /dev/null +++ b/src/payjoin/error.rs @@ -0,0 +1,8 @@ +use thiserror::Error; + +#[allow(clippy::large_enum_variant)] +#[derive(Error, Debug)] +pub enum PayjoinError { + #[error("PayjoinError - Error")] + Error, +} diff --git a/src/payjoin/mod.rs b/src/payjoin/mod.rs new file mode 100644 index 00000000..033b4dc8 --- /dev/null +++ b/src/payjoin/mod.rs @@ -0,0 +1,410 @@ +pub mod config; +pub mod error; + +use crate::{ + address::error::AddressError, job, payjoin::config::*, payout_queue::PayoutQueues, + primitives::AccountId, +}; +use std::{collections::HashMap, str::FromStr, time::Duration}; + +use anyhow::{anyhow, Context, Result}; +use bdk::bitcoin::{psbt::Psbt, Transaction}; + +use payjoin::{ + receive::v2::{ActiveSession, UncheckedProposal, WantsInputs, WantsOutputs}, + send::RequestContext, +}; +use tokio::runtime::Handle; +use url::Url; + +type ProtoClient = + crate::api::proto::bria_service_client::BriaServiceClient; +use crate::{ + address::Addresses, + primitives::bitcoin::{self, Network}, + utxo::Utxos, + wallet::Wallets, +}; + +/// A representation of a payjoin receiver "service" +pub struct PayjoinReceiver { + rt: Handle, + pool: sqlx::PgPool, + payout_queues: PayoutQueues, + config: PayjoinConfig, + addresses: Addresses, + utxos: Utxos, + wallets: Wallets, + network: Network, +} + +impl PayjoinReceiver { + pub fn new( + pool: sqlx::PgPool, + payout_queues: PayoutQueues, + config: PayjoinConfig, + addresses: Addresses, + utxos: Utxos, + wallets: Wallets, + network: Network, + ) -> Self { + Self { + rt: Handle::current(), + pool, + payout_queues, + config, + addresses, + utxos, + wallets, + network, + } + } + + /// Initializes a payjoin session and listens for a payjoin request on a background thread. + /// TODO save the session to the database so it can be resumed after a shutdown + pub async fn init_payjoin_session( + &self, + account_id: &AccountId, + address: payjoin::bitcoin::Address, + ) -> Result<(RecvSession, payjoin::OhttpKeys), anyhow::Error> { + let payjoin_dir = Url::parse("https://payjo.in").expect("Invalid URL"); + let ohttp_relays: [Url; 2] = [ + Url::parse("https://pj.bobspacebkk.com").expect("Invalid URL"), + Url::parse("https://ohttp.payjoin.org").expect("Invalid URL"), + ]; + dbg!("fetch"); + let payjoin_dir_clone = payjoin_dir.clone(); + let ohttp_relay_clone = ohttp_relays[0].clone(); + let ohttp_keys = tokio::task::spawn_blocking(move || { + payjoin::io::fetch_ohttp_keys(ohttp_relay_clone, payjoin_dir_clone) + }) + .await? + .await?; + let http_client = reqwest::Client::builder().build()?; + dbg!("fetched"); + fn random_ohttp_relay(ohttp_relays: [Url; 2]) -> Url { + use rand::seq::SliceRandom; + use rand::thread_rng; + ohttp_relays.choose(&mut thread_rng()).unwrap().clone() + } + dbg!("enroll"); + let mut enroller = payjoin::receive::v2::SessionInitializer::new( + address, + payjoin_dir.to_owned(), + ohttp_keys.clone(), + ohttp_relays[0].to_owned(), + None, + ); + dbg!("req"); + let (req, context) = enroller + .extract_req() + .map_err(|e| anyhow::anyhow!(e.to_string()))?; + let ohttp_response = http_client + .post(req.url) + .header("Content-Type", "message/ohttp-req") + .body(req.body) + .send() + .await?; + let ohttp_response = ohttp_response.bytes().await?; + dbg!("res"); + let session = enroller + .process_res(ohttp_response.as_ref(), context) + .map_err(|e| anyhow::anyhow!(e.to_string()))?; + let recv_session = RecvSession { + account_id: account_id.clone(), + session: session.clone(), + expiry: std::time::Duration::from_secs(60 * 60 * 24), + payjoin_tx: None, + }; + self.spawn_recv_session(recv_session.clone()); + // ^^ ABOVE DOES THIS + // tokio::task::spawn(move || { + // let wants_outputs = self.sanity_check(recv_session, proposal).await?; + + // // let rt = tokio::runtime::Runtime::new().unwrap(); + // // rt.block_on(async { + // // let proposal = poll_for_fallback_psbt(&http_client, &mut recv_session).await?; + // // // TODO start listening, on a job? + // // }) + // // TODO start listening, on a job? + // // TODO listen on thread for a payjoin request + // // spawn_recv_session(recv_session, pj).await?; + // }); + // TODO save session to DB before returning + // TODO start listening, on a job? + dbg!("made sesh"); + Ok((recv_session, ohttp_keys)) + } + + async fn try_contributing_inputs( + self, + account_id: AccountId, + payjoin: WantsInputs, + ) -> Result<()> { + let available_wallets = self + .wallets + .list_by_account_id(account_id) + .await + .context("Failed to list wallets")?; + let keychain_ids = available_wallets + .iter() + .flat_map(|wallet| wallet.keychain_ids()); + let mut keychain_utxos = self + .utxos + .find_keychain_utxos(keychain_ids) + .await + .context("failed to find keychain utxos")?; + let keychain_utxos = keychain_utxos + .drain() + .map(|(_, keychain_utxos)| keychain_utxos) + .collect::>(); + + let mut available_inputs = keychain_utxos + .iter() + .flat_map(|keychain_utxos| keychain_utxos.utxos.iter()); + + let candidate_inputs: HashMap = + available_inputs + .clone() + // Why is a utxo output value NOT saved in bitcoin::Amount? How can it be partial satoshis? + .map(|i| { + let txid = + payjoin::bitcoin::Txid::from_str(&i.outpoint.txid.to_string()).unwrap(); + ( + payjoin::bitcoin::Amount::from_sat(i.value.into()), + payjoin::bitcoin::OutPoint::new(txid, i.outpoint.vout), + ) + }) + .collect(); + let selected_outpoint = payjoin + .try_preserving_privacy(candidate_inputs) + .expect("no privacy preserving utxo found"); + let selected_utxo = available_inputs + .find(|i| { + let txid = payjoin::bitcoin::Txid::from_str(&i.outpoint.txid.to_string()).unwrap(); + payjoin::bitcoin::OutPoint::new(txid, i.outpoint.vout) == selected_outpoint + }) + .context("This shouldn't happen. Failed to retrieve the privacy preserving utxo from those we provided to the seclector.")?; + + let txo_to_contribute = payjoin::bitcoin::TxOut { + value: payjoin::bitcoin::Amount::from_sat(selected_utxo.value.into()), + script_pubkey: payjoin::bitcoin::ScriptBuf::from_bytes( + selected_utxo + .address + .clone() + .ok_or_else(|| anyhow!("selected_utxo missing script"))? + .script_pubkey() + .to_bytes(), + ), + }; + payjoin.contribute_witness_inputs(vec![(selected_outpoint, txo_to_contribute)]); + Ok(()) + } + + pub async fn spawn_recv_session(&self, mut session: RecvSession) -> Result<()> { + let payout_queues = self.payout_queues.clone(); + let pool = self.pool.clone(); + let addresses = self.addresses.clone(); + let network = self.network.clone(); + tokio::spawn(async move { + let qs = payout_queues + .clone() + .list_by_account_id(session.account_id) + .await + .unwrap(); + let payout_queue_id = &qs.first().unwrap().id; + let http_client = reqwest::Client::builder().build().unwrap(); + let proposal = poll_for_fallback_psbt(session.clone(), &http_client) + .await + .unwrap(); + let wants_outputs = + check_proposal(session.clone(), proposal, network, addresses.clone()) + .await + .unwrap(); + job::spawn_process_payout_queue( + &pool.clone(), + (session.account_id, *payout_queue_id, wants_outputs), + ) + .await + .unwrap(); + // let _ = self.resume_recv_session(session).await.unwrap();d + }); + Ok(()) + } +} + +pub async fn poll_for_fallback_psbt( + session: RecvSession, + client: &reqwest::Client, +) -> Result { + let mut session = session.session; + loop { + // if stop.load(Ordering::Relaxed) { + // return Err(crate::payjoin::Error::Shutdown); + // } + + // if session.expiry < utils::now() { + // if let Some(payjoin_tx) = &session.payjoin_tx { + // wallet + // .cancel_tx(payjoin_tx) + // .map_err(|_| crate::payjoin::Error::CancelPayjoinTx)?; + // } + // let _ = storage.delete_recv_session(&session.enrolled.pubkey()); + // return Err(crate::payjoin::Error::SessionExpired); + // } + println!("POLLING RECEIVE SESSION"); + let (req, context) = session + .extract_req() + .map_err(|e| anyhow::anyhow!(e.to_string()))?; + let ohttp_response = client + .post(req.url) + .header("Content-Type", "message/ohttp-req") + .body(req.body) + .send() + .await?; + let ohttp_response = ohttp_response.bytes().await?; + let proposal = session + .process_res(ohttp_response.as_ref(), context) + .map_err(|e| anyhow::anyhow!(e.to_string()))?; + match proposal { + Some(proposal) => return Ok(proposal), + None => tokio::time::sleep(tokio::time::Duration::from_secs(5)).await, + } + } +} + +pub async fn check_proposal( + session: RecvSession, + proposal: UncheckedProposal, + network: Network, + addresses: Addresses, +) -> Result> { + // in a payment processor where the sender could go offline, this is where you schedule to broadcast the original_tx + let _to_broadcast_in_failure_case = proposal.extract_tx_to_schedule_broadcast(); + // we have to look up the output address from a list of payjoin addresses that should NOT contain change addresses + // if we hit 2x payjoin addresses, we should abort + let account_id = session.account_id; + + // Receive Check 1: Can Broadcast + let proposal = proposal + .check_broadcast_suitability(None, |_tx| { + // TODO test_mempool_accept e.g.: + // + // Fulcrum does not yet support this, so we need to devise a way to check this to the best of our ability + // Probably by using bitcoind directly and deprecating Fulcrum + Ok(true) + }) + .expect("check1 failed"); + dbg!("check2"); + let network = network.clone(); + let (tx, rx) = std::sync::mpsc::channel(); + // Receive Check 2: receiver can't sign for proposal inputs + let proposal = proposal + .check_inputs_not_owned(|input| { + // Spawn a new thread for each input check + let tx = tx.clone(); + let addresses = addresses.clone(); + let input = input.to_string(); + let network = network.clone(); + tokio::spawn(async move { + let result = match bitcoin::BdkAddress::from_str(&input) { + Ok(address) => { + match addresses + .find_by_address( + account_id, + address.require_network(network).unwrap().to_string(), + ) + .await + { + Ok(_) => Ok(true), + Err(AddressError::AddressNotFound(_)) => Ok(false), + Err(e) => { + eprintln!("ERROR: {}", e); + Err(e.to_string()) + } + } + } + Err(e) => Err(e.to_string()), + }; + tx.send(result).unwrap(); + }); + + // This will block until the async operation is complete + rx.recv() + .unwrap() + .map_err(|e| payjoin::Error::Server(e.into())) + }) + .expect("check2 failed"); + dbg!("check3"); + + // Receive Check 3: receiver can't sign for proposal inputs + let proposal = proposal.check_no_mixed_input_scripts()?; + + // Receive Check 4: have we seen this input before? More of a check for non-interactive i.e. payment processor receivers. + let payjoin = proposal + .check_no_inputs_seen_before(|input| { + // TODO implement input_seen_before database check + // Ok(!self.insert_input_seen_before(*input).map_err(|e| Error::Server(e.into()))?) + Ok(false) + }) + .expect("check4 failed"); + + // Receive Check 4: receiver can't sign for proposal inputs + let network = network.clone(); + let (tx2, rx2) = std::sync::mpsc::channel(); + let mut payjoin = payjoin + .identify_receiver_outputs(|output_script| { + // Clone transmitter for each output_script + let tx2 = tx2.clone(); + let addresses = addresses.clone(); + let output_script = output_script.to_string(); + // Spawn a new thread for each output_script check + std::thread::spawn(move || { + dbg!("check4"); + let rt = tokio::runtime::Runtime::new().unwrap(); // Create a new runtime for the thread + rt.block_on(async { + let result = match bitcoin::BdkAddress::from_str(&output_script) { + Ok(address) => { + match addresses + .find_by_address(account_id, address.assume_checked().to_string()) + .await + { + Ok(_) => Ok(true), // TODO: Confirm ownership logic if needed + Err(AddressError::AddressNotFound(_)) => Ok(false), + Err(e) => { + dbg!("ERROR!"); + Err(e.to_string()) + } + } + } + Err(e) => Err(e.to_string()), + }; + dbg!("check4"); + tx2.send(result).unwrap(); // Send the result back to the main thread + }); + }); + + // Block until the async operation is complete + rx2.recv() + .unwrap() + .map_err(|e| payjoin::Error::Server(e.into())) + }) + .expect("check5 failed"); + Ok(payjoin) +} + +#[derive(Debug, Clone, PartialEq)] +pub struct RecvSession { + pub account_id: AccountId, + pub session: ActiveSession, + pub expiry: Duration, + pub payjoin_tx: Option, +} + +#[derive(Clone, PartialEq)] +pub struct SendSession { + pub original_psbt: Psbt, + pub req_ctx: RequestContext, + pub labels: Vec, + pub expiry: Duration, +} diff --git a/src/payjoin/queue.md b/src/payjoin/queue.md new file mode 100644 index 00000000..3d59d2bf --- /dev/null +++ b/src/payjoin/queue.md @@ -0,0 +1,3 @@ +I peeled another layer back today addressing payjoin integration with the payout_queue and related abstractions. + +Once a sender's proposal is checked to be a suitable as a fallback to turn into a payjoin, we can think of it as being added to bria's mempool. This is distinct from our instance of bitcoind's mempool, since it's only in bria's section of memory, but we know it still is able to pay us if broadcast, gives us some funds in a foreign utxo to *partially* account for (since some will be paid back to the sender as change), and specifies at least one Payout, either a self-spend to one of our wallets that we may update or change that the sender has specified. \ No newline at end of file diff --git a/src/payout_queue/config.rs b/src/payout_queue/config.rs index 6b35335c..0d562d5e 100644 --- a/src/payout_queue/config.rs +++ b/src/payout_queue/config.rs @@ -12,6 +12,7 @@ pub struct PayoutQueueConfig { pub cpfp_payouts_after_blocks: Option, pub force_min_change_sats: Option, pub consolidate_deprecated_keychains: bool, + // pub(super) can_payjoin_preempt: bool, pub trigger: PayoutQueueTrigger, } @@ -56,6 +57,7 @@ impl Default for PayoutQueueConfig { }, cpfp_payouts_after_mins: None, cpfp_payouts_after_blocks: None, + // can_payjoin_preempt: true, force_min_change_sats: None, } } diff --git a/src/payout_queue/entity.rs b/src/payout_queue/entity.rs index 5dc2d551..cc1aba83 100644 --- a/src/payout_queue/entity.rs +++ b/src/payout_queue/entity.rs @@ -40,6 +40,7 @@ impl PayoutQueue { match self.config.trigger { Interval { seconds } => Some(seconds), Manual => None, + // Payjoin => None, } } diff --git a/src/primitives/mod.rs b/src/primitives/mod.rs index 3a32252b..86a70505 100644 --- a/src/primitives/mod.rs +++ b/src/primitives/mod.rs @@ -43,6 +43,7 @@ impl From for PayoutId { } crate::entity_id! { BatchId } crate::entity_id! { OutboxEventId } +crate::entity_id! { PayjoinProposalId } #[derive(Debug, Clone, Hash, PartialEq, Eq, Copy, Serialize, Deserialize)] #[serde(transparent)] @@ -88,7 +89,7 @@ pub mod bitcoin { }, consensus, hash_types::Txid, - psbt, Address as BdkAddress, Network, + psbt, Address as BdkAddress, Amount, Network, }, descriptor::ExtendedDescriptor, BlockTime, FeeRate, KeychainKind, diff --git a/src/utxo/mod.rs b/src/utxo/mod.rs index 21d2ece6..277a8d01 100644 --- a/src/utxo/mod.rs +++ b/src/utxo/mod.rs @@ -66,6 +66,42 @@ impl Utxos { Ok(tx_id.map(|id| (id, tx))) } + // #[instrument(name = "utxos.foreign_utxo_detected", skip(self), err)] + // #[allow(clippy::too_many_arguments)] + // pub async fn foreign_utxo_detected( + // &self, + // account_id: AccountId, + // wallet_id: WalletId, // AccountId/Foreign + // keychain_id: KeychainId, // None + // address: &AddressInfo, + // utxo: &LocalUtxo, + // origin_tx_fee: Satoshis, + // origin_tx_vbytes: u64, + // self_pay: bool, + // current_block_height: u32, + // ) -> Result)>, UtxoError> { + // let new_utxo = NewUtxo::builder() + // .account_id(account_id) + // .wallet_id(wallet_id) + // .keychain_id(keychain_id) + // .outpoint(utxo.outpoint) + // .kind(address.keychain) + // .address_idx(address.index) + // .address(address.to_string()) + // .script_hex(format!("{:x}", utxo.txout.script_pubkey)) + // .value(utxo.txout.value) + // .bdk_spent(utxo.is_spent) + // .detected_block_height(current_block_height) + // .origin_tx_fee(origin_tx_fee) + // .origin_tx_vbytes(origin_tx_vbytes) + // .self_pay(self_pay) + // .build() + // .expect("Could not build NewUtxo"); + // let mut tx = self.pool.begin().await?; + // let tx_id = self.utxos.persist_utxo(&mut tx, new_utxo).await?; + // Ok(tx_id.map(|id| (id, tx))) + // } + #[instrument(name = "utxos.settle_utxo", skip(self, tx), err)] pub async fn settle_utxo( &self, diff --git a/src/wallet/keychain/wallet.rs b/src/wallet/keychain/wallet.rs index 6287c2e2..a5896f49 100644 --- a/src/wallet/keychain/wallet.rs +++ b/src/wallet/keychain/wallet.rs @@ -52,7 +52,7 @@ impl KeychainWallet { if wallet.finalize_psbt(&mut psbt, SignOptions::default())? { Ok::<_, BdkError>(Some(psbt)) } else { - Ok::<_, BdkError>(None) + Ok::<_, BdkError>(Some(psbt)) } }) .await diff --git a/src/wallet/psbt_builder.rs b/src/wallet/psbt_builder.rs index 765af37d..deb93883 100644 --- a/src/wallet/psbt_builder.rs +++ b/src/wallet/psbt_builder.rs @@ -1,4 +1,5 @@ use bdk::{ + bitcoin::hashes::Hash, database::BatchDatabase, wallet::{tx_builder::TxOrdering, AddressIndex, AddressInfo}, FeeRate, Wallet, @@ -44,6 +45,7 @@ pub struct FinishedPsbtBuild { pub fee_satoshis: Satoshis, pub tx_id: Option, pub psbt: Option, + pub provisional_proposal: Option, } impl FinishedPsbtBuild { @@ -76,6 +78,8 @@ pub struct PsbtBuilderConfig { for_estimation: bool, #[builder(default)] force_min_change_output: Option, + #[builder(default)] + wants_outputs: Option, } impl PsbtBuilderConfig { @@ -127,6 +131,7 @@ pub struct PsbtBuilder { result: FinishedPsbtBuild, input_weights: HashMap, all_included_utxos: HashSet, + provisional_proposal: Option, _phantom: PhantomData, } @@ -191,7 +196,7 @@ impl PsbtBuilder { sum.keychains_with_inputs .extend(keychain_utxos.keys().copied()); } - + ret.provisional_proposal = self.provisional_proposal; ret } } @@ -241,7 +246,9 @@ impl PsbtBuilder { fee_satoshis: Satoshis::from(0), tx_id: None, psbt: None, + provisional_proposal: None, }, + provisional_proposal: None, _phantom: PhantomData, } } @@ -265,6 +272,7 @@ impl PsbtBuilder { all_included_utxos: self.all_included_utxos, input_weights: self.input_weights, result: self.result, + provisional_proposal: self.provisional_proposal, _phantom: PhantomData, } } @@ -335,6 +343,7 @@ impl PsbtBuilder { all_included_utxos: self.all_included_utxos, input_weights: self.input_weights, result: self.result, + provisional_proposal: self.provisional_proposal, _phantom: PhantomData, } } @@ -358,6 +367,19 @@ impl BdkWalletVisitor for PsbtBuilder { let mut max_payout = 0; let mut absolute_fee = 0; let mut inputs = Vec::new(); + if let Some(wants_outputs) = &self.cfg.wants_outputs { + for pj_txin in wants_outputs.original_psbt().unsigned_tx.input.iter() { + use std::str::FromStr; + // FIXME weight should be paid for by payjoin sender + let bdk_outpoint = OutPoint { + txid: bdk::bitcoin::Txid::from_str(&pj_txin.previous_output.txid.to_string()) + .unwrap(), + vout: pj_txin.previous_output.vout, + }; + // input weights must be added for try_build + self.input_weights.insert(bdk_outpoint, 0); + } + } while max_payout < self.current_payouts.len() { let (fee, ins, success) = self.try_build_current_wallet_psbt( current_keychain_id, @@ -412,7 +434,50 @@ impl BdkWalletVisitor for PsbtBuilder { .push(((payout_id, destination, satoshis), 0)); } + // - collect foreign payjoin utxos to add as input + // - add non-owned payjoin outputs as change + // - remove domain receiver outputs from payjoin original psbt to be forwarded or spent to change + let payjoin_original_psbt = if let Some(ref wants_outputs) = self.cfg.wants_outputs { + use std::str::FromStr; + let mut payjoin_original_psbt = + psbt::Psbt::from_str(&wants_outputs.original_psbt().to_string()) + .expect("failed to parse payjoin original psbt"); + let current_wallet_owned_vouts = wants_outputs.owned_vouts(); + for i in (0..payjoin_original_psbt.unsigned_tx.output.len()).rev() { + if current_wallet_owned_vouts.contains(&i) { + // remove original_psbt deposits as they'll be forwarded + payjoin_original_psbt.outputs.remove(i); + payjoin_original_psbt.unsigned_tx.output.remove(i); + } else { + // the payjoin sender's change outputs will be added as recipients + let output = &payjoin_original_psbt.unsigned_tx.output[i]; + let txout = bdk::bitcoin::TxOut { + value: output.value, + script_pubkey: bdk::bitcoin::ScriptBuf::from_bytes( + output.script_pubkey.to_bytes(), + ), + }; + builder.add_recipient(txout.script_pubkey, txout.value); + } + } + Some((current_keychain_id, payjoin_original_psbt)) + } else { + None + }; + dbg!( + "is_payjoin_original_psbt: {:?}", + &payjoin_original_psbt.is_some() + ); + if let Some((keychain_id, payjoin_original_psbt)) = payjoin_original_psbt { + self.current_wallet_psbts + .push((keychain_id, payjoin_original_psbt)); + } + dbg!( + "current_wallet_psbts.len(): {:?}", + &self.current_wallet_psbts.len() + ); for (keychain_id, psbt) in self.current_wallet_psbts.drain(..) { + dbg!("keychainid drain: {:?}", &keychain_id); for (input, psbt_input) in psbt.unsigned_tx.input.into_iter().zip(psbt.inputs) { builder.add_foreign_utxo( input.previous_output, @@ -436,8 +501,9 @@ impl BdkWalletVisitor for PsbtBuilder { self.all_included_utxos.insert(input.previous_output); } } - + dbg!("Does result.psbt exist? {}", self.result.psbt.is_some()); if let Some(result_psbt) = self.result.psbt { + dbg!("result_psbt exists"); for (input, psbt_input) in result_psbt .unsigned_tx .input @@ -462,6 +528,64 @@ impl BdkWalletVisitor for PsbtBuilder { builder.ordering(TxOrdering::Bip69Lexicographic); match builder.finish() { Ok((psbt, details)) => { + if let Some(wants_outputs) = &self.cfg.wants_outputs { + use std::str::FromStr; + // convert psbt unsigned_tx.output to payjoin::bitcoin::TxOut + let replacement_outputs: Vec = psbt + .unsigned_tx + .output + .clone() + .into_iter() + .map(|out| payjoin::bitcoin::TxOut { + value: payjoin::bitcoin::Amount::from_sat(out.value.into()), + script_pubkey: payjoin::bitcoin::ScriptBuf::from_bytes( + out.script_pubkey.to_bytes(), + ), + }) + .collect(); + let payjoin_drain_script = payjoin::bitcoin::ScriptBuf::from_bytes( + change_address.script_pubkey().to_bytes(), + ); + // TODO provide a receiver only output list, ignore sender change + let wants_inputs = wants_outputs + .clone() + .replace_receiver_outputs(replacement_outputs, &payjoin_drain_script) + .unwrap() + .commit_outputs(); + + let inputs: Vec<_> = psbt + .unsigned_tx + .input + .clone() + .into_iter() + .zip(psbt.inputs.clone()) + .map(|(txin, psbt_input)| { + ( + payjoin::bitcoin::OutPoint::new( + payjoin::bitcoin::Txid::from_str( + &txin.previous_output.txid.to_string(), + ) + .unwrap(), + txin.previous_output.vout, + ), + payjoin::bitcoin::TxOut { + value: payjoin::bitcoin::Amount::from_sat( + psbt_input.witness_utxo.clone().unwrap().value.into(), + ), + script_pubkey: payjoin::bitcoin::ScriptBuf::from_bytes( + psbt_input.witness_utxo.unwrap().script_pubkey.to_bytes(), + ), + }, + ) + }) + .collect(); + self.provisional_proposal = Some( + wants_inputs + .contribute_witness_inputs(inputs) + .unwrap() + .commit_inputs(), + ); + } // FIXME I think the fee is definitely wrong since proposal.apply_fee has not been called let fee_satoshis = Satoshis::from(details.fee.expect("fee must be present")); let current_wallet_fee = fee_satoshis - self.result.fee_satoshis; let wallet_id = self.current_wallet.expect("current wallet must be set"); @@ -544,6 +668,7 @@ impl PsbtBuilder { all_included_utxos: self.all_included_utxos, input_weights: self.input_weights, result: self.result, + provisional_proposal: self.provisional_proposal, _phantom: PhantomData, } } @@ -594,14 +719,59 @@ impl PsbtBuilder { } let mut foreign_utxos = HashSet::new(); - for (_, psbt) in self.current_wallet_psbts.iter() { + let mut input_weights = self.input_weights.clone(); + // add foreign payjoin utxos + // *try* Handle payjoin to see what happens. visit_bdk_wallet will actually use the state machine + let payjoin_original_psbt = if let Some(wants_outputs) = &self.cfg.wants_outputs { + use std::str::FromStr; + let mut payjoin_original_psbt = + psbt::Psbt::from_str(&wants_outputs.original_psbt().to_string()) + .expect("failed to parse payjoin original psbt"); + let current_wallet_owned_vouts = wants_outputs.owned_vouts(); + for i in (0..payjoin_original_psbt.unsigned_tx.output.len()).rev() { + if current_wallet_owned_vouts.contains(&i) { + // know that the receiver is liable to spend the amounts in these removed outputs + payjoin_original_psbt.outputs.remove(i); + payjoin_original_psbt.unsigned_tx.output.remove(i); + } else { + let output = &payjoin_original_psbt.unsigned_tx.output[i]; + let txout = bdk::bitcoin::TxOut { + value: output.value, + script_pubkey: bdk::bitcoin::ScriptBuf::from_bytes( + output.script_pubkey.to_bytes(), + ), + }; + builder.add_recipient(txout.script_pubkey, txout.value); + } + } + for input in payjoin_original_psbt.unsigned_tx.input.iter() { + // FIXME weight should be paid for by payjoin sender + let bdk_outpoint = OutPoint { + txid: bdk::bitcoin::Txid::from_str(&input.previous_output.txid.to_string()) + .unwrap(), + vout: input.previous_output.vout, + }; + // input weights must be added for try_build + input_weights.insert(bdk_outpoint, 0); + } + + // add inputs in following loop + Some((keychain_id, payjoin_original_psbt)) + } else { + None + }; + + let mut current_wallet_psbts = self.current_wallet_psbts.clone(); + if let Some((keychain_id, payjoin_original_psbt)) = payjoin_original_psbt { + current_wallet_psbts.push((keychain_id, payjoin_original_psbt)); + } + for (_, psbt) in current_wallet_psbts.iter() { for (input, psbt_input) in psbt.unsigned_tx.input.iter().zip(psbt.inputs.iter()) { foreign_utxos.insert(input.previous_output); builder.add_foreign_utxo( input.previous_output, psbt_input.clone(), - *self - .input_weights + *input_weights .get(&input.previous_output) .expect("weight should always be present"), )?; @@ -641,6 +811,7 @@ impl PsbtBuilder { true, )) } + // TODO different case for payjoin? Err(bdk::Error::InsufficientFunds { .. }) => Ok((0, Vec::new(), false)), Err(e) => Err(e.into()), } diff --git a/src/xpub/signing_client/bitcoind.rs b/src/xpub/signing_client/bitcoind.rs index 77ac40bd..683b28f4 100644 --- a/src/xpub/signing_client/bitcoind.rs +++ b/src/xpub/signing_client/bitcoind.rs @@ -48,12 +48,13 @@ impl RemoteSigningClient for BitcoindRemoteSigner { "Failed to sign psbt via bitcoind: {e}" )) })?; - let signed_psbt = general_purpose::STANDARD .decode(response.psbt) .map_err(|e| { SigningClientError::HexConvert(format!("Failed to convert psbt from bitcoind: {e}")) })?; - Ok(psbt::PartiallySignedTransaction::deserialize(&signed_psbt)?) + let deserialized_psbt = psbt::PartiallySignedTransaction::deserialize(&signed_psbt)?; + dbg!(&deserialized_psbt); + Ok(deserialized_psbt) } } diff --git a/tests/e2e/helpers.bash b/tests/e2e/helpers.bash index 7727f4af..96235578 100644 --- a/tests/e2e/helpers.bash +++ b/tests/e2e/helpers.bash @@ -55,6 +55,10 @@ bitcoin_cli() { docker exec "${COMPOSE_PROJECT_NAME}-bitcoind-1" bitcoin-cli $@ } +payjoin_cli() { + docker exec "${COMPOSE_PROJECT_NAME}-payjoin-cli-1" ./payjoin-cli $@ +} + bitcoin_signer_cli() { docker exec "${COMPOSE_PROJECT_NAME}-bitcoind-signer-1" bitcoin-cli $@ } @@ -100,7 +104,9 @@ bitcoind_init() { local wallet="${1:-default}" bitcoin_cli createwallet "default" || true - bitcoin_cli generatetoaddress 200 "$(bitcoin_cli getnewaddress)" + bitcoin_cli createwallet "payjoin" || true + bitcoin_cli -rpcwallet=payjoin generatetoaddress 25 "$(bitcoin_cli -rpcwallet=payjoin getnewaddress)" + bitcoin_cli -rpcwallet=default generatetoaddress 175 "$(bitcoin_cli -rpcwallet=default getnewaddress)" if [[ "${wallet}" == "default" ]]; then bitcoin_signer_cli createwallet "default" || true diff --git a/tests/e2e/payjoin.bats b/tests/e2e/payjoin.bats new file mode 100644 index 00000000..6a16a385 --- /dev/null +++ b/tests/e2e/payjoin.bats @@ -0,0 +1,52 @@ +#!/usr/bin/env bats +RUST_LOG=debug + +load "helpers" + +setup_file() { + restart_bitcoin_stack + reset_pg + bitcoind_init + start_daemon + bria_init +} + +teardown_file() { + stop_daemon +} + +@test "payjoin: Start payjoin session and retrieve uri" { + bria_address=$(bria_cmd new-address -w default | jq -r '.address') + if [ -z "$bria_address" ]; then + echo "Failed to get a new address" + exit 1 + fi + + bitcoin_cli -rpcwallet=default -regtest sendtoaddress ${bria_address} 1 + + for i in {1..30}; do + n_utxos=$(bria_cmd list-utxos -w default | jq '.keychains[0].utxos | length') + [[ "${n_utxos}" == "3" ]] && break + sleep 1 + done + cache_wallet_balance + [[ $(cached_encumbered_fees) != 0 ]] || exit 1 + [[ $(cached_pending_income) == 100000000 ]] || exit 1; + + bria_uri=$(bria_cmd new-uri -w default | jq -r '.uri') + if [ -z "$bria_uri" ] || [ "$bria_uri" = "null" ]; then + echo "Failed to get a new uri" + exit 1 + fi + echo $bria_uri + # payjoin_cli send --fee-rate 2 ${bria_uri} + + # for i in {1..30}; do + # n_utxos=$(bria_cmd list-utxos -w default | jq '.keychains[0].utxos | length') + # [[ "${n_utxos}" == "3" ]] && break + # sleep 1 + # done + # cache_wallet_balance + # [[ $(cached_encumbered_fees) != 0 ]] || exit 1 + # [[ $(cached_pending_income) == 220000000 ]] || exit 1; +} diff --git a/tests/e2e/setup.bats b/tests/e2e/setup.bats new file mode 100644 index 00000000..bbd2baff --- /dev/null +++ b/tests/e2e/setup.bats @@ -0,0 +1,20 @@ +#!/usr/bin/env bats +RUST_LOG=debug + +load "helpers" + +setup_file() { + restart_bitcoin_stack + reset_pg + bitcoind_init + start_daemon + bria_init +} + +teardown_file() { + stop_daemon +} + +@test "setup" { + echo "done" +} diff --git a/tests/helpers.rs b/tests/helpers.rs index 68f3d751..c0e15d3c 100644 --- a/tests/helpers.rs +++ b/tests/helpers.rs @@ -3,6 +3,7 @@ use anyhow::Context; use bdk::{ bitcoin::{ + psbt::PartiallySignedTransaction, secp256k1::{rand, Secp256k1}, Address, Amount, PrivateKey, }, @@ -117,6 +118,23 @@ pub fn fund_addr( Ok(tx_id) } +pub fn create_funded_psbt( + bitcoind: &BitcoindClient, + addr: &Address, + amount_in_sats: u64, +) -> anyhow::Result { + let amount = bitcoin::Amount::from_sat(amount_in_sats); + let outputs = std::collections::HashMap::from([(addr.to_string(), amount)]); + let options = bitcoincore_rpc::json::WalletCreateFundedPsbtOptions { + lock_unspent: Some(true), + fee_rate: Some(Amount::from_sat(1000)), + ..Default::default() + }; + Ok(bitcoind + .wallet_create_funded_psbt(&[], &outputs, None, Some(options), Some(true))? + .psbt) +} + pub fn lookup_tx_info( bitcoind: &BitcoindClient, tx_id: bitcoin::Txid, diff --git a/tests/psbt_builder.rs b/tests/psbt_builder.rs index e9106109..89425d84 100644 --- a/tests/psbt_builder.rs +++ b/tests/psbt_builder.rs @@ -431,6 +431,164 @@ async fn build_psbt_with_min_change_output() -> anyhow::Result<()> { Ok(()) } +/// The Domain wallet receives a payjoin from another wallet +/// +/// Test that the domain wallet is sending funds +/// and this gets merged with incoming payjoin in order to cut-through and create +/// only a single change output +/// +/// depositor -> domain -> withdrawer +#[tokio::test] +#[serial] +async fn build_psbt_with_payjoin() -> anyhow::Result<()> { + use payjoin::receive::v2::WantsOutputs; + let pool = helpers::init_pool().await?; + + // set up the PsbtBuilder domain wallet + let external = "wpkh([6f2fa1b2/84'/0'/0']tpubDDDDGYiFda8HfJRc2AHFJDxVzzEtBPrKsbh35EaW2UGd5qfzrF2G87ewAgeeRyHEz4iB3kvhAYW1sH6dpLepTkFUzAktumBN8AXeXWE9nd1/0/*)#l6n08zmr"; + let internal = "wpkh([6f2fa1b2/84'/0'/0']tpubDDDDGYiFda8HfJRc2AHFJDxVzzEtBPrKsbh35EaW2UGd5qfzrF2G87ewAgeeRyHEz4iB3kvhAYW1sH6dpLepTkFUzAktumBN8AXeXWE9nd1/1/*)#wwkw6htm"; + + let domain_current_keychain_id = Uuid::new_v4(); + let keychain_cfg = KeychainConfig::try_from((external.as_ref(), internal.as_ref()))?; + let domain_current_keychain = KeychainWallet::new( + pool.clone(), + Network::Regtest, + domain_current_keychain_id.into(), + keychain_cfg, + ); + dbg!("new keychain"); + let domain_addr = domain_current_keychain.new_external_address().await?; + let domain_change_address = domain_current_keychain.new_internal_address().await?; + let bitcoind = helpers::bitcoind_client().await?; + let domain_funding = 300_000_000; + let domain_funding_sats = Satoshis::from(domain_funding); + dbg!("funding"); + let tx_id = helpers::fund_addr(&bitcoind, &domain_addr, domain_funding)?; + dbg!("funded"); + helpers::gen_blocks(&bitcoind, 10)?; + while !find_tx_id(&pool, domain_current_keychain_id, tx_id).await? { + let blockchain = helpers::electrum_blockchain().await?; + domain_current_keychain.sync(blockchain).await?; + } + + // Build WantsOutputs for payjoin + // 1st build original_psbt for deposit depositor -> domain, not part of the builder (or a separate builder) + let deposit_addr = domain_current_keychain.new_external_address().await?; + let deposit_funding = 200_000_000; + let deposit_funding_sats = Satoshis::from(deposit_funding); + dbg!("creating funded psbt"); + let deposit_original_psbt = + helpers::create_funded_psbt(&bitcoind, &deposit_addr.address, deposit_funding)?; + use std::str::FromStr; + let deposit_original_psbt = + payjoin::bitcoin::Psbt::from_str(&deposit_original_psbt.to_string())?; + let domain_owned_vout = deposit_original_psbt + .unsigned_tx + .output + .iter() + .position(|o| o.value.to_sat() == deposit_funding) + .unwrap(); + let change_vout = if domain_owned_vout == 0 { 1 } else { 0 }; + let wants_outputs = WantsOutputs::for_psbt_mutation( + deposit_original_psbt, + change_vout, + vec![domain_owned_vout], + payjoin::bitcoin::Address::from_str(&deposit_addr.address.to_string())?.assume_checked(), + ); + + let fee = FeeRate::from_sat_per_vb(1.0); + let cfg = PsbtBuilderConfig::builder() + .consolidate_deprecated_keychains(false) // for simplicity, we don't consolidate here + .fee_rate(fee) + .wants_outputs(Some(wants_outputs)) + .build() + .unwrap(); + let builder = PsbtBuilder::new(cfg); + + let domain_wallet_id = WalletId::new(); + let withdrawal_funding = 400_000_000; + let withdrawal_funding_sats = Satoshis::from(withdrawal_funding); + // Send funds from domain to an address associated with neither depositor nor withdrawer + let withdrawer_destination = + Address::parse_from_trusted_source("mgWUuj1J1N882jmqFxtDepEC73Rr22E9GU"); + let payouts = vec![( + Uuid::new_v4(), + withdrawer_destination.clone(), + withdrawal_funding_sats, + )]; + let builder = builder + .wallet_payouts(domain_wallet_id, payouts) + .accept_current_keychain(); + + let builder = domain_current_keychain + .dispatch_bdk_wallet(builder) + .await? + .next_wallet(); + + // First, propose an original_psbt + let FinishedPsbtBuild { + psbt: unsigned_psbt, + included_payouts, + included_utxos, + wallet_totals, + fee_satoshis, + provisional_proposal, + .. + } = builder.finish(); + assert_eq!( + included_payouts + .get(&domain_wallet_id) + .expect("wallet not included in payouts") + .len(), + 1 + ); + assert_eq!(wallet_totals.len(), 1); + // let other_wallet_total = wallet_totals.get(&depositor_wallet_id).unwrap(); + // assert!(other_wallet_total.change_outpoint.is_none()); + // assert_eq!(other_wallet_total.change_address, other_change_address); + // assert_eq!( + // other_wallet_total.output_satoshis + // + other_wallet_total.change_satoshis + // + other_wallet_total.total_fee_satoshis, + // other_wallet_total.input_satoshis + // ); + // assert_eq!(other_wallet_total.total_fee_satoshis, Satoshis::from(155)); + + let mut unsigned_psbt = unsigned_psbt.expect("unsigned psbt"); + // let total_tx_outs = unsigned_psbt + // .unsigned_tx + // .output + // .iter() + // .fold(0, |acc, out| acc + out.value); + // let total_summary_outs = wallet_totals + // .values() + // .fold(Satoshis::from(0), |acc, total| { + // acc + total.output_satoshis + total.change_satoshis + // }); + // assert_eq!(total_tx_outs, u64::from(total_summary_outs)); + // assert_eq!(total_tx_outs, u64::from(total_summary_outs)); + // let total_summary_fees = wallet_totals + // .values() + // .fold(Satoshis::from(0), |acc, total| { + // acc + total.total_fee_satoshis + // }); + // assert_eq!(total_summary_fees, fee_satoshis); + assert!(unsigned_psbt.inputs.len() >= 1); // from payjoin sender only + assert_eq!(unsigned_psbt.outputs.len(), 3); // withdrawal, sender change, domain change + + let mut bitcoind_client = helpers::bitcoind_signing_client().await?; + dbg!("signing with bitcoind"); + let signed_psbt = bitcoind_client.sign_psbt(&unsigned_psbt).await?; + dbg!(&signed_psbt.to_string()); + let _tx = domain_current_keychain + .finalize_psbt(signed_psbt) // FIXME do we need to finalize before or after payjoin sender signs? + .await? + .expect("Finalize should have completed") + .extract_tx(); + // The tx won't be able to be broadcast because it's missing signature data from the payjoin sender + Ok(()) +} + async fn find_tx_id( pool: &sqlx::PgPool, keychain_id: Uuid, diff --git a/v2-notes-spawn.md b/v2-notes-spawn.md new file mode 100644 index 00000000..1ecca21a --- /dev/null +++ b/v2-notes-spawn.md @@ -0,0 +1,15 @@ +I've hooked up the payjoin v2 receiver into bria but I'm a bit lost (again) as to how to get the psbts it has processed and signed. I think you mentioned doing this without a job somehow but I'm a bit stuck since it seems like the only way coins get added and signed right now wis via a job executor picking up a payout_queue and creating a new batch + +I've hooked up the payjoin v2 receiver into bria that has a sender and receiver communicating. I'm a bit lost (again) as to how to get the psbt a receiver has checked can be processed and signed. I think you mentioned doing this without a job somehow but I'm a bit stuck since it seems like the only way coins get added and signed right now wis via a job executor picking up a payout_queue and creating a new batch. I think I understand how these pieces work now, but not how to relate them to the payjoin flow quite yet. We could address it on a call to get an e2e payjoin working if you have a moment to do so + +// TODOTODOTODO + +VERY PROBABLY: spawn_process_payout_queue + +ProcessPayoutQueueData may have PayjoinProposal or ProvisionalProposal to work with + +Do it with the batch or else I'll have to manually decouple a bunch of things + +Then, PsbtBuilderConfig should take ProvisionalProposal as input from which to "construct" (or augment) the proposal and return it. + +It should be able to be spawned manually using spawn_process_payout_queue and then triggered \ No newline at end of file