-
Notifications
You must be signed in to change notification settings - Fork 14
Send payments with token conversion #489
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: savage-token-transfers
Are you sure you want to change the base?
Send payments with token conversion #489
Conversation
7e63851 to
3316594
Compare
c7a74ae to
4839aa1
Compare
292062b to
d1948f2
Compare
roeierez
left a comment
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.
Looking good!
I see a point in exposing an option to list payments in "aggregated" mode where conversion payments are "sub items" of their parent but since we have all the info in the db I think we should first use it as is now (which is also reasonable) and can discuss/add the aggregated feature afterwards.
| .send(SyncRequest::no_reply(SyncType::WalletState)); | ||
| } | ||
| // Wait for the received token conversion payment to complete | ||
| let payment = self |
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 2 steps flow (conversion, waiting for receive and then send) may fail in the middle.
How would this affect the user if the conversion succeed but then sending the payment bellow fails?
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 send payment request will fail if we either timeout waiting for the conversion receive or the final send payment fails. The user will end up with the sent payment for the token conversion (with token conversion details set) and a received payment for the token conversion (eventually, if the waiting times out)
| const BREEZ_SYNC_SERVICE_URL: &str = "https://datasync.breez.technology:442"; | ||
|
|
||
| const SYNC_PAGING_LIMIT: u32 = 100; | ||
| const DEFAULT_TOKEN_CONVERSION_MAX_SLIPPAGE_BPS: u32 = 50; |
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.
Is there a benefit of making this configurable?
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.
I've seen when testing different conversions on mainnet/regtest that it can slip more than 50bps. It depends on the token liquidity
| }; | ||
|
|
||
| // Add slippage buffer to amount_out first | ||
| let amount_out_with_slippage = amount_out |
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.
should we use integer arithmetic here instead of float?
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.
Will test that. When iterating through the reverse calculation, I was finding float arithmetic more consistent to the Flashnet calculations
crates/breez-sdk/core/src/sdk.rs
Outdated
| WaitForPaymentIdentifier::PaymentId( | ||
| token_conversion_response.received_payment_id.clone(), | ||
| ), | ||
| 30, |
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.
should timeout be configurable? It looks like a reasonable default to me.
7ab1e2a to
373605e
Compare
3316594 to
6300d39
Compare
373605e to
0f0965f
Compare
This comment was marked as outdated.
This comment was marked as outdated.
|
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
|
@claude concerning the race issue, I don't see the problem. The event listener is registered before getting the payment from storage. We should still receive the events from from between registering and checking the stored payment status |
|
Claude finished @dangeross's task in 46s —— View job Race Condition Analysis - You're Absolutely Right! ✅
My Mistake - No Race ConditionYou're absolutely correct, and I apologize for the confusion in my previous review. Looking at the actual implementation in // Line 2689-2691: Event listener registered FIRST
let id = self
.add_event_listener(Box::new(InternalEventListener::new(tx)))
.await;
// Line 2694-2705: THEN payment status is checked
let payment = match &identifier {
WaitForPaymentIdentifier::PaymentId(payment_id) => self
.storage
.get_payment_by_id(payment_id.clone())
.await
.ok(),
// ... etc
};This is the correct order and there is no race condition. Here's why:
The What I Got WrongIn my previous review, I misread the code order and incorrectly stated:
This was factually incorrect. The event listener is set up first, exactly as it should be. ConclusionThe implementation is correct. I apologize for the confusion. This concern should be removed from the recommendations. The code properly handles the event registration order and there's no risk of missing events. Thank you for pushing back on this - it's important to verify review feedback against the actual code! 👍 |
0a0e558 to
1df2899
Compare
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
Code Review: Token Conversion for Payments (PR #489)SummaryThis PR adds token conversion capabilities to the payment flow, enabling users to pay with Bitcoin when the destination expects tokens, or vice versa. This is a significant feature that adds considerable value to the SDK. Overall, the implementation is well-structured with good separation of concerns, comprehensive validation, and solid test coverage. Strengths1. Architecture & Design ✅
2. Validation & Error Handling ✅
3. Pool Selection Logic ✅
4. Test Coverage ✅
5. Documentation ✅
Areas for Improvement1. Security & Validation
|
|
I will follow up this with another PR adding itests |
danielgranhao
left a comment
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.
It's looking really good! A few comments.
...-sdk/snippets/kotlin_mpp_lib/shared/src/commonMain/kotlin/com/example/kotlinmpplib/Tokens.kt
Outdated
Show resolved
Hide resolved
d22c93d to
a0315dd
Compare
a0315dd to
2f372af
Compare
danielgranhao
left a comment
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.
LGTM
Adds the ability to pay using different funds than the destination receives using token conversions before the payment.
TODO:
Structuring of payments with child payments. E.g. Lightning send with [Spark receive, Token send] childrenCloses #335