diff --git a/apps/ui/package.json b/apps/ui/package.json index 7ad9c00ea..40cd60aaa 100644 --- a/apps/ui/package.json +++ b/apps/ui/package.json @@ -51,7 +51,7 @@ "@solana/spl-token": "^0.3.5", "@solana/web3.js": "^1.62.0", "@swim-io/aptos": "^0.36.0", - "@swim-io/core": "^0.36.0", + "@swim-io/core": "workspace:^", "@swim-io/evm": "^0.36.0", "@swim-io/evm-contracts": "^0.36.0", "@swim-io/pool-math": "^0.36.0", diff --git a/apps/ui/src/components/SwapForm/SwapForm.tsx b/apps/ui/src/components/SwapForm/SwapForm.tsx index 1c79c92d8..5658eda0c 100644 --- a/apps/ui/src/components/SwapForm/SwapForm.tsx +++ b/apps/ui/src/components/SwapForm/SwapForm.tsx @@ -110,7 +110,8 @@ export const SwapForm = ({ maxSlippageFraction }: Props): ReactElement => { const isLargeSwap = useIsLargeSwap(fromToken, toToken, inputAmount); const isSmallEthSwap = - TOKEN_PROJECTS_BY_ID[fromToken.projectId].isStablecoin && + (TOKEN_PROJECTS_BY_ID[fromToken.projectId].isStablecoin || + TOKEN_PROJECTS_BY_ID[fromToken.projectId].isSwimUsd) && [fromToken.nativeEcosystemId, toToken.nativeEcosystemId].includes( EvmEcosystemId.Ethereum, ) && diff --git a/apps/ui/src/components/SwapFormV2/SwapFormV2.tsx b/apps/ui/src/components/SwapFormV2/SwapFormV2.tsx index 1d013d8a8..a4e894791 100644 --- a/apps/ui/src/components/SwapFormV2/SwapFormV2.tsx +++ b/apps/ui/src/components/SwapFormV2/SwapFormV2.tsx @@ -108,7 +108,8 @@ export const SwapFormV2 = ({ maxSlippageFraction }: Props): ReactElement => { inputAmount, ); const isSmallEthSwap = - TOKEN_PROJECTS_BY_ID[fromTokenConfig.projectId].isStablecoin && + (TOKEN_PROJECTS_BY_ID[fromTokenConfig.projectId].isStablecoin || + TOKEN_PROJECTS_BY_ID[fromTokenConfig.projectId].isSwimUsd) && [fromTokenOption.ecosystemId, toTokenOption.ecosystemId].includes( EvmEcosystemId.Ethereum, ) && diff --git a/apps/ui/src/hooks/swim/useIsLargeSwap.ts b/apps/ui/src/hooks/swim/useIsLargeSwap.ts index 390f84820..895339156 100644 --- a/apps/ui/src/hooks/swim/useIsLargeSwap.ts +++ b/apps/ui/src/hooks/swim/useIsLargeSwap.ts @@ -27,13 +27,15 @@ export const useIsLargeSwap = ( const inputPoolUsdValue = pools[0].poolUsdValue; const outputPoolUsdValue = pools[pools.length - 1].poolUsdValue; const outputAmount = useSwapOutputAmountEstimate(inputAmount, toToken); + const fromTokenProject = TOKEN_PROJECTS_BY_ID[fromToken.projectId]; + const toTokenProject = TOKEN_PROJECTS_BY_ID[toToken.projectId]; return ( - (TOKEN_PROJECTS_BY_ID[fromToken.projectId].isStablecoin && + ((fromTokenProject.isStablecoin || fromTokenProject.isSwimUsd) && inputPoolUsdValue !== null && inputAmount .toHuman(SOLANA_ECOSYSTEM_ID) .gt(inputPoolUsdValue.mul(0.1))) || - (TOKEN_PROJECTS_BY_ID[toToken.projectId].isStablecoin && + ((toTokenProject.isStablecoin || toTokenProject.isSwimUsd) && outputPoolUsdValue !== null && outputAmount !== null && outputAmount.toHuman(SOLANA_ECOSYSTEM_ID).gt(outputPoolUsdValue.mul(0.1))) diff --git a/apps/ui/src/hooks/swim/useIsLargeSwapV2.ts b/apps/ui/src/hooks/swim/useIsLargeSwapV2.ts index c1147059d..178762b76 100644 --- a/apps/ui/src/hooks/swim/useIsLargeSwapV2.ts +++ b/apps/ui/src/hooks/swim/useIsLargeSwapV2.ts @@ -33,11 +33,15 @@ export const useIsLargeSwapV2 = ( } const inputBalance = sum(poolBalances[0]); const outputBalance = sum(poolBalances[poolBalances.length - 1]); + const fromTokenProject = + TOKEN_PROJECTS_BY_ID[fromTokenOption.tokenConfig.projectId]; + const toTokenProject = + TOKEN_PROJECTS_BY_ID[toTokenOption.tokenConfig.projectId]; return ( - (TOKEN_PROJECTS_BY_ID[fromTokenOption.tokenConfig.projectId].isStablecoin && + ((fromTokenProject.isStablecoin || fromTokenProject.isSwimUsd) && inputBalance !== null && inputAmount.gt(inputBalance.mul(0.1))) || - (TOKEN_PROJECTS_BY_ID[toTokenOption.tokenConfig.projectId].isStablecoin && + ((toTokenProject.isStablecoin || toTokenProject.isSwimUsd) && outputBalance !== null && outputAmount !== null && outputAmount.gt(outputBalance.mul(0.1))) diff --git a/apps/ui/src/hooks/swim/usePoolUsdValues.ts b/apps/ui/src/hooks/swim/usePoolUsdValues.ts index 9d8448ed9..e7c005e84 100644 --- a/apps/ui/src/hooks/swim/usePoolUsdValues.ts +++ b/apps/ui/src/hooks/swim/usePoolUsdValues.ts @@ -30,15 +30,18 @@ export const usePoolUsdValues = (poolSpecs: readonly PoolSpec[]) => { poolTokens.some( (tokenConfig) => !TOKEN_PROJECTS_BY_ID[tokenConfig.projectId].isStablecoin && + !TOKEN_PROJECTS_BY_ID[tokenConfig.projectId].isSwimUsd && !prices.get(tokenConfig.id), ) ) { return new Decimal(0); } return poolTokens.reduce((sum, tokenConfig, i) => { - const price = TOKEN_PROJECTS_BY_ID[tokenConfig.projectId].isStablecoin - ? new Decimal(1) - : prices.get(tokenConfig.id) ?? new Decimal(1); + const price = + TOKEN_PROJECTS_BY_ID[tokenConfig.projectId].isStablecoin || + TOKEN_PROJECTS_BY_ID[tokenConfig.projectId].isSwimUsd + ? new Decimal(1) + : prices.get(tokenConfig.id) ?? new Decimal(1); return sum.add(poolBalances[i].mul(price)); }, new Decimal(0)); } diff --git a/apps/ui/src/models/amount.ts b/apps/ui/src/models/amount.ts index 01ce3fd9e..fba91bbf6 100644 --- a/apps/ui/src/models/amount.ts +++ b/apps/ui/src/models/amount.ts @@ -114,7 +114,8 @@ export class Amount { i18next.resolvedLanguage, ); const numberFormatter = new Intl.NumberFormat(language, { - ...(TOKEN_PROJECTS_BY_ID[this.tokenConfig.projectId].isStablecoin + ...(TOKEN_PROJECTS_BY_ID[this.tokenConfig.projectId].isStablecoin || + TOKEN_PROJECTS_BY_ID[this.tokenConfig.projectId].isSwimUsd ? { minimumFractionDigits: 2, maximumFractionDigits: 2, diff --git a/apps/ui/src/models/swim/utils.ts b/apps/ui/src/models/swim/utils.ts index 4b01038d6..45969fbe8 100644 --- a/apps/ui/src/models/swim/utils.ts +++ b/apps/ui/src/models/swim/utils.ts @@ -187,9 +187,12 @@ export const getPoolUsdValue = ( tokens: readonly TokenConfig[], poolTokenAccounts: readonly TokenAccount[], ): Decimal | null => - tokens.every( - (tokenConfig) => TOKEN_PROJECTS_BY_ID[tokenConfig.projectId].isStablecoin, - ) + tokens.every((tokenConfig) => { + return ( + TOKEN_PROJECTS_BY_ID[tokenConfig.projectId].isStablecoin || + TOKEN_PROJECTS_BY_ID[tokenConfig.projectId].isSwimUsd + ); + }) ? poolTokenAccounts.reduce((acc, account) => { const tokenConfig = tokens.find( (spec) => diff --git a/packages/token-projects/src/projects.test.ts b/packages/token-projects/src/projects.test.ts index d6495e0ea..94255f914 100644 --- a/packages/token-projects/src/projects.test.ts +++ b/packages/token-projects/src/projects.test.ts @@ -23,13 +23,22 @@ describe("Token Project", () => { expect(tokenNumbers).toEqual(Array.from(new Set(tokenNumbers))); }); + it.each(Object.values(TOKEN_PROJECTS_BY_ID))( + "should have correct isSwimUsd flag ($id)", + (tokenProject) => { + expect(tokenProject.isSwimUsd).toBe( + /swimUSD/i.test(tokenProject.displayName), + ); + }, + ); + it.each(Object.values(TOKEN_PROJECTS_BY_ID))( "should have unique token number within range ($id)", (tokenProject) => { /* eslint-disable jest/no-conditional-expect */ if (typeof tokenProject.tokenNumber !== "number") { expect(tokenProject.tokenNumber).toBeNull(); - } else if (tokenProject.isStablecoin && tokenProject.isLp) { + } else if (tokenProject.isSwimUsd) { // case for swimUSD expect(tokenProject.tokenNumber).toBeGreaterThanOrEqual(0x0000); expect(tokenProject.tokenNumber).toBeLessThanOrEqual(0x00ff); diff --git a/packages/token-projects/src/projects.ts b/packages/token-projects/src/projects.ts index d68a68e94..6f0677a0d 100644 --- a/packages/token-projects/src/projects.ts +++ b/packages/token-projects/src/projects.ts @@ -73,6 +73,7 @@ export interface TokenProject { readonly displayName: string; /** URL of an icon for the token */ readonly icon: string; + readonly isSwimUsd: boolean; readonly isStablecoin: boolean; readonly isLp: boolean; readonly tokenNumber: number | null; @@ -87,6 +88,7 @@ export const TOKEN_PROJECTS_BY_ID: ReadonlyRecord< symbol: "USDC", displayName: "USD Coin", icon: USDC_SVG, + isSwimUsd: false, isStablecoin: true, isLp: false, tokenNumber: 0x0100, @@ -96,6 +98,7 @@ export const TOKEN_PROJECTS_BY_ID: ReadonlyRecord< symbol: "USDT", displayName: "Tether USD", icon: USDT_SVG, + isSwimUsd: false, isStablecoin: true, isLp: false, tokenNumber: 0x0101, @@ -105,6 +108,7 @@ export const TOKEN_PROJECTS_BY_ID: ReadonlyRecord< symbol: "USN", displayName: "USN", icon: USN_SVG, + isSwimUsd: false, isStablecoin: true, isLp: false, tokenNumber: 0x0102, @@ -114,6 +118,7 @@ export const TOKEN_PROJECTS_BY_ID: ReadonlyRecord< symbol: "BUSD", displayName: "Binance USD", icon: BUSD_SVG, + isSwimUsd: false, isStablecoin: true, isLp: false, tokenNumber: 0x0103, @@ -123,6 +128,7 @@ export const TOKEN_PROJECTS_BY_ID: ReadonlyRecord< symbol: "aUSD", displayName: "Acala USD", icon: AUSD_SVG, + isSwimUsd: false, isStablecoin: true, isLp: false, tokenNumber: 0x0104, @@ -132,6 +138,7 @@ export const TOKEN_PROJECTS_BY_ID: ReadonlyRecord< symbol: "GST", displayName: "Green Satoshi Token", icon: GST_SVG, + isSwimUsd: false, isStablecoin: false, isLp: false, tokenNumber: 0x8000, @@ -141,6 +148,7 @@ export const TOKEN_PROJECTS_BY_ID: ReadonlyRecord< symbol: "GMT", displayName: "STEPN", icon: GMT_SVG, + isSwimUsd: false, isStablecoin: false, isLp: false, tokenNumber: 0x8001, @@ -150,7 +158,8 @@ export const TOKEN_PROJECTS_BY_ID: ReadonlyRecord< symbol: "swimUSD", displayName: "swimUSD (Swim Hexapool LP)", icon: SWIM_USD_SVG, - isStablecoin: true, + isSwimUsd: true, + isStablecoin: false, isLp: true, tokenNumber: null, }, @@ -159,6 +168,7 @@ export const TOKEN_PROJECTS_BY_ID: ReadonlyRecord< symbol: "SWIM", displayName: "Swim Protocol Token", icon: SWIM_TOKEN_SVG, + isSwimUsd: false, isStablecoin: false, isLp: false, tokenNumber: null, @@ -168,6 +178,7 @@ export const TOKEN_PROJECTS_BY_ID: ReadonlyRecord< symbol: "xSWIM", displayName: "xSWIM (SwimLake LP)", icon: XSWIM_TOKEN_SVG, + isSwimUsd: false, isStablecoin: false, isLp: true, tokenNumber: null, @@ -177,6 +188,7 @@ export const TOKEN_PROJECTS_BY_ID: ReadonlyRecord< symbol: "SWIM-AVALANCHE-USDC-LP", displayName: "Avalanche USDC LP", icon: LP_AVALANCHE_USDC_SVG, + isSwimUsd: false, isStablecoin: false, isLp: true, tokenNumber: null, @@ -186,6 +198,7 @@ export const TOKEN_PROJECTS_BY_ID: ReadonlyRecord< symbol: "SWIM-AVALANCHE-USDT-LP", displayName: "Avalanche USDT LP", icon: LP_AVALANCHE_USDT_SVG, + isSwimUsd: false, isStablecoin: false, isLp: true, tokenNumber: null, @@ -195,6 +208,7 @@ export const TOKEN_PROJECTS_BY_ID: ReadonlyRecord< symbol: "SWIM-POLYGON-USDC-LP", displayName: "Polygon USDC LP", icon: LP_POLYGON_USDC_SVG, + isSwimUsd: false, isStablecoin: false, isLp: true, tokenNumber: null, @@ -204,6 +218,7 @@ export const TOKEN_PROJECTS_BY_ID: ReadonlyRecord< symbol: "SWIM-POLYGON-USDT-LP", displayName: "Polygon USDT LP", icon: LP_POLYGON_USDT_SVG, + isSwimUsd: false, isStablecoin: false, isLp: true, tokenNumber: null, @@ -213,6 +228,7 @@ export const TOKEN_PROJECTS_BY_ID: ReadonlyRecord< symbol: "solaGST-binaGST", displayName: "Swim Solana GST Binance GST LP", icon: LP_GST_SVG, + isSwimUsd: false, isStablecoin: false, isLp: true, tokenNumber: null, @@ -222,6 +238,7 @@ export const TOKEN_PROJECTS_BY_ID: ReadonlyRecord< symbol: "solaGMT-binaGMT", displayName: "Swim Solana GMT Binance GMT LP", icon: LP_GMT_SVG, + isSwimUsd: false, isStablecoin: false, isLp: true, tokenNumber: null, @@ -231,6 +248,7 @@ export const TOKEN_PROJECTS_BY_ID: ReadonlyRecord< symbol: "SWIM-AURORA-USDC-LP", displayName: "Aurora USDC LP", icon: LP_AURORA_USDC_SVG, + isSwimUsd: false, isStablecoin: false, isLp: true, tokenNumber: null, @@ -240,6 +258,7 @@ export const TOKEN_PROJECTS_BY_ID: ReadonlyRecord< symbol: "SWIM-AURORA-USDT-LP", displayName: "Aurora USDT LP", icon: LP_AURORA_USDT_SVG, + isSwimUsd: false, isStablecoin: false, isLp: true, tokenNumber: null, @@ -249,6 +268,7 @@ export const TOKEN_PROJECTS_BY_ID: ReadonlyRecord< symbol: "SWIM-AURORA-USN-LP", displayName: "Aurora USN LP", icon: LP_AURORA_USN_SVG, + isSwimUsd: false, isStablecoin: false, isLp: true, tokenNumber: null, @@ -258,6 +278,7 @@ export const TOKEN_PROJECTS_BY_ID: ReadonlyRecord< symbol: "SWIM-FANTOM-USDC-LP", displayName: "Fantom USDC LP", icon: LP_FANTOM_USDC_SVG, + isSwimUsd: false, isStablecoin: false, isLp: true, tokenNumber: null, @@ -267,6 +288,7 @@ export const TOKEN_PROJECTS_BY_ID: ReadonlyRecord< symbol: "SWIM-KARURA-AUSD-LP", displayName: "Karura AUSD LP", icon: LP_KARURA_AUSD_SVG, + isSwimUsd: false, isStablecoin: false, isLp: true, tokenNumber: null, @@ -276,6 +298,7 @@ export const TOKEN_PROJECTS_BY_ID: ReadonlyRecord< symbol: "SWIM-KARURA-USDT-LP", displayName: "Karura USDT LP", icon: LP_KARURA_USDT_SVG, + isSwimUsd: false, isStablecoin: false, isLp: true, tokenNumber: null, @@ -285,6 +308,7 @@ export const TOKEN_PROJECTS_BY_ID: ReadonlyRecord< symbol: "SWIM-ACALA-AUSD-LP", displayName: "Acala AUSD LP", icon: LP_ACALA_AUSD_SVG, + isSwimUsd: false, isStablecoin: false, isLp: true, tokenNumber: null, @@ -296,7 +320,8 @@ export const TOKEN_PROJECTS_BY_ID: ReadonlyRecord< symbol: "swimUSDv2", // TODO: update displayName: "swimUSD (v2)", // TODO: update icon: SWIM_USD_SVG, // TODO: update - isStablecoin: true, + isSwimUsd: true, + isStablecoin: false, isLp: true, tokenNumber: 0x0000, }, @@ -305,6 +330,7 @@ export const TOKEN_PROJECTS_BY_ID: ReadonlyRecord< symbol: "SWIM-LP-ETHEREUM-USDC-USDT", displayName: "Ethereum USDC/USDT Pool LP", icon: SWIM_USD_SVG, // TODO: update + isSwimUsd: false, isStablecoin: false, isLp: true, tokenNumber: null, @@ -314,6 +340,7 @@ export const TOKEN_PROJECTS_BY_ID: ReadonlyRecord< symbol: "SWIM-LP-BNB-BUSD-USDT", displayName: "BNB BUSD/USDT Pool LP", icon: SWIM_USD_SVG, // TODO: update + isSwimUsd: false, isStablecoin: false, isLp: true, tokenNumber: null, @@ -323,6 +350,7 @@ export const TOKEN_PROJECTS_BY_ID: ReadonlyRecord< symbol: "SWIM-LP-AVALANCHE-USDC-USDT", displayName: "Avalanche USDC/USDT Pool LP", icon: SWIM_USD_SVG, // TODO: update + isSwimUsd: false, isStablecoin: false, isLp: true, tokenNumber: null, @@ -332,6 +360,7 @@ export const TOKEN_PROJECTS_BY_ID: ReadonlyRecord< symbol: "SWIM-LP-POLYGON-USDC-USDT", displayName: "Polygon USDC/USDT Pool LP", icon: SWIM_USD_SVG, // TODO: update + isSwimUsd: false, isStablecoin: false, isLp: true, tokenNumber: null, @@ -341,6 +370,7 @@ export const TOKEN_PROJECTS_BY_ID: ReadonlyRecord< symbol: "SWIM-LP-AURORA-USDC-USDT", displayName: "Aurora USDC/USDT Pool LP", icon: SWIM_USD_SVG, // TODO: update + isSwimUsd: false, isStablecoin: false, isLp: true, tokenNumber: null, @@ -350,6 +380,7 @@ export const TOKEN_PROJECTS_BY_ID: ReadonlyRecord< symbol: "SWIM-LP-AURORA-USN", displayName: "Aurora USN Pool LP", icon: SWIM_USD_SVG, // TODO: update + isSwimUsd: false, isStablecoin: false, isLp: true, tokenNumber: null, @@ -359,6 +390,7 @@ export const TOKEN_PROJECTS_BY_ID: ReadonlyRecord< symbol: "SWIM-LP-FANTOM-USDC", displayName: "Fantom USDC Pool LP", icon: SWIM_USD_SVG, // TODO: update + isSwimUsd: false, isStablecoin: false, isLp: true, tokenNumber: null, @@ -368,6 +400,7 @@ export const TOKEN_PROJECTS_BY_ID: ReadonlyRecord< symbol: "SWIM-LP-KARURA-USDT", displayName: "Karura USDT Pool LP", icon: SWIM_USD_SVG, // TODO: update + isSwimUsd: false, isStablecoin: false, isLp: true, tokenNumber: null, @@ -377,6 +410,7 @@ export const TOKEN_PROJECTS_BY_ID: ReadonlyRecord< symbol: "SWIM-LP-KARURA-AUSD", displayName: "Karura AUSD Pool LP", icon: SWIM_USD_SVG, // TODO: update + isSwimUsd: false, isStablecoin: false, isLp: true, tokenNumber: null, @@ -386,6 +420,7 @@ export const TOKEN_PROJECTS_BY_ID: ReadonlyRecord< symbol: "SWIM-LP-ACALA-AUSD", displayName: "Acala AUSD Pool LP", icon: SWIM_USD_SVG, // TODO: update + isSwimUsd: false, isStablecoin: false, isLp: true, tokenNumber: null, diff --git a/yarn.lock b/yarn.lock index a76316596..62093dde3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7304,7 +7304,7 @@ __metadata: "@storybook/node-logger": ^6.5.10 "@storybook/react": ^6.5.10 "@swim-io/aptos": ^0.36.0 - "@swim-io/core": ^0.36.0 + "@swim-io/core": "workspace:^" "@swim-io/eslint-config": "workspace:^" "@swim-io/evm": ^0.36.0 "@swim-io/evm-contracts": ^0.36.0