From a7edd0bfd4b6c4e0ec3710d1285958a9ff56502f Mon Sep 17 00:00:00 2001 From: plubber Date: Wed, 10 Jan 2024 16:47:24 -0500 Subject: [PATCH 01/10] fix: dropdown --- src/txs/feeAbstraction/DisplayFees.tsx | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/src/txs/feeAbstraction/DisplayFees.tsx b/src/txs/feeAbstraction/DisplayFees.tsx index 2cb3d4265..f8cec0a14 100644 --- a/src/txs/feeAbstraction/DisplayFees.tsx +++ b/src/txs/feeAbstraction/DisplayFees.tsx @@ -2,7 +2,7 @@ import { useNetwork } from "auth/hooks/useNetwork" import { Select } from "components/form" import { ReactNode, useEffect, useState } from "react" import { useTranslation } from "react-i18next" -import { LoadingCircular, SummaryTable } from "@terra-money/station-ui" +import { Dropdown, LoadingCircular, SummaryTable } from "@terra-money/station-ui" import styles from "./DisplayFees.module.scss" import { useNativeDenoms } from "data/token" import { Read } from "components/token" @@ -127,18 +127,11 @@ export default function DisplayFees({
{t("Fee")}{" "} {availableGasDenoms.length > 1 && ( - + options={availableGasDenoms.map((denom) => ({value: denom, label:readNativeDenom(denom, chainID).symbol }))} + onChange={(val) => setGasDenom(val)} + /> )}
), From 7dd3f34d0e9f8bdd7926c16bcb725efd39e556cc Mon Sep 17 00:00:00 2001 From: plubber Date: Wed, 6 Mar 2024 14:26:06 -0500 Subject: [PATCH 02/10] Refactor activity list and details pages --- src/pages/activity/ActivityList.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/pages/activity/ActivityList.tsx b/src/pages/activity/ActivityList.tsx index 5301f6a5a..0783b9ac6 100644 --- a/src/pages/activity/ActivityList.tsx +++ b/src/pages/activity/ActivityList.tsx @@ -46,6 +46,7 @@ const IbcActivityItem = ({ const ActivityList = () => { //const { ibcTxs } = useIbcTxs() const { activitySorted: activity, state } = useTxActivity() + console.log("activity", activity) const activityItemsPerPage = 20 const [visibleActivity, setVisibleActivity] = useState(activityItemsPerPage) From 907aef8de012c7266804ec529548c62caa262fa9 Mon Sep 17 00:00:00 2001 From: plubber Date: Wed, 6 Mar 2024 14:27:30 -0500 Subject: [PATCH 03/10] Remove console.log statement in ActivityList component --- src/pages/activity/ActivityList.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/pages/activity/ActivityList.tsx b/src/pages/activity/ActivityList.tsx index 0783b9ac6..5301f6a5a 100644 --- a/src/pages/activity/ActivityList.tsx +++ b/src/pages/activity/ActivityList.tsx @@ -46,7 +46,6 @@ const IbcActivityItem = ({ const ActivityList = () => { //const { ibcTxs } = useIbcTxs() const { activitySorted: activity, state } = useTxActivity() - console.log("activity", activity) const activityItemsPerPage = 20 const [visibleActivity, setVisibleActivity] = useState(activityItemsPerPage) From 7de89bd7ccb1e9eff7e855126acf8709d7a4dd52 Mon Sep 17 00:00:00 2001 From: Alessandro Candeago <54709706+alecande11@users.noreply.github.com> Date: Wed, 13 Mar 2024 15:56:33 +0100 Subject: [PATCH 04/10] Fix signBytes error --- scripts/contentScript.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/scripts/contentScript.js b/scripts/contentScript.js index 790ac87db..f8c5d0cf0 100644 --- a/scripts/contentScript.js +++ b/scripts/contentScript.js @@ -310,8 +310,9 @@ function setupEvents() { const createEvent = (changes, namespace) => { if (namespace === "local") { if ( - changes.wallet && - (changes.wallet.oldValue.address !== changes.wallet.newValue.address || + changes.wallet && changes.wallet.oldValue && changes.wallet.newValue && + (changes.wallet.oldValue.address !== + changes.wallet.newValue.address || changes.wallet.oldValue.name !== changes.wallet.newValue.name || Object.values(changes.wallet.oldValue.pubkey || {}).join(",") !== Object.values(changes.wallet.newValue.pubkey || {}).join(",")) From c1da5e9bffce176a13da2983ff8c29ab7e820ead Mon Sep 17 00:00:00 2001 From: Alessandro Candeago <54709706+alecande11@users.noreply.github.com> Date: Thu, 14 Mar 2024 09:40:05 +0100 Subject: [PATCH 05/10] Fix classic fee estimation --- src/extension/modules/ConfirmTx.tsx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/extension/modules/ConfirmTx.tsx b/src/extension/modules/ConfirmTx.tsx index f7642a6c8..2a9ca5f8e 100644 --- a/src/extension/modules/ConfirmTx.tsx +++ b/src/extension/modules/ConfirmTx.tsx @@ -143,7 +143,10 @@ const ConfirmTx = (props: TxRequest | SignBytesRequest) => { gas = tx.fee?.gas_limit || Math.ceil((estimatedGas ?? 0) * gasAdjustment) fee = isClassic - ? tx.fee + ? tx.fee ?? + new Fee(gas, { + [feeDenom as string]: Math.ceil(gasPrices[feeDenom as string] * gas), + }) : new Fee(gas, { [feeDenom as string]: Math.ceil(gasPrices[feeDenom as string] * gas), }) From a3b2809b5be369b5dadbc0f419c314668f7c5c02 Mon Sep 17 00:00:00 2001 From: Joshua Date: Thu, 14 Mar 2024 11:49:40 -0500 Subject: [PATCH 06/10] added new chain loader to Asset and Activity tabs --- src/app/InitNetworks.tsx | 4 ++ src/pages/activity/ActivityList.module.scss | 5 ++ src/pages/activity/ActivityList.tsx | 60 ++++++--------------- src/pages/wallet/AssetList.module.scss | 7 ++- src/pages/wallet/AssetList.tsx | 44 ++++++++------- 5 files changed, 51 insertions(+), 69 deletions(-) diff --git a/src/app/InitNetworks.tsx b/src/app/InitNetworks.tsx index 635077854..5b627fb0f 100644 --- a/src/app/InitNetworks.tsx +++ b/src/app/InitNetworks.tsx @@ -11,6 +11,8 @@ import { InterchainNetworks } from "types/network" export const [useNetworks, NetworksProvider] = createContext<{ networks: InterchainNetworks networksLoading: boolean + validationResultLength: number + validNetworksLength: number filterEnabledNetworks: (network: Record) => Record filterDisabledNetworks: (network: Record) => Record }>("useNetworks") @@ -82,6 +84,8 @@ const InitNetworks = ({ children }: PropsWithChildren<{}>) => { value={{ networks, networksLoading: validationState.isLoading, + validationResultLength: validationResult.length, + validNetworksLength: validNetworks.length, filterEnabledNetworks: (networks) => Object.fromEntries( Object.entries(networks ?? {}).filter( diff --git a/src/pages/activity/ActivityList.module.scss b/src/pages/activity/ActivityList.module.scss index d277884ad..3d6ebf55c 100644 --- a/src/pages/activity/ActivityList.module.scss +++ b/src/pages/activity/ActivityList.module.scss @@ -6,6 +6,11 @@ width: 100%; } +.chain__loader__container { + padding: 10px 10px 0px; + margin-bottom: 12px; +} + .loader { color: var(--token-dark-900); display: flex; diff --git a/src/pages/activity/ActivityList.tsx b/src/pages/activity/ActivityList.tsx index 5301f6a5a..45da42e06 100644 --- a/src/pages/activity/ActivityList.tsx +++ b/src/pages/activity/ActivityList.tsx @@ -1,51 +1,22 @@ import { useState } from "react" +import { useTranslation } from "react-i18next" +import moment from "moment" import { + ChainLoader, LoadingCircular, SectionHeader, SubmitButton, } from "@terra-money/station-ui" import { useTxActivity } from "data/queries/activity" -import styles from "./ActivityList.module.scss" -import ActivityItem from "./ActivityItem" import { Page } from "components/layout" -import moment from "moment" -//import useIbcTxs, { IbcTxState } from "txs/useIbcTxs" -//import { useTranslation } from "react-i18next" -/* -interface IbcActivityItemProps { - chainID: string - txhash: string - state: IbcTxState - index: number - timestamp: any - msgs: Object[] -} +import { useNetworks } from "app/InitNetworks" +import ActivityItem from "./ActivityItem" +import styles from "./ActivityList.module.scss" -const IbcActivityItem = ({ - txhash, - chainID, - state, - index, - timestamp, - msgs, -}: IbcActivityItemProps) => { - const data = { tx: { body: { messages: msgs } }, txhash, code: 0 } - const { t } = useTranslation() - return ( - : null} - variant={state} - showProgress - /> - ) -} -*/ const ActivityList = () => { - //const { ibcTxs } = useIbcTxs() + const { t } = useTranslation() const { activitySorted: activity, state } = useTxActivity() + const { validNetworksLength, validationResultLength } = useNetworks() const activityItemsPerPage = 20 const [visibleActivity, setVisibleActivity] = useState(activityItemsPerPage) @@ -56,11 +27,6 @@ const ActivityList = () => { let priorDisplayDate = "" const visibleActivityItems = activity - // do not show pending txs in the main activity page - /*.filter( - ({ txhash }) => - !ibcTxs.find(({ txhash: ibcTxhash }) => ibcTxhash === txhash) - )*/ .slice(0, visibleActivity) .map((activityItem: AccountHistoryItem & { chain: string }) => { const activityItemDate = new Date(activityItem.timestamp) @@ -97,9 +63,13 @@ const ActivityList = () => { ) } else if (activity?.length && state.isLoading) { loader = ( - - Gathering activity across all chains... - +
+ +
) } else if (!activity?.length && !state.isLoading) { loader = ( diff --git a/src/pages/wallet/AssetList.module.scss b/src/pages/wallet/AssetList.module.scss index 4a9e92396..625697f9f 100644 --- a/src/pages/wallet/AssetList.module.scss +++ b/src/pages/wallet/AssetList.module.scss @@ -1,11 +1,16 @@ @import "mixins"; +.chain__loader__container { + padding: 0 10px; + margin-bottom: 12px; +} + .assetlist { display: grid; grid-template-areas: "title" "list"; grid-template-rows: min-content auto; overflow-y: hidden; - row-gap: 16px; + row-gap: 22px; } .assetlist__title { diff --git a/src/pages/wallet/AssetList.tsx b/src/pages/wallet/AssetList.tsx index 073d8fca6..3edb8bf67 100644 --- a/src/pages/wallet/AssetList.tsx +++ b/src/pages/wallet/AssetList.tsx @@ -1,25 +1,23 @@ +import { useMemo, useState } from "react" +import classNames from "classnames" +import { encode } from "js-base64" +import { useTranslation } from "react-i18next" +import { useNavigate } from "react-router-dom" import { SectionHeader, Button, Banner, Input, FilterIcon, + ChainLoader, } from "@terra-money/station-ui" -// import { -// useCustomTokensCW20, -// useCustomTokensNative, -// } from "data/settings/CustomTokens" import { useIsWalletEmpty } from "data/queries/bank" -import { useTokenFilters } from "utils/localStorage" import { useParsedAssetList } from "data/token" -import { useTranslation } from "react-i18next" -import { useNavigate } from "react-router-dom" -import styles from "./AssetList.module.scss" -import { useMemo, useState } from "react" -import classNames from "classnames" -import { encode } from "js-base64" -import Asset from "./Asset" +import { useTokenFilters } from "utils/localStorage" import { toInput } from "txs/utils" +import { useNetworks } from "app/InitNetworks" +import Asset from "./Asset" +import styles from "./AssetList.module.scss" const cx = classNames.bind(styles) @@ -27,12 +25,12 @@ const AssetList = () => { const { t } = useTranslation() const isWalletEmpty = useIsWalletEmpty() const { onlyShowWhitelist, hideLowBal, toggleHideLowBal } = useTokenFilters() - // const native = useCustomTokensNative() - // const cw20 = useCustomTokensCW20() const list = useParsedAssetList() const [search, setSearch] = useState("") const [showFilter, setShowFilter] = useState(false) const navigate = useNavigate() + const { networksLoading, validNetworksLength, validationResultLength } = + useNetworks() const showHideText = hideLowBal ? "Show" : "Hide" const toggleFilter = () => { @@ -40,15 +38,6 @@ const AssetList = () => { setShowFilter(!showFilter) } - // const alwaysVisibleDenoms = useMemo( - // () => - // new Set([ - // ...cw20.list.map((a) => a.token), - // ...native.list.map((a) => a.denom), - // ]), - // [cw20.list, native.list] - // ) - const assets = useMemo(() => { const filtered = list .filter((a) => (onlyShowWhitelist ? a.whitelisted : true)) @@ -126,6 +115,15 @@ const AssetList = () => { /> )} + {networksLoading && ( +
+ +
+ )} {assets.visible.map(renderAsset)} {assets.lowBal.length > 0 && ( <> From 29e6aa455a781b01cd3c74ff10cee47b55de80fc Mon Sep 17 00:00:00 2001 From: Joshua Date: Thu, 14 Mar 2024 16:50:39 -0500 Subject: [PATCH 07/10] updated a couple of routes to not display the TopHeader and updated the modals to be full height --- src/extension/App.tsx | 9 ++++++++- src/pages/wallet/SendPage/SendTx.tsx | 1 + src/pages/wallet/WalletRouter.tsx | 4 ++++ src/txs/swap/SwapTx.tsx | 1 + 4 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/extension/App.tsx b/src/extension/App.tsx index 35b011575..13828d069 100644 --- a/src/extension/App.tsx +++ b/src/extension/App.tsx @@ -97,7 +97,14 @@ const App = () => { return } // main page - const hidePaths = ["/auth/", "/manage-wallet/", "/preferences"] + const hidePaths = [ + "/auth/", + "/manage-wallet/", + "/preferences", + "/send", + "/swap", + "/receive", + ] const hideHeader = hidePaths.some((p) => location.pathname.startsWith(p)) return ( diff --git a/src/pages/wallet/SendPage/SendTx.tsx b/src/pages/wallet/SendPage/SendTx.tsx index b90715b90..dab33fd16 100644 --- a/src/pages/wallet/SendPage/SendTx.tsx +++ b/src/pages/wallet/SendPage/SendTx.tsx @@ -38,6 +38,7 @@ const SendTx = () => { {r.element} diff --git a/src/pages/wallet/WalletRouter.tsx b/src/pages/wallet/WalletRouter.tsx index 9a3d4979b..5bc618726 100644 --- a/src/pages/wallet/WalletRouter.tsx +++ b/src/pages/wallet/WalletRouter.tsx @@ -15,6 +15,7 @@ interface IRoute { element: React.ReactNode title?: string backPath?: string + isFullHeight?: boolean } export const useWalletRoutes = (): IRoute[] => { @@ -31,12 +32,14 @@ export const useWalletRoutes = (): IRoute[] => { path: "/receive", title: t("Receive"), element: , + isFullHeight: true, }, { path: "/receive/:address", backPath: "/receive", element: , title: t("Copy Address"), + isFullHeight: true, }, { path: "/send/*", @@ -69,6 +72,7 @@ export default function WalletRouter() { {route.element} diff --git a/src/txs/swap/SwapTx.tsx b/src/txs/swap/SwapTx.tsx index 7c4ca8b87..15ae30ed1 100644 --- a/src/txs/swap/SwapTx.tsx +++ b/src/txs/swap/SwapTx.tsx @@ -32,6 +32,7 @@ const SwapTx = () => { backButtonPath={backPath} title={t(r.title)} overNavbar={r.path !== "/"} + fullHeight > {r.element} From ab13eaea7eae5593c7aa9a9d0d49281e6e47533d Mon Sep 17 00:00:00 2001 From: Alessandro Candeago <54709706+alecande11@users.noreply.github.com> Date: Sat, 16 Mar 2024 13:55:30 +0100 Subject: [PATCH 08/10] Fix signature verification failed --- package-lock.json | 144 ++--- package.json | 4 +- src/auth/hooks/useAuth.ts | 2 +- src/data/queries/gov.ts | 197 ------- src/extension/RequestContainer.tsx | 15 +- src/extension/modules/ConfirmTx.tsx | 2 +- src/pages/activity/ActivityTxMessage.tsx | 10 +- src/pages/gov/Governance.tsx | 23 - src/pages/gov/GovernanceParams.module.scss | 3 - src/pages/gov/GovernanceParams.tsx | 60 -- src/pages/gov/ProposalActions.tsx | 20 - src/pages/gov/ProposalDepositors.tsx | 47 -- src/pages/gov/ProposalDeposits.module.scss | 42 -- src/pages/gov/ProposalDeposits.tsx | 90 --- src/pages/gov/ProposalDescription.tsx | 20 - src/pages/gov/ProposalHeader.module.scss | 35 -- src/pages/gov/ProposalHeader.tsx | 44 -- src/pages/gov/ProposalItem.module.scss | 5 - src/pages/gov/ProposalItem.tsx | 27 - src/pages/gov/ProposalParams.tsx | 39 -- src/pages/gov/ProposalSummary.tsx | 43 -- src/pages/gov/ProposalVotes.module.scss | 41 -- src/pages/gov/ProposalVotes.tsx | 199 ------- .../gov/ProposalVotesByValidator.module.scss | 46 -- src/pages/gov/ProposalVotesByValidator.tsx | 198 ------- src/pages/gov/Proposals.tsx | 23 - src/pages/gov/ProposalsByStatus.module.scss | 22 - src/pages/gov/ProposalsByStatus.tsx | 115 ---- src/pages/gov/components/DataList.module.scss | 19 - src/pages/gov/components/DataList.tsx | 26 - src/pages/gov/components/Orb.module.scss | 33 -- src/pages/gov/components/Orb.tsx | 21 - src/pages/gov/components/Tilde.svg | 3 - .../gov/components/VoteProgress.module.scss | 33 -- src/pages/gov/components/VoteProgress.tsx | 37 -- src/pages/gov/useProposalId.ts | 8 - src/pages/stake/ValidatorVotes.tsx | 65 --- src/txs/feeAbstraction/DisplayFees.tsx | 12 +- src/txs/gov/DepositForm.tsx | 111 ---- src/txs/gov/DepositTx.tsx | 29 - src/txs/gov/SubmitProposalForm.tsx | 516 ------------------ src/txs/gov/SubmitProposalTx.tsx | 21 - src/txs/gov/VoteForm.module.scss | 32 -- src/txs/gov/VoteForm.tsx | 94 ---- src/txs/gov/VoteTx.tsx | 29 - 45 files changed, 73 insertions(+), 2532 deletions(-) delete mode 100644 src/data/queries/gov.ts delete mode 100644 src/pages/gov/Governance.tsx delete mode 100644 src/pages/gov/GovernanceParams.module.scss delete mode 100644 src/pages/gov/GovernanceParams.tsx delete mode 100644 src/pages/gov/ProposalActions.tsx delete mode 100644 src/pages/gov/ProposalDepositors.tsx delete mode 100644 src/pages/gov/ProposalDeposits.module.scss delete mode 100644 src/pages/gov/ProposalDeposits.tsx delete mode 100644 src/pages/gov/ProposalDescription.tsx delete mode 100644 src/pages/gov/ProposalHeader.module.scss delete mode 100644 src/pages/gov/ProposalHeader.tsx delete mode 100644 src/pages/gov/ProposalItem.module.scss delete mode 100644 src/pages/gov/ProposalItem.tsx delete mode 100644 src/pages/gov/ProposalParams.tsx delete mode 100644 src/pages/gov/ProposalSummary.tsx delete mode 100644 src/pages/gov/ProposalVotes.module.scss delete mode 100644 src/pages/gov/ProposalVotes.tsx delete mode 100644 src/pages/gov/ProposalVotesByValidator.module.scss delete mode 100644 src/pages/gov/ProposalVotesByValidator.tsx delete mode 100644 src/pages/gov/Proposals.tsx delete mode 100644 src/pages/gov/ProposalsByStatus.module.scss delete mode 100644 src/pages/gov/ProposalsByStatus.tsx delete mode 100644 src/pages/gov/components/DataList.module.scss delete mode 100644 src/pages/gov/components/DataList.tsx delete mode 100644 src/pages/gov/components/Orb.module.scss delete mode 100644 src/pages/gov/components/Orb.tsx delete mode 100644 src/pages/gov/components/Tilde.svg delete mode 100644 src/pages/gov/components/VoteProgress.module.scss delete mode 100644 src/pages/gov/components/VoteProgress.tsx delete mode 100644 src/pages/gov/useProposalId.ts delete mode 100644 src/pages/stake/ValidatorVotes.tsx delete mode 100644 src/txs/gov/DepositForm.tsx delete mode 100644 src/txs/gov/DepositTx.tsx delete mode 100644 src/txs/gov/SubmitProposalForm.tsx delete mode 100644 src/txs/gov/SubmitProposalTx.tsx delete mode 100644 src/txs/gov/VoteForm.module.scss delete mode 100644 src/txs/gov/VoteForm.tsx delete mode 100644 src/txs/gov/VoteTx.tsx diff --git a/package-lock.json b/package-lock.json index 29b073509..3bbe2eb88 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,11 +13,11 @@ "@mui/icons-material": "^5.8.0", "@mui/material": "^5.9.1", "@sentry/react": "^7.53.1", - "@terra-money/feather.js": "1.0.11", + "@terra-money/feather.js": "^2.0.4", "@terra-money/ledger-station-js": "^1.3.7", "@terra-money/log-finder-ruleset": "^3.0.3", "@terra-money/msg-reader": "^3.0.1", - "@terra-money/station-connector": "^1.0.17-beta.6", + "@terra-money/station-connector": "^1.1.0", "@terra-money/station-ui": "^1.0.6", "@terra-money/terra-utils": "^1.2.0-beta.8", "@terra-money/terra.js": "^3.1.9", @@ -7944,13 +7944,12 @@ } }, "node_modules/@terra-money/feather.js": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/@terra-money/feather.js/-/feather.js-1.0.11.tgz", - "integrity": "sha512-oHXSwbbUyEw7r5r9OJMEGz/U/+KTk5IUiIJd0Oaani2FnMhdqnoEEJYGGf2+IvIMdsktzgwoXzFOOAL+Ah9q/g==", + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@terra-money/feather.js/-/feather.js-2.0.4.tgz", + "integrity": "sha512-Ab3EBh6aOrd+eLmpIEX8TB5ptJR7aAbtSX5KhGuiGgEA1k5agKzqefFy+ZBqfmdKiymHuioJ0SXCs/ZNJMItpA==", "dependencies": { - "@ethersproject/bytes": "^5.7.0", "@terra-money/legacy.proto": "npm:@terra-money/terra.proto@^0.1.7", - "@terra-money/terra.proto": "^3.1.0-alpha.1", + "@terra-money/terra.proto": "^4.0.4", "assert": "^2.0.0", "axios": "^0.27.2", "bech32": "^2.0.0", @@ -7959,7 +7958,6 @@ "bufferutil": "^4.0.3", "crypto-browserify": "^3.12.0", "decimal.js": "^10.2.1", - "ethers": "^5.7.2", "jscrypto": "^1.0.1", "keccak256": "^1.0.6", "long": "^5.2.3", @@ -7974,11 +7972,12 @@ } }, "node_modules/@terra-money/feather.js/node_modules/@terra-money/terra.proto": { - "version": "3.1.0-alpha.1", - "resolved": "https://registry.npmjs.org/@terra-money/terra.proto/-/terra.proto-3.1.0-alpha.1.tgz", - "integrity": "sha512-aMgfEVqEPh8PUGHM8GVsgVMVLnWHuPHCA+8gfBjZ8vcC0UJYafB6jirRSMd7CRuRbkepE70eRqVt8ip35QBx2A==", + "version": "4.0.10", + "resolved": "https://registry.npmjs.org/@terra-money/terra.proto/-/terra.proto-4.0.10.tgz", + "integrity": "sha512-cSTGri/X7r+RjTHKQ40lUDM7+lwWIiodLmBvuCUWMH8svji0D45StZTVGfaQ5wCnPr7KcDbZTERzyLKiSwsBqg==", "dependencies": { "@improbable-eng/grpc-web": "^0.14.1", + "browser-headers": "^0.4.1", "google-protobuf": "^3.17.3", "long": "^4.0.0", "protobufjs": "~6.11.2" @@ -8053,9 +8052,9 @@ } }, "node_modules/@terra-money/station-connector": { - "version": "1.0.17-beta.6", - "resolved": "https://registry.npmjs.org/@terra-money/station-connector/-/station-connector-1.0.17-beta.6.tgz", - "integrity": "sha512-EcfYjQBbdzr2C0zRVwRD80FcmuUgeeNQSqJntvG3qhvWbJrigXjrY/mo3NxAG3FoH/EO8kjeszYgWEY9ft8tOw==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@terra-money/station-connector/-/station-connector-1.1.0.tgz", + "integrity": "sha512-InaiuZjLBF92s88aFHxDXJZS751mFr+pa5xbjwyIWWhfWV6RdONXGvuOZ79OPg6H8fUQHJGfosNxeNteGO+Yaw==", "dependencies": { "bech32": "^2.0.0" }, @@ -8064,7 +8063,7 @@ }, "peerDependencies": { "@cosmjs/amino": "^0.31.0", - "@terra-money/feather.js": "^1.0.8", + "@terra-money/feather.js": "^3.0.0-beta.1", "axios": "^0.27.2" } }, @@ -8412,9 +8411,9 @@ } }, "node_modules/@terra-money/station-ui/node_modules/typescript": { - "version": "5.3.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.3.tgz", - "integrity": "sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==", + "version": "5.4.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.2.tgz", + "integrity": "sha512-+2/g0Fds1ERlP6JsakQQDXjZdZMM+rqpamFZJEKh4kwTIn3iDkgKtby0CeNd5ATNZ4Ry1ax15TMx0W2V+miizQ==", "peer": true, "bin": { "tsc": "bin/tsc", @@ -8577,36 +8576,6 @@ } } }, - "node_modules/@terra-money/station-wallet": { - "version": "1.0.16", - "license": "Apache-2.0", - "dependencies": { - "@terra-money/station-connector": "^1.0.16", - "@terra-money/wallet-interface": "^1.0.16" - }, - "engines": { - "node": ">=16" - }, - "peerDependencies": { - "@terra-money/feather.js": "^1.0.8" - } - }, - "node_modules/@terra-money/station-wallet/node_modules/@terra-money/station-connector": { - "version": "1.0.16", - "resolved": "https://registry.npmjs.org/@terra-money/station-connector/-/station-connector-1.0.16.tgz", - "integrity": "sha512-m16a4KkUWF+Mhmf4LiBO1TvCdIabJFudbCC+Cr2JwknZnPQ2SmMHSfyBhS5SaJGWIhmHd4yZalRdNBr+QUc6hA==", - "dependencies": { - "bech32": "^2.0.0" - }, - "engines": { - "node": ">=16" - }, - "peerDependencies": { - "@cosmjs/amino": "^0.31.0", - "@terra-money/feather.js": "^1.0.8", - "axios": "^0.27.2" - } - }, "node_modules/@terra-money/terra-utils": { "version": "1.2.0-beta.8", "resolved": "https://registry.npmjs.org/@terra-money/terra-utils/-/terra-utils-1.2.0-beta.8.tgz", @@ -8624,50 +8593,6 @@ "node": ">=10" } }, - "node_modules/@terra-money/terra-utils/node_modules/@terra-money/feather.js": { - "version": "2.0.0-beta.15", - "license": "MIT", - "dependencies": { - "@ethersproject/bytes": "^5.7.0", - "@terra-money/legacy.proto": "npm:@terra-money/terra.proto@^0.1.7", - "@terra-money/terra.proto": "^4.0.4", - "assert": "^2.0.0", - "axios": "^0.27.2", - "bech32": "^2.0.0", - "bip32": "^2.0.6", - "bip39": "^3.0.3", - "bufferutil": "^4.0.3", - "crypto-browserify": "^3.12.0", - "decimal.js": "^10.2.1", - "ethers": "^5.7.2", - "jscrypto": "^1.0.1", - "keccak256": "^1.0.6", - "long": "^5.2.3", - "readable-stream": "^3.6.0", - "secp256k1": "^4.0.2", - "tmp": "^0.2.1", - "utf-8-validate": "^5.0.5", - "ws": "^7.5.9" - }, - "engines": { - "node": ">=16" - } - }, - "node_modules/@terra-money/terra-utils/node_modules/@terra-money/feather.js/node_modules/long": { - "version": "5.2.3", - "license": "Apache-2.0" - }, - "node_modules/@terra-money/terra-utils/node_modules/@terra-money/terra.proto": { - "version": "4.0.4", - "license": "Apache-2.0", - "dependencies": { - "@improbable-eng/grpc-web": "^0.14.1", - "browser-headers": "^0.4.1", - "google-protobuf": "^3.17.3", - "long": "^4.0.0", - "protobufjs": "~6.11.2" - } - }, "node_modules/@terra-money/terra-utils/node_modules/@types/ramda": { "version": "0.27.66", "license": "MIT", @@ -8712,30 +8637,46 @@ "protobufjs": "~6.11.2" } }, - "node_modules/@terra-money/wallet-interface": { + "node_modules/@terra-money/wallet-kit": { "version": "1.0.16", "license": "Apache-2.0", + "dependencies": { + "@terra-money/station-wallet": "^1.0.16", + "@terra-money/wallet-interface": "^1.0.16" + }, "engines": { "node": ">=16" }, "peerDependencies": { - "@terra-money/feather.js": "^1.0.8" + "@terra-money/feather.js": "^1.0.8", + "axios": "^0.27.2", + "react": "^18.2.0" } }, - "node_modules/@terra-money/wallet-kit": { + "node_modules/@terra-money/wallet-kit/node_modules/@terra-money/station-wallet": { "version": "1.0.16", - "license": "Apache-2.0", + "resolved": "https://registry.npmjs.org/@terra-money/station-wallet/-/station-wallet-1.0.16.tgz", + "integrity": "sha512-yofrC7TQFr5kRjgVLcBq++56mtYY/w1dFBFCcOyhgwi/t1Vx9r4S0ejjMm1wmhWQpkIsk49Nr7aowafn82Bdbw==", "dependencies": { - "@terra-money/station-wallet": "^1.0.16", + "@terra-money/station-connector": "^1.0.16", "@terra-money/wallet-interface": "^1.0.16" }, "engines": { "node": ">=16" }, "peerDependencies": { - "@terra-money/feather.js": "^1.0.8", - "axios": "^0.27.2", - "react": "^18.2.0" + "@terra-money/feather.js": "^1.0.8" + } + }, + "node_modules/@terra-money/wallet-kit/node_modules/@terra-money/wallet-interface": { + "version": "1.0.16", + "resolved": "https://registry.npmjs.org/@terra-money/wallet-interface/-/wallet-interface-1.0.16.tgz", + "integrity": "sha512-WUGCqr5N7HSD2GDf2+7k7G+Wl0v+SXDstUzb3MCZ562ECeIirdCjU+FYg8oc9kMmNJ3pakzm/qCNknEbPt8UIg==", + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "@terra-money/feather.js": "^1.0.8" } }, "node_modules/@tippyjs/react": { @@ -28212,8 +28153,9 @@ }, "node_modules/react-scripts/node_modules/type-fest": { "version": "0.13.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.13.1.tgz", + "integrity": "sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==", "dev": true, - "license": "(MIT OR CC0-1.0)", "optional": true, "peer": true, "engines": { diff --git a/package.json b/package.json index 9bbd98ccf..7285e2484 100644 --- a/package.json +++ b/package.json @@ -22,11 +22,11 @@ "@mui/icons-material": "^5.8.0", "@mui/material": "^5.9.1", "@sentry/react": "^7.53.1", - "@terra-money/feather.js": "1.0.11", + "@terra-money/feather.js": "^2.0.4", "@terra-money/ledger-station-js": "^1.3.7", "@terra-money/log-finder-ruleset": "^3.0.3", "@terra-money/msg-reader": "^3.0.1", - "@terra-money/station-connector": "^1.0.17-beta.6", + "@terra-money/station-connector": "^1.1.0", "@terra-money/station-ui": "^1.0.6", "@terra-money/terra-utils": "^1.2.0-beta.8", "@terra-money/terra.js": "^3.1.9", diff --git a/src/auth/hooks/useAuth.ts b/src/auth/hooks/useAuth.ts index c2d359551..597f42e9b 100644 --- a/src/auth/hooks/useAuth.ts +++ b/src/auth/hooks/useAuth.ts @@ -294,7 +294,7 @@ const useAuth = () => { Buffer.from(pk[networks[txOptions?.chainID].coinType] ?? "", "hex") ) const w = lcd.wallet(key) - return await w.createAndSignTx(txOptions) + return await w.createAndSignTx({ ...txOptions, signMode }) } } } diff --git a/src/data/queries/gov.ts b/src/data/queries/gov.ts deleted file mode 100644 index 096cd4579..000000000 --- a/src/data/queries/gov.ts +++ /dev/null @@ -1,197 +0,0 @@ -import { useTranslation } from "react-i18next" -import { useQuery } from "react-query" -import { last } from "ramda" -import { sentenceCase } from "sentence-case" -import { Proposal, Vote } from "@terra-money/feather.js" -import { Color } from "types/components" -import { Pagination, queryKey, RefetchOptions } from "../query" -import { useInterchainLCDClient } from "./lcdClient" -import { useNetwork } from "data/wallet" - -export const useVotingParams = (chain: string) => { - const lcd = useInterchainLCDClient() - return useQuery( - [queryKey.gov.votingParams, chain], - () => lcd.gov.votingParameters(chain), - { ...RefetchOptions.INFINITY } - ) -} - -export const useDepositParams = (chain: string) => { - const lcd = useInterchainLCDClient() - return useQuery( - [queryKey.gov.depositParams, chain], - () => lcd.gov.depositParameters(chain), - { ...RefetchOptions.INFINITY } - ) -} - -export const useTallyParams = (chain: string) => { - const lcd = useInterchainLCDClient() - return useQuery( - [queryKey.gov.tallyParams, chain], - () => lcd.gov.tallyParameters(chain), - { - ...RefetchOptions.INFINITY, - } - ) -} - -/* proposals */ -export const useProposals = (status: Proposal.Status) => { - const lcd = useInterchainLCDClient() - const networks = useNetwork() - return useQuery( - [queryKey.gov.proposals, status], - async () => { - const chainList = Object.keys(networks ?? {}) - // TODO: Pagination - // Required when the number of results exceed 100 - // About 50 passed propsals from 2019 to 2021 - const proposals = await Promise.all( - chainList.map((chainID) => - lcd.gov.proposals(chainID, { - proposal_status: status, - ...Pagination, - }) - ) - ) - - return proposals - .reduce( - (acc, cur, i) => { - cur[0].map((prop) => acc.push({ prop, chain: chainList[i] })) - return acc - }, - [] as { prop: Proposal; chain: string }[] - // remove proposals with unsupported protobuf content - ) - .filter(({ prop }) => prop.content) - }, - { ...RefetchOptions.DEFAULT } - ) -} - -export const useGetProposalStatusItem = () => { - const { t } = useTranslation() - - return (status: Proposal.Status) => - ({ - [Proposal.Status.PROPOSAL_STATUS_VOTING_PERIOD]: { - label: t("Voting"), - color: "info" as Color, - }, - [Proposal.Status.PROPOSAL_STATUS_DEPOSIT_PERIOD]: { - label: t("Deposit"), - color: "info" as Color, - }, - [Proposal.Status.PROPOSAL_STATUS_PASSED]: { - label: t("Passed"), - color: "success" as Color, - }, - [Proposal.Status.PROPOSAL_STATUS_REJECTED]: { - label: t("Rejected"), - color: "danger" as Color, - }, - [Proposal.Status.PROPOSAL_STATUS_FAILED]: { - label: t("Error during execution"), - color: "danger" as Color, - }, - [Proposal.Status.PROPOSAL_STATUS_UNSPECIFIED]: { - label: "", - color: "danger" as Color, - }, - [Proposal.Status.UNRECOGNIZED]: { - label: "", - color: "danger" as Color, - }, - }[status]) -} - -export const useProposalStatusItem = (status: Proposal.Status) => { - const getProposalStatusItem = useGetProposalStatusItem() - return getProposalStatusItem(status) -} - -/* proposal */ -export const useProposal = (id: number, chain: string) => { - const lcd = useInterchainLCDClient() - return useQuery( - [queryKey.gov.proposal, id, chain], - () => lcd.gov.proposal(id, chain), - { - ...RefetchOptions.INFINITY, - } - ) -} - -/* proposal: deposits */ -export const useDeposits = (id: number, chain: string) => { - const lcd = useInterchainLCDClient() - return useQuery( - [queryKey.gov.deposits, id, chain], - async () => { - // TODO: Pagination - // Required when the number of results exceed 100 - const [deposits] = await lcd.gov.deposits(id, chain) - return deposits - }, - { ...RefetchOptions.DEFAULT } - ) -} - -export const useTally = (id: number, chain: string) => { - const lcd = useInterchainLCDClient() - return useQuery( - [queryKey.gov.tally, id, chain], - () => lcd.gov.tally(id, chain), - { - ...RefetchOptions.DEFAULT, - } - ) -} - -/* proposal: votes */ -export const useGetVoteOptionItem = () => { - const { t } = useTranslation() - - const getItem = (status: Vote.Option) => - ({ - [Vote.Option.VOTE_OPTION_YES]: { - label: t("Yes"), - color: "success" as Color, - }, - [Vote.Option.VOTE_OPTION_NO]: { - label: t("No"), - color: "danger" as Color, - }, - [Vote.Option.VOTE_OPTION_NO_WITH_VETO]: { - label: t("No with veto"), - color: "warning" as Color, - }, - [Vote.Option.VOTE_OPTION_ABSTAIN]: { - label: t("Abstain"), - color: "info" as Color, - }, - [Vote.Option.VOTE_OPTION_UNSPECIFIED]: { - label: "", - color: "danger" as Color, - }, - [Vote.Option.UNRECOGNIZED]: { - label: "", - color: "danger" as Color, - }, - }[status]) - - return (param: Vote.Option | string) => { - const option = typeof param === "string" ? Vote.Option[param as any] : param - return getItem(option as Vote.Option) - } -} - -/* helpers */ -export const useParseProposalType = (content?: Proposal.Content) => { - if (!content || !content.toData()) return "Unknowm proposal" - const { "@type": type } = content.toData() - return sentenceCase(last(type.split(".")) ?? "") -} diff --git a/src/extension/RequestContainer.tsx b/src/extension/RequestContainer.tsx index 68fd802f8..3589ad379 100644 --- a/src/extension/RequestContainer.tsx +++ b/src/extension/RequestContainer.tsx @@ -13,6 +13,7 @@ import { SignBytesRequest, TxResponse } from "./utils" import { isBytes, isSign } from "./utils" import { parseBytes, parseDefault, useParseTx, toData } from "./utils" import { useChainID, useNetwork } from "data/wallet" +import { Fee } from "@terra-money/feather.js" interface RequestContext { requests: { @@ -27,7 +28,7 @@ interface RequestContext { tx: ( requestType: RequestType, request: PrimitiveDefaultRequest, - response: TxResponse + response: TxResponse & { fee?: Fee } ) => void multisigTx: (request: PrimitiveDefaultRequest) => void pubkey: () => void @@ -198,10 +199,14 @@ const RequestContainer = ({ children }: PropsWithChildren<{}>) => { ({ id, origin }) => id === request.id && origin === request.origin ) - const result = toData( - response.result, - networks[defaultChainID]?.isClassic - ) + const fee = response.fee?.toAmino() + + const result = { + fee, + ...toData(response.result, networks[defaultChainID]?.isClassic), + } + + // @ts-expect-error const next = update(index, { ...list[index], ...response, result }, list) browser.storage?.local.set({ [type]: next }).then(() => setTx(undefined)) }) diff --git a/src/extension/modules/ConfirmTx.tsx b/src/extension/modules/ConfirmTx.tsx index 2a9ca5f8e..8c09f7938 100644 --- a/src/extension/modules/ConfirmTx.tsx +++ b/src/extension/modules/ConfirmTx.tsx @@ -181,7 +181,7 @@ const ConfirmTx = (props: TxRequest | SignBytesRequest) => { else navigate({ pathname, search }) } else { const result = await auth[requestType](txOptions, password, signMode) - const response = { result, success: true } + const response = { result, success: true, fee } actions.tx(requestType, props, response) } } catch (error) { diff --git a/src/pages/activity/ActivityTxMessage.tsx b/src/pages/activity/ActivityTxMessage.tsx index c3ea92c86..8e384e466 100644 --- a/src/pages/activity/ActivityTxMessage.tsx +++ b/src/pages/activity/ActivityTxMessage.tsx @@ -7,7 +7,6 @@ import { useAddress, useNetwork } from "data/wallet" import { getChainIDFromAddress } from "utils/bech32" import { useValidators } from "data/queries/staking" import { truncate } from "@terra-money/terra-utils" -import { useProposal } from "data/queries/gov" import { Read } from "components/token" const ValidatorAddress = ({ children: address }: { children: string }) => { @@ -89,15 +88,20 @@ interface ProposalProps { } const Proposal = (props: ProposalProps) => { - const { proposalID, chainID } = props + const { + proposalID, + //chainID + } = props + /* const { data: proposal } = useProposal(proposalID, chainID) const proposalName = proposal?.content?.title ? proposal.content.title : `Proposal ID ${proposalID}` + */ - return {proposalName} + return Proposal ID {proposalID} } interface Props { diff --git a/src/pages/gov/Governance.tsx b/src/pages/gov/Governance.tsx deleted file mode 100644 index 79266150f..000000000 --- a/src/pages/gov/Governance.tsx +++ /dev/null @@ -1,23 +0,0 @@ -import { useTranslation } from "react-i18next" -import { LinkButton } from "components/general" -import { Page } from "components/layout" -import Proposals from "./Proposals" - -const Governance = () => { - const { t } = useTranslation() - - return ( - - {t("New proposal")} - - } - > - - - ) -} - -export default Governance diff --git a/src/pages/gov/GovernanceParams.module.scss b/src/pages/gov/GovernanceParams.module.scss deleted file mode 100644 index c4fd8a6c2..000000000 --- a/src/pages/gov/GovernanceParams.module.scss +++ /dev/null @@ -1,3 +0,0 @@ -.params { - margin-top: var(--grid-gap); -} diff --git a/src/pages/gov/GovernanceParams.tsx b/src/pages/gov/GovernanceParams.tsx deleted file mode 100644 index a27100e91..000000000 --- a/src/pages/gov/GovernanceParams.tsx +++ /dev/null @@ -1,60 +0,0 @@ -import { useTranslation } from "react-i18next" -import { intervalToDuration } from "date-fns" -import { useDepositParams } from "data/queries/gov" -import { useVotingParams } from "data/queries/gov" -import { Card } from "components/layout" -import { Read } from "components/token" -import DataList from "./components/DataList" -import styles from "./GovernanceParams.module.scss" -import { useNetwork } from "data/wallet" - -const GovernanceParams = ({ chain }: { chain: string }) => { - const { t } = useTranslation() - const network = useNetwork() - - const { data: votingParams } = useVotingParams(chain) - const { data: depositParams } = useDepositParams(chain) - - if (!(votingParams && depositParams)) return null - - const minDeposit = depositParams.min_deposit.get(network[chain].baseAsset) - - const contents = [ - { - title: t("Minimum deposit"), - content: minDeposit && ( - - ), - }, - { - title: t("Maximum deposit period"), - content: t(`{{d}} days`, { - d: daysFromNanoseconds(depositParams.max_deposit_period), - }), - }, - { - title: t("Voting period"), - content: t(`{{d}} days`, { - d: daysFromNanoseconds(votingParams.voting_period), - }), - }, - ] - - return ( - - - - ) -} - -export default GovernanceParams - -/* helpers */ -const daysFromNanoseconds = (second: number) => { - const end = second * 1000 - const { days } = intervalToDuration({ start: 0, end }) - return days -} diff --git a/src/pages/gov/ProposalActions.tsx b/src/pages/gov/ProposalActions.tsx deleted file mode 100644 index 651e67fc6..000000000 --- a/src/pages/gov/ProposalActions.tsx +++ /dev/null @@ -1,20 +0,0 @@ -import { useTranslation } from "react-i18next" -import { Proposal } from "@terra-money/feather.js" -import { LinkButton } from "components/general" - -const ProposalActions = ({ proposal }: { proposal: Proposal }) => { - const { t } = useTranslation() - const { status } = proposal - - return status === Proposal.Status.PROPOSAL_STATUS_VOTING_PERIOD ? ( - - {t("Vote")} - - ) : status === Proposal.Status.PROPOSAL_STATUS_DEPOSIT_PERIOD ? ( - - {t("Deposit")} - - ) : null -} - -export default ProposalActions diff --git a/src/pages/gov/ProposalDepositors.tsx b/src/pages/gov/ProposalDepositors.tsx deleted file mode 100644 index c53469073..000000000 --- a/src/pages/gov/ProposalDepositors.tsx +++ /dev/null @@ -1,47 +0,0 @@ -import { useTranslation } from "react-i18next" -import { getAmount } from "utils/coin" -import { useDeposits } from "data/queries/gov" -import { FinderLink } from "components/general" -import { Card, Table } from "components/layout" -import { Read } from "components/token" -import { useNetwork } from "data/wallet" - -// FIXME: Pagination (Client) - -const ProposalDepositors = ({ id, chain }: { id: number; chain: string }) => { - const { t } = useTranslation() - const networks = useNetwork() - const { data: deposits, ...state } = useDeposits(id, chain) - - return ( - - {deposits && ( - {address}, - }, - { - title: t("Amount"), - dataIndex: "amount", - render: (amount) => ( - - ), - align: "right", - }, - ]} - size="small" - /> - )} - - ) -} - -export default ProposalDepositors diff --git a/src/pages/gov/ProposalDeposits.module.scss b/src/pages/gov/ProposalDeposits.module.scss deleted file mode 100644 index 12bd7ec1a..000000000 --- a/src/pages/gov/ProposalDeposits.module.scss +++ /dev/null @@ -1,42 +0,0 @@ -@import "mixins"; - -.main { - display: grid; - align-items: center; -} - -.horizontal { - @include flex(flex-start); - gap: 24px; -} - -.vertical { - display: grid; - gap: 24px; - text-align: center; -} - -.orb { - flex: none; - display: grid; - justify-content: center; - gap: 8px; - font-size: 24px; - font-weight: var(--bold); -} - -.details { - display: flex; - gap: 16px; -} - -.item { - display: grid; - grid-template-rows: auto 1fr; - gap: 2px; - font-size: var(--font-size-small); - - .vertical & { - flex: 1; - } -} diff --git a/src/pages/gov/ProposalDeposits.tsx b/src/pages/gov/ProposalDeposits.tsx deleted file mode 100644 index debd417e5..000000000 --- a/src/pages/gov/ProposalDeposits.tsx +++ /dev/null @@ -1,90 +0,0 @@ -import { useTranslation } from "react-i18next" -import BigNumber from "bignumber.js" -import { readPercent } from "@terra-money/terra-utils" -import { getAmount } from "utils/coin" -import { combineState } from "data/query" -import { useProposal } from "data/queries/gov" -import { useDeposits, useDepositParams } from "data/queries/gov" -import { Card } from "components/layout" -import { Read } from "components/token" -import { ToNow } from "components/display" -import Orb from "./components/Orb" -import styles from "./ProposalDeposits.module.scss" -import { useNetwork } from "data/wallet" - -interface Props { - id: number - chain: string - card?: boolean -} - -const ProposalDeposits = ({ id, chain, card }: Props) => { - const { t } = useTranslation() - const networks = useNetwork() - const { data: proposal, ...proposalState } = useProposal(id, chain) - const { data: deposits, ...depositsState } = useDeposits(id, chain) - const { data: depositParams, ...depositParamsState } = useDepositParams(chain) - const state = combineState(proposalState, depositsState, depositParamsState) - - const render = () => { - if (!(proposal && deposits && depositParams)) return null - - const getProposalDeposited = () => { - const deposited = deposits.reduce( - (acc, { amount }) => - new BigNumber(acc) - .plus(getAmount(amount, networks[chain].baseAsset)) - .toString(), - "0" - ) - const minimum = getAmount( - depositParams.min_deposit, - networks[chain].baseAsset - ) - const ratio = Number(deposited) / Number(minimum) - return { deposited, ratio } - } - - const { deposited, ratio } = getProposalDeposited() - const { deposit_end_time } = proposal - - const contents = [ - { - title: t("Deposited"), - content: , - }, - { - title: t("Deposit end time"), - content: {deposit_end_time}, - }, - ] - - return ( -
-
- - {card && readPercent(ratio)} -
- -
- {contents.map(({ title, content }) => ( -
-

{title}

-

{content}

-
- ))} -
-
- ) - } - - return card ? ( - - {render()} - - ) : ( - render() - ) -} - -export default ProposalDeposits diff --git a/src/pages/gov/ProposalDescription.tsx b/src/pages/gov/ProposalDescription.tsx deleted file mode 100644 index 0bb7ce214..000000000 --- a/src/pages/gov/ProposalDescription.tsx +++ /dev/null @@ -1,20 +0,0 @@ -import { Proposal } from "@terra-money/feather.js" -import xss from "xss" - -const ProposalDescription = ({ proposal }: { proposal: Proposal }) => { - if (!proposal.content) return null - const { description } = proposal.content - return

-} - -export default ProposalDescription - -/* helpers */ -const linkify = (text: string) => { - return xss( - text.replace( - /(https?:\/\/[^\s]+)/g, - '$1' - ) - ) -} diff --git a/src/pages/gov/ProposalHeader.module.scss b/src/pages/gov/ProposalHeader.module.scss deleted file mode 100644 index dbacceb47..000000000 --- a/src/pages/gov/ProposalHeader.module.scss +++ /dev/null @@ -1,35 +0,0 @@ -@import "mixins"; - -.header { - overflow: hidden; -} - -.meta { - @include flex(space-between); - font-size: var(--font-size-small); - margin-bottom: 18px; - - aside { - @include flex(flex-start); - gap: 8px; - - img { - width: 34px; - height: 34px; - padding: 8px; - background-color: var(--button-default-bg); - border-radius: 50%; - } - } -} - -.title { - font-size: 20px; - font-weight: var(--normal); - margin-bottom: 8px; -} - -.date { - font-size: var(--font-size-small); - color: var(--text-muted); -} diff --git a/src/pages/gov/ProposalHeader.tsx b/src/pages/gov/ProposalHeader.tsx deleted file mode 100644 index ad1f38bc0..000000000 --- a/src/pages/gov/ProposalHeader.tsx +++ /dev/null @@ -1,44 +0,0 @@ -import { useTranslation } from "react-i18next" -import { Proposal } from "@terra-money/feather.js" -import { useParseProposalType } from "data/queries/gov" -import { useProposalStatusItem } from "data/queries/gov" -import { ToNow } from "components/display" -import styles from "./ProposalHeader.module.scss" -import { useNetwork } from "data/wallet" - -const ProposalHeader = ({ - proposal, - chain, -}: { - proposal: Proposal - chain: string -}) => { - const { id, content, status, submit_time } = proposal - const networks = useNetwork() - const { t } = useTranslation() - const type = useParseProposalType(content) - const { color, label } = useProposalStatusItem(status) - if (!content) return null - const { title } = content - - return ( -

-
- - {label} -
- -

{title}

-

- {t("Submitted")} {submit_time} -

-
- ) -} - -export default ProposalHeader diff --git a/src/pages/gov/ProposalItem.module.scss b/src/pages/gov/ProposalItem.module.scss deleted file mode 100644 index fdb161d03..000000000 --- a/src/pages/gov/ProposalItem.module.scss +++ /dev/null @@ -1,5 +0,0 @@ -.item { - height: 100%; - justify-content: space-between; - align-items: stretch; -} diff --git a/src/pages/gov/ProposalItem.tsx b/src/pages/gov/ProposalItem.tsx deleted file mode 100644 index a01b0a871..000000000 --- a/src/pages/gov/ProposalItem.tsx +++ /dev/null @@ -1,27 +0,0 @@ -import { Proposal } from "@terra-money/feather.js" -import { FlexColumn } from "components/layout" -import ProposalVotes from "./ProposalVotes" -import ProposalHeader from "./ProposalHeader" -import styles from "./ProposalItem.module.scss" - -interface Props { - proposal: Proposal - showVotes: boolean - chain: string -} - -const ProposalItem = ({ proposal, showVotes, chain }: Props) => { - const { id, status } = proposal - - return ( - - - - {showVotes && status === Proposal.Status.PROPOSAL_STATUS_VOTING_PERIOD ? ( - - ) : null} - - ) -} - -export default ProposalItem diff --git a/src/pages/gov/ProposalParams.tsx b/src/pages/gov/ProposalParams.tsx deleted file mode 100644 index 97270697c..000000000 --- a/src/pages/gov/ProposalParams.tsx +++ /dev/null @@ -1,39 +0,0 @@ -import { useTranslation } from "react-i18next" -import { readPercent } from "@terra-money/terra-utils" -import { useTallyParams } from "data/queries/gov" -import { Card } from "components/layout" -import DataList from "./components/DataList" - -const ProposalParams = ({ chain }: { chain: string }) => { - const { t } = useTranslation() - const { data: tallyParams, ...state } = useTallyParams(chain) - - const render = () => { - if (!tallyParams) return null - const { quorum, threshold, veto_threshold } = tallyParams - const contents = [ - { - title: t("Quorum"), - content: readPercent(quorum.toString()), - }, - { - title: t("Pass threshold"), - content: readPercent(threshold.toString()), - }, - { - title: t("Veto threshold"), - content: readPercent(veto_threshold.toString()), - }, - ] - - return - } - - return ( - - {render()} - - ) -} - -export default ProposalParams diff --git a/src/pages/gov/ProposalSummary.tsx b/src/pages/gov/ProposalSummary.tsx deleted file mode 100644 index 3f900159d..000000000 --- a/src/pages/gov/ProposalSummary.tsx +++ /dev/null @@ -1,43 +0,0 @@ -import { Proposal } from "@terra-money/feather.js" -import { FinderLink } from "components/general" -import { Col, Card } from "components/layout" -import { Read } from "components/token" -import DataList from "./components/DataList" - -const ProposalSummary = ({ proposal }: { proposal: Proposal }) => { - if (!proposal.content) return null - const contentData = proposal.content.toData() - - const details = Object.entries(contentData ?? {}) - .filter(([key]) => !["@type", "title", "description"].includes(key)) - .map(([key, content]) => ({ - title: capitalize(key), - content: - key === "amount" ? ( - content.map((coin: CoinData) => ) - ) : key === "recipient" ? ( - {content} - ) : key === "changes" ? ( - content.map((item: object, index: number) => ( -
{stringify(item)}
- )) - ) : ( -
{stringify(content)}
- ), - })) - - return !details.length ? null : ( -
- - - - - ) -} - -export default ProposalSummary - -/* helpers */ -const capitalize = (s: string) => s.charAt(0).toUpperCase() + s.slice(1) -const stringify = (value: string | object) => - typeof value !== "string" ? JSON.stringify(value, null, 2) : value diff --git a/src/pages/gov/ProposalVotes.module.scss b/src/pages/gov/ProposalVotes.module.scss deleted file mode 100644 index e81f06d82..000000000 --- a/src/pages/gov/ProposalVotes.module.scss +++ /dev/null @@ -1,41 +0,0 @@ -@import "mixins"; - -.total { - display: grid; - grid-template-rows: auto 1fr; - gap: 4px; - font-size: var(--font-size-small); -} - -.list { - flex: 1; - gap: 24px; - - @include desktop { - display: flex; - } - - @include mobile { - display: grid; - grid-template: repeat(2, 1fr) / repeat(2, 1fr); - } -} - -.item { - flex: 1; - border-radius: var(--border-radius); - font-size: var(--font-size-small); - padding: 16px; - - .title { - margin-bottom: 2px; - } - - .ratio { - font-size: 16px; - } -} - -.end { - margin-top: 20px; -} diff --git a/src/pages/gov/ProposalVotes.tsx b/src/pages/gov/ProposalVotes.tsx deleted file mode 100644 index 482407e10..000000000 --- a/src/pages/gov/ProposalVotes.tsx +++ /dev/null @@ -1,199 +0,0 @@ -import { useTranslation } from "react-i18next" -import classNames from "classnames/bind" -import BigNumber from "bignumber.js" -import { StakingPool, Tally, TallyParams, Vote } from "@terra-money/feather.js" -import { readAmount, readPercent } from "@terra-money/terra-utils" -import { has } from "utils/num" -import { combineState } from "data/query" -import { useGetVoteOptionItem } from "data/queries/gov" -import { useProposal, useTally, useTallyParams } from "data/queries/gov" -import { useStakingPool } from "data/queries/staking" -import { Col, Row, Card, Grid } from "components/layout" -import { Fetching, Empty } from "components/feedback" -import { Read } from "components/token" -import { ToNow } from "components/display" -import VoteProgress from "./components/VoteProgress" -import styles from "./ProposalVotes.module.scss" - -const cx = classNames.bind(styles) - -export const options = [ - Vote.Option.VOTE_OPTION_YES, - Vote.Option.VOTE_OPTION_ABSTAIN, - Vote.Option.VOTE_OPTION_NO, - Vote.Option.VOTE_OPTION_NO_WITH_VETO, -] - -const ProposalVotes = ({ - id, - chain, - card, -}: { - id: number - chain: string - card?: boolean -}) => { - const { t } = useTranslation() - const getVoteOptionItem = useGetVoteOptionItem() - - const { data: proposal, ...proposalState } = useProposal(id, chain) - const { data: tally, ...tallyState } = useTally(id, chain) - const { data: tallyParams, ...tallyParamsState } = useTallyParams(chain) - const { data: pool, ...poolState } = useStakingPool(chain) - - const state = combineState( - proposalState, - tallyState, - tallyParamsState, - poolState - ) - - const render = () => { - if (!(proposal && tally && tallyParams && pool)) return null - - const tallies = calcTallies(tally, tallyParams, pool) - const { total, list, flag, isPassing } = tallies - const { voting_end_time } = proposal - - const flagLabel = { quorum: t("Quorum"), threshold: t("Pass threshold") } - - if (!has(total.voted)) return {t("No votes yet")} - - return ( - - {card && ( - - -
-

{t("Total voted")}

-
- ( - {readPercent(total.ratio)}) -

- {isPassing ? ( - {t("Passing...")} - ) : ( - {t("Not passing...")} - )} -

-
-
- - - -
- {list.map(({ option, voted, ratio }) => { - const { color, label } = getVoteOptionItem(option) - - return ( -
-

{label}

-

- {readPercent(ratio.byVoted)} -

- -
- ) - })} -
- - - )} - - - ({ - color: getVoteOptionItem(option).color, - percent: readPercent(ratio.byStaked), - }))} - /> - - {card && ( -

- {t("Voted: {{n}} / {{d}}", { - n: readAmount(total.voted, { prefix: true }), - d: readAmount(total.staked, { prefix: true }), - })} -

- )} - -

- {voting_end_time > new Date() ? t("Ends") : t("Ended")}{" "} - {voting_end_time} -

-
- - ) - } - - return card ? ( - - {render()} - - ) : ( - - {render()} - - ) -} - -export default ProposalVotes - -/* helpers */ -const calcTallies = ( - tally: Tally, - { quorum, threshold }: TallyParams, - pool: StakingPool -) => { - const getTallyItem = (option: Vote.Option) => { - const voted = - option === Vote.Option.UNRECOGNIZED || - option === Vote.Option.VOTE_OPTION_UNSPECIFIED - ? "0" - : tallies[option] - - const byVoted = Number(voted) / Number(total.voted) - const byStaked = Number(byVoted) * Number(ratio) - - return { option, voted, ratio: { byVoted, byStaked } } - } - - const tallies = { - [Vote.Option.VOTE_OPTION_YES]: tally.yes.toString(), - [Vote.Option.VOTE_OPTION_ABSTAIN]: tally.abstain.toString(), - [Vote.Option.VOTE_OPTION_NO]: tally.no.toString(), - [Vote.Option.VOTE_OPTION_NO_WITH_VETO]: tally.no_with_veto.toString(), - } - - const total = { - voted: BigNumber.sum(...Object.values(tallies ?? {})).toString(), - staked: pool.bonded_tokens.amount.toString(), - } - - const ratio = Number(total.voted) / Number(total.staked) - const list = options.map(getTallyItem) - - /* quorum | threshold */ - const determinantThreshold = BigNumber.sum( - ...list.slice(0, 3).map((o) => o.ratio.byVoted) - ).toNumber() - - const thresholdX = threshold - .times(determinantThreshold) - .times(ratio) - .toNumber() - - const isBelowQuorum = quorum.gt(ratio) - const flag = isBelowQuorum - ? { x: quorum.toNumber(), type: "quorum" as const } - : { x: thresholdX, type: "threshold" as const } - - const consentRatio = list.slice(0, 2).map(({ ratio }) => ratio.byVoted) - const isPassing = !isBelowQuorum && BigNumber.sum(...consentRatio).gte(0.5) - - return { list, total: { ...total, ratio }, flag, isPassing } -} diff --git a/src/pages/gov/ProposalVotesByValidator.module.scss b/src/pages/gov/ProposalVotesByValidator.module.scss deleted file mode 100644 index d0a8682bd..000000000 --- a/src/pages/gov/ProposalVotesByValidator.module.scss +++ /dev/null @@ -1,46 +0,0 @@ -@import "mixins"; - -.filter { - overflow: hidden; - - @include mobile { - display: grid; - gap: 12px; - } - - @include desktop { - @include flex(space-between); - } -} - -.tabs { - overflow-x: auto; - - .inner { - white-space: nowrap; - } -} - -.tab { - border-radius: 11px; - font-size: 12px; - font-weight: var(--normal); - height: 22px; - padding: 0 15px; - - &.active { - background-color: var(--button-primary-bg); - color: var(--button-primary-text); - font-weight: var(--bold); - } -} - -/* content */ -.link { - @include inline-flex; - - &.disabled { - cursor: not-allowed; - opacity: 0.2; - } -} diff --git a/src/pages/gov/ProposalVotesByValidator.tsx b/src/pages/gov/ProposalVotesByValidator.tsx deleted file mode 100644 index 1c560110e..000000000 --- a/src/pages/gov/ProposalVotesByValidator.tsx +++ /dev/null @@ -1,198 +0,0 @@ -import { useCallback, useState } from "react" -import { useTranslation } from "react-i18next" -import { Link } from "react-router-dom" -import classNames from "classnames/bind" -import EmailOutlinedIcon from "@mui/icons-material/EmailOutlined" -import { readPercent } from "@terra-money/terra-utils" -import { ValAddress, Vote } from "@terra-money/feather.js" -import { combineState } from "data/query" -import { useDelegations, useValidators } from "data/queries/staking" -import { useGetVoteOptionItem } from "data/queries/gov" -import { getCalcVotingPowerRate } from "data/Terra/TerraAPI" -import { useTerraProposal } from "data/Terra/TerraAPI" -import { ExternalLink } from "components/general" -import { Card, Grid, Table } from "components/layout" -import { Checkbox } from "components/form" -import { Empty } from "components/feedback" -import { Tooltip } from "@terra-money/station-ui" -import { getIsUnbonded } from "../stake/Validators" -import { options } from "./ProposalVotes" -import styles from "./ProposalVotesByValidator.module.scss" -import { useChainID } from "data/wallet" - -const cx = classNames.bind(styles) - -const ProposalVotesByValidator = ({ id }: { id: number }) => { - const { t } = useTranslation() - const chainID = useChainID() - - const tooltipContents: Record = { - [Vote.Option.VOTE_OPTION_YES]: t("Agree"), - [Vote.Option.VOTE_OPTION_NO]: t("Disagree"), - [Vote.Option.VOTE_OPTION_NO_WITH_VETO]: t( - "Strongly disagree and should not return the deposit to the proposer" - ), - [Vote.Option.VOTE_OPTION_ABSTAIN]: t( - "No decision but this vote counts toward vote quorum" - ), - [Vote.Option.VOTE_OPTION_UNSPECIFIED]: "", - [Vote.Option.UNRECOGNIZED]: "", - } - - const getVoteOptionItem = useGetVoteOptionItem() - - const [tab, setTab] = useState() - const [delegatedOnly, setDelegatedOnly] = useState(false) - - const { data: delegations, ...delegationsState } = useDelegations(chainID) - const { data: TerraProposal, ...TerraProposalState } = useTerraProposal(id) - const { data: TerraValidators, ...TerraValidatorsState } = - useValidators(chainID) - - const state = combineState( - delegationsState, - TerraProposalState, - TerraValidatorsState - ) - - const getList = useCallback( - (tab?: Vote.Option) => { - if (!(delegations && TerraProposal && TerraValidators)) return [] - - const getIsDelegated = (address: ValAddress) => { - return delegations.some( - ({ validator_address }) => validator_address === address - ) - } - - const getHasVoted = (address: ValAddress, option?: Vote.Option) => { - return TerraProposal.some(({ voter, options }) => { - if (ValAddress.fromAccAddress(voter, "terra") !== address) - return false - - const voted = options.some( - (o) => (Vote.Option[o.option] as unknown as Vote.Option) === option - ) - - return !option || voted - }) - } - - return TerraValidators.filter(({ operator_address, status }) => { - if (getIsUnbonded(status)) return false - if (delegatedOnly && !getIsDelegated(operator_address)) return false - if (!tab) return !getHasVoted(operator_address) - return getHasVoted(operator_address, tab) - }) - }, - [TerraProposal, TerraValidators, delegatedOnly, delegations] - ) - - const getCount = useCallback( - (tab?: Vote.Option) => getList(tab).length, - [getList] - ) - - const render = () => { - if (!(delegations && TerraProposal && TerraValidators)) return null - - const calcRate = getCalcVotingPowerRate(TerraValidators) - - const dataSource = getList(tab) - .map((validator) => { - const voting_power_rate = calcRate(validator.operator_address) - return { ...validator, voting_power_rate } - }) - .sort((a, b) => Number(b.voting_power_rate) - Number(a.voting_power_rate)) - - return ( - -
-
-
- - - {options.map((key) => { - const { label } = getVoteOptionItem(key) - return ( - - - - ) - })} -
-
- - {delegations.length > 0 && ( - setDelegatedOnly(!delegatedOnly)} - > - {t("View my validators only")} - - )} -
- - {!dataSource.length ? ( - - ) : ( -
( - {moniker} - ), - }, - { - title: t("Voting power"), - dataIndex: "voting_power_rate", - render: (value) => readPercent(value), - align: "right", - }, - { - title: t("Contact"), - dataIndex: ["contact", "email"], - render: (value) => ( - - - - ), - align: "right", - }, - ]} - dataSource={dataSource} - pagination={5} - size="small" - key={tab} - /> - )} - - ) - } - - if (!TerraProposal?.length) return null - - return ( - - {render()} - - ) -} - -export default ProposalVotesByValidator diff --git a/src/pages/gov/Proposals.tsx b/src/pages/gov/Proposals.tsx deleted file mode 100644 index 69db6c784..000000000 --- a/src/pages/gov/Proposals.tsx +++ /dev/null @@ -1,23 +0,0 @@ -import { Proposal } from "@terra-money/feather.js" -import { useGetProposalStatusItem } from "data/queries/gov" -import { Tabs } from "components/layout" -import ProposalsByStatus from "./ProposalsByStatus" - -const Proposals = () => { - const getTranslation = useGetProposalStatusItem() - - const tabs = [ - Proposal.Status.PROPOSAL_STATUS_VOTING_PERIOD, - Proposal.Status.PROPOSAL_STATUS_DEPOSIT_PERIOD, - Proposal.Status.PROPOSAL_STATUS_PASSED, - Proposal.Status.PROPOSAL_STATUS_REJECTED, - ].map((key) => ({ - key: Proposal.Status[key], - tab: getTranslation(key).label, - children: , - })) - - return -} - -export default Proposals diff --git a/src/pages/gov/ProposalsByStatus.module.scss b/src/pages/gov/ProposalsByStatus.module.scss deleted file mode 100644 index bf6eb0fa1..000000000 --- a/src/pages/gov/ProposalsByStatus.module.scss +++ /dev/null @@ -1,22 +0,0 @@ -@import "mixins"; - -.list { - display: grid; - gap: var(--grid-gap); - - @include desktop { - grid-template-columns: repeat(2, 1fr); - } -} - -.link { - display: grid; - color: inherit; - border: var(--border-width) solid var(--card-border); - - &:hover { - text-decoration: none; - border: var(--border-width) solid var(--info); - box-sizing: border-box; - } -} diff --git a/src/pages/gov/ProposalsByStatus.tsx b/src/pages/gov/ProposalsByStatus.tsx deleted file mode 100644 index b8825fb82..000000000 --- a/src/pages/gov/ProposalsByStatus.tsx +++ /dev/null @@ -1,115 +0,0 @@ -import { useState } from "react" -import { useTranslation } from "react-i18next" -import { Proposal } from "@terra-money/feather.js" -import { combineState } from "data/query" -import { useProposals, useProposalStatusItem } from "data/queries/gov" -import { useTerraAssets } from "data/Terra/TerraAssets" -import { Col, Card } from "components/layout" -import { Fetching, Empty } from "components/feedback" -import { Toggle } from "components/form" -import ProposalItem from "./ProposalItem" -import GovernanceParams from "./GovernanceParams" -import styles from "./ProposalsByStatus.module.scss" -import { useNetworkName } from "data/wallet" -import ChainFilter from "components/layout/ChainFilter" - -const ProposalsByStatus = ({ status }: { status: Proposal.Status }) => { - const { t } = useTranslation() - const networkName = useNetworkName() - - const { data: whitelistData, ...whitelistState } = useTerraAssets<{ - [key: string]: number[] - }>("/station/proposals.json") - const whitelist = whitelistData?.[networkName] - - const [showAll, setShowAll] = useState(!!whitelist) - const toggle = () => setShowAll((state) => !state) - - const { data, ...proposalState } = useProposals(status) - const { label } = useProposalStatusItem(status) - - const state = combineState(whitelistState, proposalState) - - const render = () => { - if (!(data && whitelistData)) return null - - const proposals = - status === Proposal.Status.PROPOSAL_STATUS_VOTING_PERIOD && !showAll - ? data.filter( - ({ prop, chain }) => - chain !== "phoenix-1" || whitelist?.includes(prop.id) - ) - : data - - proposals.sort( - (a, b) => - (b.prop.voting_start_time || b.prop.submit_time).getTime() - - (a.prop.voting_start_time || a.prop.submit_time).getTime() - ) - - return ( - <> - - {(chain) => { - const filtered = proposals.filter( - (p) => !chain || p.chain === chain - ) - return !filtered.length ? ( - <> - - - {t("No proposals in {{label}} period", { - label: label.toLowerCase(), - })} - - - {chain && } - - ) : ( - <> -
- {filtered.map(({ prop, chain }, i) => ( - - - - ))} -
- {chain && } - - ) - }} -
- - ) - } - - return ( - -
- {!!whitelist && - status === Proposal.Status.PROPOSAL_STATUS_VOTING_PERIOD && ( -
- - {t("Show all")} - -
- )} - - {render()} - - - ) -} - -export default ProposalsByStatus diff --git a/src/pages/gov/components/DataList.module.scss b/src/pages/gov/components/DataList.module.scss deleted file mode 100644 index 9d1707487..000000000 --- a/src/pages/gov/components/DataList.module.scss +++ /dev/null @@ -1,19 +0,0 @@ -@import "mixins"; - -.list { - overflow: auto; -} - -.horizontal { - @include flex(space-evenly); - text-align: center; -} - -.vertical { - display: grid; - gap: 20px; -} - -.title { - font-size: var(--font-size-small); -} diff --git a/src/pages/gov/components/DataList.tsx b/src/pages/gov/components/DataList.tsx deleted file mode 100644 index 766493f64..000000000 --- a/src/pages/gov/components/DataList.tsx +++ /dev/null @@ -1,26 +0,0 @@ -import classNames from "classnames/bind" -import { Grid } from "components/layout" -import { Contents } from "types/components" -import styles from "./DataList.module.scss" - -const cx = classNames.bind(styles) - -interface Props { - list: Contents - type: "horizontal" | "vertical" -} - -const DataList = ({ list, type }: Props) => { - return ( -
- {list.map(({ title, content }, index) => ( - -

{title}

-
{content}
-
- ))} -
- ) -} - -export default DataList diff --git a/src/pages/gov/components/Orb.module.scss b/src/pages/gov/components/Orb.module.scss deleted file mode 100644 index a1ee0bb49..000000000 --- a/src/pages/gov/components/Orb.module.scss +++ /dev/null @@ -1,33 +0,0 @@ -@import "mixins"; - -.orb { - --size: 100px; - @include flex-column(flex-end, stretch); - - background: var(--bg-muted); - border-radius: 50%; - overflow: hidden; - width: var(--size); - height: var(--size); -} - -.large { - --size: 120px; -} - -.filled { - flex: none; - background: var(--success); - position: relative; -} - -.tilde { - position: absolute; - top: calc(-1 * var(--size) / 20); - left: 0; - right: 0; - - fill: var(--success); - width: var(--size); - height: calc(var(--size) / 10); -} diff --git a/src/pages/gov/components/Orb.tsx b/src/pages/gov/components/Orb.tsx deleted file mode 100644 index a9e4d404e..000000000 --- a/src/pages/gov/components/Orb.tsx +++ /dev/null @@ -1,21 +0,0 @@ -import classNames from "classnames/bind" -import BigNumber from "bignumber.js" -import { readPercent } from "@terra-money/terra-utils" -import { ReactComponent as Tilde } from "./Tilde.svg" -import styles from "./Orb.module.scss" - -const cx = classNames.bind(styles) - -const Orb = ({ ratio, size }: { ratio: number; size?: "large" }) => { - const height = readPercent(BigNumber.min(ratio, 1)) - - return ( -
-
- {!!ratio && } -
-
- ) -} - -export default Orb diff --git a/src/pages/gov/components/Tilde.svg b/src/pages/gov/components/Tilde.svg deleted file mode 100644 index e48d154ca..000000000 --- a/src/pages/gov/components/Tilde.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/pages/gov/components/VoteProgress.module.scss b/src/pages/gov/components/VoteProgress.module.scss deleted file mode 100644 index 8a530aa5f..000000000 --- a/src/pages/gov/components/VoteProgress.module.scss +++ /dev/null @@ -1,33 +0,0 @@ -@import "mixins"; - -.flag { - position: relative; - - .label, - .line { - transform: translate(-50%, 0); - } -} - -.label { - display: inline-block; - font-size: var(--font-size-small); -} - -.line { - display: block; - background: var(--text); - width: 1px; - height: 12px; -} - -/* progress bar */ -.track { - background: var(--bg-muted); - overflow: hidden; - width: 100%; -} - -.item { - height: 10px; -} diff --git a/src/pages/gov/components/VoteProgress.tsx b/src/pages/gov/components/VoteProgress.tsx deleted file mode 100644 index ed52d5a4b..000000000 --- a/src/pages/gov/components/VoteProgress.tsx +++ /dev/null @@ -1,37 +0,0 @@ -import { PropsWithChildren } from "react" -import classNames from "classnames" -import { Flex } from "components/layout" -import styles from "./VoteProgress.module.scss" - -const cx = classNames.bind(styles) - -const Flag = ({ left, children }: PropsWithChildren<{ left: string }>) => { - return ( -
- {children} - -
- ) -} - -interface Props { - flag: { percent: string; label: string } - list: { percent: string; color: string }[] -} - -const VoteProgress = ({ flag, list }: Props) => { - return ( -
- {flag.label} - - - {list.map(({ percent: width, color }) => { - const className = cx(styles.item, `bg-${color}`) - return - })} - -
- ) -} - -export default VoteProgress diff --git a/src/pages/gov/useProposalId.ts b/src/pages/gov/useProposalId.ts deleted file mode 100644 index d933c7a2b..000000000 --- a/src/pages/gov/useProposalId.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { useParams } from "react-router-dom" - -const useProposalId = () => { - const { id, chain } = useParams() - return { id: Number(id), chain: chain ?? "" } -} - -export default useProposalId diff --git a/src/pages/stake/ValidatorVotes.tsx b/src/pages/stake/ValidatorVotes.tsx deleted file mode 100644 index 874f14e01..000000000 --- a/src/pages/stake/ValidatorVotes.tsx +++ /dev/null @@ -1,65 +0,0 @@ -import { useMemo } from "react" -import { useTranslation } from "react-i18next" -import { Link } from "react-router-dom" -import { reverse } from "ramda" -import { readPercent } from "@terra-money/terra-utils" -import { TerraValidator } from "types/validator" -import { useGetVoteOptionItem } from "data/queries/gov" -import { useVotingPowerRate } from "data/Terra/TerraAPI" -import { Card, Grid, Table } from "components/layout" -import ValidatorNumbers from "./components/ValidatorNumbers" - -const ValidatorVotes = ({ validator }: { validator: TerraValidator }) => { - const { t } = useTranslation() - const getVoteOptionItem = useGetVoteOptionItem() - - const { operator_address, votes } = validator - - const { data: votingPowerRate, ...votingPowerRateState } = - useVotingPowerRate(operator_address) - - const contents = useMemo(() => { - if (!votingPowerRate) return [] - return [{ title: t("Voting power"), content: readPercent(votingPowerRate) }] - }, [t, votingPowerRate]) - - return ( - - - {contents && } - {votes && ( -
{ - return {title} - }, - }, - { - dataIndex: "options", - title: "Vote", - render: (options) => { - return options - .map(({ option }: { option: string }) => { - const { label } = getVoteOptionItem(option) - return label - }) - .join(", ") - }, - align: "right", - }, - ]} - dataSource={reverse(votes)} - pagination={5} - size="small" - /> - )} - - - ) -} - -export default ValidatorVotes diff --git a/src/txs/feeAbstraction/DisplayFees.tsx b/src/txs/feeAbstraction/DisplayFees.tsx index be74d5be9..e21a5c629 100644 --- a/src/txs/feeAbstraction/DisplayFees.tsx +++ b/src/txs/feeAbstraction/DisplayFees.tsx @@ -1,8 +1,11 @@ import { useNetwork } from "auth/hooks/useNetwork" -import { Select } from "components/form" import { ReactNode, useEffect, useState } from "react" import { useTranslation } from "react-i18next" -import { Dropdown, LoadingCircular, SummaryTable } from "@terra-money/station-ui" +import { + Dropdown, + LoadingCircular, + SummaryTable, +} from "@terra-money/station-ui" import styles from "./DisplayFees.module.scss" import { useNativeDenoms } from "data/token" import { Read } from "components/token" @@ -129,7 +132,10 @@ export default function DisplayFees({ {availableGasDenoms.length > 1 && setGasDenom && ( ({value: denom, label:readNativeDenom(denom, chainID).symbol }))} + options={availableGasDenoms.map((denom) => ({ + value: denom, + label: readNativeDenom(denom, chainID).symbol, + }))} onChange={(val) => setGasDenom(val)} /> )} diff --git a/src/txs/gov/DepositForm.tsx b/src/txs/gov/DepositForm.tsx deleted file mode 100644 index f73d736f5..000000000 --- a/src/txs/gov/DepositForm.tsx +++ /dev/null @@ -1,111 +0,0 @@ -import { useCallback, useMemo } from "react" -import { useTranslation } from "react-i18next" -import { useForm } from "react-hook-form" -import { MsgDeposit } from "@terra-money/feather.js" -import { toAmount } from "@terra-money/terra-utils" -import { queryKey } from "data/query" -import { useBankBalance } from "data/queries/bank" -import { Form, FormItem, Input } from "components/form" -import useProposalId from "pages/gov/useProposalId" -import { getPlaceholder, toInput } from "../utils" -import validate from "../validate" -import Tx from "../Tx" -import { useInterchainAddresses } from "auth/hooks/useAddress" -import { useNetwork } from "data/wallet" - -interface TxValues { - input: number -} - -const DepositForm = () => { - const { t } = useTranslation() - const { id, chain } = useProposalId() - const addresses = useInterchainAddresses() - const networks = useNetwork() - - const bankBalance = useBankBalance() - const balance = - bankBalance.find((b) => b.denom === networks[chain].baseAsset)?.amount ?? - "0" - - /* form */ - const form = useForm({ mode: "onChange" }) - const { register, trigger, watch, setValue, handleSubmit, formState } = form - const { errors } = formState - const { input } = watch() - const amount = toAmount(input) - - /* tx */ - const createTx = useCallback( - ({ input }: TxValues) => { - if (!addresses) return - const amount = toAmount(input) - const msgs = [ - new MsgDeposit( - id, - addresses[chain], - amount + networks[chain].baseAsset - ), - ] - return { msgs, chainID: chain } - }, - [addresses, id, chain, networks] - ) - - /* fee */ - const estimationTxValues = useMemo( - () => ({ input: toInput(balance) }), - [balance] - ) - - const onChangeMax = useCallback( - async (input: number) => { - setValue("input", input) - await trigger("input") - }, - [setValue, trigger] - ) - - const tx = { - token: networks[chain].baseAsset, - amount, - balance, - estimationTxValues, - createTx, - onChangeMax, - queryKeys: [[queryKey.gov.deposits, id]], - chain, - } - - return ( - - {({ max, fee, submit }) => ( -
- - - - - {fee.render()} - {submit.button} - - )} -
- ) -} - -export default DepositForm diff --git a/src/txs/gov/DepositTx.tsx b/src/txs/gov/DepositTx.tsx deleted file mode 100644 index 261f38064..000000000 --- a/src/txs/gov/DepositTx.tsx +++ /dev/null @@ -1,29 +0,0 @@ -import { useTranslation } from "react-i18next" -import { useProposal } from "data/queries/gov" -import { Auto, Page, Card } from "components/layout" -import useProposalId from "pages/gov/useProposalId" -import ProposalHeader from "pages/gov/ProposalHeader" -import DepositForm from "./DepositForm" - -const DepositTx = () => { - const { t } = useTranslation() - const { id, chain } = useProposalId() - const { data: proposal, ...state } = useProposal(id, chain) - - return ( - - - - , - - {proposal && } - , - ]} - /> - - ) -} - -export default DepositTx diff --git a/src/txs/gov/SubmitProposalForm.tsx b/src/txs/gov/SubmitProposalForm.tsx deleted file mode 100644 index d3509b77a..000000000 --- a/src/txs/gov/SubmitProposalForm.tsx +++ /dev/null @@ -1,516 +0,0 @@ -import { useCallback, useEffect, useMemo } from "react" -import { useTranslation } from "react-i18next" -import { useFieldArray, useForm } from "react-hook-form" -import AddIcon from "@mui/icons-material/Add" -import RemoveIcon from "@mui/icons-material/Remove" -import { AccAddress, Coins, MsgSubmitProposal } from "@terra-money/feather.js" -import { - TextProposal, - CommunityPoolSpendProposal, -} from "@terra-money/feather.js" -import { ParameterChangeProposal, ParamChange } from "@terra-money/feather.js" -import { ExecuteContractProposal } from "@terra-money/feather.js/dist/core/wasm/proposals" -import { isDenomTerraNative } from "@terra-money/terra-utils" -import { readAmount, toAmount } from "@terra-money/terra-utils" -import { SAMPLE_ADDRESS } from "config/constants" -import { getAmount } from "utils/coin" -import { has } from "utils/num" -import { parseJSON } from "utils/data" -import { combineState, queryKey } from "data/query" -import { useBankBalance } from "data/queries/bank" -import { ExternalLink } from "components/general" -import { Card, Grid } from "components/layout" -import { Form, FormGroup, FormItem } from "components/form" -import { FormHelp, FormWarning } from "components/form" -import { Input, TextArea, Select } from "components/form" -import { TooltipIcon } from "components/display" -import { getCoins, getPlaceholder, toInput } from "../utils" -import validate from "../validate" -import Tx from "../Tx" -import { useCommunityPool } from "data/queries/distribution" -import { useDepositParams } from "data/queries/gov" -import { useInterchainAddresses } from "auth/hooks/useAddress" -import { useNetwork } from "data/wallet" -import { useNativeDenoms } from "data/token" - -enum ProposalType { - TEXT = "Text proposal", - SPEND = "Community pool spend", - PARAMS = "Parameter change", - EXECUTE = "Execute contract", -} - -interface DefaultValues { - title: string - description: string - chain?: string - input?: number -} - -interface TextProposalValues extends DefaultValues { - type: ProposalType.TEXT -} - -interface CommunityPoolSpendProposalValues extends DefaultValues { - type: ProposalType.SPEND - spend: { input?: number; denom: CoinDenom; recipient: AccAddress } -} - -interface ParameterChangeProposalValues extends DefaultValues { - type: ProposalType.PARAMS - changes: ParamChange[] -} - -interface ExecuteContractProposalValues extends DefaultValues { - type: ProposalType.EXECUTE - runAs: AccAddress - contractAddress: AccAddress - msg: string - coins: { input?: number; denom: CoinDenom }[] -} - -type TxValues = - | TextProposalValues - | CommunityPoolSpendProposalValues - | ParameterChangeProposalValues - | ExecuteContractProposalValues - -const DEFAULT_PAREMETER_CHANGE = { - subspace: "", - key: "", - value: "", -} as ParamChange - -const SubmitProposalForm = ({ chain }: { chain: string }) => { - const { t } = useTranslation() - const addresses = useInterchainAddresses() - const networks = useNetwork() - const readNativeDenom = useNativeDenoms() - - const bankBalance = useBankBalance() - const balance = - bankBalance.find((b) => b.denom === networks[chain].baseAsset)?.amount ?? - "0" - - /* tx context */ - const defaultCoinItem = { denom: networks[chain].baseAsset } - - const { data: communityPool, ...communityPoolState } = useCommunityPool(chain) - const { data: depositParams, ...depositParamsState } = useDepositParams(chain) - const state = combineState(communityPoolState, depositParamsState) - //if(!depositParams || communityPool) return null - const minDeposit = depositParams - ? getAmount(depositParams.min_deposit, networks[chain].baseAsset) - : 0 - - /* form */ - const form = useForm({ - mode: "onChange", - defaultValues: { input: toInput(minDeposit), coins: [defaultCoinItem] }, - }) - - const { register, trigger, control, watch, setValue, handleSubmit } = form - const { errors } = form.formState - const { input, ...values } = watch() - const amount = toAmount(input) - const { fields, append, remove } = useFieldArray({ - control, - name: "changes", - }) - const coinsFieldArray = useFieldArray({ control, name: "coins" }) - - /* update input */ - useEffect(() => { - setValue("input", toInput(minDeposit)) - }, [minDeposit, setValue]) - - /* effect: ParameterChangeProposal */ - const shouldAppendChange = - values.type === ProposalType.PARAMS && !values.changes.length - - useEffect(() => { - if (shouldAppendChange) append(DEFAULT_PAREMETER_CHANGE) - }, [append, shouldAppendChange]) - - /* tx */ - const createTx = useCallback( - ({ input, title, description, ...values }: TxValues) => { - if (!addresses) return - const amount = toAmount(input) - const deposit = has(amount) - ? new Coins({ [networks[chain].baseAsset]: amount }) - : [] - - const getContent = () => { - if (values.type === ProposalType.SPEND) { - const { input, denom, recipient } = values.spend - const coins = new Coins({ [denom]: toAmount(input) }) - return new CommunityPoolSpendProposal( - title, - description, - recipient, - coins - ) - } - - if (values.type === ProposalType.PARAMS) { - const { changes } = values - return new ParameterChangeProposal(title, description, changes) - } - - if (values.type === ProposalType.EXECUTE) { - const { runAs, contractAddress, msg } = values - const execute_msg = parseJSON(msg) - const coins = getCoins(values.coins) - return new ExecuteContractProposal( - title, - description, - runAs, - contractAddress, - execute_msg, - coins - ) - } - - return new TextProposal(title, description) - } - - const msgs = [ - new MsgSubmitProposal(getContent(), deposit, addresses[chain]), - ] - return { msgs, chainID: chain ?? "" } - }, - [addresses, chain, networks] - ) - - /* fee */ - const estimationTxValues = useMemo( - (): TxValues => ({ - type: ProposalType.TEXT, - title: ESTIMATE.TITLE, - description: ESTIMATE.DESCRIPTION, - input: toInput(balance), - }), - [balance] - ) - - const onChangeMax = useCallback( - async (input: number) => { - setValue("input", input) - await trigger("input") - }, - [setValue, trigger] - ) - - const tx = { - token: networks[chain].baseAsset, - amount, - balance, - estimationTxValues, - createTx, - onChangeMax, - queryKeys: [queryKey.gov.proposals], - chain: chain ?? "", - } - - const render = () => { - if (values.type === ProposalType.SPEND) { - // @ts-expect-error - const max = values.spend && getAmount(communityPool, values.spend.denom) - const placeholder = readAmount(max, { integer: true }) - - return ( - <> - - - - - - - {[networks[chain].baseAsset].map((denom) => ( - - ))} - - } - /> - - - ) - } - - if (values.type === ProposalType.PARAMS) { - const length = fields.length - return ( - - {fields.map(({ id }, index) => ( - append(DEFAULT_PAREMETER_CHANGE), - children: , - } - : { - onClick: () => remove(index), - children: , - } - } - key={id} - > - {/* do not translate labels here */} - - - - - - - - - - - - - ))} - - ) - } - - if (values.type === ProposalType.EXECUTE) { - const { fields, append, remove } = coinsFieldArray - const length = fields.length - - return ( - <> - - - - - - - - - -