diff --git a/.gitignore b/.gitignore index 5e0db7a..e551687 100644 --- a/.gitignore +++ b/.gitignore @@ -18,6 +18,7 @@ node_modules/ .*.catchup_number .*.catchups_numbers dist +.next scripts/mainnet.pairs-catchups.sh scripts/testnet.pairs-catchups.sh diff --git a/package.json b/package.json index 2ad7224..913a235 100644 --- a/package.json +++ b/package.json @@ -23,5 +23,6 @@ "@types/jest": "^29.5.12", "jest": "^29.7.0", "ts-jest": "^29.1.2" - } + }, + "packageManager": "yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e" } diff --git a/programs/soroswap/Cargo.lock b/programs/soroswap/Cargo.lock index 2c3ea3f..634e4bc 100644 --- a/programs/soroswap/Cargo.lock +++ b/programs/soroswap/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] name = "android-tzdata" @@ -308,9 +308,9 @@ checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2" [[package]] name = "ecdsa" -version = "0.16.9" +version = "0.16.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" +checksum = "0997c976637b606099b9985693efa3581e84e41f5c11ba5255f88711058ad428" dependencies = [ "der", "digest", @@ -421,9 +421,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.15" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +checksum = "fe9006bed769170c11f845cf00c7c1e9092aeb3f268e007c3e760ac68008070f" dependencies = [ "cfg-if 1.0.0", "js-sys", @@ -587,9 +587,9 @@ dependencies = [ [[package]] name = "k256" -version = "0.13.3" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "956ff9b67e26e1a6a866cb758f12c6f8746208489e3e4a4b5580802f2f0a587b" +checksum = "cadb76004ed8e97623117f3df85b17aaa6626ab0b0831e6573f104df16cd1bcc" dependencies = [ "cfg-if 1.0.0", "ecdsa", @@ -638,10 +638,11 @@ checksum = "8452105ba047068f40ff7093dd1d9da90898e63dd61736462e9cdda6a90ad3c3" [[package]] name = "num-bigint" -version = "0.4.6" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" +checksum = "608e7659b5c3d7cba262d894801b9ec9d00de989e8a82bd4bef91d08da45cdc0" dependencies = [ + "autocfg", "num-integer", "num-traits", ] @@ -654,9 +655,9 @@ checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" [[package]] name = "num-derive" -version = "0.4.2" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" +checksum = "cfb77679af88f8b125209d354a202862602672222e7f2313fdd6dc349bad4712" dependencies = [ "proc-macro2", "quote", @@ -665,18 +666,19 @@ dependencies = [ [[package]] name = "num-integer" -version = "0.1.46" +version = "0.1.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" dependencies = [ + "autocfg", "num-traits", ] [[package]] name = "num-traits" -version = "0.2.19" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" dependencies = [ "autocfg", ] @@ -777,9 +779,9 @@ dependencies = [ [[package]] name = "prettyplease" -version = "0.2.22" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "479cf940fbbb3426c32c5d5176f62ad57549a0bb84773423ba8be9d089f5faba" +checksum = "ae005bd773ab59b4725093fd7df83fd7892f7d8eafb48dbd7de6e024e4215f9d" dependencies = [ "proc-macro2", "syn", @@ -796,18 +798,18 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.86" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" +checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.37" +version = "1.0.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" +checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" dependencies = [ "proc-macro2", ] @@ -883,9 +885,9 @@ checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" [[package]] name = "sec1" -version = "0.7.3" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" +checksum = "f0aec48e813d6b90b15f0b8948af3c63483992dee44c03e9930b3eebdabe046e" dependencies = [ "base16ct", "der", @@ -902,18 +904,18 @@ checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" [[package]] name = "serde" -version = "1.0.210" +version = "1.0.192" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a" +checksum = "bca2a08484b285dcb282d0f67b26cadc0df8b19f8c12502c13d966bf9482f001" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.210" +version = "1.0.192" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" +checksum = "d6c7207fbec9faa48073f3e3074cbe553af6ea512d7c21ba46e434e70ea9fbc1" dependencies = [ "proc-macro2", "quote", @@ -922,12 +924,11 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.128" +version = "1.0.108" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ff5456707a1de34e7e37f2a6fd3d3f808c318259cbd01ab6377795054b483d8" +checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b" dependencies = [ "itoa", - "memchr", "ryu", "serde", ] @@ -991,9 +992,9 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" [[package]] name = "signature" -version = "2.2.0" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" +checksum = "5e1788eed21689f9cf370582dfc467ef36ed9c707f073528ddafa8d83e3b8500" dependencies = [ "digest", "rand_core", @@ -1007,9 +1008,9 @@ checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" [[package]] name = "soroban-builtin-sdk-macros" -version = "21.2.1" +version = "21.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f57a68ef8777e28e274de0f3a88ad9a5a41d9a2eb461b4dd800b086f0e83b80" +checksum = "44877373b3dc6c662377cb1600e3a62706d75e484b6064f9cd22e467c676b159" dependencies = [ "itertools", "proc-macro2", @@ -1019,9 +1020,9 @@ dependencies = [ [[package]] name = "soroban-env-common" -version = "21.2.1" +version = "21.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fd1c89463835fe6da996318156d39f424b4f167c725ec692e5a7a2d4e694b3d" +checksum = "590add16843a61b01844e19e89bccaaee6aa21dc76809017b0662c17dc139ee9" dependencies = [ "crate-git-revision", "ethnum", @@ -1037,9 +1038,9 @@ dependencies = [ [[package]] name = "soroban-env-guest" -version = "21.2.1" +version = "21.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6bfb2536811045d5cd0c656a324cbe9ce4467eb734c7946b74410d90dea5d0ce" +checksum = "05ec8dc43acdd6c7e7b371acf44fc1a7dac24934ae3b2f05fafd618818548176" dependencies = [ "soroban-env-common", "static_assertions", @@ -1047,9 +1048,9 @@ dependencies = [ [[package]] name = "soroban-env-host" -version = "21.2.1" +version = "21.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b7a32c28f281c423189f1298960194f0e0fc4eeb72378028171e556d8cd6160" +checksum = "4e25aaffe0c62eb65e0e349f725b4b8b13ad0764d78a15aab5bbccb5c4797726" dependencies = [ "curve25519-dalek", "ecdsa", @@ -1079,9 +1080,9 @@ dependencies = [ [[package]] name = "soroban-env-macros" -version = "21.2.1" +version = "21.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "242926fe5e0d922f12d3796cd7cd02dd824e5ef1caa088f45fce20b618309f64" +checksum = "3e16b761459fdf3c4b62b24df3941498d14e5246e6fadfb4774ed8114d243aa4" dependencies = [ "itertools", "proc-macro2", @@ -1094,9 +1095,9 @@ dependencies = [ [[package]] name = "soroban-ledger-snapshot" -version = "21.6.0" +version = "21.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07a2c3aeb3dba21530133f7f1dc533f53d96abff0df6497a5a2fad8f0fbda200" +checksum = "a46f8b134b1e0b517f70d24dd72399cd263fd18c3c7cfcb5e56ffc6de9dad0c3" dependencies = [ "serde", "serde_json", @@ -1108,9 +1109,9 @@ dependencies = [ [[package]] name = "soroban-sdk" -version = "21.6.0" +version = "21.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cab66a39d18a5d8ed60df8cb77fc51067ef45a69af3c8fec52b6bc3bf7190351" +checksum = "994cc1c7ad1b2f09a2e803f3b5d0c9f2846ab6b181693ffbe2e1101d6624a6f0" dependencies = [ "bytes-lit", "rand", @@ -1125,9 +1126,9 @@ dependencies = [ [[package]] name = "soroban-sdk-macros" -version = "21.6.0" +version = "21.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d92e9fb43bc3ca5180ff7f115156e732817fe27f8328787991c5eb38b30c26c" +checksum = "6f24c6b0c46e41852a8603bb32d43cf6a4046ce65483f6383903ec653118cd90" dependencies = [ "crate-git-revision", "darling", @@ -1261,9 +1262,9 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "syn" -version = "2.0.77" +version = "2.0.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f35bcdf61fd8e7be6caf75f429fdca8beb3ed76584befb503b1569faee373ed" +checksum = "23e78b90f2fcf45d3e842032ce32e3f2d1545ba6636271dcbf24fa306d87be7a" dependencies = [ "proc-macro2", "quote", @@ -1272,18 +1273,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.63" +version = "1.0.55" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724" +checksum = "6e3de26b0965292219b4287ff031fcba86837900fe9cd2b34ea8ad893c0953d2" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.63" +version = "1.0.55" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261" +checksum = "268026685b2be38d7103e9e507c938a1fcb3d7e6eb15e87870b617bf37b6d581" dependencies = [ "proc-macro2", "quote", diff --git a/programs/soroswap/src/lib.rs b/programs/soroswap/src/lib.rs index a49810c..d2b47b6 100644 --- a/programs/soroswap/src/lib.rs +++ b/programs/soroswap/src/lib.rs @@ -5,6 +5,7 @@ use zephyr_sdk::{prelude::*, soroban_sdk::{xdr::{ScVal, Hash }, String as Soroba pub mod router; pub mod factory; pub mod pairs; +pub mod providers; #[derive(DatabaseDerive, Clone)] #[with_name("ssw_rt_ev")] @@ -38,6 +39,15 @@ struct ReservesChangeTable { timestamp: ScVal, } +#[derive(DatabaseDerive, Clone)] +#[with_name("ssw_prov")] +struct LiquidityProviderTable { + provider_address: ScVal, + pool_address: ScVal, + shares: ScVal, + percentage: ScVal, +} + #[test] fn test() { let factory_address_str: &'static str = env!("SOROSWAP_FACTORY"); @@ -101,9 +111,10 @@ pub extern "C" fn on_close() { } + providers::events::handle_contract_events(&env, contract_events_with_txhash.clone()); + env.log().debug(format!("After pairs_rows iteration"), None); - } diff --git a/programs/soroswap/src/providers/events.rs b/programs/soroswap/src/providers/events.rs new file mode 100644 index 0000000..8daa612 --- /dev/null +++ b/programs/soroswap/src/providers/events.rs @@ -0,0 +1,150 @@ +use zephyr_sdk::{ + prelude::*, + soroban_sdk::{ + Symbol, + Address, + }, + EnvClient, + PrettyContractEvent +}; +use crate::router::types; +use crate::LiquidityProviderTable; +use crate::PairsTable; +use crate::ScVal; + +pub(crate) fn get_pool_total_supply(env: &EnvClient, pool_address: &Address) -> i128 { + let rows: Vec = env.read_filter() + .column_equal_to_xdr("address", &env.to_scval(pool_address.clone())) + .read() + .unwrap_or_default(); + + if !rows.is_empty() { + let pair = &rows[0]; + // Get reserve values + let reserve_a: i128 = env.from_scval(&pair.reserve_a); + let reserve_b: i128 = env.from_scval(&pair.reserve_b); + if reserve_a > 0 || reserve_b > 0 { + return reserve_a + reserve_b; + } + } + 0 +} + +pub(crate) fn get_provider_data(env: &EnvClient, data: &ScVal, event_type: &str) -> LiquidityProviderTable { + if event_type == "add" { + let values: types::AddLiquidityEvent = env.from_scval(data); + let total_supply = get_pool_total_supply(env, &values.pair); + + // Calculate percentage (scaled by 1_000_000 for precision) + let percentage = if total_supply > 0 { + ((values.liquidity as f64) / (total_supply as f64) * 1_000_000.0) as i128 + } else { + 1_000_000 // First provider = 100% + }; + + LiquidityProviderTable { + provider_address: env.to_scval(values.to.clone()), + pool_address: env.to_scval(values.pair.clone()), + shares: env.to_scval(values.liquidity.clone()), + percentage: env.to_scval(percentage), + } + } else { + let values: types::RemoveLiquidityEvent = env.from_scval(data); + let total_supply = get_pool_total_supply(env, &values.pair); + + let percentage = if total_supply > values.liquidity { + ((values.liquidity as f64) / (total_supply as f64) * 1_000_000.0) as i128 + } else { + 0 // removing all liquidity + }; + + LiquidityProviderTable { + provider_address: env.to_scval(values.to.clone()), + pool_address: env.to_scval(values.pair.clone()), + shares: env.to_scval(values.liquidity.clone()), + percentage: env.to_scval(percentage), + } + } +} + +pub(crate) fn handle_contract_events(env: &EnvClient, contract_events: Vec<(PrettyContractEvent, [u8; 32])>) { + for (event, _txhash) in contract_events { + let action_result = env.try_from_scval::(&event.topics[1]); + + match action_result { + Ok(action) => { + let data = &event.data; + if action == Symbol::new(&env.soroban(), "add") { + env.log().debug( + format!("Event captured: add liquidity for provider"), + None, + ); + + let table = get_provider_data(&env, data, "add"); + + let rows: Vec = env.read_filter() + .column_equal_to_xdr("provider_address", &table.provider_address) + .column_equal_to_xdr("pool_address", &table.pool_address) + .read() + .unwrap_or_default(); + + if !rows.is_empty() { + let update = env.update() + .column_equal_to_xdr("provider_address", &table.provider_address) + .column_equal_to_xdr("pool_address", &table.pool_address) + .execute(&table); + + if update.is_err() { + env.log().error( + format!("Error updating provider: {:?}", update.err()), + None, + ); + } + } else { + table.put(&env); + } + } else if action == Symbol::new(&env.soroban(), "remove") { + env.log().debug( + format!("Event captured: remove liquidity for provider"), + None, + ); + + let table = get_provider_data(&env, data, "remove"); + + let shares: i128 = env.from_scval(&table.shares); + if shares > 0 { + // Update if there are still shares + let update = env.update() + .column_equal_to_xdr("provider_address", &table.provider_address) + .column_equal_to_xdr("pool_address", &table.pool_address) + .execute(&table); + + if update.is_err() { + env.log().error( + format!("Error updating provider: {:?}", update.err()), + None, + ); + } + } else { + // If shares are 0, update it to show 0 shares and 0 percentage + let update = env.update() + .column_equal_to_xdr("provider_address", &table.provider_address) + .column_equal_to_xdr("pool_address", &table.pool_address) + .execute(&table); + + if update.is_err() { + env.log().error( + format!("Error updating provider with zero shares: {:?}", update.err()), + None, + ); + } + } + } + }, + Err(e) => { + env.log().debug(format!("Failed to convert to Symbol: {:?}", e), None); + env.log().debug(format!("Failed with event: {:?}", event), None); + } + } + } +} \ No newline at end of file diff --git a/programs/soroswap/src/providers/mod.rs b/programs/soroswap/src/providers/mod.rs new file mode 100644 index 0000000..6226263 --- /dev/null +++ b/programs/soroswap/src/providers/mod.rs @@ -0,0 +1 @@ +pub mod events; \ No newline at end of file diff --git a/programs/soroswap/src/providers/types.rs b/programs/soroswap/src/providers/types.rs new file mode 100644 index 0000000..cc0872a --- /dev/null +++ b/programs/soroswap/src/providers/types.rs @@ -0,0 +1,19 @@ +pub struct AddLiquidityEvent { + pub token_a: Address, + pub token_b: Address, + pub pair: Address, + pub amount_a: i128, + pub amount_b: i128, + pub to: Address, + pub liquidity: i128, +} + +pub struct RemoveLiquidityEvent { + pub token_a: Address, + pub token_b: Address, + pub pair: Address, + pub amount_a: i128, + pub amount_b: i128, + pub to: Address, + pub liquidity: i128, +} \ No newline at end of file diff --git a/programs/soroswap/zephyr.toml b/programs/soroswap/zephyr.toml index 1f58269..eae1b24 100644 --- a/programs/soroswap/zephyr.toml +++ b/programs/soroswap/zephyr.toml @@ -85,5 +85,25 @@ name = "timestamp" col_type = "BYTEA" +#Soroswap Providers table + +[[tables]] +name = "ssw_prov" + +[[tables.columns]] +name = "provider_address" +col_type = "BYTEA" + +[[tables.columns]] +name = "pool_address" +col_type = "BYTEA" + +[[tables.columns]] +name = "shares" +col_type = "BYTEA" + +[[tables.columns]] +name = "percentage" +col_type = "BYTEA" diff --git a/scripts/__tests__/providers.test.ts b/scripts/__tests__/providers.test.ts new file mode 100644 index 0000000..c923569 --- /dev/null +++ b/scripts/__tests__/providers.test.ts @@ -0,0 +1,50 @@ +import { zephyrTableToGraphQLParser } from 'mercury-sdk'; +import { getProviders } from '../utils/get-providers'; +import { getZephyrTable } from '../utils/get-table'; + +test('soroswap providers in MAINNET return non empty array', async () => { + let providersTable = getZephyrTable('ssw_prov', 'MAINNET'); + const zephyrTableGraphQL = zephyrTableToGraphQLParser(providersTable); + const providers = await getProviders(zephyrTableGraphQL.address, 'MAINNET'); + expect(providers).toBeDefined(); + expect(providers.length).toBeGreaterThan(0); +}); + +test('soroswap providers in TESTNET return non empty array', async () => { + let providersTable = getZephyrTable('ssw_prov', 'TESTNET'); + const zephyrTableGraphQL = zephyrTableToGraphQLParser(providersTable); + const providers = await getProviders(zephyrTableGraphQL.address, 'TESTNET'); + expect(providers).toBeDefined(); + expect(providers.length).toBeGreaterThan(0); +}); + +test('Provider percentages are calculated correctly', async () => { + let providersTable = getZephyrTable('ssw_prov', 'MAINNET'); + const zephyrTableGraphQL = zephyrTableToGraphQLParser(providersTable); + const providers = await getProviders(zephyrTableGraphQL.address, 'MAINNET'); + + const poolAddress = providers[0].poolAddress; + const poolProviders = providers.filter((p) => p.poolAddress === poolAddress); + + // Sum of all percentages should be less than or equal to 100% + const totalPercentage = poolProviders.reduce( + (sum, provider) => sum + Number(provider.percentage), + 0 + ); + expect(totalPercentage).toBeLessThanOrEqual(1_000_000); +}); + +test('Provider records are unique per pool', async () => { + let providersTable = getZephyrTable('ssw_prov', 'TESTNET'); + const zephyrTableGraphQL = zephyrTableToGraphQLParser(providersTable); + const providers = await getProviders(zephyrTableGraphQL.address, 'TESTNET'); + + // Check for duplicate provider-pool combinations + const combinations = new Set(); + providers.forEach((provider) => { + const key = `${provider.providerAddress}-${provider.poolAddress}`; + combinations.add(key); + }); + + expect(combinations.size).toBe(providers.length); +}); diff --git a/scripts/deploy.sh b/scripts/deploy.sh index 57a9504..11227d9 100644 --- a/scripts/deploy.sh +++ b/scripts/deploy.sh @@ -1,8 +1,9 @@ #!/bin/bash # Check if protocol, network and dev/prod arguments are provided -if [ $# -ne 3 ]; then - echo "Usage: $0 [protocol] [network] [dev|prod]" +if [ $# -lt 3 ] || [ $# -gt 4 ]; then + echo "Usage: $0 [protocol] [network] [dev|prod] [force]" + echo "force parameter is optional" exit 1 fi @@ -154,6 +155,8 @@ if [ "$protocol" == "soroswap" ]; then echo zephyr_table_0 $zephyr_table_0 echo zephyr_table_1 $zephyr_table_1 echo zephyr_table_2 $zephyr_table_2 + echo zephyr_table_3 $zephyr_table_3 + # first table is events jq --arg table "$zephyr_table_0" '.soroswap_events = $table' "$zephyr_programs_addresses_file" > tmp.$$.json @@ -163,9 +166,13 @@ if [ "$protocol" == "soroswap" ]; then jq --arg table "$zephyr_table_1" '.soroswap_pairs = $table' "$zephyr_programs_addresses_file" > tmp.$$.json mv tmp.$$.json "$zephyr_programs_addresses_file" - # second table is rsv_ch + # third table is rsv_ch jq --arg table "$zephyr_table_2" '.soroswap_rsv_ch = $table' "$zephyr_programs_addresses_file" > tmp.$$.json mv tmp.$$.json "$zephyr_programs_addresses_file" + + # fourth table is rsv_ch + jq --arg table "$zephyr_table_3" '.soroswap_providers = $table' "$zephyr_programs_addresses_file" > tmp.$$.json + mv tmp.$$.json "$zephyr_programs_addresses_file" echo New $protocol $network zephyr tables file: cat $zephyr_programs_addresses_file diff --git a/scripts/utils/get-providers.ts b/scripts/utils/get-providers.ts new file mode 100644 index 0000000..21911a2 --- /dev/null +++ b/scripts/utils/get-providers.ts @@ -0,0 +1,50 @@ +import * as StellarSdk from '@stellar/stellar-sdk'; +import { getMercuryInstance } from './mercury'; + +interface Provider { + providerAddress: string; + poolAddress: string; + shares: string; + percentage: string; +} + +const parseValue = (value: any) => { + const scval = StellarSdk.xdr.ScVal.fromXDR(value, 'base64'); + return StellarSdk.scValToNative(scval); +}; + +export const getProviders = async ( + tableName: string, + network: 'MAINNET' | 'TESTNET' +) => { + const mercuryInstance = getMercuryInstance(network); + + const res = await mercuryInstance.getCustomQuery({ + request: `query Query { + events: ${tableName} { + data: nodes { + providerAddress + poolAddress + shares + percentage + } + } + }`, + }); + + if (res.ok) { + const providers = res.data.events.data.map((d: any) => { + let n: any = {}; + + for (let key in d) { + n[key] = parseValue(d[key]); + } + + return n; + }); + + return providers as Provider[]; + } + + return []; +}; diff --git a/server/src/zephyr/queries/getAllProviders.ts b/server/src/zephyr/queries/getAllProviders.ts new file mode 100644 index 0000000..1b24fa9 --- /dev/null +++ b/server/src/zephyr/queries/getAllProviders.ts @@ -0,0 +1,10 @@ +export const GET_ALL_PROVIDERS = (tableName: string) => `query Query { + events: ${tableName} { + data: nodes { + providerAddress + poolAddress + shares + percentage + } + } + }`; diff --git a/server/src/zephyr/tables.ts b/server/src/zephyr/tables.ts index 6bb0af6..84d42e7 100644 --- a/server/src/zephyr/tables.ts +++ b/server/src/zephyr/tables.ts @@ -6,6 +6,7 @@ export interface ZephyrTables { soroswap_rsv_ch: string; phoenix_pairs: string; aqua_pairs: string; + soroswap_providers:string; } const parseZephyrAddress = (address: string) => { @@ -41,6 +42,7 @@ export const fetchZephyrTables = async ({ network }: ApiNetwork) => { soroswap_rsv_ch: parseZephyrAddress(data.soroswap_rsv_ch), phoenix_pairs: parseZephyrAddress(data.phoenix_pairs), aqua_pairs: parseZephyrAddress(data.aqua_pairs), + soroswap_providers: parseZephyrAddress(data.soroswap_providers), }; return response; }