Skip to content

itest: Enhanced trustless swap#1977

Draft
GeorgeTsagk wants to merge 1 commit intomainfrom
trustless-swap-plus
Draft

itest: Enhanced trustless swap#1977
GeorgeTsagk wants to merge 1 commit intomainfrom
trustless-swap-plus

Conversation

@GeorgeTsagk
Copy link
Copy Markdown
Member

Description

A while ago we introduced vPSBT level sighashes which allowed us to build a basic trustless swap construct:
#804

One limitation there is that the seller needs to create a clean input for the assets, which doesn't carry any passive assets back to them (no change, needs to spend all).

This PR introduces an itest where we use an ANYONE_CAN_SPEND (OP_TRUE) script key for the assets, which is pre-defined by Alice (the seller) when preparing the swap offer.

Alice then creates two outputs on the asset level:

  • Output@0: Asset change, btc payment
  • Output@1: Assets to swap

As far as the input goes, she can bring in any "dirty" input that may carry more than what is involved in the swap:

  • Input@0: Total asset balance, Btc balance

What matters for the swap to be complete is for Bob to complete the BTC level transaction validity by bringing an extra btc input, which makes Alice whole at Output@0.

sequenceDiagram
      box Alice's Offer
      participant IN as Input<br/>1000 units + 330 sats
      participant O0 as Output 0<br/>400u + 69,420 sats
      participant O1 as Output 1<br/>600u + 330 sats
      end

      IN->>O0: Alice's change (protected)

      Note over IN,O0: SIGHASH_SINGLE|ANYONE_CAN_PAY
      Note over O1: OP_TRUE<br/>Finalized by Bob
Loading

Problems

  • On the vPSBT level the split root is handled by Alice, who places it at output@0 where her asset change is placed. This split root also commits to the OP_TRUE split which may be claimed by Bob. One good thing here is that even if the split is destroyed (Bob griefs / burns assets) the split root is not considered invalid and only Bob's assets are affected. The catch is that if Bob decides to burn the assets, and also create a random P2TR output in the same tx, then Alice is going to face an issue with the exclusion proofs for her assets.
  • Even if this is considered an "enhancement" over the previous trustless swap setup, there are some trade-offs:
    Alice locks additional asset balance in Input@0, which she might want to use before the swap is completed by someone. This approach reduces on-chain fees (no need to prepare an explicit input for the swap), but also limits the usability of the passive funds in that input. E.g if Alice wanted to then create another swap offer with some of the passive assets in that first offer, she'd be locked while waiting for someone to redeem the first one. From this perspective, the previous approach with "clean" asset inputs offers way greater flexibility for the swap offer creator.

Closes #813, #857

@gemini-code-assist
Copy link
Copy Markdown

Summary of Changes

Hello @GeorgeTsagk, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly improves the trustless asset swap functionality by allowing the asset seller to receive change from their asset input. By leveraging an ANYONE_CAN_SPEND script key for the swapped assets and specific PSBT signing flags, the new mechanism offers greater flexibility and reduces on-chain fees compared to previous "whole coin" transfer requirements, making asset swaps more practical and efficient.

Highlights

  • Enhanced Trustless Swaps: Introduces a new trustless swap mechanism that allows the seller (Alice) to receive asset change, addressing a limitation of previous implementations that required 'whole coin' transfers.
  • ANYONE_CAN_SPEND Script Key: Utilizes an OP_TRUE (anyone-can-spend) script key for the assets being swapped, enabling non-interactive swaps while allowing the seller to retain change.
  • Flexible PSBT Signing: Alice signs the asset-level PSBT with SIGHASH_NONE and the BTC-level PSBT with SIGHASH_SINGLE|ANYONECANPAY, providing flexibility for Bob to add inputs and for Alice to protect her change.
  • New Integration Test: Adds testPsbtTrustlessSwapAnyoneCanSpend to validate the new enhanced trustless swap flow, ensuring its correct functionality.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Changelog
  • itest/psbt_test.go
    • Added import for tapscript package.
    • Implemented testPsbtTrustlessSwapAnyoneCanSpend to test the new enhanced trustless swap flow.
  • itest/test_list_on_test.go
    • Registered the new psbt trustless swap anyone can spend test case.
Activity
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces an enhanced trustless swap mechanism that allows using "dirty" inputs by leveraging an OP_TRUE script key for the swapped assets. This is a great improvement as it adds flexibility for the swap creator. The implementation is well-tested with a new integration test that covers the end-to-end flow. The code is clear and follows the project's style guide. I have one suggestion to improve the readability and robustness of the test code by simplifying how outputs are identified.

Comment on lines +2915 to +2925
var changeVOutIdx, swapVOutIdx int = -1, -1
for i, out := range bobVPsbt.Outputs {
if out.Asset != nil && out.Asset.SplitCommitmentRoot != nil {
changeVOutIdx = i
} else if out.Asset != nil &&
len(out.Asset.PrevWitnesses) > 0 &&
out.Asset.PrevWitnesses[0].SplitCommitment != nil {

swapVOutIdx = i
}
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

The logic to identify the change and swap outputs can be simplified. Instead of inspecting the asset structure (SplitCommitmentRoot or SplitCommitment), you can use the Type field of the virtual output, similar to how it's done for Alice's side in lines 2711-2721. This would make the code more readable and less dependent on the internal structure of assets. I've also added assertions to ensure both outputs are found.

	var changeVOutIdx, swapVOutIdx int = -1, -1
	for i, out := range bobVPsbt.Outputs {
		if out.Type == tappsbt.TypeSplitRoot {
			changeVOutIdx = i
		} else {
			swapVOutIdx = i
		}
	}
	require.NotEqual(t.t, -1, changeVOutIdx, "change output not found")
	require.NotEqual(t.t, -1, swapVOutIdx, "swap output not found")
References
  1. Readable code is the most important requirement for any commit created. The suggested change improves readability by using a more direct and less implementation-dependent way to identify outputs. (link)

@coveralls
Copy link
Copy Markdown

Pull Request Test Coverage Report for Build 21709218905

Details

  • 0 of 0 changed or added relevant lines in 0 files are covered.
  • 96 unchanged lines in 20 files lost coverage.
  • Overall coverage increased (+0.001%) to 56.508%

Files with Coverage Reduction New Missed Lines %
asset/group_key.go 2 72.15%
mssmt/compacted_tree.go 2 77.19%
tapdb/mssmt.go 2 89.55%
tapdb/sqlc/mssmt.sql.go 2 48.34%
tapdb/sqlc/transfers.sql.go 2 83.33%
universe/archive.go 2 81.28%
universe_rpc_diff.go 2 76.0%
universe/syncer.go 2 85.93%
fn/errors.go 3 90.32%
itest/assertions.go 3 87.05%
Totals Coverage Status
Change from base Build 21682418749: 0.001%
Covered Lines: 67201
Relevant Lines: 118923

💛 - Coveralls

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

Labels

None yet

Projects

Status: 🆕 New

Development

Successfully merging this pull request may close these issues.

[feature]: non-interactive BTC<->asset swaps with asset-level ANYONECANSPEND

2 participants