diff --git a/Scarb.toml b/Scarb.toml index e675827..98afd5e 100644 --- a/Scarb.toml +++ b/Scarb.toml @@ -25,6 +25,21 @@ name = "mainnet" url = "https://free-rpc.nethermind.io/mainnet-juno" block_id.number = "776530" +[[tool.snforge.fork]] +name = "mainnet_prod_fix" +url = "https://free-rpc.nethermind.io/mainnet-juno" +block_id.number = "912858" + +[[tool.snforge.fork]] +name = "mainnet_before_issue_wbtc_strk" +url = "https://free-rpc.nethermind.io/mainnet-juno" +block_id.number = "794907" + +[[tool.snforge.fork]] +name = "mainnet_before_issue_wbtc_usdt" +url = "https://free-rpc.nethermind.io/mainnet-juno" +block_id.number = "808014" + [dev-dependencies] snforge_std = { git = "https://github.com/foundry-rs/starknet-foundry.git", tag = "v0.30.0" } assert_macros = "2.8.2" \ No newline at end of file diff --git a/src/oracle_test.cairo b/src/oracle_test.cairo index 96c8d9f..4b86ec5 100644 --- a/src/oracle_test.cairo +++ b/src/oracle_test.cairo @@ -7,14 +7,15 @@ use ekubo::interfaces::router::{IRouterDispatcher, IRouterDispatcherTrait, Route use ekubo::types::bounds::{Bounds}; use ekubo::types::call_points::{CallPoints}; use ekubo::types::i129::{i129}; -use ekubo::types::keys::{PoolKey}; +use ekubo::types::keys::{PoolKey, PositionKey}; use ekubo_oracle_extension::oracle::{ IOracleDispatcher, IOracleDispatcherTrait, Oracle::{MAX_TICK_SPACING, quote_amount_from_tick, tick_to_price_x128} }; use ekubo_oracle_extension::test_token::{IERC20Dispatcher, IERC20DispatcherTrait}; use snforge_std::{ - declare, DeclareResultTrait, ContractClassTrait, cheat_block_timestamp, CheatSpan, ContractClass + declare, DeclareResultTrait, ContractClassTrait, cheat_block_timestamp, CheatSpan, + cheat_caller_address, ContractClass, replace_bytecode }; use starknet::{get_contract_address, get_block_timestamp, contract_address_const, ContractAddress}; @@ -515,3 +516,499 @@ fn test_quote_amount_from_tick() { assert_eq!(quote_amount_from_tick(100, i129 { mag: 693148, sign: false }), 200); assert_eq!(quote_amount_from_tick(100, i129 { mag: 693148, sign: true }), 49); } + +#[starknet::interface] +pub trait IMigrate { + fn migrate(ref self: TContractState); +} + +#[test] +#[fork("mainnet_before_issue_wbtc_strk")] +fn test_prod_before_issue_wbtc_strk() { + // check the wbtc/strk position 576524 + let result = ekubo_core() + .get_position_with_fees( + PoolKey { + token0: contract_address_const::< + 0x3fe2b97c1fd336e750087d68b9b867997fd64a2661ff3ca5a7c771641e8e7ac + >(), + token1: contract_address_const::< + 0x4718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d + >(), + fee: 3402823669209384634633746074317682114, + tick_spacing: 19802, + extension: contract_address_const::<0>(), + }, + PositionKey { + salt: 576524, + owner: contract_address_const::< + 0x02e0af29598b407c8716b17f6d2795eca1b471413fa03fb145a5e33722184067 + >(), + bounds: Bounds { + lower: i129 { mag: 33009934, sign: false }, + upper: i129 { mag: 33643598, sign: false } + } + } + ); + assert_eq!((result.fees0, result.fees1), (14, 3265127555446091)); + + // starkli call --network mainnet --block 794907 + // 0x00000005dd3D2F4429AF886cD1a3b08289DBcEa99A294197E9eB43b0e0325b4b get_pool_tick_fees_outside + // 0x3fe2b97c1fd336e750087d68b9b867997fd64a2661ff3ca5a7c771641e8e7ac + // 0x4718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d + // 3402823669209384634633746074317682114 19802 0 33009934 0 + + // starkli call --network mainnet + // --block 794907 0x00000005dd3D2F4429AF886cD1a3b08289DBcEa99A294197E9eB43b0e0325b4b + // get_pool_tick_fees_outside 0x3fe2b97c1fd336e750087d68b9b867997fd64a2661ff3ca5a7c771641e8e7ac + // 0x4718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d + // 3402823669209384634633746074317682114 19802 0 33643598 0 + let fees_outside_lower = ekubo_core() + .get_pool_tick_fees_outside( + PoolKey { + token0: contract_address_const::< + 0x3fe2b97c1fd336e750087d68b9b867997fd64a2661ff3ca5a7c771641e8e7ac + >(), + token1: contract_address_const::< + 0x4718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d + >(), + fee: 3402823669209384634633746074317682114, + tick_spacing: 19802, + extension: contract_address_const::<0>(), + }, + i129 { mag: 33009934, sign: false } + ); + assert_eq!((fees_outside_lower.value0, fees_outside_lower.value1), (0, 0)); + let fees_outside_upper = ekubo_core() + .get_pool_tick_fees_outside( + PoolKey { + token0: contract_address_const::< + 0x3fe2b97c1fd336e750087d68b9b867997fd64a2661ff3ca5a7c771641e8e7ac + >(), + token1: contract_address_const::< + 0x4718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d + >(), + fee: 3402823669209384634633746074317682114, + tick_spacing: 19802, + extension: contract_address_const::<0>(), + }, + i129 { mag: 33643598, sign: false } + ); + assert_eq!( + (fees_outside_upper.value0, fees_outside_upper.value1), + ( + 0x00000000000000000000000000000000000000059a4782abf68bca93ec12d6e3, + 0x0000000000000000000000000005ac4ab454ab16e8db8177aab2d24832859efa + ) + ); + + // check wbtc/strk pool liquidity + assert_eq!( + ekubo_core() + .get_pool_liquidity( + PoolKey { + token0: contract_address_const::< + 0x3fe2b97c1fd336e750087d68b9b867997fd64a2661ff3ca5a7c771641e8e7ac + >(), + token1: contract_address_const::< + 0x4718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d + >(), + fee: 3402823669209384634633746074317682114, + tick_spacing: 19802, + extension: contract_address_const::<0>(), + } + ), + 3866056679271 + ); +} + +#[test] +#[fork("mainnet_before_issue_wbtc_usdt")] +fn test_prod_before_issue_wbtc_usdt() { + // check the wbtc/usdt position 36450 + let result = ekubo_core() + .get_position_with_fees( + PoolKey { + token0: contract_address_const::< + 0x3fe2b97c1fd336e750087d68b9b867997fd64a2661ff3ca5a7c771641e8e7ac + >(), + token1: contract_address_const::< + 0x68f5c6a61780768455de69077e07e89787839bf8166decfbf92b645209c0fb8 + >(), + fee: 1020847100762815411640772995208708096, + tick_spacing: 5982, + extension: contract_address_const::<0>(), + }, + PositionKey { + salt: 36450, + owner: contract_address_const::< + 0x02e0af29598b407c8716b17f6d2795eca1b471413fa03fb145a5e33722184067 + >(), + bounds: Bounds { + lower: i129 { mag: 5491476, sign: false }, + upper: i129 { mag: 5730756, sign: false } + } + } + ); + assert_eq!((result.fees0, result.fees1), (6, 2071)); + + // check the wbtc/usdt position 36947 + let result = ekubo_core() + .get_position_with_fees( + PoolKey { + token0: contract_address_const::< + 0x3fe2b97c1fd336e750087d68b9b867997fd64a2661ff3ca5a7c771641e8e7ac + >(), + token1: contract_address_const::< + 0x68f5c6a61780768455de69077e07e89787839bf8166decfbf92b645209c0fb8 + >(), + fee: 1020847100762815411640772995208708096, + tick_spacing: 5982, + extension: contract_address_const::<0>(), + }, + PositionKey { + salt: 36947, + owner: contract_address_const::< + 0x02e0af29598b407c8716b17f6d2795eca1b471413fa03fb145a5e33722184067 + >(), + bounds: Bounds { + lower: i129 { mag: 5491476, sign: false }, + upper: i129 { mag: 5730756, sign: false } + } + } + ); + assert_eq!((result.fees0, result.fees1), (641, 210691)); + + // check wbtc/usdt pool liquidity + assert_eq!( + ekubo_core() + .get_pool_liquidity( + PoolKey { + token0: contract_address_const::< + 0x3fe2b97c1fd336e750087d68b9b867997fd64a2661ff3ca5a7c771641e8e7ac + >(), + token1: contract_address_const::< + 0x68f5c6a61780768455de69077e07e89787839bf8166decfbf92b645209c0fb8 + >(), + fee: 1020847100762815411640772995208708096, + tick_spacing: 5982, + extension: contract_address_const::<0>(), + } + ), + 15958 + ); +} + + +#[test] +#[fork("mainnet_prod_fix")] +fn test_prod_no_fix() { + // check the wbtc/usdt position 36450 + let result = ekubo_core() + .get_position_with_fees( + PoolKey { + token0: contract_address_const::< + 0x3fe2b97c1fd336e750087d68b9b867997fd64a2661ff3ca5a7c771641e8e7ac + >(), + token1: contract_address_const::< + 0x68f5c6a61780768455de69077e07e89787839bf8166decfbf92b645209c0fb8 + >(), + fee: 1020847100762815411640772995208708096, + tick_spacing: 5982, + extension: contract_address_const::<0>(), + }, + PositionKey { + salt: 36450, + owner: contract_address_const::< + 0x02e0af29598b407c8716b17f6d2795eca1b471413fa03fb145a5e33722184067 + >(), + bounds: Bounds { + lower: i129 { mag: 5491476, sign: false }, + upper: i129 { mag: 5730756, sign: false } + } + } + ); + assert_eq!((result.fees0, result.fees1), (21, 187)); + + // check the wbtc/usdt position 36947 + let result = ekubo_core() + .get_position_with_fees( + PoolKey { + token0: contract_address_const::< + 0x3fe2b97c1fd336e750087d68b9b867997fd64a2661ff3ca5a7c771641e8e7ac + >(), + token1: contract_address_const::< + 0x68f5c6a61780768455de69077e07e89787839bf8166decfbf92b645209c0fb8 + >(), + fee: 1020847100762815411640772995208708096, + tick_spacing: 5982, + extension: contract_address_const::<0>(), + }, + PositionKey { + salt: 36947, + owner: contract_address_const::< + 0x02e0af29598b407c8716b17f6d2795eca1b471413fa03fb145a5e33722184067 + >(), + bounds: Bounds { + lower: i129 { mag: 5491476, sign: false }, + upper: i129 { mag: 5730756, sign: false } + } + } + ); + assert_eq!((result.fees0, result.fees1), (2173, 19046)); + + // check the wbtc/strk position 576524 + let result = ekubo_core() + .get_position_with_fees( + PoolKey { + token0: contract_address_const::< + 0x3fe2b97c1fd336e750087d68b9b867997fd64a2661ff3ca5a7c771641e8e7ac + >(), + token1: contract_address_const::< + 0x4718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d + >(), + fee: 3402823669209384634633746074317682114, + tick_spacing: 19802, + extension: contract_address_const::<0>(), + }, + PositionKey { + salt: 576524, + owner: contract_address_const::< + 0x02e0af29598b407c8716b17f6d2795eca1b471413fa03fb145a5e33722184067 + >(), + bounds: Bounds { + lower: i129 { mag: 33009934, sign: false }, + upper: i129 { mag: 33643598, sign: false } + } + } + ); + assert_eq!( + (result.fees0, result.fees1), + (21267654232132584151807308431085273080, 21267654232132584151804513786892888821) + ); + + // check wbtc/usdt pool liquidity + assert_eq!( + ekubo_core() + .get_pool_liquidity( + PoolKey { + token0: contract_address_const::< + 0x3fe2b97c1fd336e750087d68b9b867997fd64a2661ff3ca5a7c771641e8e7ac + >(), + token1: contract_address_const::< + 0x68f5c6a61780768455de69077e07e89787839bf8166decfbf92b645209c0fb8 + >(), + fee: 1020847100762815411640772995208708096, + tick_spacing: 5982, + extension: contract_address_const::<0>(), + } + ), + 11780001 + ); + // check wbtc/strk pool liquidity + assert_eq!( + ekubo_core() + .get_pool_liquidity( + PoolKey { + token0: contract_address_const::< + 0x3fe2b97c1fd336e750087d68b9b867997fd64a2661ff3ca5a7c771641e8e7ac + >(), + token1: contract_address_const::< + 0x4718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d + >(), + fee: 3402823669209384634633746074317682114, + tick_spacing: 19802, + extension: contract_address_const::<0>(), + } + ), + 20088269826 + ); +} + +#[test] +#[fork("mainnet_prod_fix")] +fn test_prod_fix() { + // upgrade to migrate contract + replace_bytecode( + ekubo_core().contract_address, + 0x0359c9d2484a4dfda1664cc8f091a6a4f8199b7d550384ffb1948bdb6e13f2cb.try_into().unwrap() + ) + .expect('failed'); + + // mock call from rev buybacks to #migrate + cheat_caller_address( + ekubo_core().contract_address, + contract_address_const::< + 0x00f2e9a400ba65b13255ef2792612b45d5a20a7a7cf211ffb3f485445022ef72 + >(), + CheatSpan::TargetCalls(1) + ); + IMigrateDispatcher { contract_address: ekubo_core().contract_address }.migrate(); + + // upgrade to new core + replace_bytecode( + ekubo_core().contract_address, + 0x027ecc7248234ceab3de3c5c830cca29d56468d801023bc97337134f5c6e871b.try_into().unwrap() + ) + .expect('failed'); + + // check the wbtc/usdt position 36450 + let result = ekubo_core() + .get_position_with_fees( + PoolKey { + token0: contract_address_const::< + 0x3fe2b97c1fd336e750087d68b9b867997fd64a2661ff3ca5a7c771641e8e7ac + >(), + token1: contract_address_const::< + 0x68f5c6a61780768455de69077e07e89787839bf8166decfbf92b645209c0fb8 + >(), + fee: 1020847100762815411640772995208708096, + tick_spacing: 5982, + extension: contract_address_const::<0>(), + }, + PositionKey { + salt: 36450, + owner: contract_address_const::< + 0x02e0af29598b407c8716b17f6d2795eca1b471413fa03fb145a5e33722184067 + >(), + bounds: Bounds { + lower: i129 { mag: 5491476, sign: false }, + upper: i129 { mag: 5730756, sign: false } + } + } + ); + assert_eq!((result.fees0, result.fees1), (6, 2071)); + + // check the wbtc/usdt position 36947 + let result = ekubo_core() + .get_position_with_fees( + PoolKey { + token0: contract_address_const::< + 0x3fe2b97c1fd336e750087d68b9b867997fd64a2661ff3ca5a7c771641e8e7ac + >(), + token1: contract_address_const::< + 0x68f5c6a61780768455de69077e07e89787839bf8166decfbf92b645209c0fb8 + >(), + fee: 1020847100762815411640772995208708096, + tick_spacing: 5982, + extension: contract_address_const::<0>(), + }, + PositionKey { + salt: 36947, + owner: contract_address_const::< + 0x02e0af29598b407c8716b17f6d2795eca1b471413fa03fb145a5e33722184067 + >(), + bounds: Bounds { + lower: i129 { mag: 5491476, sign: false }, + upper: i129 { mag: 5730756, sign: false } + } + } + ); + assert_eq!((result.fees0, result.fees1), (641, 210691)); + + // check the wbtc/strk position 576524 + let result = ekubo_core() + .get_position_with_fees( + PoolKey { + token0: contract_address_const::< + 0x3fe2b97c1fd336e750087d68b9b867997fd64a2661ff3ca5a7c771641e8e7ac + >(), + token1: contract_address_const::< + 0x4718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d + >(), + fee: 3402823669209384634633746074317682114, + tick_spacing: 19802, + extension: contract_address_const::<0>(), + }, + PositionKey { + salt: 576524, + owner: contract_address_const::< + 0x02e0af29598b407c8716b17f6d2795eca1b471413fa03fb145a5e33722184067 + >(), + bounds: Bounds { + lower: i129 { mag: 33009934, sign: false }, + upper: i129 { mag: 33643598, sign: false } + } + } + ); + assert_eq!((result.fees0, result.fees1), (10, 2676690448320276)); + + assert_eq!( + ekubo_core() + .get_pool_liquidity( + PoolKey { + token0: contract_address_const::< + 0x3fe2b97c1fd336e750087d68b9b867997fd64a2661ff3ca5a7c771641e8e7ac + >(), + token1: contract_address_const::< + 0x68f5c6a61780768455de69077e07e89787839bf8166decfbf92b645209c0fb8 + >(), + fee: 1020847100762815411640772995208708096, + tick_spacing: 5982, + extension: contract_address_const::<0>(), + } + ), + 0 + ); + assert_eq!( + ekubo_core() + .get_pool_liquidity( + PoolKey { + token0: contract_address_const::< + 0x3fe2b97c1fd336e750087d68b9b867997fd64a2661ff3ca5a7c771641e8e7ac + >(), + token1: contract_address_const::< + 0x4718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d + >(), + fee: 3402823669209384634633746074317682114, + tick_spacing: 19802, + extension: contract_address_const::<0>(), + } + ), + 0 + ); + + let fees_outside_lower = ekubo_core() + .get_pool_tick_fees_outside( + PoolKey { + token0: contract_address_const::< + 0x3fe2b97c1fd336e750087d68b9b867997fd64a2661ff3ca5a7c771641e8e7ac + >(), + token1: contract_address_const::< + 0x4718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d + >(), + fee: 3402823669209384634633746074317682114, + tick_spacing: 19802, + extension: contract_address_const::<0>(), + }, + i129 { mag: 33009934, sign: false } + ); + // the lower tick is not changed by the migration, and it records some fees earned below the + // tick in the same block as the errant swap + assert_eq!( + (fees_outside_lower.value0, fees_outside_lower.value1), + (67757426571503971088360988731, 9967746019506406502585138425801173947142540) + ); + let fees_outside_upper = ekubo_core() + .get_pool_tick_fees_outside( + PoolKey { + token0: contract_address_const::< + 0x3fe2b97c1fd336e750087d68b9b867997fd64a2661ff3ca5a7c771641e8e7ac + >(), + token1: contract_address_const::< + 0x4718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d + >(), + fee: 3402823669209384634633746074317682114, + tick_spacing: 19802, + extension: contract_address_const::<0>(), + }, + i129 { mag: 33643598, sign: false } + ); + assert_eq!( + (fees_outside_upper.value0, fees_outside_upper.value1), + ( + 0x00000000000000000000000000000000000000059a4782abf68bca93ec12d6e3, + 0x0000000000000000000000000005ac4ab454ab16e8db8177aab2d24832859efa + ) + ); +}