From bd1a3b69ba6998189ba7e34043a8e83a3b000aff Mon Sep 17 00:00:00 2001 From: Piotr Gesicki Date: Fri, 8 Dec 2023 01:41:51 +0100 Subject: [PATCH 1/7] feat: add usdc noble support (balances, stats, pool) --- app/public/images/noble.png | Bin 0 -> 11603 bytes app/public/images/tokens/NOBLE.svg | 210 ++++++++++++++++++ .../services/DataService/DataService.ts | 3 +- app/src/hooks/useChangeLog.ts | 3 +- app/src/hooks/usePoolStats.ts | 44 ++-- app/src/views/PoolPage/PoolPage.tsx | 6 +- app/src/views/PoolPage/usePoolPageData.tsx | 84 ++++--- app/src/views/StatsPage/useStatsPageData.ts | 8 +- app/tsconfig.json | 1 + core/src/clients/chains/NobleChain.ts | 13 ++ core/src/clients/chains/_BaseChain.ts | 5 +- core/src/clients/index.ts | 2 + .../wallets/cosmos/CosmosWalletProvider.ts | 16 +- core/src/config/chains/index.ts | 2 + core/src/config/chains/noble/index.ts | 12 + core/src/config/chains/noble/noble-mainnet.ts | 58 +++++ .../sifchain/assets.sifchain.mainnet.json | 18 ++ core/src/entities/Network.ts | 1 + yarn.lock | 6 +- 19 files changed, 419 insertions(+), 73 deletions(-) create mode 100644 app/public/images/noble.png create mode 100644 app/public/images/tokens/NOBLE.svg create mode 100644 core/src/clients/chains/NobleChain.ts create mode 100644 core/src/config/chains/noble/index.ts create mode 100644 core/src/config/chains/noble/noble-mainnet.ts diff --git a/app/public/images/noble.png b/app/public/images/noble.png new file mode 100644 index 0000000000000000000000000000000000000000..16b044b63cacce413e137158c5af0d7656f8730d GIT binary patch literal 11603 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 R%ZUI0002ovPDHLkV1nuMef$6b literal 0 HcmV?d00001 diff --git a/app/public/images/tokens/NOBLE.svg b/app/public/images/tokens/NOBLE.svg new file mode 100644 index 000000000..dee55030e --- /dev/null +++ b/app/public/images/tokens/NOBLE.svg @@ -0,0 +1,210 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/business/services/DataService/DataService.ts b/app/src/business/services/DataService/DataService.ts index 325d5f8be..8a3bb7610 100644 --- a/app/src/business/services/DataService/DataService.ts +++ b/app/src/business/services/DataService/DataService.ts @@ -159,7 +159,8 @@ export default class DataService { "tokenStats", () => fetchJSON( - `${this.baseUrl}/asset/tokenStatsPMTP`, + // `${this.baseUrl}/asset/tokenStatsPMTP`, + "https://proxies.sifchain.finance/api/vanir/betanet/beta/asset/tokenStatsPMTP", ), 60000 * 5, // cache for 5 minutes ); diff --git a/app/src/hooks/useChangeLog.ts b/app/src/hooks/useChangeLog.ts index 0ce295226..eb0285531 100644 --- a/app/src/hooks/useChangeLog.ts +++ b/app/src/hooks/useChangeLog.ts @@ -14,7 +14,8 @@ async function fetchChangelogData() { ? `v${VITE_APP_SHA}` : VITE_APP_SHA; - const data = await fetch(`${CHANGES_SERVER_URL}/api/changes/${tag}`).then( + const data = await fetch(`${CHANGES_SERVER_URL}/api/changes/2.14.9`).then( + // const data = await fetch(`${CHANGES_SERVER_URL}/api/changes/${tag}`).then( (res) => res.json() as Promise, ); diff --git a/app/src/hooks/usePoolStats.ts b/app/src/hooks/usePoolStats.ts index 5fb9bcbd5..790d13618 100644 --- a/app/src/hooks/usePoolStats.ts +++ b/app/src/hooks/usePoolStats.ts @@ -14,6 +14,7 @@ export interface PoolStatsResponseData { } export interface PoolStat { + denom: string; symbol: string; priceToken: number; poolDepth: number; @@ -130,8 +131,8 @@ export function usePoolStats() { poolStatsRes.data.value?.poolData.pools?.forEach((poolStat) => { const asset = - assetLookup[poolStat.symbol.toLowerCase()] || - assetLookup[poolStat.symbol]; + assetLookup[poolStat.denom.toLowerCase()] || + assetLookup[poolStat.denom]; if (!asset) { if (!hasLoggedError[poolStat.symbol]) { @@ -154,23 +155,28 @@ export function usePoolStats() { // poolStats endpoint might not have data for EVERY pool that exists // in store.pools. so use store.pools as source of truth for which pools // exist, then if poolStats doesn't have data default to empty. - const pools = Object.values(store.pools).map((pool) => ({ - ...pool, - rowanUSD: poolStatsRes.data.value?.rowanUSD || 0, - })); - return pools.map((pool) => { - const [, externalAssetAmount] = pool.amounts; - return ( - poolStatLookup[externalAssetAmount.asset.symbol] || { - symbol: externalAssetAmount.asset.symbol, - priceToken: null, - rowanUSD: null, - poolDepth: null, - volume: null, - arb: null, - } - ); - }); + // const pools = Object.values(store.pools).map((pool) => ({ + // ...pool, + // rowanUSD: poolStatsRes.data.value?.rowanUSD || 0, + // })); + // return pools.map((pool) => { + // const [, externalAssetAmount] = pool.amounts; + // console.log( + // "externalAssetAmount.asset.symbol=", + // externalAssetAmount.asset.symbol, + // ); + // return ( + // poolStatLookup[externalAssetAmount.asset.symbol] || { + // symbol: externalAssetAmount.asset.symbol, + // priceToken: null, + // rowanUSD: null, + // poolDepth: null, + // volume: null, + // arb: null, + // } + // ); + // }); + return poolStatLookup; }); const wrappedData = computed(() => { diff --git a/app/src/views/PoolPage/PoolPage.tsx b/app/src/views/PoolPage/PoolPage.tsx index 1ac70d462..254abc489 100644 --- a/app/src/views/PoolPage/PoolPage.tsx +++ b/app/src/views/PoolPage/PoolPage.tsx @@ -94,11 +94,7 @@ export default defineComponent({ return; } - if ( - isAssetFlaggedDisabled(asset) || - // TODO: remove this once atom pool is enabled - (this.isATOMPoolsDisabled && item.pool.symbol() === "rowan_uatom") - ) { + if (isAssetFlaggedDisabled(asset)) { return false; } diff --git a/app/src/views/PoolPage/usePoolPageData.tsx b/app/src/views/PoolPage/usePoolPageData.tsx index c1547d385..618b08134 100644 --- a/app/src/views/PoolPage/usePoolPageData.tsx +++ b/app/src/views/PoolPage/usePoolPageData.tsx @@ -135,43 +135,57 @@ export const usePoolPageData = () => { const allPoolsData = computed(() => { const sifchainChain = useChains().get(Network.SIFCHAIN); - return (statsRes.data?.value?.poolData?.pools || []).map((poolStat) => { - const poolKey = createPoolKey( - sifchainChain.lookupAssetOrThrow("rowan"), - sifchainChain.lookupAssetOrThrow(poolStat.symbol), - ); - let accountPool: AccountPool | undefined = undefined; - if (sifAddress.value) { - accountPool = useCore().store.accountpools[sifAddress.value][poolKey]; - } - - const liquidityProvider = - liquidityProvidersQuery.data.value?.liquidityProviderData.find((x) => { - const tokenRegistryEntry = - tokenRegistryEntriesQuery.data.value?.registry?.entries.find( - (y) => y.denom === x.liquidityProvider?.asset?.symbol, - ); - - return tokenRegistryEntry?.baseDenom === poolStat.symbol; - }); - - const pool = useCore().store.pools[poolKey]; - - const denomOrSymbol = - pool.externalAmount.ibcDenom ?? pool.externalAmount.symbol; - - const lppdPoolRewards = lppdRewards?.value?.hasRewards - ? lppdRewards.value.rewards.byPool[denomOrSymbol] - : undefined; - + if (!statsRes.data.value) { return { - poolStat, - pool, - accountPool, - liquidityProvider, - lppdRewards: lppdPoolRewards, + poolStat: null, + pool: null, + accountPool: null, + liquidityProvider: null, + lppdRewards: null, }; - }); + } else { + const { poolData } = statsRes.data.value; + const pools = poolData.pools as Record; + return Object.entries(pools).map(([key, poolStat]) => { + const poolKey = createPoolKey( + sifchainChain.lookupAssetOrThrow("rowan"), + sifchainChain.lookupAssetOrThrow(poolStat.symbol), + ); + let accountPool: AccountPool | undefined = undefined; + if (sifAddress.value) { + accountPool = useCore().store.accountpools[sifAddress.value][poolKey]; + } + + const liquidityProvider = + liquidityProvidersQuery.data.value?.liquidityProviderData.find( + (x) => { + const tokenRegistryEntry = + tokenRegistryEntriesQuery.data.value?.registry?.entries.find( + (y) => y.denom === x.liquidityProvider?.asset?.symbol, + ); + + return tokenRegistryEntry?.baseDenom === poolStat.symbol; + }, + ); + + const pool = useCore().store.pools[poolKey]; + + const denomOrSymbol = + pool.externalAmount.ibcDenom ?? pool.externalAmount.symbol; + + const lppdPoolRewards = lppdRewards?.value?.hasRewards + ? lppdRewards.value.rewards.byPool[denomOrSymbol] + : undefined; + + return { + poolStat, + pool, + accountPool, + liquidityProvider, + lppdRewards: lppdPoolRewards, + }; + }); + } }); return { diff --git a/app/src/views/StatsPage/useStatsPageData.ts b/app/src/views/StatsPage/useStatsPageData.ts index 6e7abef9e..668f05fff 100644 --- a/app/src/views/StatsPage/useStatsPageData.ts +++ b/app/src/views/StatsPage/useStatsPageData.ts @@ -1,7 +1,7 @@ import { reactive, computed, onMounted, onUnmounted } from "vue"; import { Asset } from "@sifchain/sdk"; -import { usePoolStats } from "~/hooks/usePoolStats"; +import { PoolStat, usePoolStats } from "~/hooks/usePoolStats"; import { useCore } from "~/hooks/useCore"; import { isAssetFlaggedDisabled } from "~/store/modules/flags"; @@ -33,9 +33,9 @@ export function useStatsPageData(initialState: StatsPageState) { const statsRef = computed(() => { if (!res.data.value) return []; const { poolData } = res.data.value; - - const array = poolData.pools - .map((pool) => { + const pools = poolData.pools as Record; + const array = Object.entries(pools) + .map(([key, pool]) => { const asset = Asset.get(pool.symbol); const item = { asset, diff --git a/app/tsconfig.json b/app/tsconfig.json index 299079fd3..4a6ec35e7 100644 --- a/app/tsconfig.json +++ b/app/tsconfig.json @@ -1,6 +1,7 @@ { "extends": "@vue/tsconfig/tsconfig.json", "compilerOptions": { + "jsx": "react", "importHelpers": true, "allowSyntheticDefaultImports": true, "importsNotUsedAsValues": "remove", diff --git a/core/src/clients/chains/NobleChain.ts b/core/src/clients/chains/NobleChain.ts new file mode 100644 index 000000000..55fe8296e --- /dev/null +++ b/core/src/clients/chains/NobleChain.ts @@ -0,0 +1,13 @@ +import { urlJoin } from "url-join-ts"; + +import { Chain, IAssetAmount } from "../../entities"; +import { BaseChain } from "./_BaseChain"; + +export class NobleChain extends BaseChain implements Chain { + getBlockExplorerUrlForTxHash(hash: string) { + return urlJoin(this.chainConfig.blockExplorerUrl, "txs", hash); + } + getBlockExplorerUrlForAddress(hash: string) { + return urlJoin(this.chainConfig.blockExplorerUrl, "account", hash); + } +} diff --git a/core/src/clients/chains/_BaseChain.ts b/core/src/clients/chains/_BaseChain.ts index 0402cb4ae..3c046b4a9 100644 --- a/core/src/clients/chains/_BaseChain.ts +++ b/core/src/clients/chains/_BaseChain.ts @@ -49,7 +49,10 @@ export class BaseChain implements Chain { } findAssetWithLikeSymbol(symbol: string) { - return this.assets.find((asset) => isLikeSymbol(asset.symbol, symbol)); + return this.assets.find( + (asset) => asset.symbol.toLowerCase() === symbol.toLowerCase(), + ); + // return this.assets.find((asset) => isLikeSymbol(asset.symbol, symbol)); } findAssetWithLikeSymbolOrThrow(symbol: string) { diff --git a/core/src/clients/index.ts b/core/src/clients/index.ts index a735bfbbb..ddb5f33ca 100644 --- a/core/src/clients/index.ts +++ b/core/src/clients/index.ts @@ -28,6 +28,7 @@ import { } from "../clients/chains"; import { Network } from ".."; +import { NobleChain } from "./chains/NobleChain"; export const networkChainCtorLookup = { [Network.SIFCHAIN]: SifchainChain, @@ -40,6 +41,7 @@ export const networkChainCtorLookup = { [Network.PERSISTENCE]: PersistenceChain, [Network.REGEN]: RegenChain, [Network.OSMOSIS]: OsmosisChain, + [Network.NOBLE]: NobleChain, [Network.TERRA]: TerraChain, [Network.JUNO]: JunoChain, [Network.IXO]: IxoChain, diff --git a/core/src/clients/wallets/cosmos/CosmosWalletProvider.ts b/core/src/clients/wallets/cosmos/CosmosWalletProvider.ts index d714aab21..af1bac47b 100644 --- a/core/src/clients/wallets/cosmos/CosmosWalletProvider.ts +++ b/core/src/clients/wallets/cosmos/CosmosWalletProvider.ts @@ -333,15 +333,23 @@ export abstract class CosmosWalletProvider extends WalletProvider // invalid token, ignore } } - if (!denomTrace) { continue; // Ignore, it's an invalid coin from invalid chain } const registry = await this.tokenRegistry.load(); - const entry = registry.find((e) => { - return e.baseDenom === denomTrace.baseDenom; - }); + // TODO - refactor (this logic should be redundant) - special handling for Osmosis USDC.axl + const entry = + denomTrace.baseDenom === "uusdc" && + coin.denom !== + "ibc/8FCD92E4B97E69EC1A334EADDFF903A6C44408A8C9B03A40B3FBCABE575A8359" + ? registry.find((e) => { + return e.baseDenom === "uaxlusdc"; + }) + : registry.find((e) => { + return e.baseDenom === denomTrace.baseDenom; + }); + console.log("entry=", entry); if (!entry) continue; try { diff --git a/core/src/config/chains/index.ts b/core/src/config/chains/index.ts index 2f94396dd..2d80cda83 100644 --- a/core/src/config/chains/index.ts +++ b/core/src/config/chains/index.ts @@ -10,6 +10,7 @@ import cryptoOrg from "./crypto-org"; import persistence from "./persistence"; import regen from "./regen"; import osmosis from "./osmosis"; +import noble from "./noble"; import terra from "./terra"; import juno from "./juno"; import ixo from "./ixo"; @@ -40,6 +41,7 @@ export const chainConfigByNetworkEnv = Object.fromEntries( [Network.ETHEREUM]: ethereum[env], [Network.CRYPTO_ORG]: cryptoOrg[env], [Network.OSMOSIS]: osmosis[env], + [Network.NOBLE]: noble[env], [Network.PERSISTENCE]: persistence[env], [Network.REGEN]: regen[env], [Network.TERRA]: terra[env], diff --git a/core/src/config/chains/noble/index.ts b/core/src/config/chains/noble/index.ts new file mode 100644 index 000000000..e242690a2 --- /dev/null +++ b/core/src/config/chains/noble/index.ts @@ -0,0 +1,12 @@ +import { NetworkEnv } from "../../getEnv"; +import { NetEnvChainConfigLookup } from "../NetEnvChainConfigLookup"; +import { NOBLE_MAINNET } from "./noble-mainnet"; + +export default { + [NetworkEnv.LOCALNET]: NOBLE_MAINNET, + [NetworkEnv.DEVNET]: NOBLE_MAINNET, + [NetworkEnv.TESTNET]: NOBLE_MAINNET, + [NetworkEnv.MAINNET]: NOBLE_MAINNET, + [NetworkEnv.TEMPNET]: NOBLE_MAINNET, + [NetworkEnv.STAGING]: NOBLE_MAINNET, +}; diff --git a/core/src/config/chains/noble/noble-mainnet.ts b/core/src/config/chains/noble/noble-mainnet.ts new file mode 100644 index 000000000..f0dea5448 --- /dev/null +++ b/core/src/config/chains/noble/noble-mainnet.ts @@ -0,0 +1,58 @@ +import { Network, IBCChainConfig } from "../../../entities"; + +export const NOBLE_MAINNET: IBCChainConfig = { + chainType: "ibc", + network: Network.NOBLE, + displayName: "Noble", + blockExplorerUrl: "https://www.mintscan.io/noble", + nativeAssetSymbol: "uusdc", + chainId: "noble-1", + rpcUrl: "https://proxies.sifchain.finance/api/noble-1/rpc", + restUrl: "https://proxies.sifchain.finance/api/noble-1/rest", + features: { + erc20Transfers: false, + }, + keplrChainInfo: { + rpc: "https://proxies.sifchain.finance/api/noble-1/rpc", + rest: "https://proxies.sifchain.finance/api/noble-1/rest", + chainId: "noble-1", + chainName: "Noble", + stakeCurrency: { + coinDenom: "USDC (Noble)", + coinMinimalDenom: "uusdc", + coinDecimals: 6, + coinGeckoId: "usdc", + }, + walletUrl: "https://wallet.keplr.app/#/noble/stake", + walletUrlForStaking: "https://wallet.keplr.app/#/cosmoshub/stake", + bip44: { + coinType: 118, + }, + bech32Config: { + bech32PrefixAccAddr: "noble", + bech32PrefixAccPub: "noblepub", + bech32PrefixValAddr: "noblevaloper", + bech32PrefixValPub: "noblevaloperpub", + bech32PrefixConsAddr: "noblevalcons", + bech32PrefixConsPub: "noblevalconspub", + }, + currencies: [ + { + coinDenom: "USDC (Noble)", + coinMinimalDenom: "uusdc", + coinDecimals: 6, + coinGeckoId: "usdc", + }, + ], + feeCurrencies: [ + { + coinDenom: "USDC", + coinMinimalDenom: "uusdc", + coinDecimals: 6, + coinGeckoId: "usdc", + }, + ], + coinType: 118, + features: ["stargate", "ibc-transfer"], + }, +}; diff --git a/core/src/config/networks/sifchain/assets.sifchain.mainnet.json b/core/src/config/networks/sifchain/assets.sifchain.mainnet.json index 751787d97..c1a2daa74 100644 --- a/core/src/config/networks/sifchain/assets.sifchain.mainnet.json +++ b/core/src/config/networks/sifchain/assets.sifchain.mainnet.json @@ -955,6 +955,24 @@ "network": "sifchain", "imageUrl": "https://assets.coingecko.com/coins/images/22363/small/stars.png?1645256657", "homeNetwork": "stargaze" + }, + { + "symbol": "uaxlusdc", + "displaySymbol": "USDC (Axelar)", + "decimals": 6, + "name": "USD Coin (Axelar)", + "network": "sifchain", + "imageUrl": "https://assets.coingecko.com/coins/images/6319/thumb/USD_Coin_icon.png?1547042389", + "homeNetwork": "osmosis" + }, + { + "symbol": "uusdc", + "displaySymbol": "USDC (Noble)", + "decimals": 6, + "name": "USD Coin (Noble)", + "network": "sifchain", + "imageUrl": "https://assets.coingecko.com/coins/images/6319/thumb/USD_Coin_icon.png?1547042389", + "homeNetwork": "noble" } ] } diff --git a/core/src/entities/Network.ts b/core/src/entities/Network.ts index 563155064..3dd90cfe5 100644 --- a/core/src/entities/Network.ts +++ b/core/src/entities/Network.ts @@ -11,6 +11,7 @@ export enum Network { JUNO = "juno", LIKECOIN = "likecoin", OSMOSIS = "osmosis", + NOBLE = "noble", PERSISTENCE = "persistence", REGEN = "regen", SENTINEL = "sentinel", diff --git a/yarn.lock b/yarn.lock index aeeb72d21..b4c1c1564 100644 --- a/yarn.lock +++ b/yarn.lock @@ -9846,9 +9846,9 @@ __metadata: linkType: hard "caniuse-lite@npm:^1.0.30001286, caniuse-lite@npm:^1.0.30001317, caniuse-lite@npm:^1.0.30001332, caniuse-lite@npm:^1.0.30001335": - version: 1.0.30001481 - resolution: "caniuse-lite@npm:1.0.30001481" - checksum: 8200a043c191b4fd4fe0beda37a58fd61869c895ab93f87bdd0420e5927453f48434d716ce9da8552ff6c3ecc4dcd1366354cda3a134f3cc844af741574a7cab + version: 1.0.30001565 + resolution: "caniuse-lite@npm:1.0.30001565" + checksum: 7621f358d0e1158557430a111ca5506008ae0b2c796039ef53aeebf4e2ba15e5241cb89def21ea3a633b6a609273085835b44a522165d871fa44067cdf29cccd languageName: node linkType: hard From a2b1e0c125e71b171f197de29335fe7604bca8f1 Mon Sep 17 00:00:00 2001 From: Piotr Gesicki Date: Fri, 8 Dec 2023 01:42:26 +0100 Subject: [PATCH 2/7] testnet release 2.14.21 --- app/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/package.json b/app/package.json index 7b725b27a..a523ab8d4 100644 --- a/app/package.json +++ b/app/package.json @@ -1,6 +1,6 @@ { "name": "app", - "version": "2.14.20", + "version": "2.14.21", "private": true, "scripts": { "bump": "bump patch --tag --commit 'testnet release '", From 16b07b78c8adf488311a3f59fd61c2719bc9b93c Mon Sep 17 00:00:00 2001 From: Piotr Gesicki Date: Fri, 8 Dec 2023 01:45:18 +0100 Subject: [PATCH 3/7] remove hardcoded values --- app/src/business/services/DataService/DataService.ts | 3 +-- app/src/hooks/useChangeLog.ts | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/app/src/business/services/DataService/DataService.ts b/app/src/business/services/DataService/DataService.ts index 8a3bb7610..325d5f8be 100644 --- a/app/src/business/services/DataService/DataService.ts +++ b/app/src/business/services/DataService/DataService.ts @@ -159,8 +159,7 @@ export default class DataService { "tokenStats", () => fetchJSON( - // `${this.baseUrl}/asset/tokenStatsPMTP`, - "https://proxies.sifchain.finance/api/vanir/betanet/beta/asset/tokenStatsPMTP", + `${this.baseUrl}/asset/tokenStatsPMTP`, ), 60000 * 5, // cache for 5 minutes ); diff --git a/app/src/hooks/useChangeLog.ts b/app/src/hooks/useChangeLog.ts index eb0285531..0ce295226 100644 --- a/app/src/hooks/useChangeLog.ts +++ b/app/src/hooks/useChangeLog.ts @@ -14,8 +14,7 @@ async function fetchChangelogData() { ? `v${VITE_APP_SHA}` : VITE_APP_SHA; - const data = await fetch(`${CHANGES_SERVER_URL}/api/changes/2.14.9`).then( - // const data = await fetch(`${CHANGES_SERVER_URL}/api/changes/${tag}`).then( + const data = await fetch(`${CHANGES_SERVER_URL}/api/changes/${tag}`).then( (res) => res.json() as Promise, ); From 2077c1179d54ad3de35d2ed86af7796971c9db5e Mon Sep 17 00:00:00 2001 From: Piotr Gesicki Date: Fri, 8 Dec 2023 01:45:32 +0100 Subject: [PATCH 4/7] testnet release 2.14.22 --- app/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/package.json b/app/package.json index a523ab8d4..3b4f91954 100644 --- a/app/package.json +++ b/app/package.json @@ -1,6 +1,6 @@ { "name": "app", - "version": "2.14.21", + "version": "2.14.22", "private": true, "scripts": { "bump": "bump patch --tag --commit 'testnet release '", From 7e73eae4002ca9ca760acc93035823d408e63aea Mon Sep 17 00:00:00 2001 From: Piotr Gesicki Date: Fri, 8 Dec 2023 08:28:12 +0100 Subject: [PATCH 5/7] remove unused code --- app/src/hooks/usePoolStats.ts | 24 ------------------------ 1 file changed, 24 deletions(-) diff --git a/app/src/hooks/usePoolStats.ts b/app/src/hooks/usePoolStats.ts index 790d13618..2de553bdb 100644 --- a/app/src/hooks/usePoolStats.ts +++ b/app/src/hooks/usePoolStats.ts @@ -152,30 +152,6 @@ export function usePoolStats() { }; }); - // poolStats endpoint might not have data for EVERY pool that exists - // in store.pools. so use store.pools as source of truth for which pools - // exist, then if poolStats doesn't have data default to empty. - // const pools = Object.values(store.pools).map((pool) => ({ - // ...pool, - // rowanUSD: poolStatsRes.data.value?.rowanUSD || 0, - // })); - // return pools.map((pool) => { - // const [, externalAssetAmount] = pool.amounts; - // console.log( - // "externalAssetAmount.asset.symbol=", - // externalAssetAmount.asset.symbol, - // ); - // return ( - // poolStatLookup[externalAssetAmount.asset.symbol] || { - // symbol: externalAssetAmount.asset.symbol, - // priceToken: null, - // rowanUSD: null, - // poolDepth: null, - // volume: null, - // arb: null, - // } - // ); - // }); return poolStatLookup; }); From b20c9ee5111f9debfd04ac3f9eb2e4bc8bff3cd5 Mon Sep 17 00:00:00 2001 From: Piotr Gesicki Date: Fri, 8 Dec 2023 09:25:55 +0100 Subject: [PATCH 6/7] testnet release 2.14.23 --- app/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/package.json b/app/package.json index 3b4f91954..871fb01c3 100644 --- a/app/package.json +++ b/app/package.json @@ -1,6 +1,6 @@ { "name": "app", - "version": "2.14.22", + "version": "2.14.23", "private": true, "scripts": { "bump": "bump patch --tag --commit 'testnet release '", From 719fa2e0425a6bfb0168b9568b91636728af9e35 Mon Sep 17 00:00:00 2001 From: Piotr Gesicki Date: Fri, 8 Dec 2023 10:33:24 +0100 Subject: [PATCH 7/7] Update version --- app/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/package.json b/app/package.json index 871fb01c3..a523ab8d4 100644 --- a/app/package.json +++ b/app/package.json @@ -1,6 +1,6 @@ { "name": "app", - "version": "2.14.23", + "version": "2.14.21", "private": true, "scripts": { "bump": "bump patch --tag --commit 'testnet release '",