Skip to content

Commit

Permalink
Feat/liquidation checker (#663)
Browse files Browse the repository at this point in the history
* refactor integration tests

* tested liquidation checker

* fix coding style
  • Loading branch information
sparqet authored Jun 15, 2024
1 parent 67d545f commit 35a1adf
Showing 1 changed file with 393 additions and 0 deletions.
393 changes: 393 additions & 0 deletions tests/integration/test_long_integration.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -2092,6 +2092,399 @@ fn test_long_18_close_integration() {
teardown(data_store, market_factory);
}

#[test]
fn test_long_liquidable_market_integration() {
// *********************************************************************************************
// * SETUP *
// *********************************************************************************************
let (
caller_address,
market_factory_address,
role_store_address,
data_store_address,
market_token_class_hash,
market_factory,
role_store,
data_store,
event_emitter,
exchange_router,
deposit_handler,
deposit_vault,
oracle,
order_handler,
order_vault,
reader,
referal_storage,
withdrawal_handler,
withdrawal_vault,
) =
setup();

// *********************************************************************************************
// * TEST LOGIC *
// *********************************************************************************************

// Create a market.
let market = data_store.get_market(create_market(market_factory));

// Set params in data_store
data_store.set_address(keys::fee_token(), market.index_token);
data_store.set_u256(keys::max_swap_path_length(), 5);

// Set max pool amount.
data_store
.set_u256(
keys::max_pool_amount_key(market.market_token, market.long_token),
5000000000000000000000000000000000000000000 //500 000 ETH
);
data_store
.set_u256(
keys::max_pool_amount_key(market.market_token, market.short_token),
2500000000000000000000000000000000000000000000 //250 000 000 USDC
);

let factor_for_deposits: felt252 = keys::max_pnl_factor_for_deposits();
data_store
.set_u256(
keys::max_pnl_factor_key(factor_for_deposits, market.market_token, true),
50000000000000000000000000000000000000000000000
);
let factor_for_withdrawal: felt252 = keys::max_pnl_factor_for_withdrawals();
data_store
.set_u256(
keys::max_pnl_factor_key(factor_for_withdrawal, market.market_token, true),
50000000000000000000000000000000000000000000000
);

oracle.set_primary_prices(market.long_token, 5000);
oracle.set_primary_prices(market.short_token, 1);

'fill the pool'.print();
// Fill the pool.
IERC20Dispatcher { contract_address: market.long_token }
.mint(market.market_token, 50000000000000000000000000000000000000); // 5 ETH
IERC20Dispatcher { contract_address: market.short_token }
.mint(market.market_token, 25000000000000000000000000000000000000000); // 25000 USDC
'filled pool 1'.print();

IERC20Dispatcher { contract_address: market.long_token }
.mint(caller_address, 9999999999999000000); // 9.999 ETH
IERC20Dispatcher { contract_address: market.short_token }
.mint(caller_address, 49999999999999999000000); // 49.999 UDC
'filled account'.print();

// INITIAL LONG TOKEN IN POOL : 5 ETH
// INITIAL SHORT TOKEN IN POOL : 25000 USDC

// TODO Check why we don't need to set pool_amount_key
// // Set pool amount in data_store.
// let mut key = keys::pool_amount_key(market.market_token, contract_address_const::<'ETH'>());

let balance_deposit_vault_before = IERC20Dispatcher { contract_address: market.short_token }
.balance_of(deposit_vault.contract_address);
let balance_caller_ETH = IERC20Dispatcher { contract_address: market.long_token }
.balance_of(caller_address);
let balance_caller_USDC = IERC20Dispatcher { contract_address: market.short_token }
.balance_of(caller_address);

assert(balance_deposit_vault_before == 0, 'balance deposit should be 0');
assert(balance_caller_ETH == 10000000000000000000, 'balanc ETH should be 10 ETH');
assert(balance_caller_USDC == 50000000000000000000000, 'USDC be 50 000 USDC');

// Send token to deposit in the deposit vault (this should be in a multi call with create_deposit)
'get balances'.print();
// start_prank(market.long_token, caller_address);
// IERC20Dispatcher { contract_address: market.long_token }
// .transfer(deposit_vault.contract_address, 5000000000000000000); // 5 ETH

// start_prank(market.short_token, caller_address);
// IERC20Dispatcher { contract_address: market.short_token }
// .transfer(deposit_vault.contract_address, 25000000000000000000000); // 25000 USDC
// 'make transfer'.print();

IERC20Dispatcher { contract_address: market.long_token }
.mint(deposit_vault.contract_address, 50000000000000000000000000000); // 50 000 000 000
IERC20Dispatcher { contract_address: market.short_token }
.mint(deposit_vault.contract_address, 50000000000000000000000000000); // 50 000 000 000
// Create Deposit

let addresss_zero: ContractAddress = 0.try_into().unwrap();

let params = CreateDepositParams {
receiver: caller_address,
callback_contract: addresss_zero,
ui_fee_receiver: addresss_zero,
market: market.market_token,
initial_long_token: market.long_token,
initial_short_token: market.short_token,
long_token_swap_path: Array32Trait::<ContractAddress>::span32(@array![]),
short_token_swap_path: Array32Trait::<ContractAddress>::span32(@array![]),
min_market_tokens: 0,
execution_fee: 0,
callback_gas_limit: 0,
};
'create deposit'.print();

start_roll(deposit_handler.contract_address, 1910);
let key = deposit_handler.create_deposit(caller_address, params);
let first_deposit = data_store.get_deposit(key);

'created deposit'.print();

assert(first_deposit.account == caller_address, 'Wrong account depositer');
assert(first_deposit.receiver == caller_address, 'Wrong account receiver');
assert(first_deposit.initial_long_token == market.long_token, 'Wrong initial long token');
assert(
first_deposit.initial_long_token_amount == 50000000000000000000000000000,
'Wrong initial long token amount'
);
assert(
first_deposit.initial_short_token_amount == 50000000000000000000000000000,
'Wrong init short token amount'
);

let price_params = SetPricesParams { // TODO
signer_info: 1,
tokens: array![contract_address_const::<'ETH'>(), contract_address_const::<'USDC'>()],
compacted_min_oracle_block_numbers: array![1900, 1900],
compacted_max_oracle_block_numbers: array![1910, 1910],
compacted_oracle_timestamps: array![9999, 9999],
compacted_decimals: array![18, 18],
compacted_min_prices: array![4294967346000000], // 50000000, 1000000 compacted
compacted_min_prices_indexes: array![0],
compacted_max_prices: array![4294967346000000], // 50000000, 1000000 compacted
compacted_max_prices_indexes: array![0],
signatures: array![
array!['signatures1', 'signatures2'].span(), array!['signatures1', 'signatures2'].span()
],
price_feed_tokens: array![]
};

start_prank(role_store.contract_address, caller_address);

role_store.grant_role(caller_address, role::ORDER_KEEPER);
role_store.grant_role(caller_address, role::ROLE_ADMIN);
role_store.grant_role(caller_address, role::CONTROLLER);
role_store.grant_role(caller_address, role::MARKET_KEEPER);

'execute deposit'.print();

// Execute Deposit
start_roll(deposit_handler.contract_address, 1915);
deposit_handler.execute_deposit(key, price_params);

'executed deposit'.print();

// let pool_value_info = market_utils::get_pool_value_info(
// data_store,
// market,
// Price { min: 2000, max: 2000 },
// Price { min: 2000, max: 2000 },
// Price { min: 2000, max: 2000 },
// keys::max_pnl_factor_for_deposits(),
// true,
// );

// assert(pool_value_info.pool_value.mag == 42000000000000000000000, 'wrong pool value amount');
// assert(pool_value_info.long_token_amount == 6000000000000000000, 'wrong long token amount');
// assert(pool_value_info.short_token_amount == 30000000000000000000000, 'wrong short token amount');

let not_deposit = data_store.get_deposit(key);
let default_deposit: Deposit = Default::default();
assert(not_deposit == default_deposit, 'Still existing deposit');

let market_token_dispatcher = IMarketTokenDispatcher { contract_address: market.market_token };
let balance_market_token = market_token_dispatcher.balance_of(caller_address);

assert(balance_market_token != 0, 'should receive market token');

let balance_deposit_vault_after = IERC20Dispatcher { contract_address: market.short_token }
.balance_of(deposit_vault.contract_address);

// let pool_value_info = market_utils::get_pool_value_info(
// data_store,
// market,
// Price { min: 5000, max: 5000, },
// Price { min: 5000, max: 5000, },
// Price { min: 1, max: 1, },
// keys::max_pnl_factor_for_deposits(),
// true,
// );

// pool_value_info.pool_value.mag.print(); // 10000 000000000000000000
// pool_value_info.long_token_amount.print(); // 5 000000000000000000
// pool_value_info.short_token_amount.print(); // 25000 000000000000000000

// ************************************* TEST LONG *********************************************

'Begining of LONG TEST'.print();

let key_open_interest = keys::open_interest_key(
market.market_token, contract_address_const::<'ETH'>(), true
);
data_store.set_u256(key_open_interest, 1);
let max_key_open_interest = keys::max_open_interest_key(market.market_token, true);
data_store
.set_u256(
max_key_open_interest, 1000000000000000000000000000000000000000000000000000
); // 1 000 000

// Send token to order_vault in multicall with create_order
start_prank(contract_address_const::<'ETH'>(), caller_address);
IERC20Dispatcher { contract_address: contract_address_const::<'ETH'>() }
.transfer(order_vault.contract_address, 2000000000000000000); // 2ETH

'transfer made'.print();
// Create order_params Struct
let contract_address = contract_address_const::<0>();
start_prank(market.market_token, caller_address);
start_prank(market.long_token, caller_address);
let order_params_long = CreateOrderParams {
receiver: caller_address,
callback_contract: contract_address,
ui_fee_receiver: contract_address,
market: market.market_token,
initial_collateral_token: market.long_token,
swap_path: Array32Trait::<ContractAddress>::span32(@array![]),
size_delta_usd: 10000000000000000000000,
initial_collateral_delta_amount: 2000000000000000000, // 10^18
trigger_price: 5000,
acceptable_price: 5500,
execution_fee: 0,
callback_gas_limit: 0,
min_output_amount: 0,
order_type: OrderType::MarketIncrease(()),
decrease_position_swap_type: DecreasePositionSwapType::NoSwap(()),
is_long: true,
referral_code: 0
};
// Create the swap order.
start_roll(order_handler.contract_address, 1930);
'try to create prder'.print();
start_prank(order_handler.contract_address, caller_address);
let key_long = order_handler.create_order(caller_address, order_params_long);
'long created'.print();
let got_order_long = data_store.get_order(key_long);
// data_store.set_u256(keys::pool_amount_key(market.market_token, contract_address_const::<'USDC'>()), );
// data_store.set_u256(keys::pool_amount_key(market.market_token, contract_address_const::<'ETH'>()), 1000000);
// Execute the swap order.

data_store
.set_u256(
keys::pool_amount_key(market.market_token, contract_address_const::<'USDC'>()),
50000000000000000000000000000
);
data_store
.set_u256(
keys::pool_amount_key(market.market_token, contract_address_const::<'ETH'>()),
50000000000000000000000000000
);

let signatures: Span<felt252> = array![0].span();
let set_price_params = SetPricesParams {
signer_info: 2,
tokens: array![contract_address_const::<'ETH'>(), contract_address_const::<'USDC'>()],
compacted_min_oracle_block_numbers: array![1910, 1910],
compacted_max_oracle_block_numbers: array![1920, 1920],
compacted_oracle_timestamps: array![9999, 9999],
compacted_decimals: array![1, 1],
compacted_min_prices: array![2147483648010000], // 500000, 10000 compacted
compacted_min_prices_indexes: array![0],
compacted_max_prices: array![2147483648010000], // 500000, 10000 compacted
compacted_max_prices_indexes: array![0],
signatures: array![
array!['signatures1', 'signatures2'].span(), array!['signatures1', 'signatures2'].span()
],
price_feed_tokens: array![]
};

let keeper_address = contract_address_const::<'keeper'>();
role_store.grant_role(keeper_address, role::ORDER_KEEPER);

stop_prank(order_handler.contract_address);
start_prank(order_handler.contract_address, keeper_address);
start_roll(order_handler.contract_address, 1935);
// TODO add real signatures check on Oracle Account
order_handler.execute_order_keeper(key_long, set_price_params, keeper_address);
'long position SUCCEEDED'.print();
let position_key = data_store.get_account_position_keys(caller_address, 0, 10);

let position_key_1: felt252 = *position_key.at(0);
let first_position = data_store.get_position(position_key_1);
let market_prices = market_utils::MarketPrices {
index_token_price: Price { min: 8000, max: 8000, },
long_token_price: Price { min: 8000, max: 8000, },
short_token_price: Price { min: 1, max: 1, },
};
'size tokens'.print();
first_position.size_in_tokens.print();
'size in usd'.print();
first_position.size_in_usd.print();
'OKAAAAAYYYYYY'.print();
oracle.set_primary_prices(market.long_token, 6000);
let first_position_after_pump = data_store.get_position(position_key_1);
'size tokens after pump'.print();
first_position_after_pump.size_in_tokens.print();
'size in usd after pump'.print();
first_position_after_pump.size_in_usd.print();

let position_info = reader
.get_position_info(
data_store, referal_storage, position_key_1, market_prices, 0, contract_address, true
);
'pnl'.print();
position_info.base_pnl_usd.mag.print();

// let second_swap_pool_value_info = market_utils::get_pool_value_info(
// data_store,
// market,
// Price { min: 5000, max: 5000, },
// Price { min: 5000, max: 5000, },
// Price { min: 1, max: 1, },
// keys::max_pnl_factor_for_deposits(),
// true,
// );

// second_swap_pool_value_info.pool_value.mag.print();
// second_swap_pool_value_info.long_token_amount.print();
// second_swap_pool_value_info.short_token_amount.print();
// let (position_pnl_usd, uncapped_position_pnl_usd, size_delta_in_tokens) =
// position_utils::get_position_pnl_usd(
// data_store, market, market_prices, first_position, 5000
// );
// position_pnl_usd.mag.print();

// ------------------------Check Liquidation---------------------------
let market_prices_liquidation = market_utils::MarketPrices {
index_token_price: Price { min: 4000, max: 4000, },
long_token_price: Price { min: 4000, max: 4000, },
short_token_price: Price { min: 1, max: 1, },
};

let (is_liquid, why_liquid) = position_utils::is_position_liquiditable(
data_store, referal_storage, first_position, market, market_prices_liquidation, false
);

assert(is_liquid == false, 'position not liquid');

let market_prices_liquidation = market_utils::MarketPrices {
index_token_price: Price { min: 100, max: 100, },
long_token_price: Price { min: 100, max: 100, },
short_token_price: Price { min: 1, max: 1, },
};

let (is_liquid, why_liquid) = position_utils::is_position_liquiditable(
data_store, referal_storage, first_position, market, market_prices_liquidation, false
);

assert(is_liquid == true, 'position liquidable');

// *********************************************************************************************
// * TEARDOWN *
// *********************************************************************************************
teardown(data_store, market_factory);
}

fn create_market(market_factory: IMarketFactoryDispatcher) -> ContractAddress {
// Create a market.
let (index_token, short_token) = deploy_tokens();
Expand Down

0 comments on commit 35a1adf

Please sign in to comment.