Skip to content

Commit

Permalink
feat: support additional testnet tokens (#529)
Browse files Browse the repository at this point in the history
  • Loading branch information
jurevans authored Dec 18, 2023
1 parent a293920 commit 17c378c
Show file tree
Hide file tree
Showing 8 changed files with 93 additions and 34 deletions.
9 changes: 7 additions & 2 deletions apps/extension/src/background/keyring/keyring.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import {
SubmitUnbondMsgValue,
SubmitVoteProposalMsgValue,
SubmitWithdrawMsgValue,
Tokens,
TransferMsgValue,
} from "@namada/types";

Expand Down Expand Up @@ -82,7 +83,7 @@ export class KeyRing {
protected readonly sdk: Sdk,
protected readonly query: Query,
protected readonly cryptoMemory: WebAssembly.Memory
) {}
) { }

public get status(): KeyRingStatus {
return this._status;
Expand Down Expand Up @@ -855,8 +856,12 @@ export class KeyRing {
async queryBalances(
owner: string
): Promise<{ token: string; amount: string }[]> {
const tokenAddresses: string[] = Object.values(Tokens)
.filter((token) => token.address)
.map(({ address }) => address);

try {
return (await this.query.query_balance(owner)).map(
return (await this.query.query_balance(owner, tokenAddresses)).map(
([token, amount]: [string, string]) => {
return {
token,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,9 @@ import {
// Import PNG images assets
import AssetNamadaNamLight from "./assets/asset-namada-nam-light.png";
import AssetNamadaNamDark from "./assets/asset-namada-nam-dark.png";
import AssetCosmosAtom from "./assets/asset-cosmos-atom.png";
import AssetEthereumEther from "./assets/asset-ethereum-ether.png";
import AssetBitcoin from "./assets/asset-bitcoin-btc.png";
import AssetPolkadot from "./assets/asset-polkadot-dot.png";

import { useAppDispatch, useAppSelector } from "store";
import { AccountsState, Balance } from "slices/accounts";
Expand All @@ -52,9 +53,25 @@ const assetIconByToken: Record<TokenType, { light: string; dark: string }> = {
light: AssetEthereumEther,
dark: AssetEthereumEther,
},
["ATOM"]: {
light: AssetCosmosAtom,
dark: AssetCosmosAtom,
["BTC"]: {
light: AssetBitcoin,
dark: AssetBitcoin,
},
["DOT"]: {
light: AssetPolkadot,
dark: AssetPolkadot
},
["SCH"]: {
light: AssetNamadaNamLight,
dark: AssetNamadaNamDark,
},
["APF"]: {
light: AssetNamadaNamLight,
dark: AssetNamadaNamDark,
},
["KAR"]: {
light: AssetNamadaNamLight,
dark: AssetNamadaNamDark,
},
};

Expand Down Expand Up @@ -90,6 +107,7 @@ const DerivedAccounts = ({ setTotal }: Props): JSX.Element => {

const balanceToFiat = (balance: Balance): BigNumber => {
return Object.entries(balance).reduce((acc, [token, value]) => {

return acc.plus(
rates[token] && rates[token][fiatCurrency]
? value.multipliedBy(rates[token][fiatCurrency].rate)
Expand Down Expand Up @@ -170,6 +188,7 @@ const DerivedAccounts = ({ setTotal }: Props): JSX.Element => {
? 1
: -1;
})
.filter(([_, amount]) => amount.isGreaterThan(0))
.map(([token, amount]) => {
return (
<TokenBalance key={`${address}-${token}`}>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -288,7 +288,7 @@ const IBCTransfer = (): JSX.Element => {

const isAmountValid = (amount: BigNumber, balance: BigNumber): boolean =>
amount.isLessThan(
token === "ATOM" ? balance.multipliedBy(1_000_000) : balance
token === "DOT" ? balance.multipliedBy(1_000_000) : balance
);

const validateForm = (): boolean => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ const TokenSend = (): JSX.Element => {

const [activeTab, setActiveTab] = useState(tabs[defaultTab]);
const [token, setToken] = useState<TokenType>(
chains[chainId].currency.symbol
chains[chainId].currency.symbol as TokenType
);

const handleTokenChange =
Expand Down
8 changes: 4 additions & 4 deletions apps/namada-interface/src/store/mocks.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import BigNumber from "bignumber.js";

import { AccountType } from "@namada/types";
import { RootState } from "./store";
import { StakingOrUnstakingState } from "slices/StakingAndGovernance";
import { RootState } from "./store";

export const mockAppState: RootState = {
accounts: {
Expand All @@ -18,7 +18,7 @@ export const mockAppState: RootState = {
},
balance: {
NAM: new BigNumber(1000),
ATOM: new BigNumber(1000),
DOT: new BigNumber(1000),
ETH: new BigNumber(1000),
},
},
Expand All @@ -34,7 +34,7 @@ export const mockAppState: RootState = {
},
balance: {
NAM: new BigNumber(1000),
ATOM: new BigNumber(1000),
DOT: new BigNumber(1000),
ETH: new BigNumber(1000),
},
},
Expand All @@ -51,7 +51,7 @@ export const mockAppState: RootState = {

balance: {
NAM: new BigNumber(1000),
ATOM: new BigNumber(1000),
DOT: new BigNumber(1000),
ETH: new BigNumber(1000),
},
},
Expand Down
25 changes: 14 additions & 11 deletions packages/shared/lib/src/query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -234,16 +234,15 @@ impl Query {
async fn query_transparent_balance(
&self,
owner: Address,
tokens: Box<[JsValue]>,
) -> Result<Vec<(Address, token::Amount)>, JsError> {
//TODO: Move hardcoded tokens somewhere else
let tokens: HashSet<Address> = HashSet::from([
// NAM
Address::from_str("tnam1q9mjvqd45u7w54kee2aquugtv7vn7h3xrcrau7xy")?,
// DOT
Address::from_str("tnam1q9dg4r9uteahgx7qyc2h8crq3lg7zrxdduwyrss4")?,
// ETH
Address::from_str("tnam1q9anasrx0gqeuxrc22a0uefe82kw08avhcasevng")?,
]);
let tokens: Vec<Address> = tokens
.into_iter()
.map(|address| {
let address_str = &(address.as_string().unwrap()[..]);
Address::from_str(address_str).unwrap()
})
.collect();

let mut result = vec![];
for token in tokens {
Expand Down Expand Up @@ -287,9 +286,13 @@ impl Query {
Ok(Self::get_decoded_balance(decoded_balance))
}

pub async fn query_balance(&self, owner: String) -> Result<JsValue, JsError> {
pub async fn query_balance(
&self,
owner: String,
tokens: Box<[JsValue]>,
) -> Result<JsValue, JsError> {
let result = match Address::from_str(&owner) {
Ok(addr) => self.query_transparent_balance(addr).await,
Ok(addr) => self.query_transparent_balance(addr, tokens).await,
Err(e1) => match ExtendedViewingKey::from_str(&owner) {
Ok(xvk) => self.query_shielded_balance(xvk).await,
Err(e2) => return Err(JsError::new(&format!("{} {}", e1, e2))),
Expand Down
4 changes: 1 addition & 3 deletions packages/types/src/chain.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
import { TokenType } from "./tx";

const {
// Load extension download URL from env
NAMADA_INTERFACE_EXTENSION_URL: extensionUrl,
} = process.env;

export type Currency = {
token: string;
symbol: TokenType;
symbol: string;
gasPriceStep?: {
low: number;
average: number;
Expand Down
50 changes: 42 additions & 8 deletions packages/types/src/tx/tokens/types/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { registeredCoinTypes, RegisteredCoinType } from "slip44";
import { RegisteredCoinType, registeredCoinTypes } from "slip44";

export type TokenInfo = {
symbol: string;
Expand All @@ -13,9 +13,18 @@ export type TokenInfo = {
};

// Declare symbols for tokens we support:
export const Symbols = ["NAM", "ATOM", "ETH"] as const;
// TODO: This will need to be refactored for mainnet!
export const Symbols = [
"NAM",
"BTC",
"DOT",
"ETH",
"SCH",
"APF",
"KAR",
] as const;

export type TokenType = typeof Symbols[number];
export type TokenType = (typeof Symbols)[number];
type Tokens = Record<TokenType, TokenInfo>;

const supportedCoinTypes: RegisteredCoinType[] = [
Expand Down Expand Up @@ -49,12 +58,10 @@ Tokens["NAM"] = {
address: "tnam1q9mjvqd45u7w54kee2aquugtv7vn7h3xrcrau7xy",
};

// TODO: We don't have a address for this. The address for DOT
// from the dev & e2e genesis is being used here:
Tokens["ATOM"] = {
...Tokens["ATOM"],
Tokens["DOT"] = {
...Tokens["DOT"],
address: "tnam1q9dg4r9uteahgx7qyc2h8crq3lg7zrxdduwyrss4",
coinGeckoId: "cosmos",
coinGeckoId: "polkadot",
};

Tokens["ETH"] = {
Expand All @@ -63,4 +70,31 @@ Tokens["ETH"] = {
coinGeckoId: "ethereum",
};

Tokens["BTC"] = {
...Tokens["BTC"],
address: "tnam1qxwpxk3t4rwwshuwudkj9j2565gey088753n4ska",
coinGeckoId: "bitcoin",
};

Tokens["SCH"] = {
...Tokens["SCH"],
coin: "Schnitzel",
symbol: "SCH",
address: "tnam1q9u0qaas5dc7h56ezwsmcurdt7h5ksv7csel5lm9",
};

Tokens["APF"] = {
...Tokens["APF"],
coin: "Apfel",
symbol: "APF",
address: "tnam1qxv8l458h02uf56g5s3zx7g36uqc5fn0hy208d8d",
};

Tokens["KAR"] = {
...Tokens["KAR"],
coin: "Kartoffel",
symbol: "KAR",
address: "tnam1qxajrany4v37lpvxcsqxjax8sxvuc3zszu7gr406",
};

export type TokenBalance = { token: TokenType; amount: string };

1 comment on commit 17c378c

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.