-
Couldn't load subscription status.
- Fork 122
assets swap deposits [3/N]: extend swapserverrpc with asset deposit RPCs #981
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Summary of Changes
Hello @bhandras, 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 extends the swapserverrpc with new RPCs to support asset deposits, laying the groundwork for asset-based swaps. It introduces comprehensive client-side utilities for managing Taproot Assets, including the creation and handling of HTLCs for atomic swaps, and general-purpose asset transaction preparation and execution.
Highlights
- New Asset Deposit RPCs: A new
AssetDepositServicehas been introduced inswapserverrpc, defining RPCs for initiating, managing, and completing asset deposits. This includesNewAssetDepositto create a deposit address,WithdrawAssetDepositsto retrieve asset keys, andPushAssetDepositHtlcSigs/PushAssetDepositKeysfor signature and key exchange in HTLC-based asset transfers. - Enhanced Taproot Assets Client Capabilities: The
TapdClientinassets/client.gohas been significantly extended to support new asset-related operations. This includes functions for funding and signing virtual PSBTs (FundAndSignVpacket), preparing and committing asset transactions (PrepareAndCommitVirtualPsbts), logging and publishing transfers (LogAndPublish), managing asset balances, deriving new asset keys, and importing asset proofs. It also adds new event subscription mechanisms for asset receives and sends. - HTLC Scripting and SwapKit for Assets: A new
assets/htlcpackage has been added, providing core components for constructing and managing Hashed Timelock Contracts (HTLCs) specifically for Taproot Asset swaps. This includes functions for generating Bitcoin scripts for HTLC success and timeout paths, computing aggregate keys, creating virtual PSBTs for asset HTLCs, and generating Bitcoin control blocks for HTLC spending paths. - General Taproot Asset Utilities: A new
assets/tapkit.gofile introduces general utility functions for Taproot Assets, such asCreateOpTrueSweepVpktfor creating virtual PSBTs to sweep assets withOP_TRUETapscripts, which is a common pattern for receiving assets into a wallet.
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 in your pull request via creating an issue comment (i.e. comment on the pull request page) using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands.
| 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 issue 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 is currently in preview and 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 to provide feedback.
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
-
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. ↩
There was a problem hiding this 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 significant new functionality for asset swaps and deposits, including new RPCs, a new htlc package, and extensions to the TapdClient. The changes are extensive. My review focuses on correctness, security, and maintainability. I've found some critical issues, such as a potential panic on context cancellation and a TODO indicating risk of fund loss. There are also several high-severity issues related to unhandled errors, potential panics from slice out-of-bounds, a goroutine leak, and a security concern with sending private keys over RPC. I've also included several medium-severity comments on maintainability and performance.
| for { | ||
| select { | ||
| case <-receiveEventsClient.Context().Done(): | ||
| panic(receiveEventsClient.Context().Err()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A library function should not panic, especially on a context cancellation which is a normal way to signal termination. Panicking will crash the entire application. The goroutine should gracefully exit by sending the context error on the error channel.
errChan <- receiveEventsClient.Context().Err()
return
assets/tapkit.go
Outdated
| // TODO(bhandras): set this to the actual internal key derived | ||
| // from the sender node, otherwise they'll lose the 1000 sats | ||
| // of the tombstone output. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| assetTxOut := &wire.TxOut{ | ||
| PkScript: sweepBtcPacket.Inputs[0].WitnessUtxo.PkScript, | ||
| Value: sweepBtcPacket.Inputs[0].WitnessUtxo.Value, | ||
| } | ||
| feeTxOut := &wire.TxOut{ | ||
| PkScript: sweepBtcPacket.Inputs[1].WitnessUtxo.PkScript, | ||
| Value: sweepBtcPacket.Inputs[1].WitnessUtxo.Value, | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| if changeKeyDesc != nil { | ||
| err = addP2WPKHOutputToPsbt( | ||
| btcPkt, *changeKeyDesc, btcutil.Amount(1), params, | ||
| ) | ||
| commitRequest.AnchorChangeOutput = | ||
| &assetwalletrpc.CommitVirtualPsbtsRequest_ExistingOutputIndex{ //nolint:lll | ||
| ExistingOutputIndex: 1, | ||
| } | ||
| } else { | ||
| commitRequest.AnchorChangeOutput = | ||
| &assetwalletrpc.CommitVirtualPsbtsRequest_Add{ | ||
| Add: true, | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The else block is redundant. The commitRequest.AnchorChangeOutput field is already initialized with &assetwalletrpc.CommitVirtualPsbtsRequest_Add{Add: true} on line 438. You can remove this else block to simplify the code. Also, the error returned by addP2WPKHOutputToPsbt on line 453 is not being handled, which could lead to silent failures.
if changeKeyDesc != nil {
err = addP2WPKHOutputToPsbt(
btcPkt, *changeKeyDesc, btcutil.Amount(1), params,
)
if err != nil {
return nil, nil, nil, nil, err
}
commitRequest.AnchorChangeOutput =
&assetwalletrpc.CommitVirtualPsbtsRequest_ExistingOutputIndex{
ExistingOutputIndex: 1,
}
}| // PushAssetDepositKeysReq holds private keys of one or more deposits. | ||
| message PushAssetDepositKeysReq { | ||
| // deposit_keys is a map wich maps deposit_id to deposit internal private | ||
| // key. | ||
| map<string, bytes> deposit_keys = 1; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sending private keys over an RPC interface is a significant security risk. Even if the connection is encrypted, it exposes sensitive material that should ideally never leave the client. Consider refactoring the protocol to send signatures instead of private keys. The client should perform the signing operation and send the resulting signature to the server.
Also, there is a typo in the comment: "wich" should be "which".
// PushAssetDepositKeysReq holds private keys of one or more deposits.
message PushAssetDepositKeysReq {
// deposit_keys is a map which maps deposit_id to deposit internal private
// key.
map<string, bytes> deposit_keys = 1;
}
|
|
||
| // GenTaprootAssetRootFromProof generates the taproot asset root from the proof | ||
| // of the swap. | ||
| func GenTaprootAssetRootFromProof(proof *proof.Proof) ([]byte, error) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This function GenTaprootAssetRootFromProof seems to be a duplicate of the one defined in assets/htlc/swapkit.go. To avoid code duplication, consider moving this function to a shared utility package or choosing one of the two implementations to be the canonical one and call it from the other location.
assets/tapkit.go
Outdated
| /* | ||
| addressRecvVpkt, err := tappsbt.FromAddresses([]*address.Tap{addr}, 0) | ||
| if err != nil { | ||
| return nil, err | ||
| } | ||
| sweepVpkt.Outputs = addressRecvVpkt.Outputs | ||
| */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
assets/client.go
Outdated
| func handleReceiveEvent(event *taprpc.ReceiveEvent, | ||
| resChan chan<- TapReceiveEvent) (bool, error) { | ||
|
|
||
| fmt.Printf("!!! Received event: %v\n", event.Status) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| // one ore more deposits to a zero fee HTLC. | ||
| rpc PushAssetDepositHtlcSigs (PushAssetDepositHtlcSigsReq) | ||
| returns (PushAssetDepositHtlcSigsRes); | ||
|
|
||
| // PushKeys pushes (ie reveals) the private keys of one ore more deposits to | ||
| // the server. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are a couple of typos in the comments for this service:
- Line 23: "one ore more" -> "one or more"
- Line 27: "one ore more" -> "one or more"
These should be corrected for clarity in the generated documentation.
// one or more deposits to a zero fee HTLC.
rpc PushAssetDepositHtlcSigs (PushAssetDepositHtlcSigsReq)
returns (PushAssetDepositHtlcSigsRes);
// PushKeys pushes (ie reveals) the private keys of one or more deposits to
// the server.
| func (t *TapdClient) GetUnEncumberedAssetBalance(ctx context.Context, | ||
| assetID []byte) (uint64, error) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This function iterates over all assets by calling ListAssets without a filter, and then filters them in memory. This can be inefficient if the node holds a large number of assets. If the ListAssets RPC supports filtering by asset ID, it would be more efficient to use that. If not, this is the best that can be done, but it's worth noting the potential performance issue.
e0abd45 to
0fe5327
Compare
0fe5327 to
070b2a9
Compare
9bc3acf to
da384ef
Compare
With this commit we add high level helpers along with scripts to create asset HTLCs.
This commit enables package relayed HTLCs by making the CSV check in the success path optional.
This commit adds additional scaffolding to our tapd client, along with new high-level helpers in the assets package, which will be used later for swaps and deposits.
da384ef to
5bf08b2
Compare
Currently on top of: #980 (can be separated).
Pull Request Checklist
release_notes.mdif your PR contains major features, breaking changes or bugfixes