-
Notifications
You must be signed in to change notification settings - Fork 40
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
solana: Fix logic error in Inbox release process #336
base: main
Are you sure you want to change the base?
solana: Fix logic error in Inbox release process #336
Conversation
@@ -54,8 +54,8 @@ pub struct ReleaseInboundMint<'info> { | |||
} | |||
|
|||
/// Release an inbound transfer and mint the tokens to the recipient. | |||
/// When `revert_on_error` is true, the transaction will revert if the | |||
/// release timestamp has not been reached. When `revert_on_error` is false, the | |||
/// When `revert_on_delay` is true, the transaction will revert if the |
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 actual argument is called revert_on_delay
. But perhaps this flag should revert on any error and not just the case where the transaction is not ready to be released?
I think we should keep the existing behaviour, but potentially think of a name for the flag that better describes it? Something like The thinking here is that it's convenient for the client to send all the instructions in a single transaction (the transceiver redeem one, then the inbound release one). Whether the transaction can be redeemed immediately cannot be determined on the client side atomically, so the client would either have to perform two transactions, or do some non-trivial computation (involving a lookup) to figure out whether the transceiver redeem ix hits the threshold. The intention of this flag is definitely to "attempt to redeem if we can". I originally called the flag "revert on error" (as you point out in the comment), but that's not a very good name because the function errors out if the message is already release regardless of the flag. |
OK, makes sense. I'm happy with renaming the flag. if revert_on_delay == true and ReleaseStatus::NotApproved, try_release() reverts with CantReleaseYet Maybe this could return |
Yeah that makes sense to me. Maybe the cleanest way to do that is to propagate the boolean flag to |
Sounds good to me. I'll update this PR |
065aa32
to
b8ce756
Compare
b8ce756
to
c8ae28f
Compare
There are a few suspicious aspects of the inbox release logic: 1. `release_inbound_unlock` takes a flag that determines whether a `false` result from `try_release` should cause an error. The flag indicates that it should revert on delay. However, `try_release` can also return `false` when a transaction has not been approved. If the flag is set, the transaction will not return an error when a user tries to release a transaction that is not approved even though whether a transaction is approved has nothing to do with its expected behaviour when it is delayed 2. The custom error TransferNotApproved is defined but unused Taken together, I believe `try_release()` should revert with the TransferNotApproved error. This would disambiguate the various 'false' results and provide more intuitive behaviour when a user tries to release a transaction that is not approved.
c8ae28f
to
ed933ac
Compare
@@ -3353,7 +3353,7 @@ export const IDL: ExampleNativeTokenTransfers = { | |||
"kind": "struct", | |||
"fields": [ | |||
{ | |||
"name": "revertOnDelay", |
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.
not sure it's worth introducing a breaking change at this point
There are a few suspicious aspects of the inbox release logic:
release_inbound_unlock
takes a flag that determines whether afalse
result fromtry_release
should result in an error being returned. The flag indicates that it should revert on delay. However,try_release
can also returnfalse
when a transaction has not been approved (regardless of whether or not it is delayed).If the flag is set, the transaction will not return an error when a user tries to release a transaction that is not approved even though whether a transaction is approved has nothing to do with its expected behaviour when it is delayed.
Context:
try_release()
returnsOk(false)
when a transfer is not approved (L37)https://github.com/wormhole-foundation/example-native-token-transfers/blob/93350abef9c3b520a01dd150a1b09a603c1e1160/solana/programs/example-native-token-transfers/src/queue/inbox.rs#L33-L47
release_inbound_mint
(andrelease_inbound_unlock
) returnOk(())
when transfer not approved and therevert_on_delay
flag is false (L75)https://github.com/wormhole-foundation/example-native-token-transfers/blob/93350abef9c3b520a01dd150a1b09a603c1e1160/solana/programs/example-native-token-transfers/src/instructions/release_inbound.rs#L63-L79
TransferNotApproved
is defined but unused in the codebaseTaken together, I believe
try_release()
should revert with the TransferNotApproved error. This would disambiguate the various 'false' results and provide more intuitive behaviour when a user tries to release a transaction that is not approved.Current behaviour:
revert_on_delay == false
andReleaseStatus::NotApproved
,try_release()
returnsOk(())
revert_on_delay == true
andReleaseStatus::NotApproved
,try_release()
reverts withCantReleaseYet
New behaviour:
revert_on_delay == false
andReleaseStatus::NotApproved
,try_release()
reverts withTransferNotApproved
revert_on_delay == true
andReleaseStatus::NotApproved
,try_release()
reverts withTransferNotApproved
Note that funds are safe in both cases.
assert
statements in bothrelease_inbound
functions check that the ReleaseStatus is Redeemed before minting funds.