Skip to content

[BUG] Large native NEAR withdrawals will be stuck forever #251

@mitinarseny

Description

@mitinarseny

Large amounts of native NEAR will always fail to finalize and, thus, remain stuck in omni-bridge contract forever:

.near_withdraw(amount_to_transfer)
.then(
Promise::new(recipient)
.transfer(NearToken::from_yoctonear(amount_to_transfer.0)),
)

An example situation when this might happen would be if omni-bridge has only 100 native NEAR balance, while relayer tries to finalize 1000 native NEAR withdrawal, even if the contract owns 1000+ wNEAR.

The reason for that is sharded Near architecture: when Near VM schedules a native transfer Promise to increase balance of recipient, it also subtracts the amount from current_account_id during execution of current receipt, but not when scheduled promise is executed. If there is not enough native NEAR balance on the contract at the time of Promise creation, then current receipt will fail with ExecutionError("Exceeded the account balance.").

To mitigate this issue, an additional Promise should be scheduled as a callback to near_withdraw, and the actual transfer Promise should only be created in this callback:

// first withdraw
.near_withdraw(U128(withdraw.amount.as_yoctonear()))
.then(
    // do_native_withdraw only after unwrapping NEAR
    Contract::ext(CURRENT_ACCOUNT_ID.clone())
        .with_static_gas(Contract::DO_NATIVE_WITHDRAW_GAS)
        .do_native_withdraw(withdraw),
)

// ...
#[private]
pub fn do_native_withdraw(&mut self, withdraw: NativeWithdraw) -> Promise {
    require!(
        matches!(env::promise_result(0), PromiseResult::Successful(data) if data.is_empty()),
        "near_withdraw failed",
    );

    Promise::new(withdraw.receiver_id).transfer(withdraw.amount)
}

PS: please, note that current implementation of #147 also suffers from such issue.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions