Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/liquidation checker #663

Merged
merged 17 commits into from
Jun 15, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading