Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save nopara73/bb17e89d7dc9af536ca41f50f705d329 to your computer and use it in GitHub Desktop.
Save nopara73/bb17e89d7dc9af536ca41f50f705d329 to your computer and use it in GitHub Desktop.
Author: Kukks

New protocol design: Discrete Payments through Wabisabi coinjoins and Nostr ecnrypted communication

  1. Merchant creates invoice of 0.1BTC
  2. Merchant generates a unique key for invoice
  3. Merchant shows the pubkey of (2), a recommended nostr relay uri
  4. Customer generates a unique key for this invoice payment
  5. Customer posts an encrypted event addressed to pubkey of (3) with a message stating intent to pay invoice of 0.1BTC using a specific wabisabi coordinator
  6. Merchant replies with an encrypted event with acknowledgement (or rejects)
  7. Customer joins next round, adds inputs >0.1 BTC, gets credentials
  8. Customer reissues credentials, gets one credential of 0.1BTC
  9. Customer posts an encrypted event addressed to pubkey of (3) with the credential in a text format
  10. Merchant reissues credentials
  11. Merchant replies with an encrypted event with acknowledgement (or rejects)
  12. Round enters output registration stage
  13. Merchant registers outputs
  14. Round enters tx signing stage
  15. Merchant verifies output is there
  16. Merchant replies with an encrypted event stating payment is present in tx hash
  17. Customer verifies round tx equals hash
  18. Customer signs

Notes:

  • a pseudo nostr relay will connect to multiple relays and retrieve all relelavnt events and aggregate. This will then serve them in a unified entrypoint, allowing users to not leak their ip to a dedicated nostr relay for private payments
  • Customer specifies which coordinator to use, not tied to only one
  • Merchant can provide own coins to same coinjoin to increase anonymity
  • Can theoretically chain the payments to other hops within the same coinjoin, serves as a trustless, private layer 3 equivalent to ecash systems, without the custodians (but with a much stricter time horizon)
@Kukks
Copy link

Kukks commented Jan 10, 2023

Pros over normal payjoin:

  • don't need to start a web server (because of nostr, I think we can do the same for payjoin though)
  • Sender does not reveal his coins to the receiver
  • Receiver does not reveal where he received his coins
  • Dos protection included in coinjoin protocol itself
  • You can do multiple hops of payments between different users, as long as the round hasn't ended yet.
  • Cost can actually be decent. Entering a coinjoin with readymixed coins is free. Coins under 1m sats are also free to join a round. Coins one hop away from a previous coinjoin are also free. You pay for your inputs and output mining cost but in payjoin you pay for those plus tx body and at least one of the receivers input cost

@Kukks
Copy link

Kukks commented Jul 21, 2023

Receiver creates payment link bip21: bitcoin:address?amount=1&ws="npub1..." (BIP21)
Share payment link to Sender
Sender parses the ws value, extracting a public key (KEYRECEIVER1) and a set of relay uris

Sender creates a new ephemeral key (KEYSENDER1) and creates a dedicated tor circuit
Sender connects to nostr relays using previously created tor circuit
Sender sends a NIP4 event (EVT1) using key KEYSENDER1 as author, addressed to KEYRECEIVER1, with contents:

{
"bip21":{BIP21},
coordinatorsSupported: ["xyz.com", "zyx.onion"]
}

Receiver chooses a coordinator from list CHOSENCOORD
Receiver replies to EVT1 with a new event (EVT2), with contents:

["OK", "{CHOSENCOORD}"]

Sender waits for a round to be present that has at least X minutes remaining in input registration, ROUNDX
Sender replies to EVT2 with a new event (EVT3), with contents:

["{CHOSENCOORD}", "{ROUNDX}"]

Sender joins round ROUNDX, registers utxos and receives credentials, then reissues into 2 credentials: CREDENTIALPAY and CREDENTIALCHANGE
Sender replies to EVT3 with new event (EVT4) with contents:

["{CHOSENCOORD}", "{ROUNDX}", "{CREDENTIALPAY}"]

Receiver joins round {ROUNDX}, reissues {CREDENTIALPAY}, registers additional UTXOs
When Round switches to ReadyToSign, RECEIVER sends a new event (EVT5) to Sender with contents:

{
["{CHOSENCOORD}", "{ROUNDX}", "{COINJOIN_TXID}", "{BIP21}", "ACKNOWLEDGEMENT OF PAYMENT"]
}

Sender signs coinjoin
Receiver signs coinjoin
Receiver marks payment as received (but not settled)
On successful round and transaction confirmation, mark payment as settled

@Kukks
Copy link

Kukks commented Sep 5, 2024

Savings analysis when applying this tech towards fee savings for businesses (no privacy decomposition done). (yes I used ai to fluff up the text around the formulas)

Detailed Formulas and Analysis of Batching Bitcoin Transactions

Batching transactions in Bitcoin involves combining multiple deposits and withdrawals into fewer transactions to save on fees and reduce UTXO bloat. This process can significantly optimize transaction costs and improve network efficiency. Below, we outline the formulas for calculating transaction sizes and savings across three modes: Single Transaction Mode, Withdrawal Batching Mode, and Full Batching Mode.

Variables and Constants

  • N_d: Number of deposits.
  • N_w: Number of withdrawals.
  • I: Input size in bytes (approximately 148 bytes per input).
  • O: Output size in bytes (approximately 34 bytes per output).
  • H: Overhead size per transaction (approximately 10 bytes).
  • F: Fee rate per byte.
  • T: Time interval for batching transactions (e.g., in seconds or minutes).
  • λ_d: Average rate of deposit requests per time interval T.
  • λ_w: Average rate of withdrawal requests per time interval T.

Transaction Modes

  1. Single Transaction Mode
    In Single Transaction Mode, each deposit and each withdrawal are processed as separate transactions. This mode represents the highest cost due to the repeated overhead of many small transactions.

    Transaction Size Calculation:

    • For Deposits: Each deposit transaction has 1 input, 1 output to the business, and 1 change output.
    • For Withdrawals: Each withdrawal transaction has 1 input from the business, 1 output to the user, and 1 change output.

    Total Size for Single Transaction Mode:

    Total Size_single = N_d × (I + O + O + H) + N_w × (I + O + O + H)
    

    Where:

    • The terms account for the input, main output, change output, and transaction overhead for both deposits and withdrawals.
  2. Withdrawal Batching Mode
    In Withdrawal Batching Mode, deposits remain as individual transactions, but all withdrawals are combined into a single batched transaction. This mode reduces the overhead cost associated with processing multiple withdrawals separately.

    Transaction Size Calculation:

    • Deposits: Handled individually, with each deposit contributing its inputs and outputs.
    • Withdrawals: All withdrawals are batched into a single transaction, which minimizes the overhead.

    Total Size for Withdrawal Batching Mode:

    Total Size_batch_withdrawal = N_d × (I + O + O + H) + (N_w × I + N_w × O + O + H)
    

    Where:

    • The first part represents individual deposit transactions.
    • The second part combines multiple withdrawals into one transaction with a single overhead.
  3. Full Batching Mode
    Full Batching Mode represents the most efficient strategy, where deposits and withdrawals are combined into a single transaction. This mode minimizes the total number of inputs and outputs by using deposits directly to fund withdrawals and consolidating change outputs.

    Transaction Size Calculation:

    • Inputs: Inputs come from user-funded deposits.
    • Outputs: Include outputs for each withdrawal, deposit change outputs, and a single final change output if needed.

    Total Size for Full Batching Mode:

    Total Size_full_batching = N_d × I + (N_w × O + N_d × O + O + H)
    

    Where:

    • Inputs are reduced to the necessary user inputs, and the output count is minimized.

Calculating Savings
To determine the savings achieved by batching methods compared to the baseline single transaction approach, we use the following formulas:

  1. Savings Between Single Transaction and Withdrawal Batching:

    Savings_batch_withdrawal = 1 - (Total Size_batch_withdrawal / Total Size_single)
    
  2. Savings Between Single Transaction and Full Batching:

    Savings_full_batching = 1 - (Total Size_full_batching / Total Size_single)
    
  3. Savings Between Withdrawal Batching and Full Batching:

    Savings_full_vs_withdrawal = 1 - (Total Size_full_batching / Total Size_batch_withdrawal)
    

Forward-Facing Savings and Efficiency Gains
Batching not only provides immediate savings but also leads to forward-facing benefits, including:

  1. Reduced UTXO Bloat:

    • Fewer transactions mean fewer UTXOs, simplifying management and lowering future costs.
    • Minimizes the need for costly UTXO consolidation operations.
  2. Elimination of Dust Outputs:

    • Efficient batching reduces or eliminates small, unspendable dust outputs, optimizing wallet performance.
    • Prevents clutter and inefficiencies in the UTXO set, contributing to long-term savings.
  3. Long-Term Transaction Efficiency:

    • Lower future transaction fees due to fewer required inputs in future transactions.
    • Enhanced wallet performance and reduced blockchain growth, supporting overall network health.

Conclusion
Batching Bitcoin transactions significantly reduces transaction costs by minimizing redundant inputs, outputs, and overhead. Full batching, in particular, achieves the greatest savings by directly utilizing deposits to fund withdrawals and optimizing UTXO management. These savings are compounded over time, making batching a crucial strategy for sustainable and efficient Bitcoin transaction processing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment