fix(swapv2): offline validation, tx visibility check and one-shot rebroadcast#2646
fix(swapv2): offline validation, tx visibility check and one-shot rebroadcast#2646
Conversation
…ayment while adding tx visibility check and one rebroadcast as fallback
|
A question (maybe because I have done full review yet): |
mariocynicys
left a comment
There was a problem hiding this comment.
only 2 comments.
looks good otherwise :D
| ) | ||
| .await; | ||
|
|
||
| if !visible { |
There was a problem hiding this comment.
i fear this extra check might create problems.
i don't think this check is necessary here though (for a non confirm-required case). being visible in the mempool isn't any guarantee that it won't be rbf or replaced by nonce later. we already confirm this tx at later stage also (i guess, but must be true otherwise the protocol is broken xD)
There was a problem hiding this comment.
being visible in the mempool isn't any guarantee that it won't be rbf or replaced by nonce later
I am aware, this is about quick refund if maker sent taker a p2p message that they broadcasted their payment but it's not to be seen. Otherwise, the taker will wait maker_payment_conf_timeout for refund which is a lot.
There was a problem hiding this comment.
Why rush to refund though, if we did not see the tx in mempool?
Indeed it's not guaranteed tx was in the node mempool (even if we did rebroadcast we still may not see it in the connected nodes) but tx may eventually appear in the block.
There was a problem hiding this comment.
Why rush to refund though, if we did not see the tx in mempool?
I don't think it's rushed, 30 seconds is 2 eth blocktimes and any other EVM is less than that. As for UTXOs, it should be in the mempool by then. It's on the other side (the maker) to have a good fee to make it appear quickly, we don't want taker funds or the swap to hang for a long time as this is bad for usability. In the future, makers reputation or other means (slashing) should be tied to that to since taker will lose network / mining fees. Basically when maker sends the taker a p2p message that they broadcasted the tx they should guarantee it will appear in less than 30 seconds.
There was a problem hiding this comment.
P.S. after testing and seeing how this works in real environment the 30 seconds wait time can be changed if needed, this is just my own thinking of what a good value should be to strike balance between returning funds early and giving the tx time to appear. I guess there are other factors like web3 nodes / electrums being down etc... but I don't think a swap should continue in such conditions.
There was a problem hiding this comment.
Should we even do / allow swaps in such times?
on DOGE, the problem persisted for a pretty long time, like couple months.... after i figured out those mitigations swaps worked fine
so i think, if we can keep it working, then we should also allow the users to do the swaps... they will complain anyway if we don't :-)
There was a problem hiding this comment.
ok, seems like a config option that is documented in a good way and lists the cons of increasing it's value should be good enough. I might improve on this code as well, in this PR or in the future, I didn't want to rely on errors returned from nodes, but maybe a mixture of both will make things more robust.
There was a problem hiding this comment.
IMHO, as a general case when we did not see a tx in mempool we could not know for sure about it: the tx may be not valid or may be valid but just did not get into a specific node mempool (e.g. due to the node policy).
Maybe it's better to wait for the next block to be sure (well I think at least this is okay for refund: better to wait longer than disrupt the swap) .
There was a problem hiding this comment.
I agree not seeing a tx does not prove it is invalid, but in the non cooperating model we are following, the maker must produce quick public evidence once they claim that they broadcasted the transaction by sending the p2p message. The taker cannot wait open ended for something that might be withheld or stuck. Waiting a block does not guarantee visibility within this block either in cases like the Doge case mentioned by @cipig.
As mentioned in this comment:
https://github.com/KomodoPlatform/komodo-defi-framework/blob/30d0638eb5651c776e8586ac3b34a0ddb8e393f5/mm2src/mm2_main/src/lp_swap/swap_v2_common.rs#L89-L93
For non trusted makers we can require maker payment first, this is the cost to gain trust. We can add makers explicitly as trusted once they have enough volume, until a reputation index or other means are in place. Trusted makers keep the current flow while allowing longer waits or confirmations, so this PR is only a step in this direction.
I suggest to keep this 30 seconds for now and test it in real scenarios and maybe add an RPC later for takers to choose to refund immediately whenever they want as they incur the network / mining fees, or make the wait time configurable per coin or whatever we find necessary later.
There was a problem hiding this comment.
I guess this fix indeed matters for TPU as its whole idea was to make it grief-free.
That is, in case of any signs of manipulation from the Maker side the Taker should be able to release their funds ASAP.
| if self.require_taker_funding_confirm_before_maker_payment { | ||
| self.conf_settings.taker_coin_confs.min(1) |
There was a problem hiding this comment.
this might return 0 if taker_coin_confs is set to 0 making this require_taker_funding_confirm_before_maker_payment parameter essentially useless.
There was a problem hiding this comment.
I found problems with this approach ref. #2646 (comment)
There was a problem hiding this comment.
this might return 0 if taker_coin_confs is set to 0 making this require_taker_funding_confirm_before_maker_payment parameter essentially useless.
require_taker_funding_confirm_before_maker_payment is a global requirement that can be overridden by specific coins configs, so coin config takes precedence here as an opt-out mechanism for makers. Eventually, the plan is to make this flag (and similar ones) user-togglable, but for now this is how it’s wired, this was my thinking at least. In any case, please wait for 2 more commits from my side before continuing reviews.
There was a problem hiding this comment.
Will be disabled in next commit with lots of code comments/notes about the decision and all the different tradeoffs.
… behaviour before the PR). Add lots of notes and doc comments for insight into the different decisions.
75ae3ac to
30d0638
Compare
| /// | ||
| /// Important: | ||
| /// - Offline semantic validation only (destination address/script, value/ABI args/pubs). | ||
| /// - Must not perform any network I/O: no RPC calls, no mempool lookups, no confirmation checks. | ||
| /// - Presence and confirmations are enforced by the swap state machine | ||
| /// (e.g., before the taker waits for maker payment confirmation to allow for fast failure). | ||
| async fn validate_maker_payment_v2(&self, args: ValidateMakerPaymentArgs<'_, Self>) -> ValidatePaymentResult<()>; |
There was a problem hiding this comment.
Perhaps, add a offline prefix to the function (e.g., offline_maker_payment_validation_v2)?
There was a problem hiding this comment.
Well, validation in the crypto sense is an offline operation after fetching or getting all the needed info from the chain / p2p / light nodes / etc..., I think it would be excessive to add offline to this but it's fine by me if you insist.
dimxy
left a comment
There was a problem hiding this comment.
TBH the idea of refund if we did not find the payment tx in mempool looks debatable for me.
Apart from that, LGTM
Thanks @dimxy, I answered here #2646 (comment) with my rationale. Like I said, this can be changed / enhanced later once tested. |
|
@onur-ozkan all your comments should have been addressed in the latest commit |
This is a follow‑up to #2618.
Problem
Taker‑side validation failed when the maker broadcasted via private/MEV‑protected relays (e.g., Polygon Protect RPC), because the tx wasn’t visible on public RPCs. This caused false negatives and unnecessary refunds.
Previous PR (#2618)
What this PR changes
ensure_tx_is_broadcasted(…): polls by tx hash within a grace window, on the first miss performs a one‑shot rebroadcast, continues polling until timeout.validate_taker_funding_impl: now parsesSignedEthTxand validates from/to, ABI inputs and value offline (no RPC fetch for the tx).validate_maker_payment_v2uses it so a change invalidate_maker_payment_v2might follow, it's not a big issue for UTXO but will be done for completeness.How this fixes the problem
Not done from prior “Future Work” in #2618 and why
“Add taker rebroadcast fallback after a short pre‑wait”
“Treat rebroadcast as success only based on transport responses”
“Do not treat ‘nonce too low’ or ‘replacement underpriced’ as success, query tx by hash”
Defaults and constants
require_taker_funding_confirm_before_maker_payment = true(wait up to 1 confirmation).SWAP_TX_VISIBILITY_GRACE_SECS = 30sSWAP_TX_VISIBILITY_POLL_SECS = 1sTodo in this PR:
validate_maker_payment_v2validates tx offline only (UTXO parity). Not required for resolving the private‑relay false‑negative, but desirable for completeness.