diff --git a/src/benches/eth_deploy_code.rs b/src/benches/eth_deploy_code.rs index 1c0714ca5..565dd01bc 100644 --- a/src/benches/eth_deploy_code.rs +++ b/src/benches/eth_deploy_code.rs @@ -2,10 +2,11 @@ use criterion::{BatchSize, BenchmarkId, Criterion, Throughput}; use secp256k1::SecretKey; use crate::test_utils::{address_from_secret_key, create_eth_transaction, deploy_evm, SUBMIT}; +use crate::types::Wei; -const INITIAL_BALANCE: u64 = 1000; +const INITIAL_BALANCE: Wei = Wei::new_u64(1000); const INITIAL_NONCE: u64 = 0; -const TRANSFER_AMOUNT: u64 = 0; +const TRANSFER_AMOUNT: Wei = Wei::zero(); pub(crate) fn eth_deploy_code_benchmark(c: &mut Criterion) { let mut runner = deploy_evm(); @@ -13,7 +14,7 @@ pub(crate) fn eth_deploy_code_benchmark(c: &mut Criterion) { let source_account = SecretKey::random(&mut rng); runner.create_address( address_from_secret_key(&source_account), - INITIAL_BALANCE.into(), + INITIAL_BALANCE, INITIAL_NONCE.into(), ); let inputs: Vec<_> = [1, 4, 8, 12, 16] diff --git a/src/benches/eth_erc20.rs b/src/benches/eth_erc20.rs index 4dbca6449..d8f2424a1 100644 --- a/src/benches/eth_erc20.rs +++ b/src/benches/eth_erc20.rs @@ -15,7 +15,7 @@ pub(crate) fn eth_erc20_benchmark(c: &mut Criterion) { let source_account = SecretKey::random(&mut rng); runner.create_address( address_from_secret_key(&source_account), - INITIAL_BALANCE.into(), + crate::types::Wei::new_u64(INITIAL_BALANCE), INITIAL_NONCE.into(), ); let calling_account_id = "some-account.near".to_string(); diff --git a/src/benches/eth_standard_precompiles.rs b/src/benches/eth_standard_precompiles.rs index 8e6449943..fd57ce697 100644 --- a/src/benches/eth_standard_precompiles.rs +++ b/src/benches/eth_standard_precompiles.rs @@ -4,8 +4,9 @@ use secp256k1::SecretKey; use crate::test_utils::standard_precompiles::{PrecompilesConstructor, PrecompilesContract}; use crate::test_utils::{address_from_secret_key, deploy_evm, sign_transaction, SUBMIT}; +use crate::types::Wei; -const INITIAL_BALANCE: u64 = 1000; +const INITIAL_BALANCE: Wei = Wei::new_u64(1000); const INITIAL_NONCE: u64 = 0; pub(crate) fn eth_standard_precompiles_benchmark(c: &mut Criterion) { @@ -14,7 +15,7 @@ pub(crate) fn eth_standard_precompiles_benchmark(c: &mut Criterion) { let source_account = SecretKey::random(&mut rng); runner.create_address( address_from_secret_key(&source_account), - INITIAL_BALANCE.into(), + INITIAL_BALANCE, INITIAL_NONCE.into(), ); let calling_account_id = "some-account.near".to_string(); diff --git a/src/benches/eth_transfer.rs b/src/benches/eth_transfer.rs index 5532d07d5..2a0ec6c22 100644 --- a/src/benches/eth_transfer.rs +++ b/src/benches/eth_transfer.rs @@ -2,10 +2,11 @@ use criterion::{BatchSize, Criterion}; use secp256k1::SecretKey; use crate::test_utils::{address_from_secret_key, create_eth_transaction, deploy_evm, SUBMIT}; +use crate::types::Wei; -const INITIAL_BALANCE: u64 = 1000; +const INITIAL_BALANCE: Wei = Wei::new_u64(1000); const INITIAL_NONCE: u64 = 0; -const TRANSFER_AMOUNT: u64 = 123; +const TRANSFER_AMOUNT: Wei = Wei::new_u64(123); pub(crate) fn eth_transfer_benchmark(c: &mut Criterion) { let mut runner = deploy_evm(); @@ -13,13 +14,13 @@ pub(crate) fn eth_transfer_benchmark(c: &mut Criterion) { let source_account = SecretKey::random(&mut rng); runner.create_address( address_from_secret_key(&source_account), - INITIAL_BALANCE.into(), + INITIAL_BALANCE, INITIAL_NONCE.into(), ); let dest_account = address_from_secret_key(&SecretKey::random(&mut rng)); let transaction = create_eth_transaction( Some(dest_account), - TRANSFER_AMOUNT.into(), + TRANSFER_AMOUNT, vec![], Some(runner.chain_id), &source_account, diff --git a/src/engine.rs b/src/engine.rs index a1190b97d..1f232bb7e 100644 --- a/src/engine.rs +++ b/src/engine.rs @@ -10,7 +10,7 @@ use crate::precompiles; use crate::prelude::{Address, TryInto, Vec, H256, U256}; use crate::sdk; use crate::storage::{address_to_key, bytes_to_key, storage_to_key, KeyPrefix, KeyPrefixU8}; -use crate::types::{u256_to_arr, AccountId}; +use crate::types::{u256_to_arr, AccountId, Wei}; /// Errors with the EVM engine. #[derive(Debug, Clone, Eq, PartialEq)] @@ -205,10 +205,10 @@ impl Engine { .unwrap_or_else(U256::zero) } - pub fn set_balance(address: &Address, balance: &U256) { + pub fn set_balance(address: &Address, balance: &Wei) { sdk::write_storage( &address_to_key(KeyPrefix::Balance, address), - &u256_to_arr(balance), + &balance.to_bytes(), ); } @@ -216,10 +216,11 @@ impl Engine { sdk::remove_storage(&address_to_key(KeyPrefix::Balance, address)) } - pub fn get_balance(address: &Address) -> U256 { - sdk::read_storage(&address_to_key(KeyPrefix::Balance, address)) + pub fn get_balance(address: &Address) -> Wei { + let raw = sdk::read_storage(&address_to_key(KeyPrefix::Balance, address)) .map(|value| U256::from_big_endian(&value)) - .unwrap_or_else(U256::zero) + .unwrap_or_else(U256::zero); + Wei::new(raw) } pub fn remove_storage(address: &Address, key: &H256) { @@ -240,7 +241,7 @@ impl Engine { let balance = Self::get_balance(address); let nonce = Self::get_nonce(address); let code_len = Self::get_code_size(address); - balance == U256::zero() && nonce == U256::zero() && code_len == 0 + balance.is_zero() && nonce.is_zero() && code_len == 0 } /// Removes all storage for the given address. @@ -272,20 +273,20 @@ impl Engine { pub fn deploy_code_with_input(&mut self, input: Vec) -> EngineResult { let origin = self.origin(); - let value = U256::zero(); + let value = Wei::zero(); self.deploy_code(origin, value, input) } pub fn deploy_code( &mut self, origin: Address, - value: U256, + value: Wei, input: Vec, ) -> EngineResult { let mut executor = self.make_executor(); let address = executor.create_address(CreateScheme::Legacy { caller: origin }); let (status, result) = ( - executor.transact_create(origin, value, input, u64::MAX), + executor.transact_create(origin, value.raw(), input, u64::MAX), address, ); @@ -306,7 +307,7 @@ impl Engine { pub fn call_with_args(&mut self, args: FunctionCallArgs) -> EngineResult { let origin = self.origin(); let contract = Address(args.contract); - let value = U256::zero(); + let value = Wei::zero(); self.call(origin, contract, value, args.input) } @@ -314,11 +315,12 @@ impl Engine { &mut self, origin: Address, contract: Address, - value: U256, + value: Wei, input: Vec, ) -> EngineResult { let mut executor = self.make_executor(); - let (status, result) = executor.transact_call(origin, contract, value, input, u64::MAX); + let (status, result) = + executor.transact_call(origin, contract, value.raw(), input, u64::MAX); let used_gas = executor.used_gas(); let (values, logs) = executor.into_state().deconstruct(); @@ -362,18 +364,19 @@ impl Engine { let origin = Address::from_slice(&args.sender); let contract = Address::from_slice(&args.address); let value = U256::from_big_endian(&args.amount); - self.view(origin, contract, value, args.input) + self.view(origin, contract, Wei::new(value), args.input) } pub fn view( &self, origin: Address, contract: Address, - value: U256, + value: Wei, input: Vec, ) -> EngineResult> { let mut executor = self.make_executor(); - let (status, result) = executor.transact_call(origin, contract, value, input, u64::MAX); + let (status, result) = + executor.transact_call(origin, contract, value.raw(), input, u64::MAX); status.into_result()?; Ok(result) } @@ -492,7 +495,7 @@ impl evm::backend::Backend for Engine { fn basic(&self, address: Address) -> Basic { Basic { nonce: Engine::get_nonce(&address), - balance: Engine::get_balance(&address), + balance: Engine::get_balance(&address).raw(), } } @@ -531,7 +534,7 @@ impl ApplyBackend for Engine { reset_storage, } => { Engine::set_nonce(&address, &basic.nonce); - Engine::set_balance(&address, &basic.balance); + Engine::set_balance(&address, &Wei::new(basic.balance)); if let Some(code) = code { Engine::set_code(&address, &code) } diff --git a/src/lib.rs b/src/lib.rs index 6ef419227..5f18e475b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -305,7 +305,7 @@ mod contract { pub extern "C" fn get_balance() { let address = sdk::read_input_arr20(); let balance = Engine::get_balance(&Address(address)); - sdk::return_output(&u256_to_arr(&balance)) + sdk::return_output(&balance.to_bytes()) } #[no_mangle] diff --git a/src/meta_parsing.rs b/src/meta_parsing.rs index 219f2302c..6a8e6aaea 100644 --- a/src/meta_parsing.rs +++ b/src/meta_parsing.rs @@ -5,7 +5,7 @@ use rlp::{Decodable, DecoderError, Rlp}; use crate::parameters::MetaCallArgs; use crate::prelude::{vec, Address, Box, HashMap, String, ToOwned, ToString, Vec, H256, U256}; -use crate::types::{keccak, u256_to_arr, InternalMetaCallArgs, RawU256}; +use crate::types::{keccak, u256_to_arr, InternalMetaCallArgs, RawU256, Wei}; /// Internal errors to propagate up and format in the single place. pub enum ParsingError { @@ -493,10 +493,10 @@ pub fn prepare_meta_call_args( bytes.extend_from_slice(&keccak(types.as_bytes()).as_bytes()); bytes.extend_from_slice(&keccak(account_id).as_bytes()); bytes.extend_from_slice(&u256_to_arr(&input.nonce)); - bytes.extend_from_slice(&u256_to_arr(&input.fee_amount)); + bytes.extend_from_slice(&input.fee_amount.to_bytes()); bytes.extend_from_slice(&encode_address(input.fee_address)); bytes.extend_from_slice(&encode_address(input.contract_address)); - bytes.extend_from_slice(&u256_to_arr(&input.value)); + bytes.extend_from_slice(&input.value.to_bytes()); let methods = MethodAndTypes::parse(&method_def)?; let method_sig = method_signature(&methods); @@ -544,10 +544,10 @@ pub fn parse_meta_call( let meta_tx = MetaCallArgs::try_from_slice(&args).map_err(|_| ParsingError::ArgumentParseError)?; let nonce = U256::from(meta_tx.nonce); - let fee_amount = U256::from(meta_tx.fee_amount); + let fee_amount = Wei::new(U256::from(meta_tx.fee_amount)); let fee_address = Address::from(meta_tx.fee_address); let contract_address = Address::from(meta_tx.contract_address); - let value = U256::from(meta_tx.value); + let value = Wei::new(U256::from(meta_tx.value)); let mut result = InternalMetaCallArgs { sender: Address::zero(), diff --git a/src/prelude.rs b/src/prelude.rs index 841c87dfc..86dd659c9 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -11,12 +11,29 @@ pub use alloc::{ vec::Vec, }; #[cfg(not(feature = "std"))] -pub use core::{convert::TryInto, marker::PhantomData, mem}; +pub use core::{ + convert::TryInto, + marker::PhantomData, + mem, + ops::{Add, Sub}, +}; #[cfg(feature = "std")] pub use std::{ - borrow::Cow, borrow::Cow::Borrowed, borrow::ToOwned, boxed::Box, collections::HashMap, - convert::TryInto, error::Error, fmt, format, marker::PhantomData, mem, string::String, - string::ToString, vec, vec::Vec, + borrow::Cow, + borrow::Cow::Borrowed, + borrow::ToOwned, + boxed::Box, + collections::HashMap, + convert::TryInto, + error::Error, + fmt, format, + marker::PhantomData, + mem, + ops::{Add, Sub}, + string::String, + string::ToString, + vec, + vec::Vec, }; pub use primitive_types::{H160, H256, U256}; diff --git a/src/test_utils/mod.rs b/src/test_utils/mod.rs index 6e2809350..9cd3c2a09 100644 --- a/src/test_utils/mod.rs +++ b/src/test_utils/mod.rs @@ -114,11 +114,11 @@ impl AuroraRunner { ) } - pub fn create_address(&mut self, address: Address, init_balance: U256, init_nonce: U256) { + pub fn create_address(&mut self, address: Address, init_balance: types::Wei, init_nonce: U256) { let trie = &mut self.ext.fake_trie; let balance_key = storage::address_to_key(storage::KeyPrefix::Balance, &address); - let balance_value = types::u256_to_arr(&init_balance); + let balance_value = init_balance.to_bytes(); let nonce_key = storage::address_to_key(storage::KeyPrefix::Nonce, &address); let nonce_value = types::u256_to_arr(&init_nonce); @@ -170,8 +170,8 @@ impl AuroraRunner { } } - pub fn get_balance(&self, address: Address) -> U256 { - self.getter_method_call("get_balance", address) + pub fn get_balance(&self, address: Address) -> types::Wei { + types::Wei::new(self.getter_method_call("get_balance", address)) } pub fn get_nonce(&self, address: Address) -> U256 { @@ -262,7 +262,7 @@ pub(crate) fn deploy_evm() -> AuroraRunner { pub(crate) fn create_eth_transaction( to: Option
, - value: U256, + value: types::Wei, data: Vec, chain_id: Option, secret_key: &SecretKey, @@ -322,7 +322,7 @@ pub(crate) fn parse_eth_gas(output: &VMOutcome) -> u64 { pub(crate) fn validate_address_balance_and_nonce( runner: &AuroraRunner, address: Address, - expected_balance: U256, + expected_balance: types::Wei, expected_nonce: U256, ) { assert_eq!(runner.get_balance(address), expected_balance, "balance"); diff --git a/src/tests/erc20.rs b/src/tests/erc20.rs index 4790bb3a8..54769bde8 100644 --- a/src/tests/erc20.rs +++ b/src/tests/erc20.rs @@ -3,6 +3,7 @@ use crate::test_utils::{ self, erc20::{ERC20Constructor, ERC20}, }; +use crate::types::Wei; use bstr::ByteSlice; use secp256k1::SecretKey; @@ -211,7 +212,11 @@ fn initialize_erc20() -> (test_utils::AuroraRunner, SecretKey, Address, ERC20) { let mut rng = rand::thread_rng(); let source_account = SecretKey::random(&mut rng); let source_address = test_utils::address_from_secret_key(&source_account); - runner.create_address(source_address, INITIAL_BALANCE.into(), INITIAL_NONCE.into()); + runner.create_address( + source_address, + Wei::new_u64(INITIAL_BALANCE), + INITIAL_NONCE.into(), + ); let dest_address = test_utils::address_from_secret_key(&SecretKey::random(&mut rng)); let constructor = ERC20Constructor::load(); diff --git a/src/tests/sanity.rs b/src/tests/sanity.rs index 067119a5b..b89a81887 100644 --- a/src/tests/sanity.rs +++ b/src/tests/sanity.rs @@ -1,11 +1,12 @@ use crate::prelude::Address; use crate::test_utils; use crate::transaction::EthTransaction; +use crate::types::Wei; use secp256k1::SecretKey; -const INITIAL_BALANCE: u64 = 1000; +const INITIAL_BALANCE: Wei = Wei::new_u64(1000); const INITIAL_NONCE: u64 = 0; -const TRANSFER_AMOUNT: u64 = 123; +const TRANSFER_AMOUNT: Wei = Wei::new_u64(123); /// Tests we can transfer Eth from one account to another and that the balances are correctly /// updated. @@ -28,10 +29,10 @@ fn test_eth_transfer_success() { test_utils::validate_address_balance_and_nonce( &runner, source_address, - INITIAL_BALANCE.into(), + INITIAL_BALANCE, INITIAL_NONCE.into(), ); - test_utils::validate_address_balance_and_nonce(&runner, dest_address, 0.into(), 0.into()); + test_utils::validate_address_balance_and_nonce(&runner, dest_address, Wei::zero(), 0.into()); // perform transfer let (_, maybe_err) = runner.call(test_utils::SUBMIT, calling_account_id, input); @@ -41,13 +42,13 @@ fn test_eth_transfer_success() { test_utils::validate_address_balance_and_nonce( &runner, source_address, - (INITIAL_BALANCE - TRANSFER_AMOUNT).into(), + INITIAL_BALANCE - TRANSFER_AMOUNT, (INITIAL_NONCE + 1).into(), ); test_utils::validate_address_balance_and_nonce( &runner, dest_address, - TRANSFER_AMOUNT.into(), + TRANSFER_AMOUNT, 0.into(), ); } @@ -59,7 +60,7 @@ fn test_eth_transfer_insufficient_balance() { let source_address = test_utils::address_from_secret_key(&source_account); let transaction = test_utils::create_eth_transaction( Some(dest_address), - (2 * INITIAL_BALANCE).into(), // trying to transfer more than we have + INITIAL_BALANCE + INITIAL_BALANCE, // trying to transfer more than we have vec![], Some(runner.chain_id), &source_account, @@ -71,10 +72,10 @@ fn test_eth_transfer_insufficient_balance() { test_utils::validate_address_balance_and_nonce( &runner, source_address, - INITIAL_BALANCE.into(), + INITIAL_BALANCE, INITIAL_NONCE.into(), ); - test_utils::validate_address_balance_and_nonce(&runner, dest_address, 0.into(), 0.into()); + test_utils::validate_address_balance_and_nonce(&runner, dest_address, Wei::zero(), 0.into()); // attempt transfer let (_, maybe_err) = runner.call(test_utils::SUBMIT, calling_account_id, input); @@ -85,11 +86,11 @@ fn test_eth_transfer_insufficient_balance() { test_utils::validate_address_balance_and_nonce( &runner, source_address, - INITIAL_BALANCE.into(), + INITIAL_BALANCE, // the nonce is still incremented even though the transfer failed (INITIAL_NONCE + 1).into(), ); - test_utils::validate_address_balance_and_nonce(&runner, dest_address, 0.into(), 0.into()); + test_utils::validate_address_balance_and_nonce(&runner, dest_address, Wei::zero(), 0.into()); } /// Tests the case where the nonce on the transaction does not match the address @@ -114,10 +115,10 @@ fn test_eth_transfer_incorrect_nonce() { test_utils::validate_address_balance_and_nonce( &runner, source_address, - INITIAL_BALANCE.into(), + INITIAL_BALANCE, INITIAL_NONCE.into(), ); - test_utils::validate_address_balance_and_nonce(&runner, dest_address, 0.into(), 0.into()); + test_utils::validate_address_balance_and_nonce(&runner, dest_address, Wei::zero(), 0.into()); // attempt transfer let (_, maybe_err) = runner.call(test_utils::SUBMIT, calling_account_id, input); @@ -128,10 +129,10 @@ fn test_eth_transfer_incorrect_nonce() { test_utils::validate_address_balance_and_nonce( &runner, source_address, - INITIAL_BALANCE.into(), + INITIAL_BALANCE, INITIAL_NONCE.into(), ); - test_utils::validate_address_balance_and_nonce(&runner, dest_address, 0.into(), 0.into()); + test_utils::validate_address_balance_and_nonce(&runner, dest_address, Wei::zero(), 0.into()); } fn initialize_transfer() -> (test_utils::AuroraRunner, SecretKey, Address) { @@ -140,7 +141,7 @@ fn initialize_transfer() -> (test_utils::AuroraRunner, SecretKey, Address) { let mut rng = rand::thread_rng(); let source_account = SecretKey::random(&mut rng); let source_address = test_utils::address_from_secret_key(&source_account); - runner.create_address(source_address, INITIAL_BALANCE.into(), INITIAL_NONCE.into()); + runner.create_address(source_address, INITIAL_BALANCE, INITIAL_NONCE.into()); let dest_address = test_utils::address_from_secret_key(&SecretKey::random(&mut rng)); (runner, source_account, dest_address) diff --git a/src/tests/standard_precompiles.rs b/src/tests/standard_precompiles.rs index 15e986182..bf2ca483a 100644 --- a/src/tests/standard_precompiles.rs +++ b/src/tests/standard_precompiles.rs @@ -2,9 +2,10 @@ use crate::test_utils::{ self, standard_precompiles::{PrecompilesConstructor, PrecompilesContract}, }; +use crate::types::Wei; use secp256k1::SecretKey; -const INITIAL_BALANCE: u64 = 1000; +const INITIAL_BALANCE: Wei = Wei::new_u64(1000); const INITIAL_NONCE: u64 = 0; #[test] @@ -14,7 +15,7 @@ fn standard_precompiles() { let source_account = SecretKey::random(&mut rng); runner.create_address( test_utils::address_from_secret_key(&source_account), - INITIAL_BALANCE.into(), + INITIAL_BALANCE, INITIAL_NONCE.into(), ); diff --git a/src/transaction.rs b/src/transaction.rs index 91152d292..fe1be41ba 100644 --- a/src/transaction.rs +++ b/src/transaction.rs @@ -1,4 +1,5 @@ use crate::prelude::{Address, Vec, U256}; +use crate::types::Wei; use rlp::{Decodable, DecoderError, Encodable, Rlp, RlpStream}; #[derive(Debug, Eq, PartialEq)] @@ -12,7 +13,7 @@ pub struct EthTransaction { /// The receiving address (`None` for the zero address) pub to: Option
, /// The amount of ETH to transfer - pub value: U256, + pub value: Wei, /// Arbitrary binary data for a contract call invocation pub data: Vec, } @@ -27,7 +28,7 @@ impl EthTransaction { None => s.append(&""), Some(address) => s.append(address), }; - s.append(&self.value); + s.append(&self.value.raw()); s.append(&self.data); if let Some(chain_id) = chain_id { s.append(&chain_id); @@ -87,7 +88,7 @@ impl Encodable for EthSignedTransaction { None => s.append(&""), Some(address) => s.append(address), }; - s.append(&self.transaction.value); + s.append(&self.transaction.value.raw()); s.append(&self.transaction.data); s.append(&self.v); s.append(&self.r); @@ -120,7 +121,7 @@ impl Decodable for EthSignedTransaction { } } }; - let value = rlp.val_at(4)?; + let value = Wei::new(rlp.val_at(4)?); let data = rlp.val_at(5)?; let v = rlp.val_at(6)?; let r = rlp.val_at(7)?; @@ -181,7 +182,7 @@ mod tests { to: Some(address_from_arr( &hex::decode("F0109fC8DF283027b6285cc889F5aA624EaC1F55").unwrap() )), - value: U256::from(1000000000), + value: Wei::new_u64(1000000000), data: vec![], } ); diff --git a/src/types.rs b/src/types.rs index c73783d43..4a4a84700 100644 --- a/src/types.rs +++ b/src/types.rs @@ -1,4 +1,4 @@ -use crate::prelude::{Address, String, Vec, H256, U256}; +use crate::prelude::{self, Address, String, Vec, H256, U256}; use borsh::{BorshDeserialize, BorshSerialize}; #[cfg(not(feature = "contract"))] @@ -14,6 +14,60 @@ pub type RawH256 = [u8; 32]; // Unformatted binary data of fixed length. pub type Gas = u64; pub type Balance = u128; +/// Newtype to distinguish balances (denominated in Wei) from other U256 types. +#[derive(Debug, Eq, PartialEq, Copy, Clone, Default)] +pub struct Wei(U256); +impl Wei { + const ETH_TO_WEI: U256 = U256([1_000_000_000_000_000_000, 0, 0, 0]); + + pub const fn zero() -> Self { + Self(U256([0, 0, 0, 0])) + } + + pub fn new(amount: U256) -> Self { + Self(amount) + } + + // Purposely not implementing `From` because I want the call site to always + // say `Wei::`. If `From` is implemented then the caller might write + // `amount.into()` without thinking too hard about the units. Explicitly writing + // `Wei` reminds the developer to think about whether the amount they enter is really + // in units of `Wei` or not. + pub const fn new_u64(amount: u64) -> Self { + Self(U256([amount, 0, 0, 0])) + } + + pub fn from_eth(amount: U256) -> Option { + amount.checked_mul(Self::ETH_TO_WEI).map(Self) + } + + pub fn to_bytes(&self) -> [u8; 32] { + u256_to_arr(&self.0) + } + + pub fn is_zero(&self) -> bool { + self.0.is_zero() + } + + pub fn raw(self) -> U256 { + self.0 + } +} +impl prelude::Sub for Wei { + type Output = Self; + + fn sub(self, other: Self) -> Self::Output { + Self(self.0 - other.0) + } +} +impl prelude::Add for Wei { + type Output = Self; + + fn add(self, other: Self) -> Self::Output { + Self(self.0 + other.0) + } +} + #[derive(BorshSerialize, BorshDeserialize)] pub struct U128(pub u128); @@ -24,14 +78,13 @@ pub const STORAGE_PRICE_PER_BYTE: u128 = 10_000_000_000_000_000_000; // 1e19yN, pub struct InternalMetaCallArgs { pub sender: Address, pub nonce: U256, - pub fee_amount: U256, + pub fee_amount: Wei, pub fee_address: Address, pub contract_address: Address, - pub value: U256, + pub value: Wei, pub input: Vec, } -#[allow(dead_code)] pub fn u256_to_arr(value: &U256) -> [u8; 32] { let mut result = [0u8; 32]; value.to_big_endian(&mut result); @@ -78,4 +131,17 @@ mod tests { "0001ff10".to_string() ); } + + #[test] + fn test_wei_from_u64() { + let x: u64 = rand::random(); + assert_eq!(Wei::new_u64(x).raw().as_u64(), x); + } + + #[test] + fn test_wei_from_eth() { + let eth_amount: u64 = rand::random(); + let wei_amount = U256::from(eth_amount) * U256::from(10).pow(18.into()); + assert_eq!(Wei::from_eth(eth_amount.into()), Some(Wei::new(wei_amount))); + } } diff --git a/tests/test_meta_parsing.rs b/tests/test_meta_parsing.rs index 5a518b323..0552badc3 100644 --- a/tests/test_meta_parsing.rs +++ b/tests/test_meta_parsing.rs @@ -5,16 +5,16 @@ use near_crypto::{InMemorySigner, KeyType, PublicKey, Signature, Signer}; use aurora_engine::meta_parsing::{near_erc712_domain, parse_meta_call, prepare_meta_call_args}; use aurora_engine::parameters::MetaCallArgs; use aurora_engine::prelude::{Address, U256}; -use aurora_engine::types::{keccak, u256_to_arr, InternalMetaCallArgs}; +use aurora_engine::types::{keccak, u256_to_arr, InternalMetaCallArgs, Wei}; pub fn encode_meta_call_function_args( signer: &dyn Signer, chain_id: u64, nonce: U256, - fee_amount: U256, + fee_amount: Wei, fee_address: Address, contract_address: Address, - value: U256, + value: Wei, method_def: &str, args: Vec, ) -> Vec { @@ -47,10 +47,10 @@ pub fn encode_meta_call_function_args( // Add 27 to align eth-sig-util signature format v: 27, nonce: u256_to_arr(&nonce), - fee_amount: u256_to_arr(&fee_amount), + fee_amount: fee_amount.to_bytes(), fee_address: fee_address.0, contract_address: contract_address.0, - value: u256_to_arr(&value), + value: value.to_bytes(), method_def: method_def.to_string(), args, } @@ -84,10 +84,10 @@ fn test_meta_parsing() { &signer, chain_id, U256::from(14), - U256::from(6), + Wei::new_u64(6), Address::from_slice(&[0u8; 20]), signer_addr.clone(), - U256::from(0), + Wei::zero(), "adopt(uint256 petId)", // RLP encode of ["0x09"] hex::decode("c109").unwrap(), @@ -104,10 +104,10 @@ fn test_meta_parsing() { &signer, chain_id, U256::from(14), - U256::from(6), + Wei::new_u64(6), Address::from_slice(&[0u8; 20]), signer_addr.clone(), - U256::from(0), + Wei::zero(), "adopt(uint256 petId,PetObj petObject)PetObj(string petName,address owner)", // RLP encode of ["0x09", ["0x436170734C6F636B", "0x0123456789012345678901234567890123456789"]] hex::decode("e009de88436170734c6f636b940123456789012345678901234567890123456789").unwrap(),