Skip to content

Commit

Permalink
hyp_erc20_collateral_test (#111)
Browse files Browse the repository at this point in the history
* exposed token router impl

* added function signature to support collateral token functions

* collateral test

* formatted

---------

Co-authored-by: Sameer Kumar <[email protected]>
  • Loading branch information
cyberhawk12121 and sameer-nethermind authored Sep 13, 2024
1 parent 02be20d commit 4a9f443
Show file tree
Hide file tree
Showing 3 changed files with 166 additions and 1 deletion.
6 changes: 5 additions & 1 deletion cairo/src/contracts/token/hyp_erc20_collateral.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ pub mod HypErc20Collateral {
use hyperlane_starknet::contracts::client::router_component::RouterComponent;
use hyperlane_starknet::contracts::token::components::{
token_router::{
TokenRouterComponent, TokenRouterComponent::MessageRecipientInternalHookImpl
TokenRouterComponent, TokenRouterComponent::MessageRecipientInternalHookImpl,
TokenRouterTransferRemoteHookDefaultImpl
},
hyp_erc20_collateral_component::{
HypErc20CollateralComponent, HypErc20CollateralComponent::TokenRouterHooksImpl
Expand Down Expand Up @@ -51,6 +52,9 @@ pub mod HypErc20Collateral {
HypErc20CollateralComponent::HypErc20CollateralInternalImpl<ContractState>;
// Upgradeable
impl UpgradeableInternalImpl = UpgradeableComponent::InternalImpl<ContractState>;
// TokenRouter
#[abi(embed_v0)]
impl TokenRouterImpl = TokenRouterComponent::TokenRouterImpl<ContractState>;

#[storage]
struct Storage {
Expand Down
6 changes: 6 additions & 0 deletions cairo/src/tests/token/hyp_erc20/common.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,12 @@ pub fn SYMBOL() -> ByteArray {

#[starknet::interface]
pub trait IHypERC20Test<TContractState> {
// Collateral
fn transfer_from_sender_hook(ref self: TContractState, amount_or_id: u256) -> Bytes;
fn transfer_to_hook(
ref self: TContractState, recipient: ContractAddress, amount: u256, metadata: Bytes
) -> bool;
fn get_wrapped_token(self: @TContractState) -> ContractAddress;
// MailboxClient
fn set_hook(ref self: TContractState, _hook: ContractAddress);
fn set_interchain_security_module(ref self: TContractState, _module: ContractAddress);
Expand Down
155 changes: 155 additions & 0 deletions cairo/src/tests/token/hyp_erc20/hyp_erc20_collateral_test.cairo
Original file line number Diff line number Diff line change
@@ -1 +1,156 @@
use alexandria_bytes::{Bytes, BytesTrait};
use hyperlane_starknet::contracts::client::gas_router_component::{
GasRouterComponent::GasRouterConfig, IGasRouterDispatcher, IGasRouterDispatcherTrait
};
use hyperlane_starknet::contracts::mocks::{
test_post_dispatch_hook::{
ITestPostDispatchHookDispatcher, ITestPostDispatchHookDispatcherTrait
},
mock_mailbox::{IMockMailboxDispatcher, IMockMailboxDispatcherTrait},
test_erc20::{ITestERC20Dispatcher, ITestERC20DispatcherTrait},
test_interchain_gas_payment::{
ITestInterchainGasPaymentDispatcher, ITestInterchainGasPaymentDispatcherTrait
},
mock_eth::{MockEthDispatcher, MockEthDispatcherTrait}
};
use hyperlane_starknet::contracts::token::hyp_erc20_collateral::HypErc20Collateral;
use hyperlane_starknet::tests::setup::{
OWNER, LOCAL_DOMAIN, DESTINATION_DOMAIN, RECIPIENT_ADDRESS, MAILBOX, DESTINATION_MAILBOX,
setup_protocol_fee, setup_mock_hook, PROTOCOL_FEE, INITIAL_SUPPLY, setup_mock_fee_hook,
setup_mock_ism, setup_mock_token
};
use hyperlane_starknet::tests::token::hyp_erc20::common::{
setup, Setup, TOTAL_SUPPLY, DECIMALS, ORIGIN, DESTINATION, TRANSFER_AMT, ALICE, BOB,
perform_remote_transfer_with_emit, perform_remote_transfer_and_gas, E18,
IHypERC20TestDispatcher, IHypERC20TestDispatcherTrait, enroll_remote_router,
enroll_local_router, set_custom_gas_config, REQUIRED_VALUE, GAS_LIMIT
};
use hyperlane_starknet::utils::utils::U256TryIntoContractAddress;
use openzeppelin::token::erc20::interface::{IERC20Dispatcher, IERC20DispatcherTrait};
use snforge_std::{
start_prank, stop_prank, declare, ContractClassTrait, CheatTarget, spy_events, SpyOn
};
use starknet::ContractAddress;

fn setup_hyp_erc20_collateral() -> (IHypERC20TestDispatcher, Setup) {
let setup = setup();
let hyp_erc20_collateral_contract = declare("HypErc20Collateral").unwrap();
let constructor_args: Array<felt252> = array![
setup.local_mailbox.contract_address.into(),
setup.primary_token.contract_address.into(),
ALICE().into(),
setup.noop_hook.contract_address.into(),
setup.primary_token.contract_address.into() // just a placeholder
];

let (collateral_address, _) = hyp_erc20_collateral_contract.deploy(@constructor_args).unwrap();
let collateral = IHypERC20TestDispatcher { contract_address: collateral_address };

// Enroll remote router
let remote_token_address: felt252 = setup.remote_token.contract_address.into();
start_prank(CheatTarget::One(collateral.contract_address), ALICE());
collateral.enroll_remote_router(DESTINATION, remote_token_address.into());
stop_prank(CheatTarget::One(collateral.contract_address));

// Transfer tokens to collateral contract and ALICE
setup.primary_token.transfer(collateral.contract_address, 1000 * E18);
setup.primary_token.transfer(ALICE(), 1000 * E18);
let addr: felt252 = collateral.contract_address.into();
// Enroll remote router for the remote token
setup.remote_token.enroll_remote_router(ORIGIN, addr.into());
(collateral, setup)
}

fn perform_remote_transfer_collateral(
setup: @Setup,
collateral: @IHypERC20TestDispatcher,
msg_value: u256,
extra_gas: u256,
amount: u256,
approve: bool
) {
// Approve
if approve {
start_prank(CheatTarget::One(*setup.primary_token.contract_address), ALICE());
(*setup.primary_token).approve(*collateral.contract_address, amount);
stop_prank(CheatTarget::One(*setup.primary_token.contract_address));
}
// Remote transfer
start_prank(CheatTarget::One(*collateral.contract_address), ALICE());
let bob_felt: felt252 = BOB().into();
let bob_address: u256 = bob_felt.into();
(*collateral)
.transfer_remote(DESTINATION, bob_address, amount, msg_value, Option::None, Option::None);

process_transfers_collateral(setup, collateral, BOB(), amount);

let remote_token = IERC20Dispatcher {
contract_address: (*setup).remote_token.contract_address
};
assert_eq!(remote_token.balance_of(BOB()), amount);

stop_prank(CheatTarget::One(*collateral.contract_address));
}

fn process_transfers_collateral(
setup: @Setup, collateral: @IHypERC20TestDispatcher, recipient: ContractAddress, amount: u256
) {
start_prank(
CheatTarget::One((*setup).remote_token.contract_address),
(*setup).remote_mailbox.contract_address
);
let local_token_address: felt252 = (*collateral).contract_address.into();
let mut message = BytesTrait::new_empty();
message.append_address(recipient);
message.append_u256(amount);
(*setup).remote_token.handle(ORIGIN, local_token_address.into(), message);
stop_prank(CheatTarget::One((*setup).remote_token.contract_address));
}

#[test]
fn test_remote_transfer() {
let (collateral, setup) = setup_hyp_erc20_collateral();
let balance_before = collateral.balance_of(ALICE());
start_prank(CheatTarget::One(collateral.contract_address), ALICE());
perform_remote_transfer_collateral(@setup, @collateral, REQUIRED_VALUE, 0, TRANSFER_AMT, true);
stop_prank(CheatTarget::One(collateral.contract_address));
// Check balance after transfer
assert_eq!(
collateral.balance_of(ALICE()),
balance_before - TRANSFER_AMT,
"Incorrect balance after transfer"
);
}

#[test]
#[should_panic]
fn test_remote_transfer_invalid_allowance() {
let (collateral, setup) = setup_hyp_erc20_collateral();
start_prank(CheatTarget::One(collateral.contract_address), ALICE());
perform_remote_transfer_collateral(@setup, @collateral, REQUIRED_VALUE, 0, TRANSFER_AMT, false);
stop_prank(CheatTarget::One(collateral.contract_address));
}

#[test]
fn test_remote_transfer_with_custom_gas_config() {
let (collateral, setup) = setup_hyp_erc20_collateral();
// Check balance before transfer
let balance_before = collateral.balance_of(ALICE());
start_prank(CheatTarget::One(collateral.contract_address), ALICE());
// Set custom gas config
collateral.set_hook(setup.igp.contract_address);
let config = array![GasRouterConfig { domain: DESTINATION, gas: GAS_LIMIT }];
collateral.set_destination_gas(Option::Some(config), Option::None, Option::None);
// Do a remote transfer
perform_remote_transfer_collateral(
@setup, @collateral, REQUIRED_VALUE, setup.igp.gas_price(), TRANSFER_AMT, true
);

stop_prank(CheatTarget::One(collateral.contract_address));
// Check balance after transfer
assert_eq!(
collateral.balance_of(ALICE()),
balance_before - TRANSFER_AMT,
"Incorrect balance after transfer"
);
}

0 comments on commit 4a9f443

Please sign in to comment.