From 299b5d8934b2b8e2ad9929c7faa506dd7d556e2a Mon Sep 17 00:00:00 2001 From: stefanpetkov90 Date: Wed, 28 Sep 2022 13:42:38 +0300 Subject: [PATCH] CUDOS-1537 Add Cosmostation support --- index.html | 1 + package.json | 2 + src/App.tsx | 28 +- src/assets/vectors/cosmostation-logo.svg | 9 + .../components/DelegationModal/Delegation.tsx | 28 +- src/components/Layout/UserInfo.tsx | 26 +- src/components/Layout/styles.ts | 10 +- .../RequireLedger.tsx} | 4 +- .../ConnectWallet/ConnectWallet.tsx | 78 ++++- src/containers/ConnectWallet/styles.ts | 16 +- .../components/DepositModal/Deposit.tsx | 7 +- .../components/ProposalModal/Proposals.tsx | 7 +- .../Proposals/components/VotingModal/Vote.tsx | 7 +- .../RedelegationModal/Redelegation.tsx | 34 +- .../UndelegationModal/Undelegation.tsx | 36 +- src/ledgers/CosmoStationLedger.ts | 67 ++++ src/ledgers/CosmosNetworkConfig.ts | 4 + src/ledgers/KeplrLedger.tsx | 5 +- src/ledgers/transactions.ts | 100 +++--- src/ledgers/utils.ts | 64 +++- src/store/profile.ts | 6 +- yarn.lock | 329 +++++++++++++++++- 22 files changed, 723 insertions(+), 145 deletions(-) create mode 100644 src/assets/vectors/cosmostation-logo.svg rename src/components/{RequireKeplr/RequireKeplr.tsx => RequireLedger/RequireLedger.tsx} (85%) create mode 100644 src/ledgers/CosmoStationLedger.ts diff --git a/index.html b/index.html index 70abfc3..71e197b 100644 --- a/index.html +++ b/index.html @@ -16,5 +16,6 @@
+ diff --git a/package.json b/package.json index 1812e24..73e925c 100644 --- a/package.json +++ b/package.json @@ -10,6 +10,8 @@ }, "dependencies": { "@apollo/client": "^3.5.10", + "@cosmostation/cosmos-client": "^0.0.1", + "@cosmostation/extension-client": "0.1.7", "@emotion/react": "^11.8.2", "@emotion/styled": "^11.8.1", "@fontsource/poppins": "^4.5.5", diff --git a/src/App.tsx b/src/App.tsx index 97b2473..1fafdfc 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -8,18 +8,20 @@ import { Routes, Route, useLocation, Navigate } from 'react-router-dom' import { fetchRedelegations } from 'api/getAccountRedelegations' import { fetchUndedelegations } from 'api/getAccountUndelegations' import BigNumber from 'bignumber.js' -import { ConnectLedger } from 'ledgers/KeplrLedger' import { updateUser } from 'store/profile' import { updateUserTransactions } from 'store/userTransactions' import { fetchRewards } from 'api/getRewards' import NotificationPopup from 'components/NotificationPopup' import { fetchDelegations } from 'api/getAccountDelegations' +import CosmosNetworkConfig from 'ledgers/CosmosNetworkConfig' +import { connectKeplrLedger } from 'ledgers/KeplrLedger' +import { connectCosmostationLedger } from 'ledgers/CosmoStationLedger' import { switchLedgerType } from 'ledgers/utils' import { getUnbondingBalance } from 'api/getUnbondingBalance' import { getStakedBalance, getWalletBalance } from './utils/projectUtils' import { useApollo } from './graphql/client' import Layout from './components/Layout' -import RequireKeplr from './components/RequireKeplr/RequireKeplr' +import RequireLedger from './components/RequireLedger/RequireLedger' import ConnectWallet from './containers/ConnectWallet/ConnectWallet' import Dashboard from './containers/Dashboard' import Proposals from './containers/Proposals' @@ -41,9 +43,9 @@ const App = () => { const dispatch = useDispatch() - const connectAccount = useCallback(async () => { + const connectAccount = useCallback(async (ledgerType: string) => { try { - const { address, keplrName } = await ConnectLedger() + const { address, accountName } = await switchLedgerType(ledgerType) if (address !== lastLoggedAddress || lastLoggedAddress === '') { dispatch( updateUserTransactions({ @@ -72,7 +74,8 @@ const App = () => { updateUser({ address, lastLoggedAddress: address, - keplrName, + connectedLedger: ledgerType, + accountName, balance: new BigNumber(balance), availableRewards: new BigNumber(totalRewards), stakedValidators: validatorArray, @@ -100,12 +103,21 @@ const App = () => { }) ) - await connectAccount() + await connectAccount(CosmosNetworkConfig.KEPLR_LEDGER) }) + if (window.cosmostation) { + window.cosmostation.cosmos.on('accountChanged', async () => { + await connectAccount(CosmosNetworkConfig.COSMOSTATION_LEDGER) + }) + } + return () => { window.removeEventListener('keplr_keystorechange', async () => { - await connectAccount() + await connectAccount(CosmosNetworkConfig.KEPLR_LEDGER) + }) + window.removeEventListener('accountChanged', async () => { + await connectAccount(CosmosNetworkConfig.COSMOSTATION_LEDGER) }) } }, []) @@ -125,7 +137,7 @@ const App = () => { {location.pathname === '/' ? null : ( - }> + }> } /> diff --git a/src/assets/vectors/cosmostation-logo.svg b/src/assets/vectors/cosmostation-logo.svg new file mode 100644 index 0000000..b926f2b --- /dev/null +++ b/src/assets/vectors/cosmostation-logo.svg @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/src/components/Dialog/components/DelegationModal/Delegation.tsx b/src/components/Dialog/components/DelegationModal/Delegation.tsx index c9a8c0a..30a6c10 100644 --- a/src/components/Dialog/components/DelegationModal/Delegation.tsx +++ b/src/components/Dialog/components/DelegationModal/Delegation.tsx @@ -54,14 +54,19 @@ const Delegation: React.FC = ({ modalProps, handleModal }) => { const [delegationAmount, setDelegationAmount] = useState('') const { validator, amount, fee } = modalProps - const { address } = useSelector(({ profile }: RootState) => profile) + const { address, connectedLedger } = useSelector( + ({ profile }: RootState) => profile + ) const dispatch = useDispatch() useEffect(() => { const loadBalance = async () => { - const walletBalance = await ( - await signingClient - ).getBalance(address, CosmosNetworkConfig.CURRENCY_DENOM) + const client = await signingClient(connectedLedger) + + const walletBalance = await client.getBalance( + address, + CosmosNetworkConfig.CURRENCY_DENOM + ) setBalance( new BigNumber(walletBalance.amount) @@ -90,9 +95,9 @@ const Delegation: React.FC = ({ modalProps, handleModal }) => { value: msg } - const gasUsed = await ( - await signingClient - ).simulate(address, [msgAny], 'memo') + const client = await signingClient(connectedLedger) + + const gasUsed = await client.simulate(address, [msgAny], 'memo') const gasLimit = Math.round(gasUsed * feeMultiplier) @@ -153,15 +158,12 @@ const Delegation: React.FC = ({ modalProps, handleModal }) => { handleModal({ status: ModalStatus.LOADING }) try { - const walletAccount = await window.keplr.getKey( - import.meta.env.VITE_APP_CHAIN_ID - ) - const delegationResult = await delegate( - walletAccount.bech32Address, + address, validator?.address || '', amount || '', - '' + '', + connectedLedger ) handleModal({ diff --git a/src/components/Layout/UserInfo.tsx b/src/components/Layout/UserInfo.tsx index 90425bb..51d244f 100644 --- a/src/components/Layout/UserInfo.tsx +++ b/src/components/Layout/UserInfo.tsx @@ -6,6 +6,8 @@ import BigNumber from 'bignumber.js' import { RootState } from 'store' import { updateUser } from 'store/profile' import { copyToClipboard, formatAddress } from 'utils/projectUtils' +import KeplrLogo from 'assets/vectors/keplr-logo.svg' +import CosmostationLogo from 'assets/vectors/cosmostation-logo.svg' import LinkIcon from 'assets/vectors/link-icon.svg' import CopyIcon from 'assets/vectors/copy-icon.svg' import ArrowIcon from 'assets/vectors/arrow-down.svg' @@ -16,7 +18,7 @@ import { styles } from './styles' const UserInfo = () => { const navigate = useNavigate() const dispatch = useDispatch() - const { address, lastLoggedAddress, keplrName } = useSelector( + const { address, accountName, connectedLedger } = useSelector( (state: RootState) => state.profile ) @@ -40,7 +42,7 @@ const UserInfo = () => { dispatch( updateUser({ address: '', - keplrName: '', + accountName: '', lastLoggedAddress: address, balance: new BigNumber(0), availableRewards: new BigNumber(0), @@ -48,7 +50,8 @@ const UserInfo = () => { stakedBalance: new BigNumber(0), delegations: [], redelegations: [], - undelegations: [] + undelegations: [], + connectedLedger: '' }) ) navigate('/') @@ -58,17 +61,30 @@ const UserInfo = () => { setOpen(false)}> setOpen(true)} sx={styles.userContainer}> + + Logo + Hi, - {` ${getMiddleEllipsis(keplrName, { beginning: 8, ending: 4 })}`} + {` ${getMiddleEllipsis(accountName, { + beginning: 8, + ending: 4 + })}`} Arrow Icon ({ @@ -58,7 +62,6 @@ export const styles: SxMap = { } }), footerContainer: { - // position: 'relative', display: 'flex', justifyContent: 'flex-start', alignItems: 'center', @@ -73,6 +76,7 @@ export const styles: SxMap = { marginRight: '20px' }), user: ({ custom }) => ({ + position: 'relative', maxWidth: '224px', maxHeight: '48px', borderRadius: '55px', diff --git a/src/components/RequireKeplr/RequireKeplr.tsx b/src/components/RequireLedger/RequireLedger.tsx similarity index 85% rename from src/components/RequireKeplr/RequireKeplr.tsx rename to src/components/RequireLedger/RequireLedger.tsx index 32654b5..d9a36e2 100644 --- a/src/components/RequireKeplr/RequireKeplr.tsx +++ b/src/components/RequireLedger/RequireLedger.tsx @@ -2,7 +2,7 @@ import { Navigate, useLocation, Outlet } from 'react-router-dom' import { useSelector } from 'react-redux' import { RootState } from 'store' -const RequireKeplr = () => { +const RequireLedger = () => { const { address } = useSelector((state: RootState) => state.profile) const location = useLocation() @@ -13,4 +13,4 @@ const RequireKeplr = () => { ) } -export default RequireKeplr +export default RequireLedger diff --git a/src/containers/ConnectWallet/ConnectWallet.tsx b/src/containers/ConnectWallet/ConnectWallet.tsx index 5d3aa7a..06cd2ab 100644 --- a/src/containers/ConnectWallet/ConnectWallet.tsx +++ b/src/containers/ConnectWallet/ConnectWallet.tsx @@ -1,5 +1,6 @@ /* eslint-disable @typescript-eslint/no-non-null-assertion */ -import { Box, Button, Typography } from '@mui/material' +import { useState } from 'react' +import { Box, Button, CircularProgress, Typography } from '@mui/material' import { useNavigate } from 'react-router-dom' import { useDispatch, useSelector } from 'react-redux' import BigNumber from 'bignumber.js' @@ -7,9 +8,10 @@ import { RootState } from 'store' import { updateUserTransactions } from 'store/userTransactions' import { fetchRewards } from 'api/getRewards' import { updateUser } from 'store/profile' -import { ConnectLedger } from 'ledgers/KeplrLedger' +import { connectKeplrLedger } from 'ledgers/KeplrLedger' import { getStakedBalance, getWalletBalance } from 'utils/projectUtils' import InfoIcon from 'assets/vectors/info-icon.svg' +import CosmostationLogo from 'assets/vectors/cosmostation-logo.svg' import KeplrLogo from 'assets/vectors/keplr-logo.svg' import Header from 'components/Layout/Header' import { useNotifications } from 'components/NotificationPopup/hooks' @@ -19,6 +21,7 @@ import { fetchRedelegations } from 'api/getAccountRedelegations' import { fetchUndedelegations } from 'api/getAccountUndelegations' import { getUnbondingBalance } from 'api/getUnbondingBalance' import CosmosNetworkConfig from 'ledgers/CosmosNetworkConfig' +import { connectCosmostationLedger } from 'ledgers/CosmoStationLedger' import { switchLedgerType } from 'ledgers/utils' import { COLORS_DARK_THEME } from 'theme/colors' @@ -29,10 +32,14 @@ const ConnectWallet = () => { const navigate = useNavigate() const { lastLoggedAddress } = useSelector((state: RootState) => state.profile) const { setWarning } = useNotifications() + const [loading, setLoading] = useState(false) + const [ledger, setLedger] = useState('') - const connect = async () => { + const connect = async (ledgerType: string) => { try { - const { address, keplrName } = await ConnectLedger() + setLedger(ledgerType) + setLoading(true) + const { address, accountName } = await switchLedgerType(ledgerType) if (address !== lastLoggedAddress) { dispatch(updateUserTransactions({ offsetCount: 0, data: [] })) } @@ -47,7 +54,8 @@ const ConnectWallet = () => { dispatch( updateUser({ address, - keplrName, + accountName, + connectedLedger: ledgerType, balance: new BigNumber(balance), availableRewards: new BigNumber(totalRewards), stakedValidators: validatorArray, @@ -58,10 +66,13 @@ const ConnectWallet = () => { undelegations: undelegationsArray }) ) + setLoading(false) navigate('dashboard') } catch (error) { + setLedger('') + setLoading(false) setWarning( - 'Failed connecting to wallet! Please check your Keplr installation.' + `Failed connecting to wallet! Please check your ${ledgerType} installation.` ) } } @@ -83,17 +94,66 @@ const ConnectWallet = () => { + + + Info - Make sure you have Keplr plugin downloaded. + Make sure you have either Keplr or Cosmostation plugin downloaded. diff --git a/src/containers/ConnectWallet/styles.ts b/src/containers/ConnectWallet/styles.ts index 0f18043..d425a23 100644 --- a/src/containers/ConnectWallet/styles.ts +++ b/src/containers/ConnectWallet/styles.ts @@ -10,7 +10,7 @@ export const styles = { left: '50%', marginRight: '-50%', transform: 'translate(-50%, -50%)', - maxWidth: '535px' + maxWidth: '600px' }, subHeaderContainer: { display: 'flex', @@ -18,12 +18,17 @@ export const styles = { }, connectButton: { height: '50px', - width: '250px', + width: '290px', marginTop: '50px', + marginBottom: '30px' + }, + cosmostationConnectBtn: { + height: '50px', + width: '290px', marginBottom: '40px' }, pluginWarning: { - maxWidth: '490px', + maxWidth: '600px', fontSize: '14px', height: '60px', backgroundColor: 'rgba(82, 166, 248, 0.1)', @@ -36,6 +41,11 @@ export const styles = { keplrLogo: { marginRight: '10px' }, + cosmostationLogo: { + marginRight: '10px', + width: '30px', + height: '30px' + }, infoIcon: { display: 'flex', marginRight: '10px' diff --git a/src/containers/Proposals/components/DepositModal/Deposit.tsx b/src/containers/Proposals/components/DepositModal/Deposit.tsx index 5c679f6..b0e1df2 100644 --- a/src/containers/Proposals/components/DepositModal/Deposit.tsx +++ b/src/containers/Proposals/components/DepositModal/Deposit.tsx @@ -20,7 +20,9 @@ type DepositProps = { const Deposit: React.FC = ({ handleModal, modalProps }) => { const [depositAmount, setDepositAmount] = useState('') - const { address, balance } = useSelector((state: RootState) => state.profile) + const { address, balance, connectedLedger } = useSelector( + (state: RootState) => state.profile + ) const { id, title } = modalProps @@ -43,7 +45,8 @@ const Deposit: React.FC = ({ handleModal, modalProps }) => { const { gasFee, result } = await depositProposal( depositorAddress, proposalId, - amount + amount, + connectedLedger ) handleModal({ diff --git a/src/containers/Proposals/components/ProposalModal/Proposals.tsx b/src/containers/Proposals/components/ProposalModal/Proposals.tsx index 7075ca5..6454b42 100644 --- a/src/containers/Proposals/components/ProposalModal/Proposals.tsx +++ b/src/containers/Proposals/components/ProposalModal/Proposals.tsx @@ -30,7 +30,9 @@ type ProposalProps = { const Proposals: React.FC = ({ handleModal, modalProps }) => { const { setError } = useNotifications() - const { address } = useSelector(({ profile }: RootState) => profile) + const { address, connectedLedger } = useSelector( + ({ profile }: RootState) => profile + ) const { proposalData } = modalProps const [proposal, setProposal] = useState('1') @@ -75,7 +77,8 @@ const Proposals: React.FC = ({ handleModal, modalProps }) => { }) const { result, gasFee } = await createProposal( proposalData, - proposerAddress + proposerAddress, + connectedLedger ) handleModal({ open: true, diff --git a/src/containers/Proposals/components/VotingModal/Vote.tsx b/src/containers/Proposals/components/VotingModal/Vote.tsx index 6418321..33475d9 100644 --- a/src/containers/Proposals/components/VotingModal/Vote.tsx +++ b/src/containers/Proposals/components/VotingModal/Vote.tsx @@ -23,7 +23,9 @@ const Vote: React.FC = ({ handleModal, modalProps }) => { const { id, title } = modalProps - const { address } = useSelector((state: RootState) => state.profile) + const { address, connectedLedger } = useSelector( + (state: RootState) => state.profile + ) const handleSubmitVote = async ( voterAddress: string, @@ -38,7 +40,8 @@ const Vote: React.FC = ({ handleModal, modalProps }) => { const { gasFee, result } = await voteProposal( voterAddress, proposalId, - votingOption + votingOption, + connectedLedger ) handleModal({ diff --git a/src/containers/ValidatorDetails/components/Details/components/ValidatorInfo/components/RedelegationModal/Redelegation.tsx b/src/containers/ValidatorDetails/components/Details/components/ValidatorInfo/components/RedelegationModal/Redelegation.tsx index 7e63f5a..58e8227 100644 --- a/src/containers/ValidatorDetails/components/Details/components/ValidatorInfo/components/RedelegationModal/Redelegation.tsx +++ b/src/containers/ValidatorDetails/components/Details/components/ValidatorInfo/components/RedelegationModal/Redelegation.tsx @@ -52,7 +52,9 @@ const Redelegation: React.FC = ({ const { validator, amount, fee } = modalProps const dispatch = useDispatch() - const { address } = useSelector(({ profile }: RootState) => profile) + const { address, connectedLedger } = useSelector( + ({ profile }: RootState) => profile + ) const validators = useSelector(({ validator }: RootState) => validator.items) const data = validators.map((item) => ({ value: item.validator, @@ -71,9 +73,12 @@ const Redelegation: React.FC = ({ useEffect(() => { const loadBalance = async () => { - const walletBalance = await ( - await signingClient - ).getDelegation(address, validator?.address || '') + const client = await signingClient(connectedLedger) + + const walletBalance = await client.getDelegation( + address, + validator?.address || '' + ) setDelegated( new BigNumber(walletBalance?.amount || 0) @@ -109,9 +114,9 @@ const Redelegation: React.FC = ({ value: msg } - const gasUsed = await ( - await signingClient - ).simulate(address, [msgAny], 'memo') + const client = await signingClient(connectedLedger) + + const gasUsed = await client.simulate(address, [msgAny], 'memo') const gasLimit = Math.round(gasUsed * feeMultiplier) @@ -155,9 +160,9 @@ const Redelegation: React.FC = ({ value: msg } - const gasUsed = await ( - await signingClient - ).simulate(address, [msgAny], 'memo') + const client = await signingClient(connectedLedger) + + const gasUsed = await client.simulate(address, [msgAny], 'memo') const gasLimit = Math.round(gasUsed * feeMultiplier) @@ -190,16 +195,13 @@ const Redelegation: React.FC = ({ handleModal({ status: ModalStatus.LOADING }) try { - const walletAccount = await window.keplr.getKey( - import.meta.env.VITE_APP_CHAIN_ID - ) - const redelegationResult = await redelegate( - walletAccount.bech32Address, + address, validator?.address || '', redelegationAddress, amount || '', - '' + '', + connectedLedger ) handleModal({ diff --git a/src/containers/ValidatorDetails/components/Details/components/ValidatorInfo/components/UndelegationModal/Undelegation.tsx b/src/containers/ValidatorDetails/components/Details/components/ValidatorInfo/components/UndelegationModal/Undelegation.tsx index f6289aa..67fa1ab 100644 --- a/src/containers/ValidatorDetails/components/Details/components/ValidatorInfo/components/UndelegationModal/Undelegation.tsx +++ b/src/containers/ValidatorDetails/components/Details/components/ValidatorInfo/components/UndelegationModal/Undelegation.tsx @@ -1,6 +1,6 @@ import { useEffect, useState } from 'react' import { Typography, Box, InputAdornment, Button, Stack } from '@mui/material' -import _ from 'lodash' +import _, { add } from 'lodash' import { AccountBalanceWalletRounded as AccountBalanceWalletRoundedIcon, ArrowCircleRightRounded as ArrowCircleRightRoundedIcon @@ -50,13 +50,18 @@ const Undelegation: React.FC = ({ const { validator, amount, fee } = modalProps const dispatch = useDispatch() - const { address } = useSelector(({ profile }: RootState) => profile) + const { address, connectedLedger } = useSelector( + ({ profile }: RootState) => profile + ) useEffect(() => { const loadBalance = async () => { - const walletBalance = await ( - await signingClient - ).getDelegation(address, validator?.address || '') + const client = await signingClient(connectedLedger) + + const walletBalance = await client.getDelegation( + address, + validator?.address || '' + ) setDelegated( new BigNumber(walletBalance?.amount || 0) @@ -86,9 +91,9 @@ const Undelegation: React.FC = ({ value: msg } - const gasUsed = await ( - await signingClient - ).simulate(address, [msgAny], 'memo') + const client = await signingClient(connectedLedger) + + const gasUsed = await client.simulate(address, [msgAny], 'memo') const gasLimit = Math.round(gasUsed * feeMultiplier) @@ -131,9 +136,9 @@ const Undelegation: React.FC = ({ value: msg } - const gasUsed = await ( - await signingClient - ).simulate(address, [msgAny], 'memo') + const client = await signingClient(connectedLedger) + + const gasUsed = await client.simulate(address, [msgAny], 'memo') const gasLimit = Math.round(gasUsed * feeMultiplier) @@ -166,15 +171,12 @@ const Undelegation: React.FC = ({ handleModal({ status: ModalStatus.LOADING }) try { - const walletAccount = await window.keplr.getKey( - import.meta.env.VITE_APP_CHAIN_ID - ) - const undelegationResult = await undelegate( - walletAccount.bech32Address, + address, validator?.address || '', amount || '', - '' + '', + connectedLedger ) handleModal({ diff --git a/src/ledgers/CosmoStationLedger.ts b/src/ledgers/CosmoStationLedger.ts new file mode 100644 index 0000000..44341fe --- /dev/null +++ b/src/ledgers/CosmoStationLedger.ts @@ -0,0 +1,67 @@ +import { cosmos, InstallError } from '@cosmostation/extension-client' +import CosmosNetworkConfig from './CosmosNetworkConfig' + +export const connectCosmostationLedger = async (): Promise<{ + address: string + accountName: string +}> => { + let userAccountAddress = '' + + let userAccountName = '' + + try { + const provider = await cosmos() + + const activatedChains = await provider.getActivatedChains() + + if ( + !activatedChains.includes( + import.meta.env.VITE_APP_CHAIN_NAME.toLowerCase() + ) + ) { + await provider.addChain({ + chainId: import.meta.env.VITE_APP_CHAIN_ID, + + chainName: import.meta.env.VITE_APP_CHAIN_NAME, + + addressPrefix: CosmosNetworkConfig.BECH32_PREFIX_ACC_ADDR, + + baseDenom: CosmosNetworkConfig.CURRENCY_DENOM, + + displayDenom: CosmosNetworkConfig.CURRENCY_DISPLAY_NAME, + + restURL: import.meta.env.VITE_APP_API, + + decimals: 18, + + coinGeckoId: CosmosNetworkConfig.BECH32_PREFIX_ACC_ADDR, + + gasRate: { + average: (Number(import.meta.env.VITE_APP_GAS_PRICE) * 2).toString(), + + low: (Number(import.meta.env.VITE_APP_GAS_PRICE) * 2).toString(), + + tiny: import.meta.env.VITE_APP_GAS_PRICE.toString() + } + }) + } + + const acccount = await provider.requestAccount( + import.meta.env.VITE_APP_CHAIN_NAME + ) + + userAccountAddress = acccount.address + + userAccountName = acccount.name + } catch (e: any) { + if (e instanceof InstallError) { + throw new Error('Cosmostation extension not found') + } + + if (e.code === 4001) { + throw new Error('user rejected request') + } + } + + return { address: userAccountAddress, accountName: userAccountName } +} diff --git a/src/ledgers/CosmosNetworkConfig.ts b/src/ledgers/CosmosNetworkConfig.ts index 8995f7f..9aeb371 100644 --- a/src/ledgers/CosmosNetworkConfig.ts +++ b/src/ledgers/CosmosNetworkConfig.ts @@ -28,4 +28,8 @@ export default class CosmosNetworkConfig { static BECH32_PREFIX_CONS_PUB = 'cudosvalconspub' static BECH32_ACC_ADDR_LENGTH = 44 + + static KEPLR_LEDGER = 'Keplr' + + static COSMOSTATION_LEDGER = 'Cosmostation' } diff --git a/src/ledgers/KeplrLedger.tsx b/src/ledgers/KeplrLedger.tsx index 61d2e4f..72adc1e 100644 --- a/src/ledgers/KeplrLedger.tsx +++ b/src/ledgers/KeplrLedger.tsx @@ -3,13 +3,14 @@ import { KeplrWallet } from 'cudosjs' declare global { interface Window { keplr: any + cosmostation: any getOfflineSigner: any getOfflineSignerOnlyAmino: any meta: any } } -export const ConnectLedger = async () => { +export const connectKeplrLedger = async () => { const wallet = new KeplrWallet({ CHAIN_ID: import.meta.env.VITE_APP_CHAIN_ID, CHAIN_NAME: import.meta.env.VITE_APP_CHAIN_NAME, @@ -23,5 +24,5 @@ export const ConnectLedger = async () => { const key = await window.keplr.getKey(import.meta.env.VITE_APP_CHAIN_ID) - return { address: key.bech32Address, keplrName: key.name } + return { address: key.bech32Address, accountName: key.name } } diff --git a/src/ledgers/transactions.ts b/src/ledgers/transactions.ts index 3f80864..d1bf1e8 100644 --- a/src/ledgers/transactions.ts +++ b/src/ledgers/transactions.ts @@ -69,8 +69,14 @@ export const calculateFee = (gasLimit: number, gasPrice: string | GasPrice) => { } } -export const getFee = async (address: string, message: any[], memo: string) => { - const gasUsed = await (await signingClient).simulate(address, message, memo) +export const getFee = async ( + address: string, + ledgerType: string, + message: any[], + memo: string +) => { + const client = await signingClient(ledgerType) + const gasUsed = await client.simulate(address, message, memo) const gasLimit = Math.round(gasUsed * feeMultiplier) @@ -83,7 +89,8 @@ export const delegate = async ( delegatorAddress: string, validatorAddress: string, amount: string, - memo: string + memo: string, + ledgerType: string ): Promise => { const delegationAmount = { amount: new BigNumber(amount) @@ -108,11 +115,11 @@ export const delegate = async ( value: msg } - const fee = await getFee(delegatorAddress, [msgAny], memo) + const fee = await getFee(delegatorAddress, ledgerType, [msgAny], memo) - const result = await ( - await signingClient - ).delegateTokens( + const client = await signingClient(ledgerType) + + const result = await client.delegateTokens( delegatorAddress, validatorAddress, delegationAmount, @@ -127,7 +134,8 @@ export const undelegate = async ( delegatorAddress: string, validatorAddress: string, amount: string, - memo: string + memo: string, + ledgerType: string ): Promise => { const undelegationAmount = { amount: new BigNumber(amount || 0) @@ -152,11 +160,11 @@ export const undelegate = async ( value: msg } - const fee = await getFee(delegatorAddress, [msgAny], memo) + const fee = await getFee(delegatorAddress, ledgerType, [msgAny], memo) - const result = await ( - await signingClient - ).undelegateTokens( + const client = await signingClient(ledgerType) + + const result = await client.undelegateTokens( delegatorAddress, validatorAddress, undelegationAmount, @@ -172,7 +180,8 @@ export const redelegate = async ( validatorSrcAddress: string, validatorDstAddress: string, amount: string, - memo: string + memo: string, + ledgerType: string ): Promise => { const msg = MsgBeginRedelegate.fromPartial({ delegatorAddress, @@ -191,11 +200,16 @@ export const redelegate = async ( value: msg } - const fee = await getFee(delegatorAddress, [msgAny], memo) + const fee = await getFee(delegatorAddress, ledgerType, [msgAny], memo) - const result = await ( - await signingClient - ).signAndBroadcast(delegatorAddress, [msgAny], fee, memo) + const client = await signingClient(ledgerType) + + const result = await client.signAndBroadcast( + delegatorAddress, + [msgAny], + fee, + memo + ) return result } @@ -262,9 +276,9 @@ export const claimRewards = async ( fee = await getFee(address, ledgerType, [...msgAny], msgMemo) - const result = await ( - await signingClient - ).signAndBroadcast(address, msgAny, fee, msgMemo) + const client = await signingClient(ledgerType) + + const result = await client.signAndBroadcast(address, msgAny, fee, msgMemo) if (claimAndRestakeSeparateMsg) { stakedValidators.forEach((validator) => { @@ -306,7 +320,8 @@ export const claimRewards = async ( export const voteProposal = async ( voterAddress: string, proposalId: number | undefined, - votingOption: number + votingOption: number, + ledgerType: string ) => { const msg = MsgVote.fromPartial({ proposalId, @@ -321,11 +336,16 @@ export const voteProposal = async ( const memo = 'Sent via CUDOS Dashboard' - const fee = await getFee(voterAddress, [msgAny], memo) + const fee = await getFee(voterAddress, ledgerType, [msgAny], memo) + + const client = await signingClient(ledgerType) - const result = await ( - await signingClient - ).signAndBroadcast(voterAddress, [msgAny], fee, memo) + const result = await client.signAndBroadcast( + voterAddress, + [msgAny], + fee, + memo + ) return { result, @@ -336,7 +356,8 @@ export const voteProposal = async ( export const depositProposal = async ( depositorAddress: string, proposalId: number | undefined, - amount: string + amount: string, + ledgerType: string ) => { const msg = MsgDeposit.fromPartial({ proposalId, @@ -358,11 +379,16 @@ export const depositProposal = async ( const memo = 'Sent via CUDOS Dashboard' - const fee = await getFee(depositorAddress, [msgAny], memo) + const fee = await getFee(depositorAddress, ledgerType, [msgAny], memo) - const result = await ( - await signingClient - ).signAndBroadcast(depositorAddress, [msgAny], fee, memo) + const client = await signingClient(ledgerType) + + const result = await client.signAndBroadcast( + depositorAddress, + [msgAny], + fee, + memo + ) return { result, @@ -468,16 +494,10 @@ export const getProposalContent = (proposalData: any) => { export const createProposal = async ( proposalData: any, - proposerAddress: string + proposerAddress: string, + ledgerType: string ) => { - const offlineSigner = window.getOfflineSigner( - import.meta.env.VITE_APP_CHAIN_ID - ) - - const client = await SigningStargateClient.connectWithSigner( - import.meta.env.VITE_APP_RPC, - offlineSigner - ) + const client = await signingClient(ledgerType) const content = getProposalContent(proposalData) @@ -501,7 +521,7 @@ export const createProposal = async ( const memo = 'Sent via CUDOS Dashboard' - const fee = await getFee(proposerAddress, [msgAny], memo) + const fee = await getFee(proposerAddress, ledgerType, [msgAny], memo) const result = await client.signAndBroadcast( proposerAddress, diff --git a/src/ledgers/utils.ts b/src/ledgers/utils.ts index e3e4a5d..d6e7b12 100644 --- a/src/ledgers/utils.ts +++ b/src/ledgers/utils.ts @@ -1,4 +1,8 @@ -import { SigningStargateClient, StargateClient } from 'cudosjs' +import { OfflineSigner, SigningStargateClient, StargateClient } from 'cudosjs' +import { getOfflineSigner as cosmostationSigner } from '@cosmostation/cosmos-client' +import CosmosNetworkConfig from './CosmosNetworkConfig' +import { connectKeplrLedger } from './KeplrLedger' +import { connectCosmostationLedger } from './CosmoStationLedger' const colors = { staking: '#3d5afe', @@ -433,28 +437,56 @@ export const unknownMessage = { displayName: 'Unknown' } -export const signingClient = (async () => { - try { +export const switchLedgerType = async (ledgerType: string) => { + let ledger + switch (ledgerType) { + case CosmosNetworkConfig.KEPLR_LEDGER: + ledger = await connectKeplrLedger() + return ledger + case CosmosNetworkConfig.COSMOSTATION_LEDGER: + ledger = await connectCosmostationLedger() + return ledger + default: + return { address: '', accountName: '' } + } +} + +const switchSigningClient = async ( + ledgerType: string +): Promise => { + let client + switch (ledgerType) { + case CosmosNetworkConfig.KEPLR_LEDGER: + client = await window.getOfflineSigner(import.meta.env.VITE_APP_CHAIN_ID) + return client + case CosmosNetworkConfig.COSMOSTATION_LEDGER: + client = await cosmostationSigner(import.meta.env.VITE_APP_CHAIN_ID) + return client + default: + return undefined + } +} + +export const signingClient = async (ledgerType: string) => { + const offlineSigner = await switchSigningClient(ledgerType) + + if (window.keplr) { window.keplr.defaultOptions = { sign: { preferNoSetFee: true } } + } - const offlineSigner = window.getOfflineSignerOnlyAmino( - import.meta.env.VITE_APP_CHAIN_ID - ) - - const client = await SigningStargateClient.connectWithSigner( - import.meta.env.VITE_APP_RPC, - offlineSigner - ) - - return client - } catch (error) { - throw new Error('Check your Keplr installation.') + if (!offlineSigner) { + throw new Error('Invalid signing client') } -})() + + return SigningStargateClient.connectWithSigner( + import.meta.env.VITE_APP_RPC, + offlineSigner + ) +} export const client = (async () => { try { diff --git a/src/store/profile.ts b/src/store/profile.ts index 2f6d5a9..65cfee0 100644 --- a/src/store/profile.ts +++ b/src/store/profile.ts @@ -3,7 +3,8 @@ import BigNumber from 'bignumber.js' export interface WalletState { address: string - keplrName: string + accountName: string + connectedLedger: string lastLoggedAddress: string balance: BigNumber availableRewards: BigNumber @@ -25,7 +26,8 @@ export interface WalletState { const initialState: WalletState = { address: '', - keplrName: '', + accountName: '', + connectedLedger: '', lastLoggedAddress: '', balance: new BigNumber(0), availableRewards: new BigNumber(0), diff --git a/yarn.lock b/yarn.lock index ab506ad..b4c00b7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -625,6 +625,16 @@ "@cosmjs/math" "0.28.11" "@cosmjs/utils" "0.28.11" +"@cosmjs/amino@^0.28.4": + version "0.28.13" + resolved "https://registry.yarnpkg.com/@cosmjs/amino/-/amino-0.28.13.tgz#b51417a23c1ff8ef8b85a6862eba8492c6c44f38" + integrity sha512-IHnH2zGwaY69qT4mVAavr/pfzx6YE+ud1NHJbvVePlbGiz68CXTi5LHR+K0lrKB5mQ7E+ZErWz2mw5U/x+V1wQ== + dependencies: + "@cosmjs/crypto" "0.28.13" + "@cosmjs/encoding" "0.28.13" + "@cosmjs/math" "0.28.13" + "@cosmjs/utils" "0.28.13" + "@cosmjs/cosmwasm-stargate@^0.28.4": version "0.28.11" resolved "https://registry.yarnpkg.com/@cosmjs/cosmwasm-stargate/-/cosmwasm-stargate-0.28.11.tgz#73e30208a0f7668c0550c5a2410e5289ae46cbd2" @@ -655,6 +665,19 @@ elliptic "^6.5.3" libsodium-wrappers "^0.7.6" +"@cosmjs/crypto@0.28.13": + version "0.28.13" + resolved "https://registry.yarnpkg.com/@cosmjs/crypto/-/crypto-0.28.13.tgz#541b6a36f616b2da5a568ead46d4e83841ceb412" + integrity sha512-ynKfM0q/tMBQMHJby6ad8lR3gkgBKaelQhIsCZTjClsnuC7oYT9y3ThSZCUWr7Pa9h0J8ahU2YV2oFWFVWJQzQ== + dependencies: + "@cosmjs/encoding" "0.28.13" + "@cosmjs/math" "0.28.13" + "@cosmjs/utils" "0.28.13" + "@noble/hashes" "^1" + bn.js "^5.2.0" + elliptic "^6.5.3" + libsodium-wrappers "^0.7.6" + "@cosmjs/encoding@0.28.11": version "0.28.11" resolved "https://registry.yarnpkg.com/@cosmjs/encoding/-/encoding-0.28.11.tgz#da6dd30ff105ff6a9e045aa6abed2526c94adb12" @@ -664,6 +687,15 @@ bech32 "^1.1.4" readonly-date "^1.0.0" +"@cosmjs/encoding@0.28.13": + version "0.28.13" + resolved "https://registry.yarnpkg.com/@cosmjs/encoding/-/encoding-0.28.13.tgz#7994e8e2c435beaf0690296ffb0f7f3eaec8150b" + integrity sha512-jtXbAYtV77rLHxoIrjGFsvgGjeTKttuHRv6cvuy3toCZzY7JzTclKH5O2g36IIE4lXwD9xwuhGJ2aa6A3dhNkA== + dependencies: + base64-js "^1.3.0" + bech32 "^1.1.4" + readonly-date "^1.0.0" + "@cosmjs/json-rpc@0.28.11": version "0.28.11" resolved "https://registry.yarnpkg.com/@cosmjs/json-rpc/-/json-rpc-0.28.11.tgz#17b4c543d2de978b41bed973c88a2425a794af37" @@ -679,6 +711,13 @@ dependencies: bn.js "^5.2.0" +"@cosmjs/math@0.28.13": + version "0.28.13" + resolved "https://registry.yarnpkg.com/@cosmjs/math/-/math-0.28.13.tgz#50c05bc67007a04216f7f5e0c93f57270f8cc077" + integrity sha512-PDpL8W/kbyeWi0mQ2OruyqE8ZUAdxPs1xCbDX3WXJwy2oU+X2UTbkuweJHVpS9CIqmZulBoWQAmlf6t6zr1N/g== + dependencies: + bn.js "^5.2.0" + "@cosmjs/proto-signing@0.28.11", "@cosmjs/proto-signing@^0.28.4": version "0.28.11" resolved "https://registry.yarnpkg.com/@cosmjs/proto-signing/-/proto-signing-0.28.11.tgz#7eecb60a025ab55a409441daa14a07bb1d9b2825" @@ -748,6 +787,45 @@ resolved "https://registry.yarnpkg.com/@cosmjs/utils/-/utils-0.28.11.tgz#dee7902a4b3cac8f66563b7e8f99fa976f9c4f1f" integrity sha512-FXVEr7Pg6MX9VbY5NemuKbtFVabSlUlArWIV+R74FQg5LIuSa+0QkxSpNldCuOLBEU4/GlrzybT4uEl338vSzg== +"@cosmjs/utils@0.28.13": + version "0.28.13" + resolved "https://registry.yarnpkg.com/@cosmjs/utils/-/utils-0.28.13.tgz#2fd2844ec832d7833811e2ae1691305d09791a08" + integrity sha512-dVeMBiyg+46x7XBZEfJK8yTihphbCFpjVYmLJVqmTsHfJwymQ65cpyW/C+V/LgWARGK8hWQ/aX9HM5Ao8QmMSg== + +"@cosmostation/cosmos-client@^0.0.1": + version "0.0.1" + resolved "https://registry.yarnpkg.com/@cosmostation/cosmos-client/-/cosmos-client-0.0.1.tgz#7b12411ff5d467b01d97abdf59596a2ade564a08" + integrity sha512-GmtQCyOazGxGdudSrLC0lW4B5FAVEWTuPg75uz79sLbyXbCDtB4Tfx8/wGjEtPyWHAKLnAvvCbi5fjGWldYOuw== + dependencies: + "@cosmjs/amino" "^0.28.4" + "@cosmjs/proto-signing" "^0.28.4" + "@cosmostation/extension-client" "^0.0.6" + "@cosmostation/wc-modal" "^0.0.1" + "@walletconnect/browser-utils" "^1.6.5" + "@walletconnect/client" "^1.7.8" + "@walletconnect/utils" "^1.6.5" + +"@cosmostation/extension-client@0.1.7": + version "0.1.7" + resolved "https://registry.yarnpkg.com/@cosmostation/extension-client/-/extension-client-0.1.7.tgz#1cf4ebb68f1b8005779539ab28bf6e99f37e852e" + integrity sha512-dBgbAO7wZRQnS29ATr7FeTilgZAPitDH1eapJvoRF3ohnPUiWIPlktnQ1ZW7HcRe5KgNurVZW4JQC1TtScP+8g== + +"@cosmostation/extension-client@^0.0.6": + version "0.0.6" + resolved "https://registry.yarnpkg.com/@cosmostation/extension-client/-/extension-client-0.0.6.tgz#a04420c1c3d68b83d197e48e79787a3484fb8d2c" + integrity sha512-3N7NOz8JMOpJlVaGS++zha4AZoijJTnPkq8djEfpk/mJ6+laUNo4a1/mxANFm9i1KUZcU9HX6GKKx9v9nL/VDg== + +"@cosmostation/wc-modal@^0.0.1": + version "0.0.1" + resolved "https://registry.yarnpkg.com/@cosmostation/wc-modal/-/wc-modal-0.0.1.tgz#33a6001a426d24f05e31c8b68716cd5dcf92f922" + integrity sha512-Y88onIqSKzMzrSROI7myK+BON8AbfoMAXaTOftzboJ7Cfnj3+g43tZ4F6jWFA2zr9hQlnRYmYbcN39HlUxRYIg== + dependencies: + "@walletconnect/browser-utils" "^1.6.5" + "@walletconnect/types" "^1.6.5" + qrcode.react "^1.0.1" + react "^16.14.0" + react-dom "^16.14.0" + "@cush/relative@^1.0.0": version "1.0.0" resolved "https://registry.yarnpkg.com/@cush/relative/-/relative-1.0.0.tgz#8cd1769bf9bde3bb27dac356b1bc94af40f6cc16" @@ -1909,6 +1987,137 @@ react-refresh "^0.13.0" resolve "^1.22.0" +"@walletconnect/browser-utils@^1.6.5", "@walletconnect/browser-utils@^1.8.0": + version "1.8.0" + resolved "https://registry.yarnpkg.com/@walletconnect/browser-utils/-/browser-utils-1.8.0.tgz#33c10e777aa6be86c713095b5206d63d32df0951" + integrity sha512-Wcqqx+wjxIo9fv6eBUFHPsW1y/bGWWRboni5dfD8PtOmrihrEpOCmvRJe4rfl7xgJW8Ea9UqKEaq0bIRLHlK4A== + dependencies: + "@walletconnect/safe-json" "1.0.0" + "@walletconnect/types" "^1.8.0" + "@walletconnect/window-getters" "1.0.0" + "@walletconnect/window-metadata" "1.0.0" + detect-browser "5.2.0" + +"@walletconnect/client@^1.7.8": + version "1.8.0" + resolved "https://registry.yarnpkg.com/@walletconnect/client/-/client-1.8.0.tgz#6f46b5499c7c861c651ff1ebe5da5b66225ca696" + integrity sha512-svyBQ14NHx6Cs2j4TpkQaBI/2AF4+LXz64FojTjMtV4VMMhl81jSO1vNeg+yYhQzvjcGH/GpSwixjyCW0xFBOQ== + dependencies: + "@walletconnect/core" "^1.8.0" + "@walletconnect/iso-crypto" "^1.8.0" + "@walletconnect/types" "^1.8.0" + "@walletconnect/utils" "^1.8.0" + +"@walletconnect/core@^1.8.0": + version "1.8.0" + resolved "https://registry.yarnpkg.com/@walletconnect/core/-/core-1.8.0.tgz#6b2748b90c999d9d6a70e52e26a8d5e8bfeaa81e" + integrity sha512-aFTHvEEbXcZ8XdWBw6rpQDte41Rxwnuk3SgTD8/iKGSRTni50gI9S3YEzMj05jozSiOBxQci4pJDMVhIUMtarw== + dependencies: + "@walletconnect/socket-transport" "^1.8.0" + "@walletconnect/types" "^1.8.0" + "@walletconnect/utils" "^1.8.0" + +"@walletconnect/crypto@^1.0.2": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@walletconnect/crypto/-/crypto-1.0.2.tgz#3fcc2b2cde6f529a19eadd883dc555cd0e861992" + integrity sha512-+OlNtwieUqVcOpFTvLBvH+9J9pntEqH5evpINHfVxff1XIgwV55PpbdvkHu6r9Ib4WQDOFiD8OeeXs1vHw7xKQ== + dependencies: + "@walletconnect/encoding" "^1.0.1" + "@walletconnect/environment" "^1.0.0" + "@walletconnect/randombytes" "^1.0.2" + aes-js "^3.1.2" + hash.js "^1.1.7" + +"@walletconnect/encoding@^1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@walletconnect/encoding/-/encoding-1.0.1.tgz#93c18ce9478c3d5283dbb88c41eb2864b575269a" + integrity sha512-8opL2rs6N6E3tJfsqwS82aZQDL3gmupWUgmvuZ3CGU7z/InZs3R9jkzH8wmYtpbq0sFK3WkJkQRZFFk4BkrmFA== + dependencies: + is-typedarray "1.0.0" + typedarray-to-buffer "3.1.5" + +"@walletconnect/environment@^1.0.0": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@walletconnect/environment/-/environment-1.0.0.tgz#c4545869fa9c389ec88c364e1a5f8178e8ab5034" + integrity sha512-4BwqyWy6KpSvkocSaV7WR3BlZfrxLbJSLkg+j7Gl6pTDE+U55lLhJvQaMuDVazXYxcjBsG09k7UlH7cGiUI5vQ== + +"@walletconnect/iso-crypto@^1.8.0": + version "1.8.0" + resolved "https://registry.yarnpkg.com/@walletconnect/iso-crypto/-/iso-crypto-1.8.0.tgz#44ddf337c4f02837c062dbe33fa7ab36789df451" + integrity sha512-pWy19KCyitpfXb70hA73r9FcvklS+FvO9QUIttp3c2mfW8frxgYeRXfxLRCIQTkaYueRKvdqPjbyhPLam508XQ== + dependencies: + "@walletconnect/crypto" "^1.0.2" + "@walletconnect/types" "^1.8.0" + "@walletconnect/utils" "^1.8.0" + +"@walletconnect/jsonrpc-types@^1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@walletconnect/jsonrpc-types/-/jsonrpc-types-1.0.1.tgz#a96b4bb2bcc8838a70e06f15c1b5ab11c47d8e95" + integrity sha512-+6coTtOuChCqM+AoYyi4Q83p9l/laI6NvuM2/AHaZFuf0gT0NjW7IX2+86qGyizn7Ptq4AYZmfxurAxTnhefuw== + dependencies: + keyvaluestorage-interface "^1.0.0" + +"@walletconnect/jsonrpc-utils@^1.0.3": + version "1.0.3" + resolved "https://registry.yarnpkg.com/@walletconnect/jsonrpc-utils/-/jsonrpc-utils-1.0.3.tgz#5bd49865eef0eae48e8b45a06731dc18691cf8c7" + integrity sha512-3yb49bPk16MNLk6uIIHPSHQCpD6UAo1OMOx1rM8cW/MPEAYAzrSW5hkhG7NEUwX9SokRIgnZK3QuQkiyNzBMhQ== + dependencies: + "@walletconnect/environment" "^1.0.0" + "@walletconnect/jsonrpc-types" "^1.0.1" + +"@walletconnect/randombytes@^1.0.2": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@walletconnect/randombytes/-/randombytes-1.0.2.tgz#95c644251a15e6675f58fbffc9513a01486da49c" + integrity sha512-ivgOtAyqQnN0rLQmOFPemsgYGysd/ooLfaDA/ACQ3cyqlca56t3rZc7pXfqJOIETx/wSyoF5XbwL+BqYodw27A== + dependencies: + "@walletconnect/encoding" "^1.0.1" + "@walletconnect/environment" "^1.0.0" + randombytes "^2.1.0" + +"@walletconnect/safe-json@1.0.0": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@walletconnect/safe-json/-/safe-json-1.0.0.tgz#12eeb11d43795199c045fafde97e3c91646683b2" + integrity sha512-QJzp/S/86sUAgWY6eh5MKYmSfZaRpIlmCJdi5uG4DJlKkZrHEF7ye7gA+VtbVzvTtpM/gRwO2plQuiooIeXjfg== + +"@walletconnect/socket-transport@^1.8.0": + version "1.8.0" + resolved "https://registry.yarnpkg.com/@walletconnect/socket-transport/-/socket-transport-1.8.0.tgz#9a1128a249628a0be11a0979b522fe82b44afa1b" + integrity sha512-5DyIyWrzHXTcVp0Vd93zJ5XMW61iDM6bcWT4p8DTRfFsOtW46JquruMhxOLeCOieM4D73kcr3U7WtyR4JUsGuQ== + dependencies: + "@walletconnect/types" "^1.8.0" + "@walletconnect/utils" "^1.8.0" + ws "7.5.3" + +"@walletconnect/types@^1.6.5", "@walletconnect/types@^1.8.0": + version "1.8.0" + resolved "https://registry.yarnpkg.com/@walletconnect/types/-/types-1.8.0.tgz#3f5e85b2d6b149337f727ab8a71b8471d8d9a195" + integrity sha512-Cn+3I0V0vT9ghMuzh1KzZvCkiAxTq+1TR2eSqw5E5AVWfmCtECFkVZBP6uUJZ8YjwLqXheI+rnjqPy7sVM4Fyg== + +"@walletconnect/utils@^1.6.5", "@walletconnect/utils@^1.8.0": + version "1.8.0" + resolved "https://registry.yarnpkg.com/@walletconnect/utils/-/utils-1.8.0.tgz#2591a197c1fa7429941fe428876088fda6632060" + integrity sha512-zExzp8Mj1YiAIBfKNm5u622oNw44WOESzo6hj+Q3apSMIb0Jph9X3GDIdbZmvVZsNPxWDL7uodKgZcCInZv2vA== + dependencies: + "@walletconnect/browser-utils" "^1.8.0" + "@walletconnect/encoding" "^1.0.1" + "@walletconnect/jsonrpc-utils" "^1.0.3" + "@walletconnect/types" "^1.8.0" + bn.js "4.11.8" + js-sha3 "0.8.0" + query-string "6.13.5" + +"@walletconnect/window-getters@1.0.0", "@walletconnect/window-getters@^1.0.0": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@walletconnect/window-getters/-/window-getters-1.0.0.tgz#1053224f77e725dfd611c83931b5f6c98c32bfc8" + integrity sha512-xB0SQsLaleIYIkSsl43vm8EwETpBzJ2gnzk7e0wMF3ktqiTGS6TFHxcprMl5R44KKh4tCcHCJwolMCaDSwtAaA== + +"@walletconnect/window-metadata@1.0.0": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@walletconnect/window-metadata/-/window-metadata-1.0.0.tgz#93b1cc685e6b9b202f29c26be550fde97800c4e5" + integrity sha512-9eFvmJxIKCC3YWOL97SgRkKhlyGXkrHwamfechmqszbypFspaSk+t2jQXAEU7YClHF6Qjw5eYOmy1//zFi9/GA== + dependencies: + "@walletconnect/window-getters" "^1.0.0" + "@wry/context@^0.6.0": version "0.6.1" resolved "https://registry.yarnpkg.com/@wry/context/-/context-0.6.1.tgz#c3c29c0ad622adb00f6a53303c4f965ee06ebeb2" @@ -1947,6 +2156,11 @@ acorn@^7.4.0: resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa" integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A== +aes-js@^3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/aes-js/-/aes-js-3.1.2.tgz#db9aabde85d5caabbfc0d4f2a4446960f627146a" + integrity sha512-e5pEa2kBnBOgR4Y/p20pskXI74UEz7de8ZGVo58asOtvSVG5YAbJeELPZxOmt+Bnz3rX753YKhfIn4X4l1PPRQ== + agent-base@6: version "6.0.2" resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.2.tgz#49fff58577cfee3f37176feab4c22e00f86d7f77" @@ -2265,6 +2479,11 @@ bl@^4.1.0: inherits "^2.0.4" readable-stream "^3.4.0" +bn.js@4.11.8: + version "4.11.8" + resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.8.tgz#2cde09eb5ee341f484746bb0309b3253b1b1442f" + integrity sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA== + bn.js@^4.11.9: version "4.12.0" resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.12.0.tgz#775b3f278efbb9718eec7361f483fb36fbbfea88" @@ -2797,6 +3016,11 @@ decamelize@^1.2.0: resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA= +decode-uri-component@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545" + integrity sha512-hjf+xovcEn31w/EUYdTXQh/8smFL/dzYjohQGEIgjyNavaJfBY2p5F527Bo1VPATxv0VYTUC2bOcXvqFwk78Og== + decompress-response@^3.3.0: version "3.3.0" resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-3.3.0.tgz#80a4dd323748384bfa248083622aedec982adff3" @@ -2844,6 +3068,11 @@ dependency-graph@^0.11.0: resolved "https://registry.yarnpkg.com/dependency-graph/-/dependency-graph-0.11.0.tgz#ac0ce7ed68a54da22165a85e97a01d53f5eb2e27" integrity sha512-JeMq7fEshyepOWDfcfHK06N3MhyPhz++vtqWhMT5O9A3K42rdsEDpfdVqjaqaAhsw6a+ZqeDvQVtD0hFHQWrzg== +detect-browser@5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/detect-browser/-/detect-browser-5.2.0.tgz#c9cd5afa96a6a19fda0bbe9e9be48a6b6e1e9c97" + integrity sha512-tr7XntDAu50BVENgQfajMLzacmSe34D+qZc4zjnniz0ZVuw/TZcLcyxHQjYpJTM36sGEkZZlYLnIM1hH7alTMA== + detect-indent@^6.0.0: version "6.1.0" resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-6.1.0.tgz#592485ebbbf6b3b1ab2be175c8393d04ca0d57e6" @@ -3915,7 +4144,7 @@ has@^1.0.3: dependencies: function-bind "^1.1.1" -hash.js@^1.0.0, hash.js@^1.0.3: +hash.js@^1.0.0, hash.js@^1.0.3, hash.js@^1.1.7: version "1.1.7" resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.1.7.tgz#0babca538e8d4ee4a0f8988d68866537a003cf42" integrity sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA== @@ -4276,6 +4505,11 @@ is-symbol@^1.0.2, is-symbol@^1.0.3: dependencies: has-symbols "^1.0.2" +is-typedarray@1.0.0, is-typedarray@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" + integrity sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA== + is-unc-path@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-unc-path/-/is-unc-path-1.0.0.tgz#d731e8898ed090a12c352ad2eaed5095ad322c9d" @@ -4332,6 +4566,11 @@ jdenticon@^3.1.1: dependencies: canvas-renderer "~2.2.0" +js-sha3@0.8.0: + version "0.8.0" + resolved "https://registry.yarnpkg.com/js-sha3/-/js-sha3-0.8.0.tgz#b9b7a5da73afad7dedd0f8c463954cbde6818840" + integrity sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q== + "js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" @@ -4462,6 +4701,11 @@ keyv@^3.0.0: dependencies: json-buffer "3.0.0" +keyvaluestorage-interface@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/keyvaluestorage-interface/-/keyvaluestorage-interface-1.0.0.tgz#13ebdf71f5284ad54be94bd1ad9ed79adad515ff" + integrity sha512-8t6Q3TclQ4uZynJY9IGr2+SsIGwK9JHcO6ootkHCGA0CrQCRy+VkouYNO2xicET6b9al7QKzpebNow+gkpCL8g== + language-subtag-registry@~0.3.2: version "0.3.21" resolved "https://registry.yarnpkg.com/language-subtag-registry/-/language-subtag-registry-0.3.21.tgz#04ac218bea46f04cb039084602c6da9e788dd45a" @@ -5303,7 +5547,7 @@ promise@^7.1.1: dependencies: asap "~2.0.3" -prop-types@^15.5.0, prop-types@^15.6.2, prop-types@^15.7.2, prop-types@^15.8.1: +prop-types@^15.5.0, prop-types@^15.6.0, prop-types@^15.6.2, prop-types@^15.7.2, prop-types@^15.8.1: version "15.8.1" resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5" integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg== @@ -5363,6 +5607,29 @@ punycode@^2.1.0: resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== +qr.js@0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/qr.js/-/qr.js-0.0.0.tgz#cace86386f59a0db8050fa90d9b6b0e88a1e364f" + integrity sha512-c4iYnWb+k2E+vYpRimHqSu575b1/wKl4XFeJGpFmrJQz5I88v9aY2czh7s0w36srfCM1sXgC/xpoJz5dJfq+OQ== + +qrcode.react@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/qrcode.react/-/qrcode.react-1.0.1.tgz#2834bb50e5e275ffe5af6906eff15391fe9e38a5" + integrity sha512-8d3Tackk8IRLXTo67Y+c1rpaiXjoz/Dd2HpcMdW//62/x8J1Nbho14Kh8x974t9prsLHN6XqVgcnRiBGFptQmg== + dependencies: + loose-envify "^1.4.0" + prop-types "^15.6.0" + qr.js "0.0.0" + +query-string@6.13.5: + version "6.13.5" + resolved "https://registry.yarnpkg.com/query-string/-/query-string-6.13.5.tgz#99e95e2fb7021db90a6f373f990c0c814b3812d8" + integrity sha512-svk3xg9qHR39P3JlHuD7g3nRnyay5mHbrPctEBDUxUkHRifPHXJDhBUycdCC0NBjXoDf44Gb+IsOZL1Uwn8M/Q== + dependencies: + decode-uri-component "^0.2.0" + split-on-first "^1.0.0" + strict-uri-encode "^2.0.0" + queue-microtask@^1.2.2: version "1.2.3" resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" @@ -5373,6 +5640,13 @@ ramda@^0.28.0: resolved "https://registry.yarnpkg.com/ramda/-/ramda-0.28.0.tgz#acd785690100337e8b063cab3470019be427cc97" integrity sha512-9QnLuG/kPVgWvMQ4aODhsBUFKOUmnbUnsSXACv+NCQZcHbeb+v8Lodp8OVxtRULN1/xOyYLLaL6npE6dMq5QTA== +randombytes@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" + integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ== + dependencies: + safe-buffer "^5.1.0" + rc@^1.2.8: version "1.2.8" resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed" @@ -5391,6 +5665,16 @@ react-async-script@^1.1.1: hoist-non-react-statics "^3.3.0" prop-types "^15.5.0" +react-dom@^16.14.0: + version "16.14.0" + resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-16.14.0.tgz#7ad838ec29a777fb3c75c3a190f661cf92ab8b89" + integrity sha512-1gCeQXDLoIqMgqD3IO2Ah9bnf0w9kzhwN5q4FGnHZ67hBm9yePzB5JJAIQCc8x3pFnNlwFq4RidZggNAAkzWWw== + dependencies: + loose-envify "^1.1.0" + object-assign "^4.1.1" + prop-types "^15.6.2" + scheduler "^0.19.1" + react-dom@^17.0.2: version "17.0.2" resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-17.0.2.tgz#ecffb6845e3ad8dbfcdc498f0d0a939736502c23" @@ -5460,6 +5744,15 @@ react-transition-group@^4.4.2: loose-envify "^1.4.0" prop-types "^15.6.2" +react@^16.14.0: + version "16.14.0" + resolved "https://registry.yarnpkg.com/react/-/react-16.14.0.tgz#94d776ddd0aaa37da3eda8fc5b6b18a4c9a3114d" + integrity sha512-0X2CImDkJGApiAlcf0ODKIneSwBPhqJawOa5wCtKbu7ZECrmS26NvtSILynQ66cgkT/RJ4LidJOc3bUESwmU8g== + dependencies: + loose-envify "^1.1.0" + object-assign "^4.1.1" + prop-types "^15.6.2" + react@^17.0.2: version "17.0.2" resolved "https://registry.yarnpkg.com/react/-/react-17.0.2.tgz#d0b5cc516d29eb3eee383f75b62864cfb6800037" @@ -5721,7 +6014,7 @@ rxjs@^7.5.5: dependencies: tslib "^2.1.0" -safe-buffer@^5.0.1, safe-buffer@~5.2.0: +safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@~5.2.0: version "5.2.1" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== @@ -5736,6 +6029,14 @@ safe-buffer@~5.1.1: resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== +scheduler@^0.19.1: + version "0.19.1" + resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.19.1.tgz#4f3e2ed2c1a7d65681f4c854fa8c5a1ccb40f196" + integrity sha512-n/zwRWRYSUj0/3g/otKDRPMh6qv2SYMWNq85IEa8iZyAv8od9zDYpGSnpBEjNgcMNq6Scbu5KfIPxNF72R/2EA== + dependencies: + loose-envify "^1.1.0" + object-assign "^4.1.1" + scheduler@^0.20.2: version "0.20.2" resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.20.2.tgz#4baee39436e34aa93b4874bddcbf0fe8b8b50e91" @@ -5883,6 +6184,11 @@ source-map@^0.6.0: resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== +split-on-first@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/split-on-first/-/split-on-first-1.1.0.tgz#f610afeee3b12bce1d0c30425e76398b78249a5f" + integrity sha512-43ZssAJaMusuKWL8sKUBQXHWOpq8d6CfN/u1p4gUzfJkM05C8rxTmYrkIPTXapZpORA6LkkzcUulJ8FqA7Uudw== + sponge-case@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/sponge-case/-/sponge-case-1.0.1.tgz#260833b86453883d974f84854cdb63aecc5aef4c" @@ -5900,6 +6206,11 @@ streamsearch@^1.1.0: resolved "https://registry.yarnpkg.com/streamsearch/-/streamsearch-1.1.0.tgz#404dd1e2247ca94af554e841a8ef0eaa238da764" integrity sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg== +strict-uri-encode@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz#b9c7330c7042862f6b142dc274bbcc5866ce3546" + integrity sha512-QwiXZgpRcKkhTj2Scnn++4PKtWsH0kpzZ62L2R6c/LUVYv7hVnZqcg2+sMuT6R7Jusu1vviK/MFsu6kNJfWlEQ== + string-argv@^0.3.1: version "0.3.1" resolved "https://registry.yarnpkg.com/string-argv/-/string-argv-0.3.1.tgz#95e2fbec0427ae19184935f816d74aaa4c5c19da" @@ -6236,6 +6547,13 @@ type-fest@^0.21.3: resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.21.3.tgz#d260a24b0198436e133fa26a524a6d65fa3b2e37" integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w== +typedarray-to-buffer@3.1.5: + version "3.1.5" + resolved "https://registry.yarnpkg.com/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz#a97ee7a9ff42691b9f783ff1bc5112fe3fca9080" + integrity sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q== + dependencies: + is-typedarray "^1.0.0" + typescript@^4.5.4: version "4.6.4" resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.6.4.tgz#caa78bbc3a59e6a5c510d35703f6a09877ce45e9" @@ -6447,6 +6765,11 @@ wrappy@1: resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= +ws@7.5.3: + version "7.5.3" + resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.3.tgz#160835b63c7d97bfab418fc1b8a9fced2ac01a74" + integrity sha512-kQ/dHIzuLrS6Je9+uv81ueZomEwH0qVYstcAQ4/Z93K8zeko9gtAbttJWzoC5ukqXY1PpoouV3+VSOqEAFt5wg== + ws@^7: version "7.5.9" resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.9.tgz#54fa7db29f4c7cec68b1ddd3a89de099942bb591"