Skip to content

Conversation

@crisdut
Copy link
Contributor

@crisdut crisdut commented Sep 15, 2023

Description

This PR allows us make RGB Swaps between two wallets.

How to works

Suppose we have two users, the seller and the buyer, and both would like to swap assets and bitcoins. The users need to follow the instructions below:

  1. The seller creates an offer defining the quantity of assets and price in satoshis.
    • The BMC registry the offer in a public orderbook.
  2. The buyer visualizes the public offers and creates a bid based on offer.
    • The BMC registry the bid in a public orderbook.
    • The buyer sign the compose and sign psbt file.
  3. The seller verifies with your offer receiving a bid. If yes, he creates the swap transfer.
    • The seller signs and publishes the swap transfers and sends the consig file to buyer.
  4. Both accepted the consignment file.

New Concepts

  1. Public Offers: Now the BMC server can work with public data, which is stored via Carbonado. Today, we store users' offers to facilitate the exchange of information between them.
  2. Offers/Bids: Offers are a type of order from the user who wants to sell something. While bids are orders from a user who wants to buy something.
  3. RGB Swaps: This swap method is based on RGB scriptless atomic swaps, proposed by @fedsten. In summary, this technique allows us to exchange an asset from L3 (off-chain) for bitcoin that is in L1 (on-chain) privately and confidentially.
  4. Sigh Hash: Now we can use other sighashes conditions.

Progress

Create a rgb offer (wasm32 support).

  • Allow user to create your offer
  • Allow user to save your offer
  • Allow the user retrieve your offer
  • Allow users list your offers

Create a rgb bid (wasm32 support).

  • Allow user to create your bid
  • Allow user to save your bid
  • Allow user to retrieve your bid
  • Allow users list your bids

Publish a public offer

  • Allow user to publish your public offer
  • Allow list public offers
  • Allow filter public offers
  • Allow user to remove your public offer

Publish a public bid

  • Allow user to publish your public bid
  • Allow list public bids
  • Allow filter public bids
  • Allow user to remove your public bid

Create a swap transfer

  • Allow user co-sign swap transfer
  • BMC update offer/bid status after swap transfer
  • BMC remove offer/bid status after accept swap transfer
  • Tests with UDA

Create a swap fee output

  • Add swap fee output in PSBT Buyer step.

Public Data (wasm32) [1]

  • Allow get public data by carbonado server
  • Allow storage public data by carbonado server
  • Expose methods in web.rs

Also, the RGB Swap supports the latest features like dustless transactions, fee rate, and RBF coming soon.

[1] Two methods need to be included to ensure compatibility.

Limitations

  • Today, we need an offer to a user who can create a bid.
  • Although supported, it has yet to be possible to test the partial execution of the offers. In other words, in this version, the bidder needs to acquire everything.
  • There is no support for bundle-type offers, where a user can sell a series of assets in a single offer.
  • There needs to be more tests to cover all sign forms.

All current limitations are workable, I decided not to implement it now so you can start testing.

Closes #292

@crisdut crisdut added this to the 0.7.0 milestone Sep 15, 2023
@crisdut crisdut self-assigned this Sep 15, 2023
@crisdut crisdut requested review from cryptoquick and josediegorobles and removed request for cryptoquick September 15, 2023 05:02
@crisdut crisdut marked this pull request as draft September 15, 2023 05:06
Copy link
Member

@josediegorobles josediegorobles left a comment

Choose a reason for hiding this comment

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

LGTM

@josediegorobles
Copy link
Member

Ok,

All the sign operations must pass for bitmask-extension for the users, so in web.rs we need endpoints for that. For every of this actions:

  • Seller creates an offer defining the quantity of assets and price in satoshis.
  • Buyer visualizes the public offers and creates a bid based on offer. ---> an endpoint for visualize the public offers and another for create a bid based on offer
  • Buyer sign the compose and sign psbt file.
  • Seller verifies with your offer receiving a bid. If yes, he creates the swap transfer. ---> endpoint for verify the offer receiving a bid, and another creating the swap transfer
  • Seller signs and publishes the swap transfers and sends the consig file to buyer.

And for the accept part it's simply accept the consignment isn't it? We can keep the current part

@crisdut crisdut marked this pull request as ready for review September 21, 2023 00:36
@crisdut
Copy link
Contributor Author

crisdut commented Sep 21, 2023

Hey @josediegorobles and @cryptoquick

Please, review my PR.

I'm not very confirmable with some details of the solution, especially the public data part in carbonado. Could you please check?

Copy link
Member

@cryptoquick cryptoquick left a comment

Choose a reason for hiding this comment

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

As per our discussion yesterday:

We should use DHKE to create Carbonado files for bids and offers between peers.
The server should keep only a small centralized index of DHKE keys, bid/offer IDs, and timestamps (so we can expire old offers at a later date should they ever build up, but not necessarily automatically).

Also, let's be sure this passes tests. If we have flaky tests, we can skip them with a reason, "flaky test".

As for the workflow for how this will all happen, I'll get started on a Nostr relay and Nostr methods for listing and publishing offers and bids. We may not need to do this all with Carbonado, but it's good to have both approaches. And the Carbonado files are still needed to store the PSBTs and such for the swap, in a private manner, using keys only between both peers.

Does this all sound good?

@Gigi3d
Copy link
Contributor

Gigi3d commented Sep 22, 2023

As per our discussion yesterday:

We should use DHKE to create Carbonado files for bids and offers between peers. The server should keep only a small centralized index of DHKE keys, bid/offer IDs, and timestamps (so we can expire old offers at a later date should they ever build up, but not necessarily automatically).

Also, let's be sure this passes tests. If we have flaky tests, we can skip them with a reason, "flaky test".

As for the workflow for how this will all happen, I'll get started on a Nostr relay and Nostr methods for listing and publishing offers and bids. We may not need to do this all with Carbonado, but it's good to have both approaches. And the Carbonado files are still needed to store the PSBTs and such for the swap, in a private manner, using keys only between both peers.

Does this all sound good?

sounds good to me

@crisdut
Copy link
Contributor Author

crisdut commented Sep 23, 2023

Does this all sound good?

Okay, sure.

I elaborated on the scenarios to check if we were on the same page. I will use three characters in my examples: Alice (seller), Bob, and Carol (latest both buyers)

Scenario 1:

Alice Bob published orders (offer and bid, respectively). The bitmask (wallet/server) will generate four Carbonado files:

  1. Private file with Alice's offers, accessed only with Alice's nostr pk. I will save Alice's DHKE private key in this file.
  2. Private file with Bob's bids, accessed only with Bob's nostr pk. I will save Bob's DHKE private key in this file.
  3. Restrict file for Alice and Bob orders (swap), accessed only with DHKE shared key. The filename is a combination of Alice and Bob DHKE pubkey plus expire timestamp (i.e. {network}-{Alice}-{bob}-{timestamp}.c15).
  4. Public file with all offers and bids, accessed for everyone by bitmaskd server. This file is a centralized index of DHKE keys, bid/offer IDs, and timestamps used to list orders.

After that, Alice chooses to swap with Bob, and the bitmask (wallet/server) executes the following steps:

  1. Generate swap operation and transfer swap (extension of original Consignment file, with offer/bid ID embedded).
  2. Alice save transfer swap
  3. Bob save transfer swap
    (...after mining transaction...)
  4. Both participants accept the transfer swap
  5. Each participant tries to remove offer/bid of the public offer/bid index
  6. Each participant tries to remove offer/bid of the restricted/shared file (optional)

Steps 4, 5, and 6 occur when we call the rgb::verify_transfer function.

Scenario 2:

Alice publish one offer, and Bob and Carol publish bids based in Alice's offer. The bitmask (wallet/server) will generate six carbonado files:

  1. Private file with Alice's offers, accessed only with Alice's nostr pk. I will save Alice's DHKE private key in this file.
  2. Private file with Bob's bids, accessed only with Bob's nostr pk. I will save Bob's DHKE private key in this file.
  3. Private file with Carol's bids, accessed only with Carol's nostr pk. I will save Carol's DHKE private key in this file.
  4. Restrict file for Alice and Bob orders (swap), accessed only with DHKE shared key. The filename is a combination of Alice and Bob DHKE pubkey plus expire timestamp (i.e. {network}-{Alice}-{bob}-{timestamp}.c15).
  5. Restrict file for Alice and Carol orders (swap), accessed only with DHKE shared key. The filename is a combination of Alice and Carol DHKE pubkey plus expire timestamp (i.e. {network}-{Alice}-{carol}-{timestamp}.c15).
  6. Public file with all offers and bids, accessed for everyone by bitmaskd server. This file is a centralized index of DHKE keys, bid/offer IDs, and timestamps used to list orders.

After that, Alice chooses to swap with Carol, and the bitmask (wallet/server) executes the following steps:

  1. Generate swap operation and transfer swap (extension of original Consignment file, with offer/bid ID embedded).
  2. Alice save transfer swap
  3. Carol save transfer swap
    (after mining transaction)
  4. Both participants accept the transfer swap
  5. Each participant tries to remove offer/bid of the public offer/bid index
  6. Each participant tries to remove offer/bid of the restricted/shared file (optional)

Steps 4, 5, and 6 occur when we call the rgb::verify_transfer function.

@cryptoquick
Was it these scenarios that you thought of?

@cryptoquick
Copy link
Member

  1. No need to save the DHKE key, it can be recreated from the peer's pubkey and your sk.

The rest looks fine.

@crisdut
Copy link
Contributor Author

crisdut commented Sep 23, 2023

  1. No need to save the DHKE key, it can be recreated from the peer's pubkey and your sk.

The rest looks fine.

Will we use the same public key as nostr then?

It's not a problem? Mainly that all users will have access to this orderbook index information? I thought about creating a key per offer/bid, never reusing the keys.

@cryptoquick
Copy link
Member

The Nostr sk is used with ECDH to create a new key per peer pair... I'm not sure you call that key reuse

@crisdut
Copy link
Contributor Author

crisdut commented Sep 23, 2023

The Nostr sk is used with ECDH to create a new key per peer pair... I'm not sure you call that key reuse

I was referring to that today we use nostr sk in files, but we always produce the same public key for this, as we use the global context. For each offers/bids, I just don't use the global context.

@cryptoquick
Copy link
Member

We can use the nostr sk generated by the wallet, yes

@crisdut
Copy link
Contributor Author

crisdut commented Sep 23, 2023

I made the changes @cryptoquick and @josediegorobles

Just confirmation, the chrono is the best package to working with timestamp?

if yes, I found her terms confusing ("naive_date", etc.).

Could you confirm if the way I am generating the date is Greenwich, please?

Code example:

if let Some(expire_at) = expire_at {
    let utc = chrono::Local::now().naive_utc().timestamp();

    if expire_at.sub(utc) <= 0 {
        return Err(RgbSwapError::OfferExpired);
    }
}

@crisdut crisdut requested a review from cryptoquick September 23, 2023 19:33
Copy link
Member

@josediegorobles josediegorobles left a comment

Choose a reason for hiding this comment

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

ACK. Apparently chrono is ok and I only request a little and not problematic change, so when is done I see this for merge

offer_id: String,
status: String,
/// Offer Status
bid_status: String,
Copy link
Member

Choose a reason for hiding this comment

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

Is the comment bad? Bid status // offer status

Copy link
Member

@cryptoquick cryptoquick left a comment

Choose a reason for hiding this comment

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

Just reviewed all of the code, and I have to say, this is incredible work. I have have just a couple suggestions, and once they're addressed, I will approve.

@crisdut crisdut requested a review from cryptoquick September 29, 2023 01:09
@crisdut
Copy link
Contributor Author

crisdut commented Sep 29, 2023

Done.

Just confirmation, is this correctly?

#373 (comment)

@cryptoquick
Copy link
Member

Yes, Jose looked into it and he said your work on chrono appears to be okay.

Copy link
Member

@cryptoquick cryptoquick left a comment

Choose a reason for hiding this comment

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

ACK

Everything looks good, let's get this merged.

@cryptoquick cryptoquick added this pull request to the merge queue Oct 1, 2023
Merged via the queue into development with commit 677bab4 Oct 1, 2023
@josediegorobles josediegorobles deleted the CD/swaps branch October 5, 2023 15:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

On-chain RGB Swap PSBTs

4 participants