From 0f1d83d1b437b67e8be34e443165954aa7e67e0a Mon Sep 17 00:00:00 2001 From: Mateusz Jasiuk Date: Fri, 22 Nov 2024 11:03:34 +0100 Subject: [PATCH] feat: handle nam as denominated amount --- apps/namadillo/jest.config.ts | 23 ++++- apps/namadillo/package.json | 1 + apps/namadillo/src/atoms/accounts/atoms.ts | 7 +- apps/namadillo/src/atoms/accounts/services.ts | 8 +- apps/namadillo/src/atoms/balance/atoms.ts | 6 +- .../src/atoms/integrations/functions.ts | 19 +++++ .../src/hooks/useRegistryFeatures.tsx | 2 +- apps/namadillo/src/registry/namada-local.ts | 85 +++++++++++++++++++ apps/namadillo/src/registry/namadaAsset.ts | 8 +- apps/namadillo/src/utils/index.ts | 3 +- yarn.lock | 10 +++ 11 files changed, 150 insertions(+), 22 deletions(-) create mode 100644 apps/namadillo/src/registry/namada-local.ts diff --git a/apps/namadillo/jest.config.ts b/apps/namadillo/jest.config.ts index cfaeaadfc..f9006331a 100644 --- a/apps/namadillo/jest.config.ts +++ b/apps/namadillo/jest.config.ts @@ -1,9 +1,28 @@ -import { createDefaultPreset, pathsToModuleNameMapper } from "ts-jest"; +import { pathsToModuleNameMapper } from "ts-jest"; import { compilerOptions } from "../../tsconfig.base.json"; /** @type {import('ts-jest').JestConfigWithTsJest} */ module.exports = { - ...createDefaultPreset(), + transform: { + "^.+\\.tsx?$": [ + "ts-jest", + { + diagnostics: { + ignoreCodes: [1343], + }, + astTransformers: { + before: [ + { + path: "../../node_modules/ts-jest-mock-import-meta", + options: { + metaObjectReplacement: { env: {} }, + }, + }, + ], + }, + }, + ], + }, roots: ["src"], displayName: "Namadillo", testEnvironment: "jsdom", diff --git a/apps/namadillo/package.json b/apps/namadillo/package.json index 4f3c1c214..2b1bb0277 100644 --- a/apps/namadillo/package.json +++ b/apps/namadillo/package.json @@ -121,6 +121,7 @@ "release-it": "^17.0.1", "tailwindcss": "^3.4.0", "ts-jest": "^29.2.5", + "ts-jest-mock-import-meta": "^1.2.1", "ts-node": "^10.9.1", "tsconfig-paths-webpack-plugin": "^4.1.0", "typescript": "^5.5.4", diff --git a/apps/namadillo/src/atoms/accounts/atoms.ts b/apps/namadillo/src/atoms/accounts/atoms.ts index 2733d1307..60d103e02 100644 --- a/apps/namadillo/src/atoms/accounts/atoms.ts +++ b/apps/namadillo/src/atoms/accounts/atoms.ts @@ -7,7 +7,6 @@ import { namadaExtensionConnectedAtom } from "atoms/settings"; import { queryDependentFn } from "atoms/utils"; import BigNumber from "bignumber.js"; import { atomWithMutation, atomWithQuery } from "jotai-tanstack-query"; -import { chainConfigByName } from "registry"; import { fetchAccountBalance, fetchAccounts, @@ -85,7 +84,6 @@ export const accountBalanceAtom = atomWithQuery((get) => { const tokenAddress = get(nativeTokenAddressAtom); const enablePolling = get(shouldUpdateBalanceAtom); const api = get(indexerApiAtom); - const chainConfig = chainConfigByName("namada"); return { // TODO: subscribe to indexer events when it's done @@ -95,10 +93,7 @@ export const accountBalanceAtom = atomWithQuery((get) => { return await fetchNamAccountBalance( api, defaultAccount.data, - tokenAddress.data!, - // As this is a nam balance specific atom, we can safely assume that the - // first currency is the native token - chainConfig.currencies[0].coinDecimals + tokenAddress.data! ); }, [tokenAddress, defaultAccount]), }; diff --git a/apps/namadillo/src/atoms/accounts/services.ts b/apps/namadillo/src/atoms/accounts/services.ts index 87107af4a..568f6a561 100644 --- a/apps/namadillo/src/atoms/accounts/services.ts +++ b/apps/namadillo/src/atoms/accounts/services.ts @@ -17,14 +17,12 @@ export const fetchDefaultAccount = async (): Promise => { export const fetchNamAccountBalance = async ( api: DefaultApi, account: Account | undefined, - tokenAddress: string, - decimals: number + tokenAddress: string ): Promise => { if (!account) return BigNumber(0); const balancesResponse = await api.apiV1AccountAddressGet(account.address); const balance = balancesResponse.data - // TODO: add filter to the api call .filter(({ tokenAddress: ta }) => ta === tokenAddress) .map(({ tokenAddress, balance }) => { return { @@ -34,9 +32,7 @@ export const fetchNamAccountBalance = async ( }) .at(0); - return balance ? - BigNumber(balance.amount).shiftedBy(-decimals) - : BigNumber(0); + return balance ? BigNumber(balance.amount) : BigNumber(0); }; export const fetchAccountBalance = async ( diff --git a/apps/namadillo/src/atoms/balance/atoms.ts b/apps/namadillo/src/atoms/balance/atoms.ts index 9138caf71..e95b532bd 100644 --- a/apps/namadillo/src/atoms/balance/atoms.ts +++ b/apps/namadillo/src/atoms/balance/atoms.ts @@ -69,11 +69,7 @@ export const shieldedBalanceAtom = atomWithQuery< ); const shieldedBalance = response.map(([address, amount]) => ({ address, - amount: - // Sdk returns the nam amount as `nam` instead of `namnam` - namTokenAddressQuery.data === address ? - new BigNumber(amount).shiftedBy(6) - : new BigNumber(amount), + amount: new BigNumber(amount), })); return shieldedBalance; }, [viewingKeyQuery, tokenAddressesQuery, namTokenAddressQuery]), diff --git a/apps/namadillo/src/atoms/integrations/functions.ts b/apps/namadillo/src/atoms/integrations/functions.ts index 227a4781a..602335924 100644 --- a/apps/namadillo/src/atoms/integrations/functions.ts +++ b/apps/namadillo/src/atoms/integrations/functions.ts @@ -43,6 +43,13 @@ import internalDevnetCosmosTestnetIbc from "namada-chain-registry/_IBC/namadaint // TODO: this causes a big increase on bundle size. See #1224. import cosmosRegistry from "chain-registry"; +import { namadaLocal, namadaLocalAsset } from "registry/namada-local"; + +const { + VITE_LOCALNET: localnet = false, + VITE_LOCALNET_CHAIN_ID: localChainId, + VITE_LOCALNET_NAM_TOKEN: localToken, +} = import.meta.env; cosmosRegistry.chains.push(internalDevnetChain, housefireChain, dryrunChain); @@ -75,6 +82,18 @@ const testnetChains: ChainRegistryEntry[] = [ const mainnetAndTestnetChains = [...mainnetChains, ...testnetChains]; +if (localnet && localChainId && localToken) { + const localChain: ChainRegistryEntry = { + chain: namadaLocal(localChainId), + assets: namadaLocalAsset(localToken), + }; + + cosmosRegistry.chains.push(localChain.chain); + cosmosRegistry.assets.push(localChain.assets); + + mainnetChains.push(localChain); +} + export const getKnownChains = ( includeTestnets?: boolean ): ChainRegistryEntry[] => { diff --git a/apps/namadillo/src/hooks/useRegistryFeatures.tsx b/apps/namadillo/src/hooks/useRegistryFeatures.tsx index 93775258a..591e80070 100644 --- a/apps/namadillo/src/hooks/useRegistryFeatures.tsx +++ b/apps/namadillo/src/hooks/useRegistryFeatures.tsx @@ -7,7 +7,7 @@ import { import { useAtom, useAtomValue } from "jotai"; import { useEffect } from "react"; -const { VITE_PROXY } = process.env; +const { VITE_PROXY } = import.meta.env; const namadaChainRegistryUrl = VITE_PROXY ? diff --git a/apps/namadillo/src/registry/namada-local.ts b/apps/namadillo/src/registry/namada-local.ts new file mode 100644 index 000000000..7b615c833 --- /dev/null +++ b/apps/namadillo/src/registry/namada-local.ts @@ -0,0 +1,85 @@ +import { AssetList, Chain } from "@chain-registry/types"; + +export const namadaLocal = (chainId: string): Chain => ({ + $schema: "../chain.schema.json", + chain_name: "localnet", + status: "upcoming", + network_type: "testnet", + website: "https://namada.net", + pretty_name: "Namada", + chain_id: chainId, + slip44: 877, + bech32_prefix: "tnam", + daemon_name: "unam", + key_algos: ["ed25519"], + fees: { + fee_tokens: [ + { + denom: "unam", + fixed_min_gas_price: 0.0025, + low_gas_price: 0.0025, + average_gas_price: 0.025, + high_gas_price: 0.04, + }, + ], + }, + staking: { + staking_tokens: [ + { + denom: "unam", + }, + ], + lock_duration: { + time: "1209600s", + }, + }, + codebase: { + git_repo: "https://github.com/anoma/namada", + }, + apis: { + rpc: [ + { + address: "127.0.0.1:27657", + provider: "Localnet", + }, + ], + rest: [ + { + address: "127.0.0.1:27657", + provider: "Localnet", + }, + ], + }, + logo_URIs: { + svg: "https://raw.githubusercontent.com/anoma/namada-chain-registry/main/namada/images/namada.svg", + }, +}); + +export const namadaLocalAsset = (tokenAddress: string): AssetList => ({ + $schema: "../assetlist.schema.json", + chain_name: "localnet", + assets: [ + { + description: "The native token of Namada.", + denom_units: [ + { + denom: "unam", + exponent: 0, + }, + { + denom: "nam", + exponent: 6, + }, + ], + type_asset: "sdk.coin", + base: "unam", + name: "NAM", + display: "nam", + symbol: "NAM", + address: tokenAddress, + logo_URIs: { + svg: "https://raw.githubusercontent.com/anoma/namada-chain-registry/main/namada/images/namada.svg", + }, + }, + ], +}); diff --git a/apps/namadillo/src/registry/namadaAsset.ts b/apps/namadillo/src/registry/namadaAsset.ts index 231bb55a6..d88c59dc6 100644 --- a/apps/namadillo/src/registry/namadaAsset.ts +++ b/apps/namadillo/src/registry/namadaAsset.ts @@ -1,10 +1,16 @@ import { Asset } from "@chain-registry/types"; import namadaShieldedSvg from "./assets/namada-shielded.svg"; +const { VITE_LOCALNET: localnet = false, VITE_LOCALNET_NAM_TOKEN: localToken } = + import.meta.env; + export const namadaAsset = { name: "Namada", base: "unam", - address: "tnam1qy440ynh9fwrx8aewjvvmu38zxqgukgc259fzp6h", + address: + localnet && localToken ? localToken : ( + "tnam1qxp7u2vmlgcrpn9j0ml7hrtr79g2w2fdesteh7tu" + ), display: "nam", symbol: "NAM", denom_units: [ diff --git a/apps/namadillo/src/utils/index.ts b/apps/namadillo/src/utils/index.ts index 0a8623978..bfe79e5e0 100644 --- a/apps/namadillo/src/utils/index.ts +++ b/apps/namadillo/src/utils/index.ts @@ -128,6 +128,8 @@ export const toDisplayAmount = ( asset: Asset, baseAmount: BigNumber ): BigNumber => { + if (isNamAsset(asset)) return baseAmount; + const displayUnit = findDisplayUnit(asset); if (!displayUnit) { return baseAmount; @@ -139,7 +141,6 @@ export const toBaseAmount = ( asset: Asset, displayAmount: BigNumber ): BigNumber => { - if (isNamAsset(asset)) return displayAmount; const displayUnit = findDisplayUnit(asset); if (!displayUnit) { return displayAmount; diff --git a/yarn.lock b/yarn.lock index 59b2919f0..b38732e7e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3691,6 +3691,7 @@ __metadata: toml: "npm:^3.0.0" traverse: "npm:^0.6.9" ts-jest: "npm:^29.2.5" + ts-jest-mock-import-meta: "npm:^1.2.1" ts-node: "npm:^10.9.1" tsconfig-paths-webpack-plugin: "npm:^4.1.0" typescript: "npm:^5.5.4" @@ -20865,6 +20866,15 @@ __metadata: languageName: node linkType: hard +"ts-jest-mock-import-meta@npm:^1.2.1": + version: 1.2.1 + resolution: "ts-jest-mock-import-meta@npm:1.2.1" + peerDependencies: + ts-jest: ">=20.0.0" + checksum: 86eb214916bfbf0934eadde56c8c4562f98b0bd5d03d24baa2b636746f248b4d96d5b489a4e0b25b5aec33f9d7d93ef289c9def47d848b46f6a456e9a8f9e2cd + languageName: node + linkType: hard + "ts-jest@npm:^29.2.5": version: 29.2.5 resolution: "ts-jest@npm:29.2.5"