{"id":28481743,"url":"https://github.com/robosats/taptrade-core","last_synced_at":"2026-03-11T05:01:47.807Z","repository":{"id":248586275,"uuid":"797852576","full_name":"RoboSats/taptrade-core","owner":"RoboSats","description":"Taproot pipeline for escrowed fiat \u003c-\u003e bitcoin trades on p2p exchanges. SoB24 project.","archived":false,"fork":false,"pushed_at":"2024-09-08T08:51:05.000Z","size":10047,"stargazers_count":9,"open_issues_count":15,"forks_count":6,"subscribers_count":0,"default_branch":"research","last_synced_at":"2025-06-07T20:08:32.524Z","etag":null,"topics":["bitcoin","escrow","exchange","p2p","robosats","sob24","summer-of-bitcoin","taproot"],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/RoboSats.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-05-08T16:20:28.000Z","updated_at":"2025-02-02T06:58:36.000Z","dependencies_parsed_at":"2024-09-08T09:52:12.696Z","dependency_job_id":"975b4363-324d-4f27-a080-b1da1c116261","html_url":"https://github.com/RoboSats/taptrade-core","commit_stats":null,"previous_names":["robosats/taptrade-core"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/RoboSats/taptrade-core","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RoboSats%2Ftaptrade-core","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RoboSats%2Ftaptrade-core/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RoboSats%2Ftaptrade-core/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RoboSats%2Ftaptrade-core/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/RoboSats","download_url":"https://codeload.github.com/RoboSats/taptrade-core/tar.gz/refs/heads/research","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RoboSats%2Ftaptrade-core/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30372125,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-10T21:41:54.280Z","status":"online","status_checked_at":"2026-03-11T02:00:07.027Z","response_time":84,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["bitcoin","escrow","exchange","p2p","robosats","sob24","summer-of-bitcoin","taproot"],"created_at":"2025-06-07T20:08:33.127Z","updated_at":"2026-03-11T05:01:47.802Z","avatar_url":"https://github.com/RoboSats.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# *taptrade-core - A taproot p2p trading pipeline*\n\nImplementation of a [taproot](https://bitcoinops.org/en/topics/taproot/) escrow trading pipeline for fiat \u003c-\u003e bitcoin exchange with minimal onchain footprint. Intended for the integration in RoboSats and possibly other p2p exchanges.\n\n## Background\nCurrently, all [RoboSats](https://github.com/RoboSats/robosats) trades use the [Lightning network](https://lightning.network/) and utilize [HODL Invoices](https://bitcoinops.org/en/topics/hold-invoices/) to enable a safe exchange environment for users. In case of a dispute, e.g., the (bitcoin) selling trader claims that the buyer did not transfer the fiat money, both parties can initiate a dispute process. In this process, the coordinator collects evidence (e.g. bank statements, chat logs) and releases the funds to the appropriate party.\n\nThis model works reliably for a large number of trades but has some tradeoffs compared to an on-chain exchange model nevertheless. Currently, the trading duration is limited to around 24 hours due to technical limitations regarding Lightning payments ([HTLC](https://docs.lightning.engineering/the-lightning-network/multihop-payments/hash-time-lock-contract-htlc) timeout) to keep the risk of technical complications like [channel closes](https://docs.lightning.engineering/the-lightning-network/payment-channels/lifecycle-of-a-payment-channel) and bad UX trough [payment failures](https://thebitcoinmanual.com/articles/why-lightning-payments-may-fail/) low. Due to this limitation it is only possible to trade with fast fiat payment methods like SEPA Instant or PayPal. Longer trades would allow for slower fiat rails like traditional bank wire which can take several days to arrive. The usage of the Lightning Network also limits the trade amount to a certain maximum due to nature of payment channels.\n\nTherefore the implementation of a purely on-chain pipeline would enable larger trades and new fiat payment methods for traders. By utilizing the Taproot transaction format of Bitcoin and the [MuSig2](https://eprint.iacr.org/2020/1261) signature aggregation scheme it is possible to design a trade pipeline which, in the regular case of no disputes, looks like a very regular Taproot transaction on the blockchain. This provides the traders with a high level of privacy and a lower fee rate than currently established P2WSH trade pipelines.\n\n## Goals\n1. Definition of the trading protocol\n2. Implementation of client and coordinator\n3. Integration of the client in RoboSats frontend\n\n## Trade protocol\n#### \u003cu\u003eBonds\u003c/u\u003e\nTraders are required to submit a bond to the coordinator as first step of their trade. This bond is required to prevent misbehaviour like orderbook spamming or unreliable trade partners, it establishes a real cost to create offers and not finish them as agreed upon.\n\nThe bond is sent to the coordinator in form of a signed bitcoin transaction spending to the coordinator with a high transaction fee. The required bond amount can be communicated by the coordinator. The input to the bond transaction should be the same input that will be used in the following escrow locking transaction to reduce the risk of a griefing coordinator.\nIt can also be required that the input sum should be at least the amount of the trade for sellers so there\nis evidence the seller actually owns the bitcoin he wants to sell, increasing cost to fake offers.\nThe bond will be stored by the coordinator and the coordinator is supposed to monitor the mempool and the\nblockchain for the used inputs.\n\nIn case the trader misbehaves the coordinator can broadcast the bond transaction and receives the bond output.\nIf the trader double spends the input to the bond the coordinator is able to increase the transaction fee ([CPFP](https://bitcoinops.org/en/topics/cpfp/)) up to the amount of the bond output. Even in the case\nof [out-of-band mining](https://thebitcoinmanual.com/articles/out-of-band-btc-transaction/) of the bond input\nin another transacion the trader has a cost associated to creating offers on the exchange.\n\nThis bond mechanism should be sufficient for the associated risks as long as out-of-band mining doesn't get extremely cheap.\n\n```\nBond TX, signed, not broadcasted:\n\n                  |-----\u003e Bond output (coordinator)\nTrader input(s)--\u003e|-----\u003e Change output\n                  |-----\u003e Tx fee (high)\n```\n\nExample transaction [hex]:\n```\n0100000000010129a7c05b63693a5cb3ced62192929dc7074f988852301554cdb34e1aa04db1c90000000000feffffff02c56b029500000000225120ddce5be8a1713afb247da815f1545ccb997f593248e6b6d19e0e72a502baf6f28813000000000000225120fe8d8d8ff0985a33bc0b9c16508f8d4fe3d5d4df568a1fe6ad4c3022bbd185fb0140a448c42d65ad6a8febdae8db01d2ff388d8d746c2de84b0524ac9fc0d5af9c09a86c4f8da50ae91a993ce51ce99458bfcf9ba51f3da4aad4a43dd9ac6909cf1823180000\n```\n\n#### \u003cu\u003eEscrow locking transaction\u003c/u\u003e\nAfter a taker accepted a public offer (valid bond submitted) both traders have to lock funds in a locking transaction that can only be spent again in collaboration. This locking transaction is a collaborative transaction containing inputs of both maker and taker. Both traders have to sign the locking transaction\nwhich is then combined by the coordinator. The coordinator will allow the use of the same inputs as in the bond transaction. Once this locking transaction has sufficient confirmations the fiat exchange can begin.\n\n```\n                  |---\u003e Escrow locking output (will be used for the payout tx)\nMaker input(s)----|---\u003e Coordinator fee output (service fee for coordinator)\n                  |---\u003e Maker change output\nTaker input(s)----|---\u003e Taker change output\n                  |---\u003e Transaction fee\n\nBuyer input amount:  Bond + 1/2 coordinator service fee + 1/2 tx fee\nSeller input amount: Bond + 1/2 coordinator service fee + 1/2 tx fee + amount to sell\n```\n\nExample transaction [hex]:\n```\n01000000000102176c5c190fd523e6afeead69c04bff1269654500ffb87d67f880f08b6fe4f8cf0000000000feffffff1c97e5c22e16265cd971ba0b3ff1bf7ecf9359406547e0117d031b46215fbe0c0000000000feffffff046847019500000000225120f3ad0c624fa99f7430f63ead6343bf16508cb0d29baddd87f57bc2fb9dc2d6ce9026814a000000002251208c60833747870f8f94a947b63973ee8027615854432e5a7f9a420eccb3387f58b0ad010000000000225120dba8af662648dd045cea2986cf763e0971e034fdee96508043e0a4a9b1d27066d00700000000000022512027e02dc2cb93d385edc792b259598f52030e55cfc06d281418c95796bfc7789c01407f45bde83c7d2867d9b68f729738ad031fd9ff366337be3ba475743600362a74bd36c139cba460771804ea3a8ababb04cc1a478a3072e537f454bab239a1a2b2014045673c8327865d043d66bf59ab29a44ab4c24a1258b775244d435a4af1643b84479952e118b602b59d461806c7fee7706c5d1c3236866d0f5b2054acd28f718e22180000\n```\n#### \u003cu\u003eEscrow locking output\u003c/u\u003e\nThe [taproot](https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki) escrow output can be unlocked in different ways depending on the trade outcome. In the\ncase of a successful trade the output can be spent using the [keypath](https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki#user-content-Taproot_key_path_spending_signature_validation) with an aggregated signature from two partial signatures of maker and taker, using the MuSig2 scheme. In the case of disputes different script paths can be used to enable unlocking by the coordinator in collaboration with one of the traders.\nOther scripts can be added for edge cases, like a timeout script if the coordinator vanishes.\n```\n                     taproot output key\n                              |\n                              |\n          --------------------------------------------\n          |                                          |\n          |                                          |\n     internal key                              escrow spending scripts root\n          =                                                 =\n   Aggregated pubkey of            ---------------------          ---------------------\n     Maker and Taker              | Maker + Coordinator |   +    | Taker + Coordinator |\n                                   ---------------------          ---------------------\n                                            and more potential useful scripts\n```\n\nThe following script paths are currently implemented in the demonstrator:\n```rust\n// Maker wins escrow:\nlet policy_a_string = format!(\"and(pk({}),pk({}))\", maker_pk, coordinator_pk);\n\n// Taker wins escrow:\nlet policy_b_string = format!(\"and(pk({}),pk({}))\", taker_pk, coordinator_pk);\n\n// To prevent the possibility of extortion through the coordinator:\nlet policy_c_string = format!(\"and(pk({}),after(12228))\", maker_pk);\n\n// In case the coordinator vanishes or doesn't cooperate anymore,\n// could be used with a cli toolkit as rescue method for traders.\nlet policy_d_string = format!(\"and(and(pk({}),pk({})),after(2048))\", maker_pk, taker_pk);\n\n// a fully assembled output descriptor would look like this (containing the XOnly pubkeys):\nlet escrow_output_descriptor = \"tr(f00949d6dd1ce99a03f88a1a4f59117d553b0da51728bb7fd5b98fbf541337fb,{{and_v(v:pk(4987f3de20a9b1fa6f76c6758934953a8d615e415f1a656f0f6563694b53107d),pk(62333597c10487d959265bfc992514435daf74e26fd636f6b70e8936b4a82f3e)),and_v(v:pk(f1f1db08126af105974cde6021096525ed390cf9b7cde5fedb17a0b16ed31151),pk(62333597c10487d959265bfc992514435daf74e26fd636f6b70e8936b4a82f3e))},{and_v(v:and_v(v:pk(4987f3de20a9b1fa6f76c6758934953a8d615e415f1a656f0f6563694b53107d),pk(f1f1db08126af105974cde6021096525ed390cf9b7cde5fedb17a0b16ed31151)),after(2048)),and_v(v:pk(4987f3de20a9b1fa6f76c6758934953a8d615e415f1a656f0f6563694b53107d),after(12228))}})#wufuc530\"\n```\n\n#### \u003cu\u003ePayout transaction\u003c/u\u003e\nOnce the exchange has been completed, or a trader requested escrow, the escrow output will be spent again to complete the trade.\nThe transaction is assembled by the coordinator and shared with the clients for signing. Once the coordinator collected the\nnecessary signatures the transaction gets finalized and broadcasted.\n\n**Example transaction**, both traders satisfied, keypath spend using aggregated signature (2-of-2):\n```\n                | --\u003e bought amount + bond -\u003e Buyer\nescrow utxo --\u003e | --\u003e bond -\u003e Seller\n                | --\u003e tx fee\n(signed using\nagg. sig for\nkeypath)\n\nExample transaction [hex]: 01000000000101c544f644f6f31ca07dfa87a12aac0f103f3cf91483511f275ceeab316f6fa9c90200000000feffffff029808000000000000225120f610990da79b3bddd44a0820e31546319630c06221ea81bd3b798e4dfe9f5c6e388f0100000000002251201aa6d2c49082ae948e87ceb8551496cd6d951b093def3a3269d812db9e3808cf0140c0d07846e1b2b1deeca4a0cf35843417fefbe63086ff491ecc07638a099c0901138ac6e59a9e8b9a0878c098b206bee3427156dd0248d80de80fbdd8540ea00422180000\n```\n\n**Example transaction**, buyer sent fiat and won escrow, seller doesn't cooperate:\n```\n                | --\u003e bought amount + buyer bond + seller bond -\u003e Buyer\nescrow utxo --\u003e | --\u003e tx fee\n\n(signed using script path with buyer + coordinator signatures, could also use MuSig)\n```\n\n## Implementation\n\nThe protocol partly handled by a coordinator and partly by the client. The coordinator, running on the exchange side, handles trader matching, construction of transactions, monitoring of bonds and more tasks. The client could be bundled to a wasm library and included in the RoboSats frontend. Currently clients are only supposed to talk to the coordinator, not to each other.\n\nUsed libraries:\n* [bdk](https://docs.rs/bdk/latest/bdk/) + [rust-bitcoin](https://docs.rs/bitcoin/latest/bitcoin/index.html): Transaction construction, signing, serialization, broadcasting\n* [musig2](https://docs.rs/musig2/latest/musig2/): Signature aggregation\n* [sqlx](https://docs.rs/sqlx/latest/sqlx/): Storing trade state in a sqlite database\n* [axum](https://docs.rs/axum/latest/axum/): HTTP API (communication client \u003c-\u003e coordinator)\n\n#### Transaction sharing and signing\nTransactions are shared between client and coordinator in form of [PSBTs](https://bitcoinops.org/en/topics/psbt/). Clients add their signature and the coordinator combines the signed psbts to have a fully signed transaction.\n\n## Project Status\nThe repository contains a working CLI demonstrator that is able to complete the trade flow using the MuSig keypath spend on [regtest](https://developer.bitcoin.org/examples/testing.html#regtest-mode). This demonstrator can be used to validate and experiment with the concept but is not intended for production use.\n\n### Running the demonstrator\n1. Start the [bitcoin core](https://bitcoincore.org/) regtest node and [electrum server](https://github.com/romanz/electrs) according to [rpc_node.md](./docs/rpc_node.md)\n2. Go to the ./taptrade-cli-demo/trader dir and run it with cargo run, once as maker, once as taker\nand copy the generated bitcoin addresses\n3. Send regtest bitcoin to both addresses using ./taptrade-cli-demo/rpc_node/regtest/get-coins-to-address.sh ADDRESS\n4. Run the coordinator by running cargo run in ./taptrade-cli-demo/coordinator\n5. Run the maker and taker (different shells) by running cargo run in ./taptrade-cli-demo/trader and entering\nthe according input (load from .env with y)\n6. Watch the trade flow and act if user input is requested by the cli.\n\nTo see the transactions better you can load the [XPRVs](https://river.com/learn/terms/x/xprv-extended-private-key/) from the .env files (coordinator, maker and taker) in [Sparow wallet](https://sparrowwallet.com/) and [connect it to](https://sparrowwallet.com/docs/faq.html#how-can-i-run-testnet) the regtest node.\n\n## Contribution\nThis is an open source project under MIT license. Feel free to open PRs and ask questions in the\n[SimpleX group chat](https://simplex.chat/contact#/?v=2-5\u0026smp=smp%3A%2F%2FenEkec4hlR3UtKx2NMpOUK_K4ZuDxjWBO1d9Y4YXVaA%3D%40smp14.simplex.im%2Fl9ZKkZObVUivB5n0xviB9Rjdl2t_him7%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEA-hV3pNDT2b1DZWoIyJ4NLFMTFyMnTTL-RzUFMzPQ9Qk%253D%26srv%3Daspkyu2sopsnizbyfabtsicikr2s4r3ti35jogbcekhm3fsoeyjvgrid.onion\u0026data=%7B%22type%22%3A%22group%22%2C%22groupLinkId%22%3A%22ANU9ku4FkNjsggzUTmpYsQ%3D%3D%22%7D).\n\n## Resources\nThere are many ressources and thoughts documented in an [Obsidian](https://obsidian.md/) vault in this repo at [./docs/Obsidian](./docs/Obsidian/)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frobosats%2Ftaptrade-core","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frobosats%2Ftaptrade-core","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frobosats%2Ftaptrade-core/lists"}