Skip to content

Commit

Permalink
feat(erc20): add more tests & mock evm logging (#3)
Browse files Browse the repository at this point in the history
  • Loading branch information
alexfertel authored Mar 21, 2024
1 parent e0402e9 commit 7cb587a
Show file tree
Hide file tree
Showing 2 changed files with 109 additions and 4 deletions.
92 changes: 89 additions & 3 deletions contracts/token/src/erc20/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -383,7 +383,35 @@ mod tests {
fn reads_balance() {
test_utils::with_storage::<ERC20>(|token| {
let balance = token.balance_of(Address::ZERO);
assert_eq!(balance, U256::ZERO);
assert_eq!(U256::ZERO, balance);

let owner = msg::sender();
let one = U256::from(1);
token._balances.setter(owner).set(one);
let balance = token.balance_of(owner);
assert_eq!(one, balance);
})
}

#[test]
fn transfers() {
test_utils::with_storage::<ERC20>(|token| {
let alice = address!("A11CEacF9aa32246d767FCCD72e02d6bCbcC375d");
let bob = address!("B0B0cB49ec2e96DF5F5fFB081acaE66A2cBBc2e2");

// Alice approves `msg::sender`.
let one = U256::from(1);
token._allowances.setter(alice).setter(msg::sender()).set(one);

// Mint some tokens for Alice.
let two = U256::from(2);
token._balances.setter(alice).set(two);
assert_eq!(two, token.balance_of(alice));

token.transfer_from(alice, bob, one).unwrap();

assert_eq!(one, token.balance_of(alice));
assert_eq!(one, token.balance_of(bob));
})
}

Expand All @@ -410,7 +438,7 @@ mod tests {
}

#[test]
fn transfer_errors_when_insufficient_balance() {
fn transfer_from_errors_when_insufficient_balance() {
test_utils::with_storage::<ERC20>(|token| {
let alice = address!("A11CEacF9aa32246d767FCCD72e02d6bCbcC375d");
let bob = address!("B0B0cB49ec2e96DF5F5fFB081acaE66A2cBBc2e2");
Expand All @@ -427,7 +455,27 @@ mod tests {
}

#[test]
fn transfer_errors_when_insufficient_allowance() {
fn transfer_from_errors_when_invalid_sender() {
test_utils::with_storage::<ERC20>(|token| {
let alice = address!("A11CEacF9aa32246d767FCCD72e02d6bCbcC375d");
let one = U256::from(1);
let result = token.transfer_from(Address::ZERO, alice, one);
assert!(matches!(result, Err(Error::InvalidSender(_))));
})
}

#[test]
fn transfer_from_errors_when_invalid_receiver() {
test_utils::with_storage::<ERC20>(|token| {
let alice = address!("A11CEacF9aa32246d767FCCD72e02d6bCbcC375d");
let one = U256::from(1);
let result = token.transfer_from(alice, Address::ZERO, one);
assert!(matches!(result, Err(Error::InvalidReceiver(_))));
})
}

#[test]
fn transfer_from_errors_when_insufficient_allowance() {
test_utils::with_storage::<ERC20>(|token| {
let alice = address!("A11CEacF9aa32246d767FCCD72e02d6bCbcC375d");
let bob = address!("B0B0cB49ec2e96DF5F5fFB081acaE66A2cBBc2e2");
Expand All @@ -441,4 +489,42 @@ mod tests {
assert!(matches!(result, Err(Error::InsufficientAllowance(_))));
})
}

#[test]
fn reads_allowance() {
test_utils::with_storage::<ERC20>(|token| {
let owner = msg::sender();
let alice = address!("A11CEacF9aa32246d767FCCD72e02d6bCbcC375d");

let allowance = token.allowance(owner, alice);
assert_eq!(U256::ZERO, allowance);

let one = U256::from(1);
token._allowances.setter(owner).setter(alice).set(one);
let allowance = token.allowance(owner, alice);
assert_eq!(one, allowance);
})
}

#[test]
fn approves() {
test_utils::with_storage::<ERC20>(|token| {
let alice = address!("A11CEacF9aa32246d767FCCD72e02d6bCbcC375d");

// `msg::sender` approves Alice.
let one = U256::from(1);
token.approve(alice, one).unwrap();
assert_eq!(one, token._allowances.get(msg::sender()).get(alice));
})
}

#[test]
fn approve_errors_when_invalid_spender() {
test_utils::with_storage::<ERC20>(|token| {
// `msg::sender` approves `Address::ZERO`.
let one = U256::from(1);
let result = token.approve(Address::ZERO, one);
assert!(matches!(result, Err(Error::InvalidSpender(_))));
})
}
}
21 changes: 20 additions & 1 deletion lib/wavm-shims/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
//! Most of the documentation is taken from the [Stylus source].
//!
//! [Stylus source]: https://github.com/OffchainLabs/stylus/blob/484efac4f56fb70f96d4890748b8ec2543d88acd/arbitrator/wasm-libraries/user-host-trait/src/lib.rs
//!
//! We allow unsafe here because safety is guaranteed by the Stylus team.
#![allow(clippy::missing_safety_doc)]
use std::slice;

use storage::{read_bytes32, write_bytes32, STORAGE};
Expand Down Expand Up @@ -76,7 +79,7 @@ pub unsafe extern "C" fn storage_store_bytes32(
STORAGE.lock().unwrap().insert(key, value);
}

///
/// Dummy msg sender set for tests.
pub const MSG_SENDER: &[u8; 42] = b"0xDeaDbeefdEAdbeefdEadbEEFdeadbeEFdEaDbeeF";

/// Gets the address of the account that called the program. For normal
Expand All @@ -95,3 +98,19 @@ pub unsafe extern "C" fn msg_sender(sender: *mut u8) {
let addr = const_hex::const_decode_to_array::<20>(MSG_SENDER).unwrap();
std::ptr::copy(addr.as_ptr(), sender, 20);
}

/// Emits an EVM log with the given number of topics and data, the first bytes
/// of which should be the 32-byte-aligned topic data. The semantics are
/// equivalent to that of the EVM's [`LOG0`], [`LOG1`], [`LOG2`], [`LOG3`], and
/// [`LOG4`] opcodes based on the number of topics specified. Requesting more
/// than `4` topics will induce a revert.
///
/// [`LOG0`]: https://www.evm.codes/#a0
/// [`LOG1`]: https://www.evm.codes/#a1
/// [`LOG2`]: https://www.evm.codes/#a2
/// [`LOG3`]: https://www.evm.codes/#a3
/// [`LOG4`]: https://www.evm.codes/#a4
#[no_mangle]
pub unsafe extern "C" fn emit_log(_: *const u8, _: usize, _: usize) {
// No-op: we don't check for events in our unit-tests.
}

0 comments on commit 7cb587a

Please sign in to comment.