Skip to content

Commit

Permalink
Fix(exit precompile): Address to refund in case of error is an argume…
Browse files Browse the repository at this point in the history
…nt (#311)
  • Loading branch information
birchmd committed Nov 10, 2021
1 parent b5145bc commit 243c905
Show file tree
Hide file tree
Showing 19 changed files with 905 additions and 49 deletions.
10 changes: 7 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ ifeq ($(evm-bully),yes)
ADDITIONAL_FEATURES := $(ADDITIONAL_FEATURES),evm_bully
endif

ifeq ($(error-refund),yes)
ADDITIONAL_FEATURES := $(ADDITIONAL_FEATURES),error_refund
endif

# TODO: This isn't updating the `FEATURES` for some reason. Disabled to prevent accidental compilation of the same binary.
# all: mainnet testnet betanet
# all-debug: mainnet-debug testnet-debug betanet-debug
Expand Down Expand Up @@ -54,21 +58,21 @@ betanet-debug.wasm: target/wasm32-unknown-unknown/debug/aurora_engine.wasm
# test builds depend on release since `tests/test_upgrade.rs` includes `mainnet-release.wasm`

test-mainnet: mainnet-test-build
$(CARGO) test --features mainnet-test
$(CARGO) test --features mainnet-test$(ADDITIONAL_FEATURES)
mainnet-test-build: FEATURES=mainnet,integration-test,meta-call
mainnet-test-build: mainnet-test.wasm
mainnet-test.wasm: target/wasm32-unknown-unknown/release/aurora_engine.wasm
cp $< $@

test-testnet: testnet-test-build
$(CARGO) test --features testnet-test
$(CARGO) test --features testnet-test$(ADDITIONAL_FEATURES)
testnet-test-build: FEATURES=testnet,integration-test,meta-call
testnet-test-build: testnet-test.wasm
testnet-test.wasm: target/wasm32-unknown-unknown/release/aurora_engine.wasm
cp $< $@

test-betanet: betanet-test-build
$(CARGO) test --features betanet-test
$(CARGO) test --features betanet-test$(ADDITIONAL_FEATURES)
betanet-test-build: FEATURES=betanet,integration-test,meta-call
betanet-test-build: betanet-test.wasm
betanet-test.wasm: target/wasm32-unknown-unknown/release/aurora_engine.wasm
Expand Down
1 change: 1 addition & 0 deletions engine-precompiles/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -43,3 +43,4 @@ rand = "0.7.3"
[features]
contract = []
log = []
error_refund = []
81 changes: 66 additions & 15 deletions engine-precompiles/src/native.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,16 @@ use super::{EvmPrecompileResult, Precompile};
#[cfg(feature = "contract")]
use crate::prelude::{
format,
parameters::{PromiseCreateArgs, WithdrawCallArgs},
parameters::{PromiseArgs, PromiseCreateArgs, WithdrawCallArgs},
sdk,
storage::{bytes_to_key, KeyPrefix},
vec, AccountId, BorshSerialize, Cow, String, ToString, TryFrom, TryInto, Vec, H160, U256,
};
#[cfg(all(feature = "error_refund", feature = "contract"))]
use crate::prelude::{
parameters::{PromiseWithCallbackArgs, RefundCallArgs},
types,
};

use crate::prelude::Address;
use crate::PrecompileOutput;
Expand All @@ -25,10 +30,14 @@ mod costs {
// TODO(#51): Determine the correct amount of gas
pub(super) const EXIT_TO_ETHEREUM_GAS: Gas = 0;

// TODO(#51): Determine the correct amount of gas
// TODO(#332): Determine the correct amount of gas
pub(super) const FT_TRANSFER_GAS: Gas = 100_000_000_000_000;

// TODO(#51): Determine the correct amount of gas
// TODO(#332): Determine the correct amount of gas
#[cfg(feature = "error_refund")]
pub(super) const REFUND_ON_ERROR_GAS: Gas = 60_000_000_000_000;

// TODO(#332): Determine the correct amount of gas
pub(super) const WITHDRAWAL_GAS: Gas = 100_000_000_000_000;
}

Expand Down Expand Up @@ -227,6 +236,16 @@ impl Precompile for ExitToNear {
context: &Context,
is_static: bool,
) -> EvmPrecompileResult {
#[cfg(feature = "error_refund")]
fn parse_input(input: &[u8]) -> (Address, &[u8]) {
let refund_address = Address::from_slice(&input[1..21]);
(refund_address, &input[21..])
}
#[cfg(not(feature = "error_refund"))]
fn parse_input(input: &[u8]) -> &[u8] {
&input[1..]
}

if let Some(target_gas) = target_gas {
if Self::required_gas(input)? > target_gas {
return Err(ExitError::OutOfGas);
Expand All @@ -241,9 +260,14 @@ impl Precompile for ExitToNear {
// First byte of the input is a flag, selecting the behavior to be triggered:
// 0x0 -> Eth transfer
// 0x1 -> Erc20 transfer
let mut input = input;
let flag = input[0];
input = &input[1..];
#[cfg(feature = "error_refund")]
let (refund_address, mut input) = parse_input(input);
#[cfg(not(feature = "error_refund"))]
let mut input = parse_input(input);
let current_account_id = AccountId::try_from(sdk::current_account_id()).unwrap();
#[cfg(feature = "error_refund")]
let refund_on_error_target = current_account_id.clone();

let (nep141_address, args, exit_event) = match flag {
0x0 => {
Expand All @@ -254,7 +278,7 @@ impl Precompile for ExitToNear {

if let Ok(dest_account) = AccountId::try_from(input) {
(
AccountId::try_from(sdk::current_account_id()).unwrap(),
current_account_id,
// There is no way to inject json, given the encoding of both arguments
// as decimal and valid account id respectively.
format!(
Expand Down Expand Up @@ -322,19 +346,46 @@ impl Precompile for ExitToNear {
_ => return Err(ExitError::Other(Cow::from("ERR_INVALID_FLAG"))),
};

let promise: Vec<u8> = PromiseCreateArgs {
#[cfg(feature = "error_refund")]
let erc20_address = if flag == 0 {
None
} else {
Some(exit_event.erc20_address.0)
};
#[cfg(feature = "error_refund")]
let refund_args = RefundCallArgs {
recipient_address: refund_address.0,
erc20_address,
amount: types::u256_to_arr(&exit_event.amount),
};
#[cfg(feature = "error_refund")]
let refund_promise = PromiseCreateArgs {
target_account_id: refund_on_error_target,
method: "refund_on_error".to_string(),
args: refund_args.try_to_vec().unwrap(),
attached_balance: 0,
attached_gas: costs::REFUND_ON_ERROR_GAS,
};
let transfer_promise = PromiseCreateArgs {
target_account_id: nep141_address,
method: "ft_transfer".to_string(),
args: args.as_bytes().to_vec(),
attached_balance: 1,
attached_gas: costs::FT_TRANSFER_GAS,
}
.try_to_vec()
.unwrap();
};

#[cfg(feature = "error_refund")]
let promise = PromiseArgs::Callback(PromiseWithCallbackArgs {
base: transfer_promise,
callback: refund_promise,
});
#[cfg(not(feature = "error_refund"))]
let promise = PromiseArgs::Create(transfer_promise);

let promise_log = Log {
address: Self::ADDRESS,
topics: Vec::new(),
data: promise,
data: promise.try_to_vec().unwrap(),
};
let exit_event_log = exit_event.encode();
let exit_event_log = Log {
Expand Down Expand Up @@ -492,15 +543,15 @@ impl Precompile for ExitToEthereum {
}
};

let promise = PromiseCreateArgs {
let withdraw_promise = PromiseCreateArgs {
target_account_id: nep141_address,
method: "withdraw".to_string(),
args: serialized_args,
attached_balance: 1,
attached_gas: costs::WITHDRAWAL_GAS,
}
.try_to_vec()
.unwrap();
};

let promise = PromiseArgs::Create(withdraw_promise).try_to_vec().unwrap();
let promise_log = Log {
address: Self::ADDRESS,
topics: Vec::new(),
Expand Down
1 change: 1 addition & 0 deletions engine-tests/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -47,3 +47,4 @@ meta-call = ["aurora-engine/meta-call"]
mainnet-test = ["aurora-engine/mainnet-test"]
testnet-test = ["aurora-engine/testnet-test"]
betanet-test = ["aurora-engine/betanet-test"]
error_refund = ["aurora-engine/error_refund", "aurora-engine-precompiles/error_refund"]
7 changes: 7 additions & 0 deletions engine-tests/src/test_utils/exit_precompile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,13 @@ pub const DEST_ADDRESS: Address =
aurora_engine_precompiles::make_address(0xe0f5206b, 0xbd039e7b0592d8918820024e2a7437b9);

impl TesterConstructor {
#[cfg(feature = "error_refund")]
pub fn load() -> Self {
Self(solidity::ContractConstructor::compile_from_extended_json(
"../etc/eth-contracts/artifacts/contracts/test/TesterV2.sol/TesterV2.json",
))
}
#[cfg(not(feature = "error_refund"))]
pub fn load() -> Self {
Self(solidity::ContractConstructor::compile_from_extended_json(
"../etc/eth-contracts/artifacts/contracts/test/Tester.sol/Tester.json",
Expand Down
16 changes: 8 additions & 8 deletions engine-tests/src/tests/contract_call.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,8 @@ fn withdraw() {
let token = Address(token);

let test_data = vec![
(true, "Call contract: tt.testnet.ft_transfer"),
(false, "Call contract: tt.testnet.withdraw"),
(true, "call_contract tt.testnet.ft_transfer"),
(false, "call_contract tt.testnet.withdraw"),
];

for (is_to_near, expected) in test_data {
Expand Down Expand Up @@ -119,8 +119,8 @@ fn withdraw_and_fail() {
let (mut runner, mut signer, _token, tester) = setup_test();

let test_data = vec![
(true, "Call contract: tt.testnet.ft_transfer"),
(false, "Call contract: tt.testnet.withdraw"),
(true, "call_contract tt.testnet.ft_transfer"),
(false, "call_contract tt.testnet.withdraw"),
];

for (flag, not_expected) in test_data {
Expand All @@ -138,8 +138,8 @@ fn try_withdraw_and_avoid_fail() {
let (mut runner, mut signer, _token, tester) = setup_test();

let test_data = vec![
(true, "Call contract: tt.testnet.ft_transfer"),
(false, "Call contract: tt.testnet.withdraw"),
(true, "call_contract tt.testnet.ft_transfer"),
(false, "call_contract tt.testnet.withdraw"),
];

for (flag, not_expected) in test_data {
Expand All @@ -157,8 +157,8 @@ fn try_withdraw_and_avoid_fail_and_succeed() {
let (mut runner, mut signer, _token, tester) = setup_test();

let test_data = vec![
(true, "Call contract: tt.testnet.ft_transfer"),
(false, "Call contract: tt.testnet.withdraw"),
(true, "call_contract tt.testnet.ft_transfer"),
(false, "call_contract tt.testnet.withdraw"),
];

for (flag, expected) in test_data {
Expand Down
Loading

0 comments on commit 243c905

Please sign in to comment.