Skip to content
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

Fix(xcc): Ensure near_withdraw comes after ft_transfer #864

Merged
merged 4 commits into from
Nov 10, 2023
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions engine-standalone-storage/src/sync/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,10 @@ pub fn parse_transaction_kind(
})?;
TransactionKind::FactorySetWNearAddress(address)
}
TransactionKindTag::WithdrawWnearToRouter => {
let args = xcc::WithdrawWnearToRouterArgs::try_from_slice(&bytes).map_err(f)?;
TransactionKind::WithdrawWnearToRouter(args)
}
TransactionKindTag::SetUpgradeDelayBlocks => {
let args = parameters::SetUpgradeDelayBlocksArgs::try_from_slice(&bytes).map_err(f)?;
TransactionKind::SetUpgradeDelayBlocks(args)
Expand Down Expand Up @@ -644,6 +648,12 @@ fn non_submit_execute<I: IO + Copy>(

None
}
TransactionKind::WithdrawWnearToRouter(_) => {
let mut handler = crate::promise::NoScheduler { promise_data };
let result = contract_methods::xcc::withdraw_wnear_to_router(io, env, &mut handler)?;

Some(TransactionExecutionResult::Submit(Ok(result)))
}
TransactionKind::Unknown => None,
// Not handled in this function; is handled by the general `execute_transaction` function
TransactionKind::Submit(_) | TransactionKind::SubmitWithArgs(_) => unreachable!(),
Expand Down
39 changes: 39 additions & 0 deletions engine-standalone-storage/src/sync/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use aurora_engine::xcc::{AddressVersionUpdateArgs, FundXccArgs};
use aurora_engine_transactions::{EthTransactionKind, NormalizedEthTransaction};
use aurora_engine_types::account_id::AccountId;
use aurora_engine_types::parameters::silo;
use aurora_engine_types::parameters::xcc::WithdrawWnearToRouterArgs;
use aurora_engine_types::types::Address;
use aurora_engine_types::{
borsh::{self, BorshDeserialize, BorshSerialize},
Expand Down Expand Up @@ -146,6 +147,8 @@ pub enum TransactionKind {
FactoryUpdateAddressVersion(AddressVersionUpdateArgs),
FactorySetWNearAddress(Address),
FundXccSubAccount(FundXccArgs),
/// Self-call used during XCC flow to move wNEAR tokens to user's XCC account
WithdrawWnearToRouter(WithdrawWnearToRouterArgs),
/// Pause the contract
PauseContract,
/// Resume the contract
Expand Down Expand Up @@ -374,6 +377,31 @@ impl TransactionKind {
},
)
}
Self::WithdrawWnearToRouter(args) => {
let recipient = AccountId::new(&format!(
"{}.{}",
args.target.encode(),
engine_account.as_ref()
))
.unwrap_or_else(|_| engine_account.clone());
let wnear_address = storage
.with_engine_access(block_height, transaction_position, &[], |io| {
aurora_engine_precompiles::xcc::state::get_wnear_address(&io)
})
.result;
let call_args = aurora_engine::xcc::withdraw_wnear_call_args(
&recipient,
args.amount,
wnear_address,
);
Self::Call(call_args).eth_repr(
engine_account,
caller,
block_height,
transaction_position,
storage,
)
}
Self::Deposit(_) => Self::no_evm_execution("deposit"),
Self::FtTransferCall(_) => Self::no_evm_execution("ft_transfer_call"),
Self::FinishDeposit(_) => Self::no_evm_execution("finish_deposit"),
Expand Down Expand Up @@ -550,6 +578,8 @@ pub enum TransactionKindTag {
RemoveEntryFromWhitelist,
#[strum(serialize = "mirror_erc20_token_callback")]
MirrorErc20TokenCallback,
#[strum(serialize = "withdraw_wnear_to_router")]
WithdrawWnearToRouter,
Unknown,
}

Expand Down Expand Up @@ -592,6 +622,7 @@ impl TransactionKind {
Self::NewEngine(args) => args.try_to_vec().unwrap_or_default(),
Self::FactoryUpdateAddressVersion(args) => args.try_to_vec().unwrap_or_default(),
Self::FundXccSubAccount(args) => args.try_to_vec().unwrap_or_default(),
Self::WithdrawWnearToRouter(args) => args.try_to_vec().unwrap_or_default(),
Self::PauseContract | Self::ResumeContract | Self::Unknown => Vec::new(),
Self::SetKeyManager(args) => args.try_to_vec().unwrap_or_default(),
Self::AddRelayerKey(args) | Self::RemoveRelayerKey(args) => {
Expand Down Expand Up @@ -641,6 +672,7 @@ impl From<&TransactionKind> for TransactionKindTag {
TransactionKind::FactoryUpdate(_) => Self::FactoryUpdate,
TransactionKind::FactoryUpdateAddressVersion(_) => Self::FactoryUpdateAddressVersion,
TransactionKind::FactorySetWNearAddress(_) => Self::FactorySetWNearAddress,
TransactionKind::WithdrawWnearToRouter(_) => Self::WithdrawWnearToRouter,
TransactionKind::SetOwner(_) => Self::SetOwner,
TransactionKind::SubmitWithArgs(_) => Self::SubmitWithArgs,
TransactionKind::SetUpgradeDelayBlocks(_) => Self::SetUpgradeDelayBlocks,
Expand Down Expand Up @@ -886,6 +918,7 @@ enum BorshableTransactionKind<'a> {
SetWhitelistStatus(Cow<'a, silo::WhitelistStatusArgs>),
SetEthConnectorContractAccount(Cow<'a, parameters::SetEthConnectorContractAccountArgs>),
MirrorErc20TokenCallback(Cow<'a, parameters::MirrorErc20TokenArgs>),
WithdrawWnearToRouter(Cow<'a, WithdrawWnearToRouterArgs>),
}

impl<'a> From<&'a TransactionKind> for BorshableTransactionKind<'a> {
Expand Down Expand Up @@ -924,6 +957,9 @@ impl<'a> From<&'a TransactionKind> for BorshableTransactionKind<'a> {
TransactionKind::FactorySetWNearAddress(address) => {
Self::FactorySetWNearAddress(*address)
}
TransactionKind::WithdrawWnearToRouter(x) => {
Self::WithdrawWnearToRouter(Cow::Borrowed(x))
}
TransactionKind::Unknown => Self::Unknown,
TransactionKind::PausePrecompiles(x) => Self::PausePrecompiles(Cow::Borrowed(x)),
TransactionKind::ResumePrecompiles(x) => Self::ResumePrecompiles(Cow::Borrowed(x)),
Expand Down Expand Up @@ -1051,6 +1087,9 @@ impl<'a> TryFrom<BorshableTransactionKind<'a>> for TransactionKind {
BorshableTransactionKind::MirrorErc20TokenCallback(x) => {
Ok(Self::MirrorErc20TokenCallback(x.into_owned()))
}
BorshableTransactionKind::WithdrawWnearToRouter(x) => {
Ok(Self::WithdrawWnearToRouter(x.into_owned()))
}
}
}
}
8 changes: 7 additions & 1 deletion engine-types/src/parameters/xcc.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::account_id::AccountId;
use crate::borsh::{self, BorshDeserialize, BorshSerialize};
use crate::types::Address;
use crate::types::{Address, Yocto};

#[derive(Debug, Clone, PartialEq, Eq, BorshDeserialize, BorshSerialize)]
pub struct AddressVersionUpdateArgs {
Expand All @@ -14,6 +14,12 @@ pub struct FundXccArgs {
pub wnear_account_id: Option<AccountId>,
}

#[derive(Debug, Clone, PartialEq, Eq, BorshDeserialize, BorshSerialize)]
pub struct WithdrawWnearToRouterArgs {
pub target: Address,
pub amount: Yocto,
}

/// Type wrapper for version of router contracts.
#[derive(
Debug, Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, BorshDeserialize, BorshSerialize,
Expand Down
11 changes: 0 additions & 11 deletions engine/src/contract_methods/evm_transactions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,17 +56,6 @@ pub fn call<I: IO + Copy, E: Env, H: PromiseHandler>(
let current_account_id = env.current_account_id();
let predecessor_account_id = env.predecessor_account_id();

// During the XCC flow the Engine will call itself to move wNEAR
// to the user's sub-account. We do not want this move to happen
// if prior promises in the flow have failed.
if current_account_id == predecessor_account_id {
let check_promise: Result<(), &[u8]> = match handler.promise_result_check() {
Some(true) | None => Ok(()),
Some(false) => Err(b"ERR_CALLBACK_OF_FAILED_PROMISE"),
};
check_promise?;
}

let mut engine: Engine<_, E, AuroraModExp> = Engine::new_with_state(
state,
predecessor_address(&predecessor_account_id),
Expand Down
60 changes: 57 additions & 3 deletions engine/src/contract_methods/xcc.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,71 @@
use crate::{
contract_methods::{require_owner_only, require_running, ContractError},
contract_methods::{predecessor_address, require_owner_only, require_running, ContractError},
engine::Engine,
errors,
hashchain::with_hashchain,
hashchain::{with_hashchain, with_logs_hashchain},
state, xcc,
};
use aurora_engine_modexp::AuroraModExp;
use aurora_engine_sdk::{
env::Env,
io::{StorageIntermediate, IO},
promise::PromiseHandler,
};
use aurora_engine_types::{borsh::BorshSerialize, types::Address};
use aurora_engine_types::{
account_id::AccountId,
borsh::BorshSerialize,
format,
parameters::{engine::SubmitResult, xcc::WithdrawWnearToRouterArgs},
types::Address,
};
use function_name::named;

#[named]
pub fn withdraw_wnear_to_router<I: IO + Copy, E: Env, H: PromiseHandler>(
io: I,
env: &E,
handler: &mut H,
) -> Result<SubmitResult, ContractError> {
with_logs_hashchain(io, env, function_name!(), |io| {
let state = state::get_state(&io)?;
require_running(&state)?;
env.assert_private_call()?;
let check_promise: Result<(), &[u8]> = match handler.promise_result_check() {
birchmd marked this conversation as resolved.
Show resolved Hide resolved
Some(true) | None => Ok(()),
Some(false) => Err(b"ERR_CALLBACK_OF_FAILED_PROMISE"),
};
check_promise?;
let args: WithdrawWnearToRouterArgs = io.read_input_borsh()?;
let current_account_id = env.current_account_id();
let recipient = AccountId::new(&format!(
"{}.{}",
args.target.encode(),
current_account_id.as_ref()
))?;
birchmd marked this conversation as resolved.
Show resolved Hide resolved
let wnear_address = aurora_engine_precompiles::xcc::state::get_wnear_address(&io);
let mut engine: Engine<_, E, AuroraModExp> = Engine::new_with_state(
state,
predecessor_address(&current_account_id),
current_account_id,
io,
env,
);
let (result, ids) = xcc::withdraw_wnear_to_router(
&recipient,
args.amount,
wnear_address,
&mut engine,
handler,
)?;
if !result.status.is_ok() {
return Err(b"ERR_WITHDRAW_FAILED".into());
}
let id = ids.last().ok_or(b"ERR_NO_PROMISE_CREATED")?;
handler.promise_return(*id);
Ok(result)
})
}

#[named]
pub fn factory_update<I: IO + Copy, E: Env>(io: I, env: &E) -> Result<(), ContractError> {
with_hashchain(io, env, function_name!(), |mut io| {
Expand Down
13 changes: 13 additions & 0 deletions engine/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -388,6 +388,19 @@ mod contract {
.sdk_unwrap();
}

/// A private function (only callable by the contract itself) used as part of the XCC flow.
/// This function uses the exit to Near precompile to move wNear from Aurora to a user's
/// XCC account.
#[no_mangle]
pub extern "C" fn withdraw_wnear_to_router() {
let io = Runtime;
let env = Runtime;
let mut handler = Runtime;
contract_methods::xcc::withdraw_wnear_to_router(io, &env, &mut handler)
.map_err(ContractError::msg)
.sdk_unwrap();
}

/// Mirror existing ERC-20 token on the main Aurora contract.
/// Notice: It works if the SILO mode is on.
#[no_mangle]
Expand Down
Loading
Loading