diff --git a/frontend/chains/dydx.json b/frontend/chains/dydx.json new file mode 100644 index 000000000..d9d67c42e --- /dev/null +++ b/frontend/chains/dydx.json @@ -0,0 +1,71 @@ +{ + "enable_modules": { + "authz": true, + "feegrant": true, + "group": false + }, + "amino_config": { + "authz": false, + "feegrant": false, + "group": false + }, + "show_airdrop": false, + "logos": { + "menu": "https://raw.githubusercontent.com/cosmos/chain-registry/master/dydx/images/dydx.svg", + "toolbar": "https://raw.githubusercontent.com/cosmos/chain-registry/master/dydx/images/dydx.svg" + }, + "keplr_experimental": false, + "leap_experimental": true, + "is_testnet": false, + "explorer_tx_hash_endpoint": "https://mintscan.io/dydx/txs/", + "config": { + "chain_id": "dydx-mainnet-1", + "chain_name": "DYDX", + "rest": "https://dydx-api.lavenderfive.com:443", + "rpc": "https://dydx-rpc.lavenderfive.com:443", + "currencies": [ + { + "coin_denom": "DYDX", + "coin_minimal_denom": "adydx", + "coin_decimals": 18 + } + ], + "bip44": { + "coin_type": 118 + }, + "bech32_config": { + "bech32_prefix_acc_addr": "dydx", + "bech32_prefix_acc_pub": "dydxpub", + "bech32_prefix_val_addr": "dydxvaloper", + "bech32_prefix_val_pub": "dydxvaloperpub", + "bech32_prefix_cons_addr": "dydxvalcons", + "bech32_prefix_cons_pub": "dydxvalconspub" + }, + "wallet_url_for_staking": "https://resolute.vitwit.com/dydx/staking", + "fee_currencies": [ + { + "coin_denom": "DYDX", + "coin_minimal_denom": "adydx", + "coin_decimals": 18, + "coin_gecko_id": "dydx", + "gas_price_step": { + "low": 0.01, + "average": 0.02, + "high": 0.05 + } + } + ], + + "stake_currency": { + "coin_denom": "DYDX", + "coin_minimal_denom": "adydx", + "coin_decimals": 18, + "coin_gecko_id": "dydx" + }, + "image": "https://raw.githubusercontent.com/leapwallet/assets/2289486990e1eaf9395270fffd1c41ba344ef602/images/logo.svg", + "theme": { + "primaryColor": "#fff", + "gradient": "linear-gradient(180deg, rgba(255,255,255,0.32) 0%, rgba(255,255,255,0) 100%)" + } + } +} diff --git a/frontend/src/components/ActiveValidators.jsx b/frontend/src/components/ActiveValidators.jsx index ad772e593..4d996fde8 100644 --- a/frontend/src/components/ActiveValidators.jsx +++ b/frontend/src/components/ActiveValidators.jsx @@ -20,6 +20,9 @@ export function ActiveValidators(props) { (state) => state.staking.chains[chainID].delegations.delegatedTo ); + const wallet = useSelector(state => state.wallet); + const coinDecimals = wallet?.networks[chainID]?.network?.config?.currencies[0]?.coinDecimals || 6; + const [activeVals, setActiveVals] = useState(validators.activeSorted); useEffect(() => { @@ -36,7 +39,7 @@ export function ActiveValidators(props) { Rank Validator - Voting Power + Voting Power Status Commission Actions @@ -55,8 +58,8 @@ export function ActiveValidators(props) { {validators.active[keyName]?.description.moniker} - - {formatVotingPower(validators.active[keyName]?.tokens, 6)} + + {formatVotingPower(validators.active[keyName]?.tokens, coinDecimals)} {validators.active[keyName]?.jailed diff --git a/frontend/src/components/FilteredValidators.jsx b/frontend/src/components/FilteredValidators.jsx index 0742e6e3e..9c1368fd3 100644 --- a/frontend/src/components/FilteredValidators.jsx +++ b/frontend/src/components/FilteredValidators.jsx @@ -16,6 +16,10 @@ export function FilteredValidators(props) { (state) => state.staking.chains[chainID].delegations.delegatedTo ); + const wallet = useSelector(state => state.wallet); + const coinDecimals = wallet?.networks[chainID]?.network?.config?.currencies[0]?.coinDecimals || 6; + + return ( <> @@ -24,7 +28,7 @@ export function FilteredValidators(props) { Rank Validator - Voting Power + Voting Power Status Commission Actions @@ -42,8 +46,8 @@ export function FilteredValidators(props) { {validators.active[keyName]?.description.moniker} - - {formatVotingPower(validators.active[keyName]?.tokens, 6)} + + {formatVotingPower(validators.active[keyName]?.tokens, coinDecimals)} {validators.active[keyName]?.jailed diff --git a/frontend/src/components/InActiveValidators.jsx b/frontend/src/components/InActiveValidators.jsx index 6c8bd3bd5..57a54235e 100644 --- a/frontend/src/components/InActiveValidators.jsx +++ b/frontend/src/components/InActiveValidators.jsx @@ -22,6 +22,9 @@ export function InActiveValidators(props) { const [inactiveVals, setInactiveVals] = useState(validators.inactiveSorted); + const wallet = useSelector(state => state.wallet); + const coinDecimals = wallet?.networks[chainID]?.network?.config?.currencies[0]?.coinDecimals || 6; + useEffect(() => { setInactiveVals(validators.inactiveSorted); }, [validators]); @@ -36,7 +39,7 @@ export function InActiveValidators(props) { Rank Validator - Voting Power + Voting Power Commission Status Action @@ -55,8 +58,8 @@ export function InActiveValidators(props) { {validators.inactive[keyName]?.description.moniker} - - {formatVotingPower(validators.inactive[keyName]?.tokens, 6)} + + {formatVotingPower(validators.inactive[keyName]?.tokens, coinDecimals)} {( diff --git a/frontend/src/components/WitvalValidator.jsx b/frontend/src/components/WitvalValidator.jsx index 27a47b033..52e75a982 100644 --- a/frontend/src/components/WitvalValidator.jsx +++ b/frontend/src/components/WitvalValidator.jsx @@ -10,9 +10,13 @@ import { formatVotingPower } from "../utils/denom"; import Typography from "@mui/material/Typography"; import { formatValidatorStatus } from "../utils/util"; import { useTheme } from "@emotion/react"; +import { useSelector } from "react-redux"; export function WitvalValidator(props) { - const { validator, onMenuAction } = props; + const { validator, onMenuAction, chainID } = props; + + const wallet = useSelector(state => state.wallet); + const coinDecimals = wallet?.networks[chainID]?.network?.config?.currencies[0]?.coinDecimals || 6; const theme = useTheme(); return ( @@ -51,7 +55,7 @@ export function WitvalValidator(props) { Validator - Voting Power + Voting Power Commission Actions @@ -68,8 +72,8 @@ export function WitvalValidator(props) { ? formatValidatorStatus(true, null) : formatValidatorStatus(false, validator?.status)} - - {formatVotingPower(validator.tokens, 6)} + + {formatVotingPower(validator.tokens, coinDecimals)} {(validator.commission.commission_rates.rate * 100).toFixed( diff --git a/frontend/src/features/bank/bankSlice.js b/frontend/src/features/bank/bankSlice.js index 2ed016573..cd733901f 100644 --- a/frontend/src/features/bank/bankSlice.js +++ b/frontend/src/features/bank/bankSlice.js @@ -3,7 +3,6 @@ import { SendMsg } from "../../txns/bank"; import bankService from "./service"; import { setError, setTxHash } from "../common/commonSlice"; import { signAndBroadcast } from "../../utils/signing"; -import { parseBalance } from "../../utils/denom"; const initialState = { balances: {}, diff --git a/frontend/src/features/distribution/distributionSlice.js b/frontend/src/features/distribution/distributionSlice.js index 1dbeb9a87..cba830eea 100644 --- a/frontend/src/features/distribution/distributionSlice.js +++ b/frontend/src/features/distribution/distributionSlice.js @@ -108,7 +108,9 @@ export const distSlice = createSlice({ reducers: { resetTx: (state, action) => { let chainID = action.payload.chainID; - state.chains[chainID].tx = initialState.defaultState.tx; + if (state.chains[chainID].tx) { + state.chains[chainID].tx = initialState.defaultState.tx; + } }, resetDefaultState: (state, action) => { let chainsMap = {}; diff --git a/frontend/src/features/wallet/walletSlice.js b/frontend/src/features/wallet/walletSlice.js index b24cfe2c4..42b5bf626 100644 --- a/frontend/src/features/wallet/walletSlice.js +++ b/frontend/src/features/wallet/walletSlice.js @@ -1,6 +1,10 @@ import { toBase64 } from "@cosmjs/encoding"; import { createSlice, createAsyncThunk } from "@reduxjs/toolkit"; -import { getWalletAmino, isWalletInstalled } from "../../txns/execute"; +import { + getSignerAndAccountAmino, + getWalletAmino, + isWalletInstalled, +} from "../../txns/execute"; import { setConnected } from "../../utils/localStorage"; import { setError } from "../common/commonSlice"; @@ -11,13 +15,13 @@ const initialState = { pubKey: "", networks: {}, nameToChainIDs: {}, + errorMessage: "", }; export const connectWalletV1 = createAsyncThunk( "wallet/connectv1", async (data, { rejectWithValue, fulfillWithValue, dispatch }) => { const mainnets = data.mainnets; - const testnets = data.testnets; if (!isWalletInstalled()) { dispatch( @@ -39,45 +43,48 @@ export const connectWalletV1 = createAsyncThunk( let isNanoLedger = false; const chainInfos = {}; const nameToChainIDs = {}; + const chainIDs = []; + const chainNames = []; + const supportedChains = []; for (let i = 0; i < mainnets.length; i++) { try { - if ((data.walletName === "keplr" || data.walletName === "cosmostation" ) && mainnets[i].keplrExperimental) { + if ( + (data.walletName === "keplr" || + data.walletName === "cosmostation") && + mainnets[i].keplrExperimental + ) { await window.wallet.experimentalSuggestChain(mainnets[i].config); } if (data.walletName === "leap" && mainnets[i].leapExperimental) { await window.wallet.experimentalSuggestChain(mainnets[i].config); } - let chainId = mainnets[i].config.chainId; - const chainName = mainnets[i].config.chainName; - await getWalletAmino(chainId); - let walletInfo = await window.wallet.getKey(chainId); - walletInfo.pubKey = Buffer.from(walletInfo?.pubKey).toString('base64'); - delete walletInfo?.address; - - walletName = walletInfo?.name; - isNanoLedger = walletInfo?.isNanoLedger || false; - - - chainInfos[chainId] = { - walletInfo: walletInfo, - network: mainnets[i], - }; - nameToChainIDs[chainName?.toLowerCase().split(" ").join("")] = chainId; } catch (error) { - console.log(`unable to connect to network ${mainnets[i].config.chainName}: `, error); + console.log( + `unable to connect to network ${mainnets[i].config.chainName}: `, + error + ); + continue; } + chainIDs.push(mainnets[i].config.chainId); + chainNames.push(mainnets[i].config.chainName); + supportedChains.push(mainnets[i]); + } + + try { + await window.wallet.enable(chainIDs); + } catch (error) { + return rejectWithValue("Wallet connection request rejected"); } - for (let i = 0; i < testnets.length; i++) { + for (let i = 0; i < chainIDs.length; i++) { try { - if (testnets[i].experimental) { - await window.wallet.experimentalSuggestChain(testnets[i].config); - } - const chainId = testnets[i].config.chainId; - const chainName = testnets[i].config.chainName; - await getWalletAmino(chainId); + const chainId = chainIDs[i]; + const chainName = chainNames[i]; + await getSignerAndAccountAmino(chainId); const walletInfo = await window.wallet.getKey(chainId); - walletInfo.pubKey = Buffer.from(walletInfo?.pubKey).toString('base64'); + walletInfo.pubKey = Buffer.from(walletInfo?.pubKey).toString( + "base64" + ); delete walletInfo?.address; walletName = walletInfo?.name; @@ -85,12 +92,12 @@ export const connectWalletV1 = createAsyncThunk( chainInfos[chainId] = { walletInfo: walletInfo, - network: testnets[i], + network: supportedChains[i], }; nameToChainIDs[chainName?.toLowerCase()] = chainId; } catch (error) { - console.log(`unable to connect to network ${mainnets[i].config.chainName}: `, error); + console.log(`unable to connect to network ${chainNames[i]}: `, error); } } @@ -108,13 +115,12 @@ export const connectWalletV1 = createAsyncThunk( chainInfos, nameToChainIDs, walletName, - isNanoLedger + isNanoLedger, }); } - } } -) +); export const connectKeplrWallet = createAsyncThunk( "wallet/connect", @@ -193,7 +199,7 @@ export const walletSlice = createSlice({ }, extraReducers: (builder) => { builder - .addCase(connectKeplrWallet.pending, () => { }) + .addCase(connectKeplrWallet.pending, () => {}) .addCase(connectKeplrWallet.fulfilled, (state, action) => { const result = action.payload; state.name = result.walletInfo?.name; @@ -203,10 +209,9 @@ export const walletSlice = createSlice({ state.connected = true; state.isNanoLedger = action.payload?.walletInfo?.isNanoLedger || false; }) - .addCase(connectKeplrWallet.rejected, () => { }) - + .addCase(connectKeplrWallet.rejected, () => {}) - .addCase(connectWalletV1.pending, () => { }) + .addCase(connectWalletV1.pending, () => {}) .addCase(connectWalletV1.fulfilled, (state, action) => { const networks = action.payload.chainInfos; const nameToChainIDs = action.payload.nameToChainIDs; @@ -216,7 +221,9 @@ export const walletSlice = createSlice({ state.isNanoLedger = action.payload.isNanoLedger; state.name = action.payload.walletName; }) - .addCase(connectWalletV1.rejected, () => { }); + .addCase(connectWalletV1.rejected, (state, action) => { + state.errorMessage = action.payload || "Something went wrong"; + }); }, }); diff --git a/frontend/src/pages/staking/chain/Validators.js b/frontend/src/pages/staking/chain/Validators.js index 6c5896813..e09998ebb 100644 --- a/frontend/src/pages/staking/chain/Validators.js +++ b/frontend/src/pages/staking/chain/Validators.js @@ -693,6 +693,7 @@ export default function Validators(props) {
diff --git a/frontend/src/txns/execute.js b/frontend/src/txns/execute.js index a56a3b99f..8c616531c 100644 --- a/frontend/src/txns/execute.js +++ b/frontend/src/txns/execute.js @@ -496,6 +496,16 @@ export async function getWalletAmino(chainID) { return [offlineSigner, accounts[0]]; } +export async function getSignerAndAccountAmino(chainID) { + try { + const offlineSigner = window.wallet.getOfflineSignerOnlyAmino(chainID); + const accounts = await offlineSigner.getAccounts(); + return [offlineSigner, accounts[0]]; + } catch (error) { + throw error; + } +} + export async function getWalletDirect(chainID) { await window.wallet.enable(chainID); const offlineSigner = window.wallet.getOfflineSigner(chainID); diff --git a/frontend/src/utils/chainsInfo.ts b/frontend/src/utils/chainsInfo.ts index 3a7ebc5e6..ca2546bed 100644 --- a/frontend/src/utils/chainsInfo.ts +++ b/frontend/src/utils/chainsInfo.ts @@ -277,6 +277,76 @@ export const networks: Network[] = [ } } }, + { + enableModules: { + authz: true, + feegrant: true, + group: false + }, + aminoConfig: { + authz: false, + feegrant: false, + group: false + }, + showAirdrop: false, + logos: { + menu: "https://raw.githubusercontent.com/cosmos/chain-registry/master/dydx/images/dydx.svg", + toolbar: "https://raw.githubusercontent.com/cosmos/chain-registry/master/dydx/images/dydx.svg" + }, + keplrExperimental: false, + leapExperimental: true, + isTestnet: false, + explorerTxHashEndpoint: "https://mintscan.io/dydx/txs/", + config: { + chainId: "dydx-mainnet-1", + chainName: "DYDX", + rest: "https://dydx-api.lavenderfive.com:443", + rpc: "https://dydx-rpc.lavenderfive.com:443", + currencies: [ + { + coinDenom: "DYDX", + coinMinimalDenom: "adydx", + coinDecimals: 18 + } + ], + bip44: { + coinType: 118 + }, + bech32Config: { + bech32PrefixAccAddr: "dydx", + bech32PrefixAccPub: "dydxpub", + bech32PrefixValAddr: "dydxvaloper", + bech32PrefixValPub: "dydxvaloperpub", + bech32PrefixConsAddr: "dydxvalcons", + bech32PrefixConsPub: "dydxvalconspub" + }, + walletUrlForStaking: "https://resolute.vitwit.com/dydx/staking", + feeCurrencies: [ + { + coinDenom: "DYDX", + coinMinimalDenom: "adydx", + coinDecimals: 18, + coinGeckoId: "dydx", + gasPriceStep: { + low: 0.01, + average: 0.02, + high: 0.05 + } + } + ], + stakeCurrency: { + coinDenom: "DYDX", + coinMinimalDenom: "adydx", + coinDecimals: 18, + coinGeckoId: "dydx" + }, + image: "https://raw.githubusercontent.com/leapwallet/assets/2289486990e1eaf9395270fffd1c41ba344ef602/images/logo.svg", + theme: { + primaryColor: "#fff", + gradient: "linear-gradient(180deg, rgba(255,255,255,0.32) 0%, rgba(255,255,255,0) 100%)" + } + } + }, { enableModules: { authz: true, @@ -411,6 +481,73 @@ export const networks: Network[] = [ } } }, + { + enableModules: { + authz: true, + feegrant: true, + group: true + }, + aminoConfig: { + authz: true, + feegrant: true, + group: false + }, + showAirdrop: false, + logos: { + menu: "https://raw.githubusercontent.com/vitwit/chain-registry/f98e34339a1d30b4a2734b78d6dfcbba9cb02f8e/likecoin/images/like.png", + toolbar: "https://raw.githubusercontent.com/vitwit/chain-registry/c194a4887fdc60b96314b813eaeb435c1a15f307/likecoin/images/likecoin-chain-logo.png" + }, + keplrExperimental: false, + leapExperimental: false, + isTestnet: false, + explorerTxHashEndpoint: "https://www.mintscan.io/likecoin/txs/", + config: { + chainId: "likecoin-mainnet-2", + chainName: "LikeCoin", + rest: "https://mainnet-node.like.co", + rpc: "https://mainnet-node-rpc.like.co", + currencies: [ + { + coinDenom: "LIKE", + coinMinimalDenom: "nanolike", + coinDecimals: 9 + } + ], + bech32Config: { + bech32PrefixAccAddr: "like", + bech32PrefixAccPub: "likepub", + bech32PrefixValAddr: "likevaloper", + bech32PrefixValPub: "likevaloperpub", + bech32PrefixConsAddr: "likegvalcons", + bech32PrefixConsPub: "likevalconspub" + }, + feeCurrencies: [ + { + coinDenom: "LIKE", + coinMinimalDenom: "nanolike", + coinDecimals: 9, + gasPriceStep: { + low: 1, + average: 10, + high: 1000 + } + } + ], + bip44: { + coinType: 118 + }, + stakeCurrency: { + coinDenom: "LIKE", + coinMinimalDenom: "nanolike", + coinDecimals: 9 + }, + image: "https://raw.githubusercontent.com/leapwallet/assets/2289486990e1eaf9395270fffd1c41ba344ef602/images/logo.svg", + theme: { + primaryColor: "#fff", + gradient: "linear-gradient(180deg, rgba(255,255,255,0.32) 0%, rgba(255,255,255,0) 100%)" + } + } + }, { enableModules: { authz: true,