Skip to content

Commit

Permalink
disable_multicall_after_delay
Browse files Browse the repository at this point in the history
fix
  • Loading branch information
TAdev0 authored and enitrat committed Jan 1, 2024
1 parent be39631 commit 8585975
Show file tree
Hide file tree
Showing 3 changed files with 55 additions and 8 deletions.
26 changes: 23 additions & 3 deletions contracts/src/tests/test_unruggable_memecoin.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,8 @@ mod memecoin_entrypoints {
IERC20, ERC20ABIDispatcher, ERC20ABIDispatcherTrait
};
use snforge_std::{
declare, ContractClassTrait, start_prank, stop_prank, CheatTarget, start_warp, TxInfoMock
declare, ContractClassTrait, start_prank, stop_prank, CheatTarget, start_warp, stop_warp,
TxInfoMock
};
use starknet::{ContractAddress, contract_address_const};
use unruggable::exchanges::jediswap_adapter::{
Expand All @@ -176,7 +177,8 @@ mod memecoin_entrypoints {
deploy_eth_with_owner, OWNER, NAME, SYMBOL, DEFAULT_INITIAL_SUPPLY, INITIAL_HOLDERS,
INITIAL_HOLDER_1, INITIAL_HOLDER_2, INITIAL_HOLDERS_AMOUNTS, SALT, DefaultTxInfoMock,
deploy_memecoin_through_factory, ETH_ADDRESS, deploy_memecoin_through_factory_with_owner,
JEDI_ROUTER_ADDRESS, MEMEFACTORY_ADDRESS, ALICE, BOB, pow_256, LOCKER_ADDRESS
JEDI_ROUTER_ADDRESS, MEMEFACTORY_ADDRESS, ALICE, BOB, pow_256, LOCKER_ADDRESS,
deploy_and_launch_memecoin, TRANSFER_LIMIT_DELAY
};
use unruggable::tokens::interface::{
IUnruggableMemecoin, IUnruggableMemecoinDispatcher, IUnruggableMemecoinDispatcherTrait
Expand Down Expand Up @@ -283,13 +285,31 @@ mod memecoin_entrypoints {
#[test]
#[should_panic(expected: ('Multi calls not allowed',))]
fn test_transfer_from_multi_call() {
let (memecoin, memecoin_address) = deploy_memecoin_through_factory();
let (memecoin, memecoin_address) = deploy_and_launch_memecoin();

// Transfer token from owner to ALICE() twice - should fail because
// the tx_hash is the same for both calls
start_prank(CheatTarget::One(memecoin.contract_address), INITIAL_HOLDER_1());
let send_amount = memecoin.transfer_from(INITIAL_HOLDER_1(), ALICE(), 0);
start_prank(CheatTarget::One(memecoin.contract_address), INITIAL_HOLDER_2());
let send_amount = memecoin.transfer_from(INITIAL_HOLDER_2(), ALICE(), 0);
}

#[test]
fn test_multi_call_prevention_disallowed_after_delay() {
let (memecoin, memecoin_address) = deploy_and_launch_memecoin();

let launch_timestamp = 1;

// setting block timestamp >= launch_time + transfer_delay. Transfer should succeed
// as multi calls to the same recipient are allowed after the delay
start_warp(
CheatTarget::One(memecoin.contract_address), launch_timestamp + TRANSFER_LIMIT_DELAY + 1
);
start_prank(CheatTarget::One(memecoin.contract_address), INITIAL_HOLDER_1());
let send_amount = memecoin.transfer_from(INITIAL_HOLDER_1(), ALICE(), 0);
start_prank(CheatTarget::One(memecoin.contract_address), INITIAL_HOLDER_2());
let send_amount = memecoin.transfer_from(INITIAL_HOLDER_2(), ALICE(), 0);
}

#[test]
Expand Down
23 changes: 22 additions & 1 deletion contracts/src/tests/utils.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ use core::traits::TryInto;
use openzeppelin::token::erc20::interface::ERC20ABIDispatcher;
use openzeppelin::token::erc20::interface::ERC20ABIDispatcherTrait;
use snforge_std::{
ContractClass, ContractClassTrait, CheatTarget, declare, start_prank, stop_prank, TxInfoMock
ContractClass, ContractClassTrait, CheatTarget, declare, start_prank, stop_prank, TxInfoMock,
start_warp, stop_warp
};
use starknet::ContractAddress;
use unruggable::exchanges::{Exchange, SupportedExchanges, ExchangeTrait};
Expand Down Expand Up @@ -287,6 +288,26 @@ fn deploy_memecoin_through_factory() -> (IUnruggableMemecoinDispatcher, Contract
deploy_memecoin_through_factory_with_owner(OWNER())
}

// Sets the env block timestamp to 1 and launchs the memecoin - so that launched_at is 1
// In this context, the owner of the factory is the address of the snforge test
fn deploy_and_launch_memecoin() -> (IUnruggableMemecoinDispatcher, ContractAddress) {
let owner = starknet::get_contract_address();
let (memecoin, memecoin_address) = deploy_memecoin_through_factory_with_owner(owner);
let eth = ERC20ABIDispatcher { contract_address: ETH_ADDRESS() };

// The amount supplied as liquidity are the amount
// held by the memecoin contract pre-launch
let memecoin_bal_meme = memecoin.balanceOf(memecoin_address);
let memecoin_bal_eth = eth.balanceOf(memecoin_address);

start_prank(CheatTarget::One(JEDI_ROUTER_ADDRESS()), memecoin_address);
start_warp(CheatTarget::One(memecoin_address), 1);
let pool_address = memecoin.launch_memecoin(SupportedExchanges::JediSwap, eth.contract_address);
stop_prank(CheatTarget::One(MEMEFACTORY_ADDRESS()));
stop_warp(CheatTarget::One(memecoin_address));
(memecoin, memecoin_address)
}


impl DefaultTxInfoMock of Default<TxInfoMock> {
fn default() -> TxInfoMock {
Expand Down
14 changes: 10 additions & 4 deletions contracts/src/tokens/memecoin.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -252,7 +252,7 @@ mod UnruggableMemecoin {
// which performs a transferFrom() to send the tokens to the pool.
// Therefore, we need to bypass this validation if the sender is the memecoin contract.
if sender != get_contract_address() {
self.ensure_not_multicall(sender);
self.ensure_not_multicall(recipient);
self.enforce_max_transfer_percentage(sender, recipient, amount);
self.enforce_prelaunch_holders_limit(sender, recipient, amount);
}
Expand Down Expand Up @@ -341,9 +341,15 @@ mod UnruggableMemecoin {
// do multiple transfers when using complex routes.
#[inline(always)]
fn ensure_not_multicall(ref self: ContractState, recipient: ContractAddress) {
let tx_hash: felt252 = get_tx_info().unbox().transaction_hash;
assert(self.tx_hash_tracker.read(recipient) != tx_hash, 'Multi calls not allowed');
self.tx_hash_tracker.write(recipient, tx_hash);
let launch_time = self.launch_time.read();
let transfer_delay = self.transfer_limit_delay.read();
let current_time = get_block_timestamp();

if (current_time < (launch_time + transfer_delay) || launch_time == 0_u64) {
let tx_hash: felt252 = get_tx_info().unbox().transaction_hash;
assert(self.tx_hash_tracker.read(recipient) != tx_hash, 'Multi calls not allowed');
self.tx_hash_tracker.write(recipient, tx_hash);
}
}

/// Checks and allocates the team supply of the memecoin.
Expand Down

0 comments on commit 8585975

Please sign in to comment.