diff --git a/packages/fetch-extension/src/components/proposal/proposal-view/index.tsx b/packages/fetch-extension/src/components/proposal/proposal-view/index.tsx deleted file mode 100644 index bce8b9ec66..0000000000 --- a/packages/fetch-extension/src/components/proposal/proposal-view/index.tsx +++ /dev/null @@ -1,53 +0,0 @@ -import React from "react"; -import { FunctionComponent } from "react"; -import style from "./style.module.scss"; -import classnames from "classnames"; -import { FormattedMessage } from "react-intl"; -import { Button } from "reactstrap"; -import { useNavigate } from "react-router"; -import { useStore } from "../../../stores"; - -export const ProposalView: FunctionComponent = () => { - const navigate = useNavigate(); - const { analyticsStore } = useStore(); - - return ( -
-
-

- -

-

- -

-
-
- - -
- ); -}; diff --git a/packages/fetch-extension/src/components/proposal/proposal-view/style.module.scss b/packages/fetch-extension/src/components/proposal/proposal-view/style.module.scss deleted file mode 100644 index 8aa6285a66..0000000000 --- a/packages/fetch-extension/src/components/proposal/proposal-view/style.module.scss +++ /dev/null @@ -1,29 +0,0 @@ -@import "../../../styles/var"; - -.containerInner { - display: flex; - flex-direction: row; - - height: 48px; - justify-content: center; - align-items: center; - - .paragraphMain { - line-height: 1.35; - } - - .paragraphSub { - line-height: 1.35; - color: #8898aa; - } - - .vertical { - display: flex; - flex-direction: column; - } - - .button { - min-width: 76px; - padding: 6px 10px 4px; - } -} diff --git a/packages/fetch-extension/src/components/proposal/proposal/index.tsx b/packages/fetch-extension/src/components/proposal/proposal/index.tsx deleted file mode 100644 index b969ffb107..0000000000 --- a/packages/fetch-extension/src/components/proposal/proposal/index.tsx +++ /dev/null @@ -1,108 +0,0 @@ -import React, { useEffect, useState } from "react"; -import { FunctionComponent } from "react"; -import style from "./style.module.scss"; -import { GovStatusChip } from "@components/chips/gov-chip"; -import { useNavigate } from "react-router"; -import { proposalOptions } from "../../../pages/proposals"; -import { useStore } from "../../../stores"; -import { fetchVote } from "@utils/fetch-proposals"; -import { ProposalSetup } from "src/@types/proposal-type"; - -interface Props { - title: string; - id: string; - status: string; -} - -export const Proposal: FunctionComponent = (props) => { - const { title, status, id } = props; - const { chainStore, accountStore, proposalStore, analyticsStore } = - useStore(); - const navigate = useNavigate(); - let icon, color, background, name; - const storedProposals: ProposalSetup = proposalStore.proposals; - - const accountInfo = accountStore.getAccount(chainStore.current.chainId); - const [alreadyVoted, setAlreadyVoted] = useState(""); - useEffect(() => { - (async () => { - const proposalItem = storedProposals.votedProposals.find( - (proposal) => proposal.proposal_id === id - ); - if (!proposalItem) { - return; - } - try { - const vote = await fetchVote( - id, - accountInfo.bech32Address, - chainStore.current.rest - ); - const voted = vote.vote.option; - setAlreadyVoted(voted); - } catch (e) {} - })(); - }, []); - - switch (status) { - case proposalOptions.ProposalPassed: - icon = "gov-tick.svg"; - color = "#6AB77A"; - background = "#E3F4E7"; - name = "Passed"; - break; - case proposalOptions.ProposalActive: - icon = "gov-clock.svg"; - color = "#3B82F6"; - background = "#D0DEF5"; - name = "Active"; - break; - case proposalOptions.ProposalRejected: - icon = "gov-cross.svg"; - color = "#DC6461"; - background = "#FBECEC"; - name = "Rejected"; - break; - default: - icon = "gov-cross.svg"; - color = "#DC6461"; - background = "#FBECEC"; - name = "Failed"; - } - const handleClick = () => { - analyticsStore.logEvent("proposal_detail_click"); - if (alreadyVoted !== "" && alreadyVoted !== "Unspecified") { - const voteArr = [ - "VOTE_OPTION_UNSPECIFIED", - "VOTE_OPTION_YES", - "VOTE_OPTION_ABSTAIN", - "VOTE_OPTION_NO", - "VOTE_OPTION_NO_WITH_VETO", - ]; - navigate( - `/proposal-vote-status/${voteArr.indexOf(alreadyVoted)}/${id}?true` - ); - return; - } - navigate(`/proposal-detail/${id}`); - }; - return ( -
-
-

{title}

-

{id}

-
- -
- -
-
- ); -}; diff --git a/packages/fetch-extension/src/components/proposal/proposal/style.module.scss b/packages/fetch-extension/src/components/proposal/proposal/style.module.scss deleted file mode 100644 index a49ddb4e15..0000000000 --- a/packages/fetch-extension/src/components/proposal/proposal/style.module.scss +++ /dev/null @@ -1,42 +0,0 @@ -.proposal { - display: flex; - line-height: 20px; - justify-content: space-between; - margin: 12px 0; - background: #ffffff; - cursor: pointer; - .pContent { - width: 65%; - .pTitle { - font-weight: 400; - font-size: 16px; - color: #525f7f; - margin: 0; - line-height: 22px; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - margin-right: 10px; - &::first-letter { - text-transform: capitalize; - } - } - - .pDesc { - font-weight: 400; - font-size: 15px; - color: #808da0; - margin: 0; - line-height: 22px; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - } - } - - .govStatus { - display: flex; - width: 30%; - justify-content: space-between; - } -} diff --git a/packages/fetch-extension/src/components/proposal/vote-block/index.tsx b/packages/fetch-extension/src/components/proposal/vote-block/index.tsx deleted file mode 100644 index 45db83d10c..0000000000 --- a/packages/fetch-extension/src/components/proposal/vote-block/index.tsx +++ /dev/null @@ -1,37 +0,0 @@ -import React, { FunctionComponent } from "react"; -import style from "./style.module.scss"; -import classNames from "classnames"; -interface Props { - title: string; - icon: string; - color: string; - activeColor: string; - id: number; - selected: number; - handleClick: any; - closed: boolean; -} -export const VoteBlock: FunctionComponent = (props) => { - const { title, icon, color, activeColor, id, selected, handleClick, closed } = - props; - const isSelected = id === selected; - const bgColor = isSelected ? activeColor : color; - const txtColor = isSelected ? "white" : "#525F7F"; - const Icon = isSelected ? icon + "-white" : icon; - const cursor = closed ? "not-allowed" : "pointer"; - return ( -
handleClick(id)} - > - -

- {title} -

-
- ); -}; diff --git a/packages/fetch-extension/src/components/proposal/vote-block/style.module.scss b/packages/fetch-extension/src/components/proposal/vote-block/style.module.scss deleted file mode 100644 index 396504d104..0000000000 --- a/packages/fetch-extension/src/components/proposal/vote-block/style.module.scss +++ /dev/null @@ -1,40 +0,0 @@ -.voteBlock { - display: flex; - justify-content: center; - align-items: center; - padding: 10px; - gap: 5px; - cursor: pointer; - - border-radius: 4px; - - .voteImage { - width: 20px; - height: 20px; - } - - .voteText { - margin: 0; - text-align: center; - font-weight: 700; - line-height: 14px; - color: #525f7f; - font-size: 14px; - } -} - -.voteTick { - background: rgba(106, 183, 122, 0.3); -} - -.voteCross { - background: rgba(220, 100, 97, 0.3); -} - -.voteAbstain { - background: rgba(236, 170, 93, 0.3); -} - -.voteNoVeto { - background: rgba(62, 100, 196, 0.3); -} diff --git a/packages/fetch-extension/src/index.tsx b/packages/fetch-extension/src/index.tsx index 8e370b640d..62d9bc0ffc 100644 --- a/packages/fetch-extension/src/index.tsx +++ b/packages/fetch-extension/src/index.tsx @@ -90,9 +90,8 @@ import { ValidatorListPage } from "./pages-new/validator-list"; import { Delegate } from "./pages-new/validator/delegate"; import { Redelegate } from "./pages-new/validator/redelegate"; import { Unstake } from "./pages-new/validator/unstake"; -import { AxelarBridgeCosmos } from "./pages-unused/axelar-bridge/axelar-bridge-cosmos"; -import { AxelarBridgeEVM } from "./pages-unused/axelar-bridge/axelar-bridge-evm"; -import { ValidatorList } from "./pages-unused/validator-list"; +import { AxelarBridgeCosmos } from "./pages/axelar-bridge/axelar-bridge-cosmos"; +import { AxelarBridgeEVM } from "./pages/axelar-bridge/axelar-bridge-evm"; import { AgentChatSection } from "./pages/agent-chat-section"; import { ApproveAddChainByNetworkPage } from "./pages/approveAddChainByNetwork"; import { ApproveSwitchAccountByAddressPage } from "./pages/approveSwitchAccountPage"; @@ -121,7 +120,6 @@ import { BlockList } from "./pages/setting/chat/block"; import { Privacy } from "./pages/setting/chat/privacy"; import { ReadRecipt } from "./pages/setting/chat/readRecipt"; import { SettingEndpointsPage } from "./pages/setting/endpoints"; -import { StakeComplete } from "./pages/validator/stake-complete"; import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; import { useAutoLockMonitoring } from "./use-auto-lock-monitoring"; @@ -451,18 +449,10 @@ ReactDOM.render( path="/setting/chat/readRecipt" element={} /> - } - /> } /> - } - /> } /> void; - options: any[]; - selectedFilter: any[]; -}> = ({ onFilterChange, options, selectedFilter }) => { - const [isOpen, setIsOpen] = useState(false); - const dropdownRef = useRef(null); - const { analyticsStore } = useStore(); - const toggleDropdown = () => { - setIsOpen(!isOpen); - }; - - const handleCheckboxChange = (value: string) => { - const newFilters = selectedFilter; - if (newFilters.includes(value)) { - onFilterChange(newFilters.filter((item) => item !== value)); - } else { - onFilterChange([...newFilters, value]); - } - }; - - const handleDeselectClicks = () => { - if (selectedFilter.length != 0) onFilterChange([]); - analyticsStore.logEvent("activity_filter_click", { - action: "unselectAll", - }); - }; - - const handleSelectClicks = () => { - const allFilters = options.map((option) => option.value); - if (selectedFilter.length != allFilters.length) onFilterChange(allFilters); - analyticsStore.logEvent("activity_filter_click", { - action: "selectAll", - }); - }; - - const handleClickOutside = (event: MouseEvent) => { - if ( - dropdownRef.current && - !dropdownRef.current.contains(event.target as Node) - ) { - setIsOpen(false); - } - }; - - useEffect(() => { - document.addEventListener("mousedown", handleClickOutside); - return () => { - document.removeEventListener("mousedown", handleClickOutside); - }; - }, []); - - return ( -
-
-
- Filter - Arrow Icon -
- {isOpen && ( -
-
-
Select all
-
Unselect all
-
-
- {options.map((option) => ( - - ))} -
-
- )} -
-
- ); -}; diff --git a/packages/fetch-extension/src/pages-unused/activity/filter/style.module.scss b/packages/fetch-extension/src/pages-unused/activity/filter/style.module.scss deleted file mode 100644 index 288bfaa041..0000000000 --- a/packages/fetch-extension/src/pages-unused/activity/filter/style.module.scss +++ /dev/null @@ -1,63 +0,0 @@ -.dropdown { - font-size: 12px; -} - -.dropdownToggle { - padding: 0 10px; - height: 20px; - position: relative; - color: #000000; - cursor: pointer; - width: 50%; - margin-left: 50%; - margin-bottom: 10px; - z-index: 1; -} -.dropdownHeading { - padding: 0 10px; - height: 20px; - margin-left: -7%; - border-radius: 5px; - display: flex; - align-items: center; - border: 1px solid #f0f0f0; - justify-content: space-between; -} - -.dropdownMenuPopup { - position: absolute; - top: 100%; - left: 0; - width: 97%; - background-color: #f0f0f0; - border-radius: 0 0 4px 4px; -} - -.dropdownMenu { - display: flex; - flex-direction: column; - padding: 5px; -} - -.dropdownItem { - align-items: center; - display: flex; -} - -.arrowIcon { - transform: rotate(90deg); - width: 6px; - height: 12px; - margin-left: 10px; -} - -.select { - padding: 2px 5px 0 2px; - display: flex; - justify-content: space-around; - align-items: center; -} - -.select div:hover { - color: #3b82f6; -} diff --git a/packages/fetch-extension/src/pages-unused/activity/gov-proposals/activity-row.tsx b/packages/fetch-extension/src/pages-unused/activity/gov-proposals/activity-row.tsx deleted file mode 100644 index 0f52871b1b..0000000000 --- a/packages/fetch-extension/src/pages-unused/activity/gov-proposals/activity-row.tsx +++ /dev/null @@ -1,78 +0,0 @@ -import { formatActivityHash } from "@utils/format"; -import React from "react"; -import style from "./style.module.scss"; -import success from "@assets/icon/success.png"; -import cancel from "@assets/icon/cancel.png"; -import govPropsalIcon from "@assets/icon/gov.png"; - -const getStatusIcon = (status: string): string => { - switch (status) { - case "Success": - return success; - case "Error": - return cancel; - default: - return cancel; - } -}; -const getVoteIcon = (vote: string): string => { - switch (vote) { - case "YES": - return "gov-tick.svg"; - case "NO": - return "gov-cross.svg"; - case "ABSTAIN": - return "gov-abstain.svg"; - case "NO_WITH_VETO": - return "gov-no-veto.svg"; - default: - return "gov-tick-white.svg"; - } -}; - -const getHash = (proposal: any) => { - if (proposal && proposal.id) { - return formatActivityHash(proposal.id); - } - return null; -}; - -export const ActivityRow = ({ node }: { node: any }) => { - const details = node.option; - const hash = getHash(node); - const { status, id } = node.transaction; - return ( - -
-
- {govPropsalIcon} -
-
- {hash} -
-
- {" "} - {details} -
-
- {status} -
-
-
- ); -}; diff --git a/packages/fetch-extension/src/pages-unused/activity/gov-proposals/index.tsx b/packages/fetch-extension/src/pages-unused/activity/gov-proposals/index.tsx deleted file mode 100644 index c8247d52d2..0000000000 --- a/packages/fetch-extension/src/pages-unused/activity/gov-proposals/index.tsx +++ /dev/null @@ -1,112 +0,0 @@ -import { fetchGovProposalTransactions } from "@graphQL/activity-api"; -import React, { useEffect, useState } from "react"; -import { Button } from "reactstrap"; -import { useStore } from "../../../stores"; -import { FilterActivities } from "../filter"; -import { ActivityRow } from "./activity-row"; -import style from "../style.module.scss"; -const options = [ - { value: "YES", label: "Voted Yes" }, - { value: "NO", label: "Voted No" }, - { value: "ABSTAIN", label: "Voted Abstain" }, - { value: "NO_WITH_VETO", label: "Voted No With Veto" }, -]; - -export const GovProposalsTab = ({ latestBlock }: { latestBlock: any }) => { - const { chainStore, accountStore, analyticsStore } = useStore(); - const current = chainStore.current; - const accountInfo = accountStore.getAccount(current.chainId); - const [isLoading, setIsLoading] = useState(false); - const [loadingRequest, setLoadingRequest] = useState(false); - const [nodes, setNodes] = useState({}); - const [pageInfo, setPageInfo] = useState(); - const [filter, setFilter] = useState( - options.map((option) => option.value) - ); - - const fetchNodes = async (cursor: any) => { - setIsLoading(true); - const fetchedData = await fetchGovProposalTransactions( - current.chainId, - cursor, - accountInfo.bech32Address, - filter - ); - if (fetchedData) { - const nodeMap: any = {}; - fetchedData.nodes.map((node: any) => { - nodeMap[node.id] = node; - }); - - setPageInfo(fetchedData.pageInfo); - setNodes({ ...nodes, ...nodeMap }); - } - - setIsLoading(false); - }; - - useEffect(() => { - fetchNodes(""); - }, []); - - useEffect(() => { - fetchNodes(""); - }, [filter, latestBlock]); - - const handleClick = async () => { - analyticsStore.logEvent("activity_transactions_click", { - pageName: "Gov Proposal Tab", - }); - setLoadingRequest(true); - await fetchNodes(pageInfo.endCursor); - setLoadingRequest(false); - }; - - const handleFilterChange = (selectedFilter: string[]) => { - setPageInfo(undefined); - setNodes({}); - setFilter(selectedFilter); - analyticsStore.logEvent("activity_filter_click", { - pageName: "Gov Proposal Tab", - }); - }; - - return ( - - - {Object.keys(nodes).length > 0 ? ( - - {Object.values(nodes) - .filter((node: any) => filter.includes(node.option)) - .map((node, index) => ( - - ))} - {pageInfo?.hasNextPage && ( - - )} - - ) : isLoading ? ( -
Loading Activities...
- ) : ( -
- No activity available right now -
- )} -
- ); -}; diff --git a/packages/fetch-extension/src/pages-unused/activity/gov-proposals/style.module.scss b/packages/fetch-extension/src/pages-unused/activity/gov-proposals/style.module.scss deleted file mode 100644 index 5a7f1c0028..0000000000 --- a/packages/fetch-extension/src/pages-unused/activity/gov-proposals/style.module.scss +++ /dev/null @@ -1,42 +0,0 @@ -.activityRow { - color: #808da0; - font-size: small; - display: flex; - align-items: center; - cursor: pointer; -} - -.activityRow:hover { - background: #f0f0f0; -} - -.container { - padding: 16px; - background-color: #ffffff; - margin: 0px -12px; -} - -.title { - display: flex; - justify-content: space-between; - font-weight: 700; - font-size: 20px; - padding-bottom: 16px; -} - -.activityCol { - font-size: small; - display: flex; - align-items: center; - margin: 3px; -} - -.govActivityHeading { - display: flex; - justify-content: space-around; -} -.govImage { - width: 16px; - height: 16px; - margin-right: 10px; -} diff --git a/packages/fetch-extension/src/pages-unused/activity/index.tsx b/packages/fetch-extension/src/pages-unused/activity/index.tsx deleted file mode 100644 index e5e1bc6919..0000000000 --- a/packages/fetch-extension/src/pages-unused/activity/index.tsx +++ /dev/null @@ -1,83 +0,0 @@ -import { HeaderLayout } from "@layouts/index"; -import { observer } from "mobx-react-lite"; -import React, { FunctionComponent, useState } from "react"; -import { FormattedMessage, useIntl } from "react-intl"; -import { useNavigate } from "react-router"; -import { GovProposalsTab } from "./gov-proposals"; -import { LatestBlock } from "./latest-block"; -import { NativeTab } from "./native"; -import style from "./style.module.scss"; -import { useStore } from "../../stores"; -import { NativeEthTab } from "./native-eth"; - -export const ActivityPage: FunctionComponent = observer(() => { - const navigate = useNavigate(); - const intl = useIntl(); - const [latestBlock, setLatestBlock] = useState(); - const { chainStore, analyticsStore } = useStore(); - const isEvm = chainStore.current.features?.includes("evm") ?? false; - const [activeTab, setActiveTab] = useState(isEvm ? "eth" : "native"); - - const handleTabClick = (tab: string) => { - setActiveTab(tab); - }; - - const tabs = () => { - return ( - -
{ - handleTabClick("native"); - analyticsStore.logEvent("activity_transaction_tab_click"); - }} - > - Transactions -
-
{ - handleTabClick("gov"); - analyticsStore.logEvent("activity_gov_proposals_tab_click"); - }} - > - Gov Proposals -
-
- ); - }; - - return ( - { - analyticsStore.logEvent("back_click", { pageName: "Activity" }); - navigate(-1); - }} - > -
-
- - {!isEvm && ( - - )} -
- {!isEvm &&
{tabs()}
} - {activeTab === "native" && } - {activeTab === "gov" && } - {activeTab === "eth" && } -
-
- ); -}); diff --git a/packages/fetch-extension/src/pages-unused/activity/latest-block.tsx b/packages/fetch-extension/src/pages-unused/activity/latest-block.tsx deleted file mode 100644 index 3a370373c6..0000000000 --- a/packages/fetch-extension/src/pages-unused/activity/latest-block.tsx +++ /dev/null @@ -1,30 +0,0 @@ -import React, { FunctionComponent, useEffect, useState } from "react"; -import { fetchLatestBlock } from "@graphQL/activity-api"; -import { useStore } from "../../stores"; -import style from "./style.module.scss"; - -export const LatestBlock: FunctionComponent<{ - latestBlock: any; - setLatestBlock: any; -}> = ({ latestBlock, setLatestBlock }) => { - const [blockIsLoading, setBlockIsLoading] = useState(true); - const { chainStore } = useStore(); - const current = chainStore.current; - - useEffect(() => { - const initialize = async () => { - setBlockIsLoading(true); - const block = await fetchLatestBlock(current.chainId); - if (latestBlock != block) setLatestBlock(block); - setBlockIsLoading(false); - }; - setInterval(() => initialize(), 5000); - }, [chainStore]); - - return ( -
- Latest Block: {latestBlock}{" "} - {blockIsLoading && } -
- ); -}; diff --git a/packages/fetch-extension/src/pages-unused/activity/native-eth/index.tsx b/packages/fetch-extension/src/pages-unused/activity/native-eth/index.tsx deleted file mode 100644 index fe12d19f3b..0000000000 --- a/packages/fetch-extension/src/pages-unused/activity/native-eth/index.tsx +++ /dev/null @@ -1,322 +0,0 @@ -import React, { FunctionComponent, useEffect, useRef, useState } from "react"; -import { useStore } from "../../../stores"; -import style from "./style.module.scss"; -import sendIcon from "@assets/icon/send-grey.png"; -import pendingIcon from "@assets/icon/awaiting.png"; -import success from "@assets/icon/success.png"; -import cancel from "@assets/icon/cancel.png"; -import prohibition from "@assets/icon/prohibition.png"; -import contractIcon from "@assets/icon/contract-grey.png"; -import { ITxn } from "@keplr-wallet/stores"; -import { Button, Modal, ModalBody } from "reactstrap"; -import { useNavigate } from "react-router"; -import { useIntl } from "react-intl"; -import { useNotification } from "@components/notification"; - -const TransactionItem: FunctionComponent<{ - transactionInfo: ITxn; - setCancelOpen: React.Dispatch>; - setSpeedUpOpen: React.Dispatch>; - queued?: boolean; -}> = ({ transactionInfo, setCancelOpen, setSpeedUpOpen, queued }) => { - const { chainStore } = useStore(); - const intl = useIntl(); - - const getStatusIcon = (status: string): string => { - switch (status) { - case "success": - return success; - case "pending": - return pendingIcon; - case "cancelled": - return prohibition; - case "failed": - return cancel; - default: - return cancel; - } - }; - - const getActivityIcon = (type: string | undefined): string => { - switch (type) { - case "Send": - return sendIcon; - case "ContractInteraction": - return contractIcon; - default: - return contractIcon; - } - }; - - const displaySpeedupCancelButtons = () => { - let showSpeedUp = false; - if (transactionInfo.lastSpeedUpAt) { - const currentTime = new Date().getTime(); - const lastSpeedUpTime = new Date(transactionInfo.lastSpeedUpAt).getTime(); - showSpeedUp = (currentTime - lastSpeedUpTime) / 1000 >= 10; - } - - return ( -
- {transactionInfo.cancelled && ( -
- {" "} - Cancellation in progress{" "} - {" "} -
- )} -
- {!transactionInfo.cancelled && ( -
- -
- )} - {showSpeedUp && ( -
- -
- )} -
-
- ); - }; - - const displayActivity = (status: string, amount: string | undefined) => { - return ( -
-
- {transactionInfo.type} -
-
- {transactionInfo.type} -
-
- {amount + " " + transactionInfo.symbol} -
-
- {status} -
-
- ); - }; - - return ( -
{ - e.preventDefault(); - if (chainStore.current.explorerUrl) { - window.open( - chainStore.current.explorerUrl + "/tx/" + transactionInfo.hash, - "_blank", - "noreferrer" - ); - } - }} - > - {displayActivity(transactionInfo.status, transactionInfo.amount)} - {queued &&
Queued
} - {transactionInfo.status === "pending" && - !queued && - displaySpeedupCancelButtons()} -
- ); -}; - -export const NativeEthTab = () => { - const { chainStore, accountStore } = useStore(); - const [hashList, setHashList] = useState([]); - const [cancelOpen, setCancelOpen] = useState(""); - const [speedUpOpen, setSpeedUpOpen] = useState(""); - const notification = useNotification(); - const navigate = useNavigate(); - const timer = useRef(); - const accountInfo = accountStore.getAccount(chainStore.current.chainId); - - const refreshTxList = async () => { - if (!window.location.href.includes("#/activity") && timer.current) { - clearInterval(timer.current); - return; - } - - let txList = await accountInfo.ethereum.getTxList(); - setHashList(txList); - - await Promise.all( - txList.map(async (txData, _) => { - if (txData.status === "pending") { - await accountInfo.ethereum.checkAndUpdateTransactionStatus( - txData.hash - ); - txList = await accountInfo.ethereum.getTxList(); - setHashList(txList); - } - }) - ); - }; - - useEffect(() => { - if (!accountInfo.ethereumHexAddress) { - return; - } - - refreshTxList(); - if (!timer.current) { - timer.current = setInterval(() => refreshTxList(), 5000); - } - }, [accountInfo.ethereumHexAddress, chainStore.current.chainId]); - - return ( - - { - setCancelOpen(""); - }} - > - -
- Cancelling the transaction by increasing the current gas price by - 15%. Note that this action is irreversible as the original - transaction will be replaced. -
- -
-
- { - setSpeedUpOpen(""); - }} - > - -
- Speeding up the transaction by increasing the current gas price by - 15%. -
- -
-
- {hashList.length > 0 ? ( -
- {hashList.map((transactionInfo, index) => ( - - ))} -
- ) : ( -

No activity

- )} -
- ); -}; diff --git a/packages/fetch-extension/src/pages-unused/activity/native-eth/style.module.scss b/packages/fetch-extension/src/pages-unused/activity/native-eth/style.module.scss deleted file mode 100644 index 8998e9e4df..0000000000 --- a/packages/fetch-extension/src/pages-unused/activity/native-eth/style.module.scss +++ /dev/null @@ -1,56 +0,0 @@ -.activityRow { - color: #808da0; - font-size: small; - display: flex; - align-items: center; - cursor: pointer; -} - -.activityContainer:hover { - background: #f0f0f0; -} - -.container { - padding: 16px; - background-color: #ffffff; - margin: 0px -12px; -} - -.title { - display: flex; - justify-content: space-between; - font-weight: 700; - font-size: 20px; - padding-bottom: 16px; -} - -.activityCol { - font-size: small; - display: flex; - align-items: center; - margin: 3px; - color: #808da0; -} - -.buttonRow { - color: #808da0; - font-size: small; - display: flex; - align-items: center; - cursor: pointer; - width: 50%; -} - -.buttonCol { - font-size: small; - display: flex; - align-items: center; - margin: 3px; - width: 50%; -} - -.activityContainer { - padding: 10px; - border-top: grey solid 0.5px; - cursor: pointer; -} diff --git a/packages/fetch-extension/src/pages-unused/activity/native/activity-row.tsx b/packages/fetch-extension/src/pages-unused/activity/native/activity-row.tsx deleted file mode 100644 index fa18190ceb..0000000000 --- a/packages/fetch-extension/src/pages-unused/activity/native/activity-row.tsx +++ /dev/null @@ -1,172 +0,0 @@ -import style from "./style.module.scss"; -import sendIcon from "@assets/icon/send-grey.png"; -import stakeIcon from "@assets/icon/stake-grey.png"; -import contractIcon from "@assets/icon/contract-grey.png"; -import claimIcon from "@assets/icon/claim-grey.png"; -import success from "@assets/icon/success.png"; -import cancel from "@assets/icon/cancel.png"; -import React from "react"; -import { formatActivityHash } from "@utils/format"; -import { AppCurrency } from "@keplr-wallet/types"; -import { useStore } from "../../../stores"; - -const getActivityIcon = (type: string): string => { - switch (type) { - case "/cosmos.bank.v1beta1.MsgSend": - return sendIcon; - case "/cosmos.staking.v1beta1.MsgDelegate": - case "/cosmos.staking.v1beta1.MsgUndelegate": - case "/cosmos.staking.v1beta1.MsgBeginRedelegate": - return stakeIcon; - case "contract": - return contractIcon; - case "/cosmos.distribution.v1beta1.MsgWithdrawDelegatorReward": - return claimIcon; - default: - return contractIcon; - } -}; - -const getHash = (node: any): any => { - const { typeUrl, json } = node.transaction.messages.nodes[0]; - - switch (typeUrl) { - case "/cosmos.bank.v1beta1.MsgSend": - case "/cosmwasm.wasm.v1.MsgExecuteContract": - case "/cosmos.authz.v1beta1.MsgRevoke": - case "/ibc.applications.transfer.v1.MsgTransfer": - case "/cosmos.staking.v1beta1.MsgBeginRedelegate": - return formatActivityHash(node.transaction.id) || null; - case "/cosmos.distribution.v1beta1.MsgWithdrawDelegatorReward": - return formatActivityHash(JSON.parse(json).validatorAddress) || null; - case "/cosmos.staking.v1beta1.MsgDelegate": - case "/cosmos.staking.v1beta1.MsgUndelegate": - return formatActivityHash(JSON.parse(json).validatorAddress) || null; - default: - return formatActivityHash(node.transaction.id); - } -}; - -const getStatusIcon = (status: string): string => { - switch (status) { - case "Success": - return success; - case "Error": - return cancel; - default: - return cancel; - } -}; - -export const shortenNumber = (value: string, decimal = 18) => { - const number = Math.abs(parseFloat(value)) / 10 ** decimal; - let result = ""; - if (number >= 1000000) { - result = (number / 1000000).toFixed(2) + " M"; - } else if (number >= 1000) { - result = (number / 1000).toFixed(2) + " K"; - } else if (number >= 1) { - result = number.toFixed(2) + " "; - } else if (number >= 10 ** -3) { - result = (number * 1000).toFixed(2) + " m"; - } else if (number >= 10 ** -6) { - result = (number * 10 ** 6).toFixed(2) + " u"; - } else if (number >= 10 ** -9) { - result = (number * 10 ** 9).toFixed(2) + " n"; - } else if (number >= 10 ** -12) { - result = (number * 10 ** 9).toFixed(3) + " n"; - } else if (number >= 10 ** -18) { - result = (number * 10 ** 18).toFixed(0) + " a"; - } else { - result = number.toFixed(2) + " "; - } - - return result; -}; - -export const ActivityRow = ({ node }: { node: any }) => { - const { chainStore } = useStore(); - - const getAmount = (denom: string, amount: string) => { - const amountCurrency = chainStore.current.currencies.find( - (currency: AppCurrency) => currency.coinMinimalDenom === denom - ); - if (amountCurrency) { - const amountValue = shortenNumber(amount, amountCurrency?.coinDecimals); - - return `${amountValue}${amountCurrency.coinDenom}`; - } else return `${amount} ${denom}`; - }; - - const getDetails = (node: any): any => { - const { nodes } = node.transaction.messages; - const { typeUrl, json } = nodes[0]; - const parsedJson = JSON.parse(json); - let currency = "afet"; - const isAmountDeducted = parseFloat(node.balanceOffset) < 0; - - if (parsedJson.amount) { - currency = Array.isArray(parsedJson.amount) - ? parsedJson.amount[0].denom - : parsedJson.amount.denom; - } else if (parsedJson.token) { - currency = parsedJson.token.denom; - } - - let verb = "Spent"; - - switch (typeUrl) { - case "/cosmos.staking.v1beta1.MsgBeginRedelegate": - verb = "Redelegated"; - break; - case "/cosmos.bank.v1beta1.MsgSend": - verb = isAmountDeducted ? "Send" : "Received"; - break; - case "/ibc.applications.transfer.v1.MsgTransfer": - verb = "IBC transfer"; - break; - case "/cosmos.staking.v1beta1.MsgDelegate": - case "/cosmos.staking.v1beta1.MsgUndelegate": - verb = isAmountDeducted ? "Staked" : "Unstaked"; - break; - case "/cosmos.distribution.v1beta1.MsgWithdrawDelegatorReward": - verb = "Claimed"; - break; - case "/cosmos.authz.v1beta1.MsgExec": - case "/cosmwasm.wasm.v1.MsgExecuteContract": - case "/cosmos.authz.v1beta1.MsgRevoke": - verb = isAmountDeducted ? "Transferred" : "Received"; - break; - default: - verb = isAmountDeducted ? "Transferred" : "Received"; - } - - return getAmount(currency, node.balanceOffset) + " " + verb; - }; - - const details = getDetails(node); - const hash = getHash(node); - const { typeUrl } = node.transaction.messages.nodes[0]; - return ( - -
-
- {typeUrl} -
-
- {hash} -
-
- {details} -
-
- {node.status} -
-
-
- ); -}; diff --git a/packages/fetch-extension/src/pages-unused/activity/native/index.tsx b/packages/fetch-extension/src/pages-unused/activity/native/index.tsx deleted file mode 100644 index f4b6667333..0000000000 --- a/packages/fetch-extension/src/pages-unused/activity/native/index.tsx +++ /dev/null @@ -1,161 +0,0 @@ -import { fetchTransactions } from "@graphQL/activity-api"; -import React, { useEffect, useState } from "react"; -import { Button } from "reactstrap"; -import { useStore } from "../../../stores"; -import { FilterActivities } from "../filter"; -import { ActivityRow } from "./activity-row"; -import style from "../style.module.scss"; - -const options = [ - { value: "/cosmos.bank.v1beta1.MsgSend", label: "Funds transfers" }, - { - value: "/cosmos.staking.v1beta1.MsgDelegate", - label: "Staked Funds", - }, - { - value: "/cosmos.staking.v1beta1.MsgUndelegate", - label: "Unstaked Funds", - }, - { - value: "/cosmos.staking.v1beta1.MsgBeginRedelegate", - label: "Redelegate Funds", - }, - { - value: - "/cosmos.authz.v1beta1.MsgExec,/cosmwasm.wasm.v1.MsgExecuteContract,/cosmos.authz.v1beta1.MsgRevoke", - label: "Contract Interactions", - }, - { - value: "/cosmos.distribution.v1beta1.MsgWithdrawDelegatorReward", - label: "Claim Rewards", - }, - { - value: "/ibc.applications.transfer.v1.MsgTransfer", - label: "IBC transfers", - }, -]; - -const processFilters = (filters: string[]) => { - let result: string[] = []; - filters.map((value) => { - result = result.concat(value.split(",")); - }); - return result; -}; - -function debounce(func: any, timeout = 500) { - let timer: any; - return (...args: any) => { - clearTimeout(timer); - timer = setTimeout(() => { - func(args); - }, timeout); - }; -} - -export const NativeTab = ({ latestBlock }: { latestBlock: any }) => { - const { chainStore, accountStore, analyticsStore } = useStore(); - const current = chainStore.current; - const accountInfo = accountStore.getAccount(current.chainId); - - const [isLoading, setIsLoading] = useState(true); - const [loadingRequest, setLoadingRequest] = useState(true); - const [fetchedData, setFetchedData] = useState(); - const [nodes, setNodes] = useState({}); - const [pageInfo, setPageInfo] = useState(); - const [filter, setFilter] = useState( - options.map((option) => option.value) - ); - - const fetchNodes = debounce(async (cursor: any) => { - setIsLoading(true); - const data = await fetchTransactions( - current.chainId, - cursor, - accountInfo.bech32Address, - processFilters(filter) - ); - setFetchedData(data?.nodes); - if (!pageInfo || cursor != "") setPageInfo(data.pageInfo); - }, 1000); - - useEffect(() => { - fetchNodes(""); - }, [filter, latestBlock]); - - useEffect(() => { - if (fetchedData) { - const nodeMap: any = {}; - fetchedData.map((node: any) => { - nodeMap[node.id] = node; - }); - setNodes({ ...nodes, ...nodeMap }); - setIsLoading(false); - setLoadingRequest(false); - } - }, [fetchedData]); - - const handleClick = () => { - analyticsStore.logEvent("activity_transactions_click", { - pageName: "Transaction Tab", - }); - setLoadingRequest(true); - fetchNodes(pageInfo.endCursor); - }; - - const handleFilterChange = (selectedFilter: string[]) => { - setPageInfo(undefined); - setNodes({}); - setFilter(selectedFilter); - analyticsStore.logEvent("activity_filter_click", { - pageName: "Transaction Tab", - }); - }; - - return ( - - - {Object.values(nodes).filter((node: any) => - processFilters(filter).includes( - node.transaction.messages.nodes[0].typeUrl - ) - ).length > 0 ? ( - - {Object.values(nodes) - .filter((node: any) => - processFilters(filter).includes( - node.transaction.messages.nodes[0].typeUrl - ) - ) - .map((node, index) => ( - - ))} - {pageInfo?.hasNextPage && ( - - )} - - ) : isLoading && filter.length > 0 ? ( -
Loading Activities...
- ) : ( -
- No activity available right now -
- )} -
- ); -}; diff --git a/packages/fetch-extension/src/pages-unused/activity/native/style.module.scss b/packages/fetch-extension/src/pages-unused/activity/native/style.module.scss deleted file mode 100644 index 1316bfde72..0000000000 --- a/packages/fetch-extension/src/pages-unused/activity/native/style.module.scss +++ /dev/null @@ -1,32 +0,0 @@ -.activityRow { - color: #808da0; - font-size: small; - display: flex; - align-items: center; - cursor: pointer; -} - -.activityRow:hover { - background: #f0f0f0; -} - -.container { - padding: 16px; - background-color: #ffffff; - margin: 0px -12px; -} - -.title { - display: flex; - justify-content: space-between; - font-weight: 700; - font-size: 20px; - padding-bottom: 16px; -} - -.activityCol { - font-size: small; - display: flex; - align-items: center; - margin: 3px; -} diff --git a/packages/fetch-extension/src/pages-unused/activity/style.module.scss b/packages/fetch-extension/src/pages-unused/activity/style.module.scss deleted file mode 100644 index cefc36b8c4..0000000000 --- a/packages/fetch-extension/src/pages-unused/activity/style.module.scss +++ /dev/null @@ -1,56 +0,0 @@ -.block { - font-weight: bold; - display: flex; - color: black; - align-items: center; - font-size: 15px; -} - -.container { - padding: 16px; - background-color: #ffffff; - margin: 0px -12px; -} - -.title { - display: flex; - justify-content: space-between; - font-weight: 700; - font-size: 20px; - padding-bottom: 16px; -} - -.tabContainer { - display: flex; - flex-direction: row; - margin-bottom: 10px; -} - -.tab { - padding-top: 8px; - width: 50%; - text-align: center; - cursor: pointer; - border-bottom: 2px solid transparent; - padding-bottom: 8px; - font-weight: 500; - font-size: 16px; - color: #000000; -} - -.tab.active { - border-bottom: 2px solid #d43bf6; - color: #d43bf6; -} - -.activityMessage { - color: #808da0; - font-size: small; - text-align: center; - height: 50%; - width: 85%; - display: flex; - position: fixed; - align-items: center; - justify-content: center; -} diff --git a/packages/fetch-extension/src/pages-unused/more/index.tsx b/packages/fetch-extension/src/pages-unused/more/index.tsx deleted file mode 100644 index 2c269039fd..0000000000 --- a/packages/fetch-extension/src/pages-unused/more/index.tsx +++ /dev/null @@ -1,62 +0,0 @@ -import { FNSView } from "@components/fns-view"; -import { ProposalView } from "@components/proposal/proposal-view"; -import { SwitchUser } from "@components/switch-user"; -import { HeaderLayout } from "@layouts/index"; -import classnames from "classnames"; -import React, { FunctionComponent } from "react"; -import { Card, CardBody } from "reactstrap"; -import { FNS_CONFIG } from "../../config.ui.var"; -import { useStore } from "../../stores"; -import { IBCTransferView } from "../../pages/main/ibc-transfer"; -import { Menu } from "../../pages/main/menu"; -import style from "./style.module.scss"; -import { CHAINS } from "../../config.axl-brdige.var"; -import { AXLView } from "@components/axl-view"; - -export const MorePage: FunctionComponent = () => { - const { chainStore } = useStore(); - const AxlBrdigeDisabledChainIds = ["axelar-testnet-lisbon-3"]; - const isAxlViewVisible = CHAINS.some((chain) => { - return chain.chainId?.toString() === chainStore.current.chainId; - }); - - return ( - } - rightRenderer={} - > - - - - - - - {chainStore.current.govUrl && ( - - - - - - )} - - {Object.keys(FNS_CONFIG).includes(chainStore.current.chainId) && ( - - - - - - )} - - {isAxlViewVisible && - !AxlBrdigeDisabledChainIds.includes(chainStore.current.chainId) && ( - - - - - - )} - - ); -}; diff --git a/packages/fetch-extension/src/pages-unused/more/style.module.scss b/packages/fetch-extension/src/pages-unused/more/style.module.scss deleted file mode 100644 index c2a76fe500..0000000000 --- a/packages/fetch-extension/src/pages-unused/more/style.module.scss +++ /dev/null @@ -1,42 +0,0 @@ -@import "../../styles/var"; - -.right { - height: $header-height; - padding-right: $layout-padding; - - display: flex; - flex-direction: column; - - .signOut { - font-size: 20px; - padding: 0 8px; - - i { - cursor: pointer; - color: #8f8f8f; - - &:hover { - color: black; - } - } - } -} - -.containerAccountInner { - display: flex; - flex-direction: column; - width: 100%; - // height: 360px - 2 * $main-card-padding; -} - -.card { - margin-bottom: $layout-margin; - - &:last-of-type { - margin-bottom: 0; - } - - :global(.card-body) { - padding: $main-card-padding; - } -} diff --git a/packages/fetch-extension/src/pages-unused/settings/autolock/description-view.module.scss b/packages/fetch-extension/src/pages-unused/settings/autolock/description-view.module.scss deleted file mode 100644 index 813db64230..0000000000 --- a/packages/fetch-extension/src/pages-unused/settings/autolock/description-view.module.scss +++ /dev/null @@ -1,34 +0,0 @@ -.innerContainer { - flex: 1; - - display: flex; - flex-direction: column; - justify-content: center; - align-items: center; - - .imgLock { - height: 96px; - } - - p { - margin-top: 24px; - margin-left: 10px; - margin-right: 10px; - - font-size: 16px; - letter-spacing: -0.6px; - color: #32325d; - - text-align: center; - } - - b { - width: 100%; - - margin-bottom: 24px; - - font-size: 14px; - letter-spacing: -0.3px; - color: #32325d; - } -} diff --git a/packages/fetch-extension/src/pages-unused/settings/autolock/description-view.tsx b/packages/fetch-extension/src/pages-unused/settings/autolock/description-view.tsx deleted file mode 100644 index 35bcc8c186..0000000000 --- a/packages/fetch-extension/src/pages-unused/settings/autolock/description-view.tsx +++ /dev/null @@ -1,39 +0,0 @@ -import React, { FunctionComponent } from "react"; - -import styleDescriptionView from "./description-view.module.scss"; -import { FormattedMessage } from "react-intl"; -import { observer } from "mobx-react-lite"; -import { useStore } from "../../../stores"; - -export const DescriptionView: FunctionComponent = observer(() => { - const { uiConfigStore } = useStore(); - - return ( -
- lock - - {/* On firefox, idle api can't detect that device go sleep */} - {uiConfigStore.platform !== "firefox" ? ( -

- -

- ) : null} - - {/*

- -

- - , - }} - /> - */} -
- ); -}); diff --git a/packages/fetch-extension/src/pages-unused/settings/autolock/index.tsx b/packages/fetch-extension/src/pages-unused/settings/autolock/index.tsx deleted file mode 100644 index e80b01e059..0000000000 --- a/packages/fetch-extension/src/pages-unused/settings/autolock/index.tsx +++ /dev/null @@ -1,124 +0,0 @@ -import React, { FunctionComponent, useEffect, useState } from "react"; -import { HeaderLayout } from "../../../layouts"; - -import { useNavigate } from "react-router"; -import { Button, Form } from "reactstrap"; -import { DescriptionView } from "./description-view"; - -import { Input } from "@components/form"; -import style from "./style.module.scss"; -import { useForm } from "react-hook-form"; -import { FormattedMessage, useIntl } from "react-intl"; - -import { - GetAutoLockAccountDurationMsg, - UpdateAutoLockAccountDurationMsg, -} from "@keplr-wallet/background/src/auto-lock-account"; - -import { InExtensionMessageRequester } from "@keplr-wallet/router-extension"; -import { BACKGROUND_PORT } from "@keplr-wallet/router"; -import { useStore } from "../../../stores"; - -interface FormData { - duration: string; -} - -export const SettingAutoLockPage: FunctionComponent = () => { - const navigate = useNavigate(); - const intl = useIntl(); - const { analyticsStore } = useStore(); - - const minDuration = 0; - const maxDuration = 4320; - - const { - setValue, - register, - handleSubmit, - formState: { errors }, - } = useForm({ - defaultValues: { - duration: "0", - }, - }); - - useEffect(() => { - const msg = new GetAutoLockAccountDurationMsg(); - new InExtensionMessageRequester() - .sendMessage(BACKGROUND_PORT, msg) - .then(function (duration) { - setValue("duration", (duration / 60000).toString()); - }); - }, [setValue]); - - function updateAutoLockDuration(input: string) { - let duration = parseInt(input); - if (duration >= 0) { - duration = duration * 60000; - const msg = new UpdateAutoLockAccountDurationMsg(duration); - new InExtensionMessageRequester().sendMessage(BACKGROUND_PORT, msg); - } - navigate(-1); - } - - const [isLoading, setIsLoading] = useState(false); - - return ( - { - analyticsStore.logEvent("back_click", { - pageName: "Autolock Timer", - }); - - navigate(-1); - }} - > -
- -
{ - setIsLoading(true); - updateAutoLockDuration(data.duration); - })} - > - { - const duration = parseInt(input); - - if (Number.isNaN(duration)) { - return "NaN"; - } - - if (duration < minDuration || duration > maxDuration) { - return intl.formatMessage({ - id: "setting.autolock.error.out-of-range", - }); - } - }, - })} - type="number" - pattern="[0-9]*" - error={errors.duration && errors.duration.message} - /> - -
-
-
- ); -}; diff --git a/packages/fetch-extension/src/pages-unused/settings/autolock/style.module.scss b/packages/fetch-extension/src/pages-unused/settings/autolock/style.module.scss deleted file mode 100644 index ba64c9f66f..0000000000 --- a/packages/fetch-extension/src/pages-unused/settings/autolock/style.module.scss +++ /dev/null @@ -1,6 +0,0 @@ -.container { - display: flex; - flex-direction: column; - - height: 100%; -} diff --git a/packages/fetch-extension/src/pages-unused/settings/fiat/index.tsx b/packages/fetch-extension/src/pages-unused/settings/fiat/index.tsx deleted file mode 100644 index 2b7303733d..0000000000 --- a/packages/fetch-extension/src/pages-unused/settings/fiat/index.tsx +++ /dev/null @@ -1,80 +0,0 @@ -import React, { FunctionComponent, useMemo } from "react"; -import { HeaderLayout } from "@layouts/index"; -import { PageButton } from "../../../pages/setting/page-button"; - -import style from "../style.module.scss"; -import { useNavigate } from "react-router"; -import { useIntl } from "react-intl"; -import { observer } from "mobx-react-lite"; -import { useStore } from "../../../stores"; -import { useLanguage } from "../../../languages"; - -export const SettingFiatPage: FunctionComponent = observer(() => { - const navigate = useNavigate(); - const intl = useIntl(); - - const language = useLanguage(); - - const { priceStore, analyticsStore } = useStore(); - - const selectedIcon = useMemo( - () => [], - [] - ); - - return ( - { - analyticsStore.logEvent("back_click", { pageName: "Currency" }); - navigate(-1); - }} - > -
- { - language.setFiatCurrency(null); - navigate({ - pathname: "/", - }); - }} - icons={language.isFiatCurrencyAutomatic ? selectedIcon : undefined} - /> - {Object.keys(priceStore.supportedVsCurrencies).map((currency) => { - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - const fiatCurrency = priceStore.supportedVsCurrencies[currency]!; - - return ( - { - language.setFiatCurrency(fiatCurrency.currency); - navigate({ - pathname: "/", - }); - }} - icons={ - !language.isFiatCurrencyAutomatic - ? language.fiatCurrency === fiatCurrency.currency - ? selectedIcon - : undefined - : undefined - } - /> - ); - })} -
-
- ); -}); diff --git a/packages/fetch-extension/src/pages-unused/settings/language/index.tsx b/packages/fetch-extension/src/pages-unused/settings/language/index.tsx deleted file mode 100644 index 6e1289b803..0000000000 --- a/packages/fetch-extension/src/pages-unused/settings/language/index.tsx +++ /dev/null @@ -1,75 +0,0 @@ -import React, { FunctionComponent, useCallback, useMemo } from "react"; -import { HeaderLayout } from "@layouts/index"; -import { PageButton } from "../../../pages/setting/page-button"; - -import style from "../style.module.scss"; -import { useLanguage } from "../../../languages"; -import { useNavigate } from "react-router"; -import { useIntl } from "react-intl"; -import { useStore } from "../../../stores"; -export const SettingLanguagePage: FunctionComponent = () => { - const language = useLanguage(); - const navigate = useNavigate(); - const intl = useIntl(); - const { analyticsStore } = useStore(); - const selectedIcon = useMemo( - () => [], - [] - ); - - return ( - { - navigate(-1); - analyticsStore.logEvent("back_click", { pageName: "Language" }); - }, [navigate])} - > -
- { - language.clearLanguage(); - navigate("/"); - }, [navigate, language])} - icons={language.automatic ? selectedIcon : undefined} - /> - { - language.setLanguage("en"); - navigate("/"); - }, [navigate, language])} - icons={ - !language.automatic && language.language == "en" - ? selectedIcon - : undefined - } - /> - { - language.setLanguage("ko"); - navigate("/"); - }, [navigate, language])} - icons={ - !language.automatic && language.language == "ko" - ? selectedIcon - : undefined - } - /> -
-
- ); -}; diff --git a/packages/fetch-extension/src/pages-unused/settings/notification/index.tsx b/packages/fetch-extension/src/pages-unused/settings/notification/index.tsx deleted file mode 100644 index eade33dcaa..0000000000 --- a/packages/fetch-extension/src/pages-unused/settings/notification/index.tsx +++ /dev/null @@ -1,114 +0,0 @@ -import { HeaderLayout } from "@layouts/header-layout"; -import React, { FunctionComponent, useMemo } from "react"; -import { useNavigate } from "react-router"; -import style from "./style.module.scss"; -import { NotificationOption } from "@components/notification-option/notification-option"; -import { PageButton } from "../../../pages/setting/page-button"; -import { NotificationSetup } from "@notificationTypes"; -import { useStore } from "../../../stores"; - -export const SettingNotifications: FunctionComponent = () => { - const navigate = useNavigate(); - const { chainStore, accountStore, analyticsStore, chatStore } = useStore(); - const current = chainStore.current; - const accountInfo = accountStore.getAccount(current.chainId); - - const notificationInfo: NotificationSetup = - chatStore.userDetailsStore.notifications; - - const topicInfo = JSON.parse( - localStorage.getItem(`topics-${accountInfo.bech32Address}`) || - JSON.stringify([]) - ); - - const topicSuffix = topicInfo.length > 1 ? "s" : ""; - const orgInfo = Object.values(notificationInfo.organisations); - const orgSuffix = orgInfo.length > 1 ? "s" : ""; - - const handleOnChange = () => { - analyticsStore.logEvent( - notificationInfo.isNotificationOn - ? "notification_off_click" - : "notification_on_click" - ); - - localStorage.setItem( - `turnNotifications-${accountInfo.bech32Address}`, - notificationInfo.isNotificationOn ? "false" : "true" - ); - - /// Updating the notification status - chatStore.userDetailsStore.setNotifications({ - isNotificationOn: !notificationInfo.isNotificationOn, - }); - }; - - const icon = useMemo( - () => [], - [] - ); - return ( - { - analyticsStore.logEvent("back_click", { - pageName: "Notifications", - }); - navigate(-1); - }} - > -
-
- - {!notificationInfo.isNotificationOn && ( -

- You are not receiving notifications -

- )} -
- - {Object.values(notificationInfo.organisations).length !== 0 && - notificationInfo.isNotificationOn ? ( - - { - analyticsStore.logEvent("organisations_click", { - action: "Edit", - }); - navigate("/notification/organisations/edit"); - }} - /> - - { - analyticsStore.logEvent("topics_click", { - action: "Edit", - }); - navigate("/notification/topics/edit", { - state: { - isUpdating: true, - }, - }); - }} - /> - - ) : ( - - )} -
-
- ); -}; diff --git a/packages/fetch-extension/src/pages-unused/settings/notification/style.module.scss b/packages/fetch-extension/src/pages-unused/settings/notification/style.module.scss deleted file mode 100644 index 55814ac3bd..0000000000 --- a/packages/fetch-extension/src/pages-unused/settings/notification/style.module.scss +++ /dev/null @@ -1,37 +0,0 @@ -@import "../../../styles/var"; - -.notificationSettingContainer { - margin: 0 calc(#{$layout-padding} * -1) calc(#{$layout-padding} * -1); - - display: flex; - flex-direction: column; - height: 100%; - - .notificationOptionMainContainer { - border-bottom: 1px solid #e9ecef; - - .notificationOptionContainer { - padding: 16px; - - .notificationOption { - font-family: "Inter", serif; - font-style: normal; - font-weight: 500; - font-size: 16px; - line-height: 16px; - color: #525f7f; - display: inline; - margin-left: 8px; - } - } - - .notificationOffMsg { - font-style: normal; - font-weight: 400; - font-size: 16px; - line-height: 16px; - margin: 0 16px 8px; - color: #808da0; - } - } -} diff --git a/packages/fetch-extension/src/pages-unused/settings/security-privacy/index.tsx b/packages/fetch-extension/src/pages-unused/settings/security-privacy/index.tsx deleted file mode 100644 index 9c2b9fbe80..0000000000 --- a/packages/fetch-extension/src/pages-unused/settings/security-privacy/index.tsx +++ /dev/null @@ -1,84 +0,0 @@ -import React, { FunctionComponent, useMemo } from "react"; -import { HeaderLayout } from "../../../layouts"; -import style from "../style.module.scss"; -import { PageButton } from "../../../pages/setting/page-button"; -import { useNavigate } from "react-router"; -import { useIntl } from "react-intl"; -import { useStore } from "../../../stores"; - -export const SettingSecurityPrivacyPage: FunctionComponent = () => { - const navigate = useNavigate(); - const { analyticsStore } = useStore(); - - const intl = useIntl(); - - return ( - { - analyticsStore.logEvent("back_click", { - pageName: "Security & Privacy", - }); - navigate(-1); - }} - > -
- { - navigate("/setting/connections"); - analyticsStore.logEvent("wallet_access_permissions_click", { - pageName: "Security & Privacy", - }); - }} - icons={useMemo( - () => [], - [] - )} - /> - { - navigate("/more/permissions/get-chain-infos"); - analyticsStore.logEvent("chain_list_access_click", { - pageName: "Security & Privacy", - }); - }} - icons={useMemo( - () => [], - [] - )} - /> - { - navigate("/more/security-privacy/autolock"); - analyticsStore.logEvent("auto_lock_timer_click", { - pageName: "Security & Privacy", - }); - }} - icons={useMemo( - () => [], - [] - )} - /> -
-
- ); -}; diff --git a/packages/fetch-extension/src/pages-unused/settings/security-privacy/permissions/get-chain-infos/index.tsx b/packages/fetch-extension/src/pages-unused/settings/security-privacy/permissions/get-chain-infos/index.tsx deleted file mode 100644 index efdbf8d968..0000000000 --- a/packages/fetch-extension/src/pages-unused/settings/security-privacy/permissions/get-chain-infos/index.tsx +++ /dev/null @@ -1,107 +0,0 @@ -import React, { FunctionComponent, useEffect, useMemo, useState } from "react"; -import { HeaderLayout } from "../../../../../layouts"; -import style from "../../../style.module.scss"; -import { PageButton } from "../../../../../pages/setting/page-button"; -import { useIntl } from "react-intl"; -import { useNavigate } from "react-router"; -import { useConfirm } from "@components/confirm"; -import { InExtensionMessageRequester } from "@keplr-wallet/router-extension"; -import { - GetGlobalPermissionOriginsMsg, - RemoveGlobalPermissionOriginMsg, -} from "@keplr-wallet/background"; -import { BACKGROUND_PORT } from "@keplr-wallet/router"; -import { useStore } from "../../../../../stores"; - -export const SettingPermissionsGetChainInfosPage: FunctionComponent = () => { - const [requester] = useState(() => new InExtensionMessageRequester()); - const [origins, setOrigins] = useState([]); - const { analyticsStore, chainStore } = useStore(); - useEffect(() => { - // TODO: Handle this in store (GeneralPermissionStore?) - requester - .sendMessage( - BACKGROUND_PORT, - new GetGlobalPermissionOriginsMsg("get-chain-infos") - ) - .then((r) => setOrigins(r)); - }, [requester]); - - const navigate = useNavigate(); - const intl = useIntl(); - - const confirm = useConfirm(); - - const xIcon = useMemo( - () => [], - [] - ); - - return ( - { - analyticsStore.logEvent("back_click", { - pageName: "Chain List Access ", - }); - navigate(-1); - }} - > -
- {origins.map((origin) => { - return ( - { - e.preventDefault(); - analyticsStore.logEvent("show_hide_chain", { - chainId: chainStore.current.chainId, - chainName: chainStore.current.chainName, - }); - - if ( - await confirm.confirm({ - img: ( - unlink - ), - title: intl.formatMessage({ - id: "setting.connections.confirm.delete-connection.title", - }), - paragraph: intl.formatMessage({ - id: "setting.connections.confirm.delete-connection.paragraph", - }), - }) - ) { - await requester.sendMessage( - BACKGROUND_PORT, - new RemoveGlobalPermissionOriginMsg( - "get-chain-infos", - origin - ) - ); - - const origins = await requester.sendMessage( - BACKGROUND_PORT, - new GetGlobalPermissionOriginsMsg("get-chain-infos") - ); - setOrigins(origins); - } - }} - icons={xIcon} - /> - ); - })} -
-
- ); -}; diff --git a/packages/fetch-extension/src/pages-unused/settings/token/add/index.tsx b/packages/fetch-extension/src/pages-unused/settings/token/add/index.tsx deleted file mode 100644 index f3b838ab9c..0000000000 --- a/packages/fetch-extension/src/pages-unused/settings/token/add/index.tsx +++ /dev/null @@ -1,380 +0,0 @@ -import React, { FunctionComponent, useEffect, useState } from "react"; -import { HeaderLayout } from "@layouts/index"; -import { useLocation, useNavigate } from "react-router"; -import { useIntl, FormattedMessage } from "react-intl"; - -import style from "./style.module.scss"; -import { Button, Form } from "reactstrap"; -import { Input } from "@components/form"; -import { observer } from "mobx-react-lite"; -import { useStore } from "../../../../stores"; -import { useForm } from "react-hook-form"; -import { Bech32Address } from "@keplr-wallet/cosmos"; -import { - CW20Currency, - Erc20Currency, - Secret20Currency, -} from "@keplr-wallet/types"; -import { useInteractionInfo } from "@keplr-wallet/hooks"; -import { useLoadingIndicator } from "@components/loading-indicator"; -import { useNotification } from "@components/notification"; -import { isAddress } from "@ethersproject/address"; -import { TXNTYPE } from "../../../../config"; - -interface FormData { - contractAddress: string; - // For the secret20 - viewingKey: string; -} - -export const AddTokenPage: FunctionComponent = observer(() => { - const intl = useIntl(); - const navigate = useNavigate(); - const location = useLocation(); - - const { - chainStore, - queriesStore, - accountStore, - tokensStore, - analyticsStore, - } = useStore(); - const tokensOf = tokensStore.getTokensOf(chainStore.current.chainId); - - const accountInfo = accountStore.getAccount(chainStore.current.chainId); - - const interactionInfo = useInteractionInfo(() => { - // When creating the secret20 viewing key, this page will be moved to "/sign" page to generate the signature. - // So, if it is creating phase, don't reject the waiting datas. - if (accountInfo.txTypeInProgress !== TXNTYPE.createSecret20ViewingKey) { - tokensStore.rejectAllSuggestedTokens(); - } - }); - - const form = useForm({ - defaultValues: { - contractAddress: "", - viewingKey: "", - }, - }); - - const contractAddress = form.watch("contractAddress"); - - useEffect(() => { - if (tokensStore.waitingSuggestedToken) { - chainStore.selectChain(tokensStore.waitingSuggestedToken.data.chainId); - if ( - contractAddress !== - tokensStore.waitingSuggestedToken.data.contractAddress - ) { - form.setValue( - "contractAddress", - tokensStore.waitingSuggestedToken.data.contractAddress - ); - } - } - }, [chainStore, contractAddress, form, tokensStore.waitingSuggestedToken]); - - const isSecret20 = - (chainStore.current.features ?? []).find( - (feature) => feature === "secretwasm" - ) != null; - - const queries = queriesStore.get(chainStore.current.chainId); - - const isEvm = chainStore.current.features?.includes("evm") ?? false; - const query = isEvm - ? queries.evm.queryErc20Metadata - : isSecret20 - ? queries.secret.querySecret20ContractInfo - : queries.cosmwasm.querycw20ContractInfo; - const queryContractInfo = query.getQueryContract(contractAddress); - - const tokenInfo = queryContractInfo.tokenInfo; - const [isOpenSecret20ViewingKey, setIsOpenSecret20ViewingKey] = - useState(false); - - const notification = useNotification(); - const loadingIndicator = useLoadingIndicator(); - - const createViewingKey = async (): Promise => { - return new Promise((resolve, reject) => { - accountInfo.secret - .createSecret20ViewingKey( - contractAddress, - "", - {}, - {}, - (_, viewingKey) => { - loadingIndicator.setIsLoading("create-veiwing-key", false); - - resolve(viewingKey); - } - ) - .then(() => { - loadingIndicator.setIsLoading("create-veiwing-key", true); - }) - .catch(reject); - }); - }; - - const currencyAlreadyAdded = chainStore.current.currencies.find( - (currency) => { - return ( - "contractAddress" in currency && - currency.contractAddress.toLowerCase() === contractAddress.toLowerCase() - ); - } - ) - ? "Currency already added" - : undefined; - - const queryError = - contractAddress.length && - (form.formState.errors.contractAddress - ? form.formState.errors.contractAddress.message - : tokenInfo == null - ? (queryContractInfo.error?.data as any)?.error || - queryContractInfo.error?.message - : undefined) - ? "Invalid address" - : undefined; - - const isError = currencyAlreadyAdded || queryError; - - return ( - { - analyticsStore.logEvent("back_click", { pageName: "Add Token" }); - navigate(-1); - } - } - > -
{ - analyticsStore.logEvent("add_token_submit_click"); - if ( - tokenInfo?.decimals != null && - tokenInfo.name && - tokenInfo.symbol - ) { - if (!isSecret20) { - const currency: CW20Currency | Erc20Currency = { - type: isEvm ? "erc20" : "cw20", - contractAddress: data.contractAddress, - coinMinimalDenom: tokenInfo.name, - coinDenom: tokenInfo.symbol, - coinDecimals: tokenInfo.decimals, - }; - - if ( - interactionInfo.interaction && - tokensStore.waitingSuggestedToken - ) { - await tokensStore.approveSuggestedToken(currency); - } else { - await tokensOf.addToken(currency); - } - } else { - let viewingKey = data.viewingKey; - if (!viewingKey && !isOpenSecret20ViewingKey) { - try { - viewingKey = await createViewingKey(); - } catch (e) { - notification.push({ - placement: "top-center", - type: "danger", - duration: 2, - content: `Failed to create the viewing key: ${e.message}`, - canDelete: true, - transition: { - duration: 0.25, - }, - }); - - if ( - interactionInfo.interaction && - tokensStore.waitingSuggestedToken - ) { - await tokensStore.rejectAllSuggestedTokens(); - } - - if ( - interactionInfo.interaction && - !interactionInfo.interactionInternal - ) { - window.close(); - } else { - if (location.hash === "#agent") navigate(-1); - navigate("/"); - } - - return; - } - } - - if (!viewingKey) { - notification.push({ - placement: "top-center", - type: "danger", - duration: 2, - content: "Failed to create the viewing key", - canDelete: true, - transition: { - duration: 0.25, - }, - }); - } else { - const currency: Secret20Currency = { - type: "secret20", - contractAddress: data.contractAddress, - viewingKey, - coinMinimalDenom: tokenInfo.name, - coinDenom: tokenInfo.symbol, - coinDecimals: tokenInfo.decimals, - }; - - if ( - interactionInfo.interaction && - tokensStore.waitingSuggestedToken - ) { - await tokensStore.approveSuggestedToken(currency); - } else { - await tokensOf.addToken(currency); - } - } - } - - if ( - interactionInfo.interaction && - !interactionInfo.interactionInternal - ) { - window.close(); - } else { - if (location.hash === "#agent") navigate(-1); - navigate("/"); - } - } - })} - > - { - try { - if (isEvm) { - return isAddress(value) ? undefined : "Invalid Address"; - } - - Bech32Address.validate( - value, - chainStore.current.bech32Config.bech32PrefixAccAddr - ); - } catch { - return "Invalid address"; - } - }, - })} - error={isError} - text={ - queryContractInfo.isFetching && contractAddress.length ? ( - - ) : undefined - } - /> - - - - {isSecret20 && isOpenSecret20ViewingKey ? ( - - ) : null} -
- {isSecret20 ? ( -
- { - setIsOpenSecret20ViewingKey((value) => !value); - }} - /> - -
- ) : null} - - - - ); -}); diff --git a/packages/fetch-extension/src/pages-unused/settings/token/add/style.module.scss b/packages/fetch-extension/src/pages-unused/settings/token/add/style.module.scss deleted file mode 100644 index 70791eec99..0000000000 --- a/packages/fetch-extension/src/pages-unused/settings/token/add/style.module.scss +++ /dev/null @@ -1,18 +0,0 @@ -@import "../../../../styles/var"; - -.container { - display: flex; - flex-direction: column; - height: 100%; - - input:read-only { - box-shadow: none !important; - background: transparent; - padding: 0; - height: 20px; - } -} - -.formGroup { - margin-bottom: 2.5rem; -} diff --git a/packages/fetch-extension/src/pages-unused/settings/token/manage/index.tsx b/packages/fetch-extension/src/pages-unused/settings/token/manage/index.tsx deleted file mode 100644 index 19e9f224ae..0000000000 --- a/packages/fetch-extension/src/pages-unused/settings/token/manage/index.tsx +++ /dev/null @@ -1,211 +0,0 @@ -import React, { FunctionComponent } from "react"; -import { HeaderLayout } from "@layouts/index"; -import { useNavigate } from "react-router"; -import { PageButton } from "../../../../pages/setting/page-button"; - -import style from "./style.module.scss"; -import { observer } from "mobx-react-lite"; -import { useStore } from "../../../../stores"; -import { Bech32Address } from "@keplr-wallet/cosmos"; -import { useNotification } from "@components/notification"; -import { useConfirm } from "@components/confirm"; -import { - CW20Currency, - Erc20Currency, - Secret20Currency, -} from "@keplr-wallet/types"; -import { useIntl } from "react-intl"; -import { ToolTip } from "@components/tooltip"; - -export const ManageTokenPage: FunctionComponent = observer(() => { - const navigate = useNavigate(); - const intl = useIntl(); - const notification = useNotification(); - const confirm = useConfirm(); - - const { chainStore, tokensStore, analyticsStore } = useStore(); - - const isSecretWasm = - chainStore.current.features && - chainStore.current.features.includes("secretwasm"); - - const appCurrencies = chainStore.current.currencies.filter((currency) => { - if (isSecretWasm) { - return "type" in currency && currency.type === "secret20"; - } else { - return "type" in currency && ["cw20", "erc20"].includes(currency.type); - } - }); - - const copyText = async (text: string, messageId: string) => { - await navigator.clipboard.writeText(text); - - // TODO: Show success tooltip. - notification.push({ - placement: "top-center", - type: "success", - duration: 2, - content: intl.formatMessage({ - id: messageId, - }), - canDelete: true, - transition: { - duration: 0.25, - }, - }); - }; - - return ( - { - analyticsStore.logEvent("back_click", { pageName: "Token List" }); - navigate(-1); - }} - > -
- {appCurrencies.map((currency) => { - const cosmwasmToken = currency as - | CW20Currency - | Secret20Currency - | Erc20Currency; - - const icons: React.ReactElement[] = []; - - icons.push( - - {intl.formatMessage({ - id: "setting.token.manage.notification.contract-address.copy.hover", - })} -
- } - > - { - e.preventDefault(); - - await copyText( - cosmwasmToken.contractAddress, - "setting.token.manage.notification.contract-address.copy" - ); - }} - /> - - ); - - if ("viewingKey" in cosmwasmToken) { - icons.push( - - {intl.formatMessage({ - id: "setting.token.manage.notification.viewing-key.copy.hover", - })} -
- } - > - { - e.preventDefault(); - - await copyText( - cosmwasmToken.viewingKey, - "setting.token.manage.notification.viewing-key.copy" - ); - }} - /> - - ); - } - - /* - icons.push( - { - e.preventDefault(); - - history.push( - `/setting/connections/viewing-key/${currency.contractAddress}` - ); - }} - /> - ); - */ - - cosmwasmToken.coinDenom !== "FET" && - icons.push( - { - e.preventDefault(); - - if ( - await confirm.confirm({ - paragraph: intl.formatMessage({ - id: "setting.token.manage.confirm.remove-token", - }), - }) - ) { - await tokensStore - .getTokensOf(chainStore.current.chainId) - .removeToken(cosmwasmToken); - } - }} - /> - ); - - return ( - - ); - })} -
- - ); -}); diff --git a/packages/fetch-extension/src/pages-unused/settings/token/manage/style.module.scss b/packages/fetch-extension/src/pages-unused/settings/token/manage/style.module.scss deleted file mode 100644 index 7d98b81e49..0000000000 --- a/packages/fetch-extension/src/pages-unused/settings/token/manage/style.module.scss +++ /dev/null @@ -1,9 +0,0 @@ -@import "../../../../styles/var"; - -.container { - margin: 0 calc(#{$layout-padding} * -1) calc(#{$layout-padding} * -1); - - display: flex; - flex-direction: column; - height: 100%; -} diff --git a/packages/fetch-extension/src/pages-unused/token/add/index.tsx b/packages/fetch-extension/src/pages-unused/token/add/index.tsx deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/packages/fetch-extension/src/pages-unused/token/add/style.module.scss b/packages/fetch-extension/src/pages-unused/token/add/style.module.scss deleted file mode 100644 index 70791eec99..0000000000 --- a/packages/fetch-extension/src/pages-unused/token/add/style.module.scss +++ /dev/null @@ -1,18 +0,0 @@ -@import "../../../../styles/var"; - -.container { - display: flex; - flex-direction: column; - height: 100%; - - input:read-only { - box-shadow: none !important; - background: transparent; - padding: 0; - height: 20px; - } -} - -.formGroup { - margin-bottom: 2.5rem; -} diff --git a/packages/fetch-extension/src/pages-unused/token/manage/index.tsx b/packages/fetch-extension/src/pages-unused/token/manage/index.tsx deleted file mode 100644 index dc3e2f4edc..0000000000 --- a/packages/fetch-extension/src/pages-unused/token/manage/index.tsx +++ /dev/null @@ -1,206 +0,0 @@ -import React, { FunctionComponent } from "react"; -import { HeaderLayout } from "@layouts/index"; -import { useNavigate } from "react-router"; -import { PageButton } from "../../../pages/setting/page-button"; - -import style from "./style.module.scss"; -import { observer } from "mobx-react-lite"; -import { useStore } from "../../../stores"; -import { Bech32Address } from "@keplr-wallet/cosmos"; -import { useNotification } from "@components/notification"; -import { useConfirm } from "@components/confirm"; -import { CW20Currency, Secret20Currency } from "@keplr-wallet/types"; -import { useIntl } from "react-intl"; -import { ToolTip } from "@components/tooltip"; - -export const ManageTokenPage: FunctionComponent = observer(() => { - const navigate = useNavigate(); - const intl = useIntl(); - const notification = useNotification(); - const confirm = useConfirm(); - - const { chainStore, tokensStore, analyticsStore } = useStore(); - - const isSecretWasm = - chainStore.current.features && - chainStore.current.features.includes("secretwasm"); - - const appCurrencies = chainStore.current.currencies.filter((currency) => { - if (isSecretWasm) { - return "type" in currency && currency.type === "secret20"; - } else { - return "type" in currency && currency.type === "cw20"; - } - }); - - const copyText = async (text: string, messageId: string) => { - await navigator.clipboard.writeText(text); - - // TODO: Show success tooltip. - notification.push({ - placement: "top-center", - type: "success", - duration: 2, - content: intl.formatMessage({ - id: messageId, - }), - canDelete: true, - transition: { - duration: 0.25, - }, - }); - }; - - return ( - { - analyticsStore.logEvent("back_click", { pageName: "Token List" }); - navigate(-1); - }} - > -
- {appCurrencies.map((currency) => { - const cosmwasmToken = currency as CW20Currency | Secret20Currency; - - const icons: React.ReactElement[] = []; - - icons.push( - - {intl.formatMessage({ - id: "setting.token.manage.notification.contract-address.copy.hover", - })} -
- } - > - { - e.preventDefault(); - - await copyText( - cosmwasmToken.contractAddress, - "setting.token.manage.notification.contract-address.copy" - ); - }} - /> - - ); - - if ("viewingKey" in cosmwasmToken) { - icons.push( - - {intl.formatMessage({ - id: "setting.token.manage.notification.viewing-key.copy.hover", - })} - - } - > - { - e.preventDefault(); - - await copyText( - cosmwasmToken.viewingKey, - "setting.token.manage.notification.viewing-key.copy" - ); - }} - /> - - ); - } - - /* - icons.push( - { - e.preventDefault(); - - history.push( - `/setting/connections/viewing-key/${currency.contractAddress}` - ); - }} - /> - ); - */ - - icons.push( - { - e.preventDefault(); - analyticsStore.logEvent("token_delete_click", { action: "No" }); - - if ( - await confirm.confirm({ - paragraph: intl.formatMessage({ - id: "setting.token.manage.confirm.remove-token", - }), - }) - ) { - analyticsStore.logEvent("token_delete_click", { - action: "Yes", - }); - await tokensStore - .getTokensOf(chainStore.current.chainId) - .removeToken(cosmwasmToken); - } - }} - /> - ); - - return ( - - ); - })} - -
- ); -}); diff --git a/packages/fetch-extension/src/pages-unused/token/manage/style.module.scss b/packages/fetch-extension/src/pages-unused/token/manage/style.module.scss deleted file mode 100644 index 7d98b81e49..0000000000 --- a/packages/fetch-extension/src/pages-unused/token/manage/style.module.scss +++ /dev/null @@ -1,9 +0,0 @@ -@import "../../../../styles/var"; - -.container { - margin: 0 calc(#{$layout-padding} * -1) calc(#{$layout-padding} * -1); - - display: flex; - flex-direction: column; - height: 100%; -} diff --git a/packages/fetch-extension/src/pages-unused/validator-list/index.tsx b/packages/fetch-extension/src/pages-unused/validator-list/index.tsx deleted file mode 100644 index 467e448495..0000000000 --- a/packages/fetch-extension/src/pages-unused/validator-list/index.tsx +++ /dev/null @@ -1,167 +0,0 @@ -import { Staking } from "@keplr-wallet/stores"; -import { CoinPretty } from "@keplr-wallet/unit"; -import { HeaderLayout } from "@layouts-v2/header-layout"; -import { observer } from "mobx-react-lite"; -import React, { FunctionComponent, useEffect, useState } from "react"; -import { useLocation, useNavigate } from "react-router"; -import { useStore } from "../../stores"; -import { MyValidatorsList } from "./my-validators"; -import style from "./style.module.scss"; -import { ValidatorsList } from "./validators"; - -type ValidatorData = Staking.Validator & { amount: CoinPretty }; - -export enum ValidatorOperation { - VALIDATOR = "validator", - MY_STAKE = "myStake", -} - -export const ValidatorList: FunctionComponent = observer(() => { - const navigate = useNavigate(); - const location = useLocation(); - const operation = location.pathname.split("/")[2]; - const [validators, setValidators] = useState<{ - [key in string]: ValidatorData; - }>({}); - const [filteredValidators, setFilteredValidators] = useState( - [] - ); - const [loading, setLoading] = useState(true); - const [searchInput, setSearchInput] = useState(); - const { chainStore, queriesStore, accountStore } = useStore(); - const queries = queriesStore.get(chainStore.current.chainId); - const account = accountStore.getAccount(chainStore.current.chainId); - const queryDelegations = - queries.cosmos.queryDelegations.getQueryBech32Address( - account.bech32Address - ); - useEffect(() => { - const fetchValidators = async () => { - setLoading(true); - const bondedValidators = await queries.cosmos.queryValidators - .getQueryStatus(Staking.BondStatus.Bonded) - .waitFreshResponse(); - const unbondingValidators = await queries.cosmos.queryValidators - .getQueryStatus(Staking.BondStatus.Unbonding) - .waitFreshResponse(); - const unbondedValidators = await queries.cosmos.queryValidators - .getQueryStatus(Staking.BondStatus.Unbonded) - .waitFreshResponse(); - - const map: { - [key in string]: ValidatorData; - } = {}; - for (const val of [ - ...(bondedValidators?.data.validators || []), - ...(unbondingValidators?.data.validators || []), - ...(unbondedValidators?.data.validators || []), - ]) { - const amount = queryDelegations.getDelegationTo(val.operator_address); - - map[val.operator_address] = { ...val, amount }; - } - setValidators(map); - setFilteredValidators(Object.values(map)); - setLoading(false); - }; - fetchValidators(); - }, [queries.cosmos.queryValidators, queryDelegations]); - - const handleFilterValidators = (searchValue: string) => { - const filteredValidators = Object.values(validators).filter((validator) => - searchValue?.trim().length - ? validator.description.moniker - ?.toLowerCase() - .includes(searchValue.toLowerCase()) || - validator.operator_address - ?.toLowerCase() - .includes(searchValue.toLowerCase()) - : true - ); - setFilteredValidators(filteredValidators); - setSearchInput(searchValue); - }; - - return ( - navigate("/")} - > -
-
{ - localStorage.setItem("validatorTab", ValidatorOperation.VALIDATOR); - navigate(`/validators/${ValidatorOperation.VALIDATOR}`); - }} - > - Validators -
- -
{ - localStorage.setItem("validatorTab", ValidatorOperation.MY_STAKE); - navigate(`/validators/${ValidatorOperation.MY_STAKE}`); - }} - > - My stake -
-
-
-
- handleFilterValidators(e.target.value)} - /> - -
-
- {loading && ( -
-
- - - -
-
- Loading Validators -
- )} - - {!loading && operation === ValidatorOperation.VALIDATOR && ( - - )} - {!loading && operation === ValidatorOperation.MY_STAKE && ( - - )} -
- ); -}); diff --git a/packages/fetch-extension/src/pages-unused/validator-list/my-validator-card/index.tsx b/packages/fetch-extension/src/pages-unused/validator-list/my-validator-card/index.tsx deleted file mode 100644 index fd0ce6ce95..0000000000 --- a/packages/fetch-extension/src/pages-unused/validator-list/my-validator-card/index.tsx +++ /dev/null @@ -1,89 +0,0 @@ -import { ToolTip } from "@components/tooltip"; -import { Staking } from "@keplr-wallet/stores"; -import { CoinPretty } from "@keplr-wallet/unit"; -import { formatAddress, shortenMintingNumber } from "@utils/format"; -import React from "react"; -import { useNavigate } from "react-router"; -import { CHAIN_ID_DORADO, CHAIN_ID_FETCHHUB } from "../../../config.ui.var"; -import styleValidators from "./validators.module.scss"; -import { useLanguage } from "../../../languages"; -import { useStore } from "../../../stores"; - -export const URL: { [key in string]: string } = { - [CHAIN_ID_DORADO]: "https://explore-dorado.fetch.ai/validators", - [CHAIN_ID_FETCHHUB]: "https://www.mintscan.io/fetchai/validators", -}; - -export const MyValidatorCard = ({ - validator, -}: { - validator: Staking.Validator & { amount: CoinPretty }; - chainID: string; -}) => { - const { priceStore } = useStore(); - - const navigate = useNavigate(); - const language = useLanguage(); - const fiatCurrency = language.fiatCurrency; - - const value = priceStore.calculatePrice(validator.amount, fiatCurrency); - const inFiat = value && value.shrink(true).maxDecimals(6).toString(); - return ( -
- navigate(`/validators/${validator.operator_address}/stake`) - } - > -
-
-
- {validator.description.moniker} -
- - {validator.operator_address} -
- } - > - - {formatAddress(validator.operator_address)} - - -
- -
-
- - {shortenMintingNumber(validator.amount.toDec().toString(), 0)}{" "} - - - {validator.amount.currency.coinDenom} - -
- {inFiat && ( -
- {inFiat} - - {fiatCurrency.toUpperCase()} - -
- )} -
-
- {validator.description.website && ( - - {validator.description.website} - - )} - - ); -}; diff --git a/packages/fetch-extension/src/pages-unused/validator-list/my-validator-card/validators.module.scss b/packages/fetch-extension/src/pages-unused/validator-list/my-validator-card/validators.module.scss deleted file mode 100644 index ca52db62cd..0000000000 --- a/packages/fetch-extension/src/pages-unused/validator-list/my-validator-card/validators.module.scss +++ /dev/null @@ -1,74 +0,0 @@ -.col { - text-align: center; - display: flex; - flex-direction: column; - gap: 4px; - font-size: 12px; - text-transform: capitalize; -} - -.row { - display: flex; - justify-content: space-between; - width: 100%; -} - -.label { - font-weight: bold; - text-transform: capitalize; -} - -.address { - font-size: 12px; -} -.amountSection { - gap: 6px; - display: flex; - flex-direction: column; - align-items: end; - justify-content: center; -} - -.amount { - color: #fff; - text-align: center; - font-family: Lexend; - font-size: 14px; - font-style: normal; - font-weight: 500; - line-height: normal; -} - -.avatar { - width: 80px; - height: 80px; - line-height: initial; - text-align: center; - color: rgb(255, 255, 255); - border-radius: 100%; - background: rgb(214, 26, 127); -} -.item { - color: rgba(255, 255, 255, 0.9); - display: flex; - flex-direction: column; - gap: 8px; - width: 100%; - padding: 10px; - background: rgba(255, 255, 255, 0.1); - border-radius: 6px; - cursor: pointer; - margin: 10px 0px; -} - -.item:hover { - background: rgba(255, 255, 255, 0.2); -} - -.tooltip { - font-weight: 400; - font-size: 10px; - line-height: 10px; - - padding: 2px 4px; -} diff --git a/packages/fetch-extension/src/pages-unused/validator-list/my-validators/index.tsx b/packages/fetch-extension/src/pages-unused/validator-list/my-validators/index.tsx deleted file mode 100644 index 362f33ba8d..0000000000 --- a/packages/fetch-extension/src/pages-unused/validator-list/my-validators/index.tsx +++ /dev/null @@ -1,47 +0,0 @@ -import { Staking } from "@keplr-wallet/stores"; -import { CoinPretty } from "@keplr-wallet/unit"; -import React from "react"; -import { useStore } from "../../../stores"; -import { MyValidatorCard } from "../my-validator-card"; - -type ValidatorData = Staking.Validator & { amount: CoinPretty }; - -export const MyValidatorsList = ({ - filteredValidators, -}: { - filteredValidators: ValidatorData[]; -}) => { - const { chainStore } = useStore(); - - const filterValidators = (validator: ValidatorData) => { - return validator.amount - .toDec() - .gt(new CoinPretty(validator.amount.currency, "0").toDec()); - }; - - const sortValidators = (a: ValidatorData, b: ValidatorData) => { - return ( - parseFloat(b.amount.toDec().toString()) - - parseFloat(a.amount.toDec().toString()) - ); - }; - - return ( - - {filteredValidators.length ? ( - filteredValidators - .filter(filterValidators) - .sort(sortValidators) - .map((validator: ValidatorData) => ( - - )) - ) : ( -
No Validators Found
- )} -
- ); -}; diff --git a/packages/fetch-extension/src/pages-unused/validator-list/style.module.scss b/packages/fetch-extension/src/pages-unused/validator-list/style.module.scss deleted file mode 100644 index d24d100400..0000000000 --- a/packages/fetch-extension/src/pages-unused/validator-list/style.module.scss +++ /dev/null @@ -1,146 +0,0 @@ -.searchContainer { - margin: 12px 0px; - font-size: 14px; - display: flex; - align-items: center; - background-color: rgba(255, 255, 255, 0.1); - border-radius: 8px; - - .searchBox { - display: flex; - padding: 12px 9px; - flex: 1; - align-items: center; - gap: 10px; - img { - width: 16px; - height: 16px; - -webkit-user-drag: none; - -khtml-user-drag: none; - -moz-user-drag: none; - -o-user-drag: none; - } - input { - background: transparent; - border: none; - outline: none; - color: white; - &::placeholder { - color: white; - } - flex-grow: 1; - } - } -} - -.loader { - display: inline-block; - margin: 0 16px; - color: white; -} - -.loader { - --path: #2f3545; - --dot: #5628ee; - --duration: 2s; - width: 44px; - height: 44px; - position: relative; -} - -.loader:before { - content: ""; - width: 6px; - height: 6px; - border-radius: 50%; - position: absolute; - display: block; - background: var(--dot); - top: 37px; - left: 19px; - transform: translate(-18px, -18px); - animation: dotRect var(--duration) cubic-bezier(0.785, 0.135, 0.15, 0.86) - infinite; -} - -.loader svg { - display: block; - width: 100%; - height: 100%; -} - -.loader svg rect, -.loader svg polygon, -.loader svg circle { - fill: none; - stroke: var(--path); - stroke-width: 10px; - stroke-linejoin: round; - stroke-linecap: round; -} - -.loader svg rect { - stroke-dasharray: 192 64 192 64; - stroke-dashoffset: 0; - animation: pathRect 2s cubic-bezier(0.785, 0.135, 0.15, 0.86) infinite; -} - -.tabList { - display: flex; - flex-direction: row; - align-items: center; - color: white; - border-radius: 12px; - background: rgba(255, 255, 255, 0.1); - height: 36px; -} - -.tab { - width: 50%; - cursor: pointer; - padding: 5px; - border-radius: 12px; - font-size: 13px; - height: 32px; - font-weight: 700; - background: white; - align-items: end; - display: flex; - justify-content: center; -} - -@keyframes pathRect { - 25% { - stroke-dashoffset: 64; - } - - 50% { - stroke-dashoffset: 128; - } - - 75% { - stroke-dashoffset: 192; - } - - 100% { - stroke-dashoffset: 256; - } -} - -@keyframes dotRect { - 25% { - transform: translate(0, 0); - } - - 50% { - transform: translate(18px, -18px); - } - - 75% { - transform: translate(0, -36px); - } - - 100% { - transform: translate(-18px, -18px); - } -} diff --git a/packages/fetch-extension/src/pages-unused/validator-list/validator-card/index.tsx b/packages/fetch-extension/src/pages-unused/validator-list/validator-card/index.tsx deleted file mode 100644 index a0abb3fb69..0000000000 --- a/packages/fetch-extension/src/pages-unused/validator-list/validator-card/index.tsx +++ /dev/null @@ -1,91 +0,0 @@ -import { ToolTip } from "@components/tooltip"; -import { Staking } from "@keplr-wallet/stores"; -import { CoinPretty } from "@keplr-wallet/unit"; -import { formatAddress, shortenNumber } from "@utils/format"; -import React from "react"; -import { useNavigate } from "react-router"; -import { CHAIN_ID_DORADO, CHAIN_ID_FETCHHUB } from "../../../config.ui.var"; -import styleValidators from "./validators.module.scss"; - -export const URL: { [key in string]: string } = { - [CHAIN_ID_DORADO]: "https://explore-dorado.fetch.ai/validators", - [CHAIN_ID_FETCHHUB]: "https://www.mintscan.io/fetchai/validators", -}; - -export const ValidatorCard = ({ - validator, - chainID, -}: { - validator: Staking.Validator & { amount: CoinPretty }; - chainID: string; -}) => { - const navigate = useNavigate(); - - const status = validator.status.split("_")[2].toLowerCase(); - const commisionRate = ( - parseFloat(validator.commission.commission_rates.rate) * 100 - ).toFixed(2); - return ( -
- navigate(`/validators/${validator.operator_address}/stake`) - } - > -
-
-
- {validator.description.moniker} -
- - {validator.operator_address} -
- } - > - - {formatAddress(validator.operator_address)} - - -
- right-arrow -
-
-
- Delegated - {shortenNumber(validator.delegator_shares)} -
-
- Commission - {commisionRate}% -
-
- Status - {status} -
-
- - View in Explorer - - - ); -}; diff --git a/packages/fetch-extension/src/pages-unused/validator-list/validator-card/validators.module.scss b/packages/fetch-extension/src/pages-unused/validator-list/validator-card/validators.module.scss deleted file mode 100644 index 2cf55a0ca7..0000000000 --- a/packages/fetch-extension/src/pages-unused/validator-list/validator-card/validators.module.scss +++ /dev/null @@ -1,68 +0,0 @@ -.col { - text-align: center; - display: flex; - flex-direction: column; - gap: 4px; - font-size: 12px; - text-transform: capitalize; -} - -.row { - display: flex; - justify-content: space-between; - width: 100%; - align-items: center; -} - -.moniker { - font-weight: bold; - text-transform: capitalize; -} - -.label { - color: #fff; - text-align: center; - font-size: 14px; - font-style: normal; - font-weight: 400; - line-height: normal; - opacity: 0.6; -} - -.address { - font-size: 12px; -} - -.avatar { - width: 80px; - height: 80px; - line-height: initial; - text-align: center; - color: rgb(255, 255, 255); - border-radius: 100%; - background: rgb(214, 26, 127); -} -.item { - color: rgba(255, 255, 255, 0.9); - display: flex; - flex-direction: column; - gap: 8px; - width: 100%; - padding: 10px; - background: rgba(255, 255, 255, 0.1); - border-radius: 6px; - cursor: pointer; - margin: 10px 0px; -} - -.item:hover { - background: rgba(255, 255, 255, 0.2); -} - -.tooltip { - font-weight: 400; - font-size: 10px; - line-height: 10px; - - padding: 2px 4px; -} diff --git a/packages/fetch-extension/src/pages-unused/validator-list/validators/index.tsx b/packages/fetch-extension/src/pages-unused/validator-list/validators/index.tsx deleted file mode 100644 index 082b34dfe0..0000000000 --- a/packages/fetch-extension/src/pages-unused/validator-list/validators/index.tsx +++ /dev/null @@ -1,39 +0,0 @@ -import { Staking } from "@keplr-wallet/stores"; -import { CoinPretty } from "@keplr-wallet/unit"; -import React from "react"; -import { useStore } from "../../../stores"; -import { ValidatorCard } from "../validator-card"; - -type ValidatorData = Staking.Validator & { amount: CoinPretty }; - -export const ValidatorsList = ({ - filteredValidators, -}: { - filteredValidators: ValidatorData[]; -}) => { - const { chainStore } = useStore(); - - const sortValidators = (a: ValidatorData, b: ValidatorData) => { - return parseFloat(b.delegator_shares) - parseFloat(a.delegator_shares); - }; - - return ( - - {filteredValidators.length ? ( - filteredValidators - .sort((a, b) => sortValidators(a, b)) - .map((validator: ValidatorData) => ( - - )) - ) : ( -
- No Validators Found -
- )} -
- ); -}; diff --git a/packages/fetch-extension/src/pages-unused/validator/index.tsx b/packages/fetch-extension/src/pages-unused/validator/index.tsx deleted file mode 100644 index 99c5e5ddb5..0000000000 --- a/packages/fetch-extension/src/pages-unused/validator/index.tsx +++ /dev/null @@ -1,173 +0,0 @@ -import { Staking } from "@keplr-wallet/stores"; -import { HeaderLayout } from "@layouts-v2/header-layout"; -import { observer } from "mobx-react-lite"; -import React, { FunctionComponent, useMemo } from "react"; -import { useLocation, useNavigate } from "react-router"; -import { useStore } from "../../stores"; -import { Stake } from "./stake"; -import style from "./style.module.scss"; -import { Transfer } from "./transfer"; -import { Unstake } from "./unstake"; -import { ValidatorDetails } from "./validator-details"; -import { Dec } from "@keplr-wallet/unit"; -import styleTab from "../validator-list/style.module.scss"; -enum ValidatorOperation { - STAKE = "stake", - UNSTAKE = "unstake", - TRANSFER = "transfer", -} - -export const Validator: FunctionComponent = observer(() => { - const navigate = useNavigate(); - const location = useLocation(); - const validatorAddress = location.pathname.split("/")[2]; - const operation = location.pathname.split("/")[3]; - const validatorTab = localStorage.getItem("validatorTab") || "validator"; - const { chainStore, accountStore, queriesStore } = useStore(); - const account = accountStore.getAccount(chainStore.current.chainId); - const queries = queriesStore.get(chainStore.current.chainId); - - const bondedValidators = queries.cosmos.queryValidators.getQueryStatus( - Staking.BondStatus.Bonded - ); - const unbondingValidators = queries.cosmos.queryValidators.getQueryStatus( - Staking.BondStatus.Unbonding - ); - const unbondedValidators = queries.cosmos.queryValidators.getQueryStatus( - Staking.BondStatus.Unbonded - ); - const queryDelegations = - queries.cosmos.queryDelegations.getQueryBech32Address( - account.bech32Address - ); - const queryRewards = queries.cosmos.queryRewards.getQueryBech32Address( - account.bech32Address - ); - const { validator, amount, rewards } = useMemo(() => { - const amount = queryDelegations.getDelegationTo(validatorAddress); - const validator = - bondedValidators.getValidator(validatorAddress) || - unbondingValidators.getValidator(validatorAddress) || - unbondedValidators.getValidator(validatorAddress); - const thumbnail = - bondedValidators.getValidatorThumbnail(validatorAddress) || - unbondingValidators.getValidatorThumbnail(validatorAddress) || - unbondedValidators.getValidatorThumbnail(validatorAddress); - const rewards = queryRewards.getRewardsOf(validatorAddress); - return { - validator, - thumbnail, - rewards, - amount: amount, - }; - }, [ - queryDelegations, - validatorAddress, - bondedValidators, - unbondingValidators, - unbondedValidators, - queryRewards, - ]); - const inflation = queries.cosmos.queryInflation; - const { inflation: ARR, isFetching } = inflation; - const validatorCom: any = parseFloat( - validator?.commission.commission_rates.rate || "0" - ); - const APR = ARR.mul(new Dec(1 - validatorCom)); - return ( - navigate(`/validators/${validatorTab}`)} - > -
-
-
-
navigate(`/validators/${validatorAddress}/stake`)} - > - Stake -
- -
- navigate(`/validators/${validatorAddress}/unstake`) - } - > - Unstake -
-
- navigate(`/validators/${validatorAddress}/transfer`) - } - > - Redelegate -
-
- {operation == ValidatorOperation.STAKE && ( - - )} - {operation == ValidatorOperation.UNSTAKE && ( - - )} - {operation == ValidatorOperation.TRANSFER && ( - validator.operator_address != validatorAddress - )} - /> - )} -
- {validator && ( - - )} -
-
- ); -}); diff --git a/packages/fetch-extension/src/pages-unused/validator/stake-complete.tsx b/packages/fetch-extension/src/pages-unused/validator/stake-complete.tsx deleted file mode 100644 index b2b986d59c..0000000000 --- a/packages/fetch-extension/src/pages-unused/validator/stake-complete.tsx +++ /dev/null @@ -1,91 +0,0 @@ -import { HeaderLayout } from "@layouts/header-layout"; -import React, { FunctionComponent, useMemo } from "react"; -import { useLocation, useNavigate } from "react-router"; -import { Button } from "reactstrap"; -import activeStake from "@assets/icon/activeStake.png"; -import { Staking } from "@keplr-wallet/stores"; -import { useStore } from "../../stores"; -import { observer } from "mobx-react-lite"; - -export const StakeComplete: FunctionComponent = observer(() => { - const navigate = useNavigate(); - const validatorAddress = useLocation().pathname.split("/")[2]; - const validatorTab = localStorage.getItem("validatorTab"); - const { chainStore, queriesStore } = useStore(); - const queries = queriesStore.get(chainStore.current.chainId); - - const bondedValidators = queries.cosmos.queryValidators.getQueryStatus( - Staking.BondStatus.Bonded - ); - const unbondingValidators = queries.cosmos.queryValidators.getQueryStatus( - Staking.BondStatus.Unbonding - ); - const unbondedValidators = queries.cosmos.queryValidators.getQueryStatus( - Staking.BondStatus.Unbonded - ); - - const { validator } = useMemo(() => { - const validator = - bondedValidators.getValidator(validatorAddress) || - unbondingValidators.getValidator(validatorAddress) || - unbondedValidators.getValidator(validatorAddress); - return { - validator, - }; - }, [ - bondedValidators, - validatorAddress, - unbondingValidators, - unbondedValidators, - ]); - - return ( - -
- - {validator && ( -
- Amount processed with -
- {validator.description.moniker} -
-
- )} -
- - - - -
- ); -}); diff --git a/packages/fetch-extension/src/pages-unused/validator/stake.tsx b/packages/fetch-extension/src/pages-unused/validator/stake.tsx deleted file mode 100644 index 3594372fcd..0000000000 --- a/packages/fetch-extension/src/pages-unused/validator/stake.tsx +++ /dev/null @@ -1,280 +0,0 @@ -import { ButtonV2 } from "@components-v2/buttons/button"; -import { useNotification } from "@components/notification"; -import { - EmptyAmountError, - InsufficientAmountError, - InvalidNumberAmountError, - NegativeAmountError, - ZeroAmountError, - useDelegateTxConfig, -} from "@keplr-wallet/hooks"; -import { CoinPretty, Int } from "@keplr-wallet/unit"; -import { observer } from "mobx-react-lite"; -import React, { FunctionComponent, useMemo } from "react"; -import { useIntl } from "react-intl"; -import { useNavigate } from "react-router"; -import { FormGroup, Input, Label } from "reactstrap"; -import { useStore } from "../../stores"; -import style from "./style.module.scss"; - -export const Stake: FunctionComponent<{ - validatorAddress: string; - isFetching: boolean; - rewards: any; - amount: CoinPretty; -}> = observer(({ validatorAddress, isFetching, rewards, amount }) => { - const navigate = useNavigate(); - const { chainStore, accountStore, queriesStore, analyticsStore } = useStore(); - const account = accountStore.getAccount(chainStore.current.chainId); - - const sendConfigs = useDelegateTxConfig( - chainStore, - queriesStore, - accountStore, - chainStore.current.chainId, - account.bech32Address - ); - const { amountConfig, memoConfig, feeConfig } = sendConfigs; - - const intl = useIntl(); - const error = amountConfig.error; - - const queryBalances = queriesStore - .get(amountConfig.chainId) - .queryBalances.getQueryBech32Address(amountConfig.sender); - - const queryBalance = queryBalances.balances.find( - (bal) => - amountConfig.sendCurrency.coinMinimalDenom === - bal.currency.coinMinimalDenom - ); - const balance = queryBalance - ? queryBalance.balance - : new CoinPretty(amountConfig.sendCurrency, new Int(0)); - - const errorText: string | undefined = useMemo(() => { - if (error) { - switch (error.constructor) { - case EmptyAmountError: - // No need to show the error to user. - return; - case InvalidNumberAmountError: - return intl.formatMessage({ - id: "input.amount.error.invalid-number", - }); - case ZeroAmountError: - return intl.formatMessage({ - id: "input.amount.error.is-zero", - }); - case NegativeAmountError: - return intl.formatMessage({ - id: "input.amount.error.is-negative", - }); - case InsufficientAmountError: - return intl.formatMessage({ - id: "input.amount.error.insufficient", - }); - default: - return intl.formatMessage({ id: "input.amount.error.unknown" }); - } - } - }, [intl, error]); - - const notification = useNotification(); - - const txnResult = { - onBroadcasted: () => { - notification.push({ - type: "primary", - placement: "top-center", - duration: 2, - content: `Transaction broadcasted`, - canDelete: true, - transition: { - duration: 0.25, - }, - }); - - analyticsStore.logEvent("Stake tx broadcasted", { - chainId: chainStore.current.chainId, - chainName: chainStore.current.chainName, - }); - }, - onFulfill: (tx: any) => { - const istxnSuccess = tx.code ? false : true; - notification.push({ - type: istxnSuccess ? "success" : "danger", - placement: "top-center", - duration: 5, - content: istxnSuccess - ? `Transaction Completed` - : `Transaction Failed: ${tx.log}`, - canDelete: true, - transition: { - duration: 0.25, - }, - }); - }, - }; - const stakeClicked = async () => { - try { - await account.cosmos - .makeDelegateTx(amountConfig.amount, validatorAddress) - .send(feeConfig.toStdFee(), memoConfig.memo, undefined, txnResult); - } catch (e) { - notification.push({ - type: "danger", - placement: "top-center", - duration: 5, - content: `Transaction Failed`, - canDelete: true, - transition: { - duration: 0.25, - }, - }); - } finally { - navigate("/", { replace: true }); - } - }; - const handleClaim = async () => { - try { - await account.cosmos.sendWithdrawDelegationRewardMsgs( - [validatorAddress], - "", - undefined, - undefined, - { - onBroadcasted() { - notification.push({ - type: "primary", - placement: "top-center", - duration: 5, - content: `Transaction Broadcasted`, - canDelete: true, - transition: { - duration: 0.25, - }, - }); - }, - onFulfill: (tx: any) => { - const istxnSuccess = tx.code ? false : true; - notification.push({ - type: istxnSuccess ? "success" : "danger", - placement: "top-center", - duration: 5, - content: istxnSuccess - ? `Transaction Completed` - : `Transaction Failed`, - canDelete: true, - transition: { - duration: 0.25, - }, - }); - }, - } - ); - navigate(`/validators/${validatorAddress}/stake`); - } catch (err) { - console.error(err); - if (err.toString().includes("Error: Request rejected")) { - navigate(`/validators/${validatorAddress}/stake`); - } - } - }; - return ( - -
-
Current Staked Amount
-
- {amount.maxDecimals(4).trim(true).toString()} -
-
-
-
- Earned Rewards -
- {!isFetching ? ( -
- {!rewards || - rewards.length === 0 || - parseFloat( - rewards[0]?.maxDecimals(4).toString().split(" ")[0] - ) < 0.00001 ? ( - 0 - ) : ( - rewards[0]?.maxDecimals(4).toString() - )} -
- ) : ( - - - - )} - {(!rewards || - rewards.length !== 0 || - parseFloat(rewards[0]?.maxDecimals(4).toString().split(" ")[0]) > - 0.00001) && ( - - )} -
-
-
- - - { - e.preventDefault(); - amountConfig.setAmount(e.target.value); - }} - style={{ - color: "white", - borderRadius: "5px", - background: "rgba(255,255,255,0.1)", - }} - min={0} - autoComplete="off" - /> - {errorText != null ? ( -
{errorText}
- ) : null} - - Stake - -
-
- ); -}); diff --git a/packages/fetch-extension/src/pages-unused/validator/style.module.scss b/packages/fetch-extension/src/pages-unused/validator/style.module.scss deleted file mode 100644 index c9beefcdff..0000000000 --- a/packages/fetch-extension/src/pages-unused/validator/style.module.scss +++ /dev/null @@ -1,167 +0,0 @@ -.stakeContainer { - display: flex; - justify-content: space-between; - flex-direction: column; - height: 100%; -} -.selectValidator { - font-size: 14px; - color: white; - cursor: pointer; - border: 1px solid rgba(255, 255, 255, 0.4); - border-radius: 100px; - padding: 2px 9px; - width: fit-content; - margin-top: 10px; -} -.selectValidator:hover { - border: 1px solid white; -} -.stakedAmount { - color: white; - display: flex; - flex-direction: column; - align-items: center; - gap: 5px; - font-size: 14px; -} - -.tabList { - display: flex; - flex-direction: row; -} - -.tab { - width: 50%; - text-align: center; - cursor: pointer; - font-size: 14px; -} - -.stakeValueInput { - padding: 8px; - border: none; - margin-bottom: 10px; -} - -.nextStakedValidatorName { - text-align: center; - color: #5090ff; - margin-bottom: 10px; -} - -.nextStakedInfo { - text-align: center; -} - -.balance { - text-align: right; - font-weight: normal; - color: rgba(255, 255, 255, 0.6); - cursor: pointer; - - &:hover { - color: white; - text-decoration: underline; - } - - &.clicked { - color: black; - } -} - -.errorText { - color: #fb8c72; - font: 10px; -} - -.loader { - display: inline-block; - margin: 0 16px; -} - -.loader { - --path: #2f3545; - --dot: #5628ee; - --duration: 2s; - width: 44px; - height: 44px; - position: relative; -} - -.loader:before { - content: ""; - width: 6px; - height: 6px; - border-radius: 50%; - position: absolute; - display: block; - background: var(--dot); - top: 37px; - left: 19px; - transform: translate(-18px, -18px); - animation: dotRect var(--duration) cubic-bezier(0.785, 0.135, 0.15, 0.86) - infinite; -} - -.loader svg { - display: block; - width: 100%; - height: 100%; -} - -.loader svg rect, -.loader svg polygon, -.loader svg circle { - fill: none; - stroke: var(--path); - stroke-width: 10px; - stroke-linejoin: round; - stroke-linecap: round; -} - -.loader svg rect { - stroke-dasharray: 192 64 192 64; - stroke-dashoffset: 0; - animation: pathRect 2s cubic-bezier(0.785, 0.135, 0.15, 0.86) infinite; -} - -.dropdown:hover { - background: aliceblue !important; -} - -@keyframes pathRect { - 25% { - stroke-dashoffset: 64; - } - - 50% { - stroke-dashoffset: 128; - } - - 75% { - stroke-dashoffset: 192; - } - - 100% { - stroke-dashoffset: 256; - } -} - -@keyframes dotRect { - 25% { - transform: translate(0, 0); - } - - 50% { - transform: translate(18px, -18px); - } - - 75% { - transform: translate(0, -36px); - } - - 100% { - transform: translate(-18px, -18px); - } -} diff --git a/packages/fetch-extension/src/pages-unused/validator/transfer.tsx b/packages/fetch-extension/src/pages-unused/validator/transfer.tsx deleted file mode 100644 index 507ec64ce9..0000000000 --- a/packages/fetch-extension/src/pages-unused/validator/transfer.tsx +++ /dev/null @@ -1,216 +0,0 @@ -import { ButtonV2 } from "@components-v2/buttons/button"; -import { Card } from "@components-v2/card"; -import { Dropdown } from "@components-v2/dropdown"; -import { useNotification } from "@components/notification"; -import { - EmptyAmountError, - InsufficientAmountError, - InvalidNumberAmountError, - NegativeAmountError, - ZeroAmountError, - useRedelegateTxConfig, -} from "@keplr-wallet/hooks"; -import { Staking } from "@keplr-wallet/stores"; -import { CoinPretty } from "@keplr-wallet/unit"; -import { observer } from "mobx-react-lite"; -import React, { FunctionComponent, useMemo, useState } from "react"; -import { useIntl } from "react-intl"; -import { useNavigate } from "react-router"; -import { FormGroup, Input, Label } from "reactstrap"; -import { useStore } from "../../stores"; -import style from "./style.module.scss"; - -export const Transfer: FunctionComponent<{ - validatorAddress: string; - validatorsList: Staking.Validator[]; - balance: CoinPretty; -}> = observer(({ validatorAddress, validatorsList, balance }) => { - const navigate = useNavigate(); - const { chainStore, accountStore, queriesStore, analyticsStore } = useStore(); - const account = accountStore.getAccount(chainStore.current.chainId); - const [selectedValidator, setSelectedValidator] = useState( - validatorsList[0] - ); - console.log(validatorsList); - const [showDropdown, setShowDropdown] = useState(false); - const sendConfigs = useRedelegateTxConfig( - chainStore, - queriesStore, - accountStore, - chainStore.current.chainId, - account.bech32Address, - validatorAddress - ); - const { amountConfig, memoConfig, feeConfig } = sendConfigs; - - const intl = useIntl(); - const error = amountConfig.error; - - const errorText: string | undefined = useMemo(() => { - if (error) { - switch (error.constructor) { - case EmptyAmountError: - // No need to show the error to user. - return; - case InvalidNumberAmountError: - return intl.formatMessage({ - id: "input.amount.error.invalid-number", - }); - case ZeroAmountError: - return intl.formatMessage({ - id: "input.amount.error.is-zero", - }); - case NegativeAmountError: - return intl.formatMessage({ - id: "input.amount.error.is-negative", - }); - case InsufficientAmountError: - return intl.formatMessage({ - id: "input.amount.error.insufficient", - }); - default: - return intl.formatMessage({ id: "input.amount.error.unknown" }); - } - } - }, [intl, error]); - - const notification = useNotification(); - - const txnResult = { - onBroadcasted: () => { - notification.push({ - type: "primary", - placement: "top-center", - duration: 2, - content: `Transaction broadcasted`, - canDelete: true, - transition: { - duration: 0.25, - }, - }); - - analyticsStore.logEvent("Redelegate tx broadcasted", { - chainId: chainStore.current.chainId, - chainName: chainStore.current.chainName, - }); - }, - onFulfill: (tx: any) => { - const istxnSuccess = tx.code ? false : true; - notification.push({ - type: istxnSuccess ? "success" : "danger", - placement: "top-center", - duration: 5, - content: istxnSuccess - ? `Transaction Completed` - : `Transaction Failed: ${tx.log}`, - canDelete: true, - transition: { - duration: 0.25, - }, - }); - }, - }; - const stakeClicked = async () => { - try { - await account.cosmos - .makeBeginRedelegateTx( - amountConfig.amount, - validatorAddress, - selectedValidator.operator_address - ) - .send(feeConfig.toStdFee(), memoConfig.memo, undefined, txnResult); - } catch (e) { - notification.push({ - type: "danger", - placement: "top-center", - duration: 5, - content: `Transaction Failed`, - canDelete: true, - transition: { - duration: 0.25, - }, - }); - } finally { - navigate("/", { replace: true }); - } - }; - const toggleDropdown = () => { - setShowDropdown(!showDropdown); - }; - return ( - - -
- {selectedValidator - ? selectedValidator.description.moniker - : "Select Validator"}{" "} - -
- - setShowDropdown(false)} - title="Select Validator" - isOpen={showDropdown} - setIsOpen={setShowDropdown} - > -
- {validatorsList.map((validator) => { - return ( - { - setSelectedValidator(validator); - setShowDropdown(false); - }} - heading={validator.description.moniker} - /> - ); - })} -
-
- - { - e.preventDefault(); - amountConfig.setAmount(e.target.value); - }} - style={{ - color: "white", - borderRadius: "5px", - background: "rgba(255,255,255,0.1)", - }} - min={0} - autoComplete="off" - /> - {errorText != null ? ( -
{errorText}
- ) : null} - - - Redelegate - -
-
- ); -}); diff --git a/packages/fetch-extension/src/pages-unused/validator/unstake.tsx b/packages/fetch-extension/src/pages-unused/validator/unstake.tsx deleted file mode 100644 index a25b5dd13f..0000000000 --- a/packages/fetch-extension/src/pages-unused/validator/unstake.tsx +++ /dev/null @@ -1,177 +0,0 @@ -import { ButtonV2 } from "@components-v2/buttons/button"; -import { useNotification } from "@components/notification"; -import { - EmptyAmountError, - InsufficientAmountError, - InvalidNumberAmountError, - NegativeAmountError, - ZeroAmountError, - useUndelegateTxConfig, -} from "@keplr-wallet/hooks"; -import { observer } from "mobx-react-lite"; -import React, { FunctionComponent, useMemo } from "react"; -import { useIntl } from "react-intl"; -import { useNavigate } from "react-router"; -import { FormGroup, Input, Label } from "reactstrap"; -import { useStore } from "../../stores"; -import style from "./style.module.scss"; - -export const Unstake: FunctionComponent<{ - validatorAddress: string; -}> = observer(({ validatorAddress }) => { - const navigate = useNavigate(); - const { chainStore, accountStore, queriesStore, analyticsStore } = useStore(); - const account = accountStore.getAccount(chainStore.current.chainId); - - const sendConfigs = useUndelegateTxConfig( - chainStore, - queriesStore, - accountStore, - chainStore.current.chainId, - account.bech32Address, - validatorAddress - ); - const { amountConfig, memoConfig, feeConfig } = sendConfigs; - - const intl = useIntl(); - const error = amountConfig.error; - - const balance = queriesStore - .get(amountConfig.chainId) - .cosmos.queryDelegations.getQueryBech32Address(amountConfig.sender) - .getDelegationTo(validatorAddress); - - const errorText: string | undefined = useMemo(() => { - if (error) { - switch (error.constructor) { - case EmptyAmountError: - // No need to show the error to user. - return; - case InvalidNumberAmountError: - return intl.formatMessage({ - id: "input.amount.error.invalid-number", - }); - case ZeroAmountError: - return intl.formatMessage({ - id: "input.amount.error.is-zero", - }); - case NegativeAmountError: - return intl.formatMessage({ - id: "input.amount.error.is-negative", - }); - case InsufficientAmountError: - return intl.formatMessage({ - id: "input.amount.error.insufficient", - }); - default: - return intl.formatMessage({ id: "input.amount.error.unknown" }); - } - } - }, [intl, error]); - - const notification = useNotification(); - - const txnResult = { - onBroadcasted: () => { - notification.push({ - type: "primary", - placement: "top-center", - duration: 2, - content: `Transaction broadcasted`, - canDelete: true, - transition: { - duration: 0.25, - }, - }); - - analyticsStore.logEvent("Unstake tx broadcasted", { - chainId: chainStore.current.chainId, - chainName: chainStore.current.chainName, - }); - }, - onFulfill: (tx: any) => { - const istxnSuccess = tx.code ? false : true; - notification.push({ - type: istxnSuccess ? "success" : "danger", - placement: "top-center", - duration: 5, - content: istxnSuccess - ? `Transaction Completed` - : `Transaction Failed: ${tx.log}`, - canDelete: true, - transition: { - duration: 0.25, - }, - }); - }, - }; - - const stakeClicked = async () => { - try { - await account.cosmos - .makeUndelegateTx(amountConfig.amount, validatorAddress) - .send(feeConfig.toStdFee(), memoConfig.memo, undefined, txnResult); - } catch (e) { - notification.push({ - type: "danger", - placement: "top-center", - duration: 5, - content: `Transaction Failed`, - canDelete: true, - transition: { - duration: 0.25, - }, - }); - } finally { - navigate("/", { replace: true }); - } - }; - - return ( - - - - { - e.preventDefault(); - amountConfig.setAmount(e.target.value); - }} - style={{ - color: "white", - borderRadius: "5px", - background: "rgba(255,255,255,0.1)", - }} - min={0} - autoComplete="off" - /> - {errorText != null ? ( -
{errorText}
- ) : null} - - - Unstake - -
-
- ); -}); diff --git a/packages/fetch-extension/src/pages-unused/validator/validator-details/index.tsx b/packages/fetch-extension/src/pages-unused/validator/validator-details/index.tsx deleted file mode 100644 index 75ac8497fe..0000000000 --- a/packages/fetch-extension/src/pages-unused/validator/validator-details/index.tsx +++ /dev/null @@ -1,113 +0,0 @@ -import { ToolTip } from "@components/tooltip"; -import { Staking } from "@keplr-wallet/stores"; -import { formatAddress, shortenNumber } from "@utils/format"; -import React from "react"; -import { CHAIN_ID_DORADO, CHAIN_ID_FETCHHUB } from "../../../config.ui.var"; -import styleValidators from "./validatordetails.module.scss"; - -export const URL: { [key in string]: string } = { - [CHAIN_ID_DORADO]: "https://explore-dorado.fetch.ai/validators", - [CHAIN_ID_FETCHHUB]: "https://www.mintscan.io/fetchai/validators", -}; - -export const ValidatorDetails = ({ - validator, - chainID, - APR, - isFetching, -}: { - validator: Staking.Validator; - chainID: string; - APR: any; - isFetching: boolean; -}) => { - const status = validator.status.split("_")[2].toLowerCase(); - const commisionRate = ( - parseFloat(validator.commission.commission_rates.rate) * 100 - ).toFixed(2); - const maxCommisionRate = ( - parseFloat(validator.commission.commission_rates.max_rate) * 100 - ).toFixed(2); - - return ( -
-
-
- {validator.description.website ? ( - - {validator.description.moniker} - - ) : ( - {validator.description.moniker} - )} -
- - {validator.operator_address} -
- } - > - - {formatAddress(validator.operator_address)} - - -
- {validator.description.details && ( -
- {validator.description.details} -
- )} -
-
-
Delegated
-
- {shortenNumber(validator.delegator_shares)} -
-
-
-
Commission
-
- {commisionRate}% ({maxCommisionRate}% Max) -
-
-
-
Status
-
{status}
-
-
-
APR
-
- {!isFetching ? ( - APR.maxDecimals(2).trim(true).toString() + "%" - ) : ( - - - - )} -
-
-
- - - View in Explorer for more Details - - {validator.jailed && ( -
- This validator is currently jailed. Redelegate your tokens. -
- )} - - ); -}; diff --git a/packages/fetch-extension/src/pages-unused/validator/validator-details/validatordetails.module.scss b/packages/fetch-extension/src/pages-unused/validator/validator-details/validatordetails.module.scss deleted file mode 100644 index 42782e6788..0000000000 --- a/packages/fetch-extension/src/pages-unused/validator/validator-details/validatordetails.module.scss +++ /dev/null @@ -1,107 +0,0 @@ -.col { - text-align: center; - display: flex; - flex-direction: column; - gap: 4px; - font-size: 12px; -} - -.title { - display: flex; - flex-direction: column; - justify-content: space-between; - width: 100%; - font-size: 14px; -} - -.label { - color: rgba(255, 255, 255, 0.6); - text-align: center; - font-size: 14px; - font-style: normal; - font-weight: 400; - line-height: normal; -} - -.value { - color: #fff; - text-align: center; - text-transform: capitalize; - font-size: 14px; - font-style: normal; - font-weight: 500; - line-height: normal; -} - -.moniker { - color: #fff; - font-size: 20px; - font-style: normal; - font-weight: 500; - line-height: normal; -} - -.address { - color: #fff; - text-align: center; - opacity: 0.8; - font-size: 14px; - font-style: normal; - font-weight: 400; - line-height: normal; -} - -.description { - font-size: 14px; - display: flex; - flex-direction: column; - width: 100%; - line-height: 160%; -} - -.row { - display: flex; - justify-content: space-between; - width: 100%; - padding: 8px 0px; - border-bottom: 1px solid rgba(255, 255, 255, 0.1); -} - -.details { - justify-content: space-between; - width: 100%; -} - -.item { - display: flex; - flex-direction: column; - gap: 16px; - width: 100%; - padding: 10px; - color: #ffffff; - border-radius: 12px; - margin-top: 24px; - background: rgba(255, 255, 255, 0.1); -} - -.tooltip { - font-weight: 400; - font-size: 10px; - line-height: 10px; - - padding: 2px 4px; -} -.jailed { - color: red; - text-align: center; - font-size: 10px; -} -.claimButton { - font-weight: bold; - cursor: pointer; - padding: 0px 13px; - text-decoration: underline; - color: #3b82f6; - border: none; - background: transparent; -} diff --git a/packages/fetch-extension/src/pages-unused/axelar-bridge/axelar-bridge-cosmos/get-deposit-address.tsx b/packages/fetch-extension/src/pages/axelar-bridge/axelar-bridge-cosmos/get-deposit-address.tsx similarity index 100% rename from packages/fetch-extension/src/pages-unused/axelar-bridge/axelar-bridge-cosmos/get-deposit-address.tsx rename to packages/fetch-extension/src/pages/axelar-bridge/axelar-bridge-cosmos/get-deposit-address.tsx diff --git a/packages/fetch-extension/src/pages-unused/axelar-bridge/axelar-bridge-cosmos/index.tsx b/packages/fetch-extension/src/pages/axelar-bridge/axelar-bridge-cosmos/index.tsx similarity index 100% rename from packages/fetch-extension/src/pages-unused/axelar-bridge/axelar-bridge-cosmos/index.tsx rename to packages/fetch-extension/src/pages/axelar-bridge/axelar-bridge-cosmos/index.tsx diff --git a/packages/fetch-extension/src/pages-unused/axelar-bridge/axelar-bridge-cosmos/send-token.tsx b/packages/fetch-extension/src/pages/axelar-bridge/axelar-bridge-cosmos/send-token.tsx similarity index 100% rename from packages/fetch-extension/src/pages-unused/axelar-bridge/axelar-bridge-cosmos/send-token.tsx rename to packages/fetch-extension/src/pages/axelar-bridge/axelar-bridge-cosmos/send-token.tsx diff --git a/packages/fetch-extension/src/pages-unused/axelar-bridge/axelar-bridge-evm/get-deposit-address.tsx b/packages/fetch-extension/src/pages/axelar-bridge/axelar-bridge-evm/get-deposit-address.tsx similarity index 100% rename from packages/fetch-extension/src/pages-unused/axelar-bridge/axelar-bridge-evm/get-deposit-address.tsx rename to packages/fetch-extension/src/pages/axelar-bridge/axelar-bridge-evm/get-deposit-address.tsx diff --git a/packages/fetch-extension/src/pages-unused/axelar-bridge/axelar-bridge-evm/index.tsx b/packages/fetch-extension/src/pages/axelar-bridge/axelar-bridge-evm/index.tsx similarity index 100% rename from packages/fetch-extension/src/pages-unused/axelar-bridge/axelar-bridge-evm/index.tsx rename to packages/fetch-extension/src/pages/axelar-bridge/axelar-bridge-evm/index.tsx diff --git a/packages/fetch-extension/src/pages-unused/axelar-bridge/axelar-bridge-evm/send-token.tsx b/packages/fetch-extension/src/pages/axelar-bridge/axelar-bridge-evm/send-token.tsx similarity index 100% rename from packages/fetch-extension/src/pages-unused/axelar-bridge/axelar-bridge-evm/send-token.tsx rename to packages/fetch-extension/src/pages/axelar-bridge/axelar-bridge-evm/send-token.tsx diff --git a/packages/fetch-extension/src/pages-unused/axelar-bridge/chain-select.tsx b/packages/fetch-extension/src/pages/axelar-bridge/chain-select.tsx similarity index 100% rename from packages/fetch-extension/src/pages-unused/axelar-bridge/chain-select.tsx rename to packages/fetch-extension/src/pages/axelar-bridge/chain-select.tsx diff --git a/packages/fetch-extension/src/pages-unused/axelar-bridge/gas-and-details.tsx b/packages/fetch-extension/src/pages/axelar-bridge/gas-and-details.tsx similarity index 96% rename from packages/fetch-extension/src/pages-unused/axelar-bridge/gas-and-details.tsx rename to packages/fetch-extension/src/pages/axelar-bridge/gas-and-details.tsx index 4025f6015f..1cc6d4efdf 100644 --- a/packages/fetch-extension/src/pages-unused/axelar-bridge/gas-and-details.tsx +++ b/packages/fetch-extension/src/pages/axelar-bridge/gas-and-details.tsx @@ -3,7 +3,7 @@ import { AxelarQueryAPI } from "@axelar-network/axelarjs-sdk"; import { useNotification } from "@components/notification"; import { formatAmount } from "@utils/format"; import React, { useCallback, useEffect, useState } from "react"; -// import { TooltipForDomainNames } from "../fetch-name-service/domain-details"; +import { TooltipForDomainNames } from "../fetch-name-service/domain-details"; import style from "./style.module.scss"; interface GasAndDetailsProps { @@ -164,7 +164,7 @@ export const GasAndDetails: React.FC = ({ style={{ cursor: "pointer" }} onClick={() => copyAddress(depositAddress)} > - {/* {} */} + {} ) : null} diff --git a/packages/fetch-extension/src/pages-unused/axelar-bridge/recipient-address.tsx b/packages/fetch-extension/src/pages/axelar-bridge/recipient-address.tsx similarity index 100% rename from packages/fetch-extension/src/pages-unused/axelar-bridge/recipient-address.tsx rename to packages/fetch-extension/src/pages/axelar-bridge/recipient-address.tsx diff --git a/packages/fetch-extension/src/pages-unused/axelar-bridge/style.module.scss b/packages/fetch-extension/src/pages/axelar-bridge/style.module.scss similarity index 100% rename from packages/fetch-extension/src/pages-unused/axelar-bridge/style.module.scss rename to packages/fetch-extension/src/pages/axelar-bridge/style.module.scss diff --git a/packages/fetch-extension/src/pages-unused/axelar-bridge/token-balances.tsx b/packages/fetch-extension/src/pages/axelar-bridge/token-balances.tsx similarity index 100% rename from packages/fetch-extension/src/pages-unused/axelar-bridge/token-balances.tsx rename to packages/fetch-extension/src/pages/axelar-bridge/token-balances.tsx diff --git a/packages/fetch-extension/src/pages-unused/axelar-bridge/token-select.tsx b/packages/fetch-extension/src/pages/axelar-bridge/token-select.tsx similarity index 100% rename from packages/fetch-extension/src/pages-unused/axelar-bridge/token-select.tsx rename to packages/fetch-extension/src/pages/axelar-bridge/token-select.tsx diff --git a/packages/fetch-extension/src/pages/bridge/bridge-history.tsx b/packages/fetch-extension/src/pages/bridge/bridge-history.tsx deleted file mode 100644 index ce929b650c..0000000000 --- a/packages/fetch-extension/src/pages/bridge/bridge-history.tsx +++ /dev/null @@ -1,208 +0,0 @@ -import { HeaderLayout } from "@layouts/header-layout"; -import React, { FunctionComponent } from "react"; -import { useNavigate } from "react-router"; -import { observer } from "mobx-react-lite"; -import style from "./style.module.scss"; -import { useStore } from "../../stores"; -import { FormattedMessage } from "react-intl"; -import { CoinPretty } from "@keplr-wallet/unit"; -import { BridgeHistory } from "@keplr-wallet/stores"; -import { Bech32Address } from "@keplr-wallet/cosmos"; -import { Button } from "reactstrap"; -import restartIcon from "@assets/icon/undo.png"; - -export const proposalOptions = { - ProposalActive: "PROPOSAL_STATUS_VOTING_PERIOD", - ProposalPassed: "PROPOSAL_STATUS_PASSED", - ProposalRejected: "PROPOSAL_STATUS_REJECTED", - ProposalFailed: "PROPOSAL_STATUS_FAILED", -}; - -const FETCHSTATION_TXN_URL = "https://www.mintscan.io/fetchai/tx/"; -const ETHERSCAN_TXN_URL = "https://etherscan.io/tx/"; - -export const BridgeHistoryView: FunctionComponent = observer(() => { - const navigate = useNavigate(); - - const { chainStore, accountStore, queriesStore, analyticsStore } = useStore(); - const accountInfo = accountStore.getAccount(chainStore.current.chainId); - - const isEvm = chainStore.current.features?.includes("evm") ?? false; - const currentQueriesStore = queriesStore.get(chainStore.current.chainId); - - const currentChainBridgeHistoryQuery = isEvm - ? currentQueriesStore.evm.queryBridgeHistory - : currentQueriesStore.cosmwasm.queryBridgeHistory; - const bridgeHistory = currentChainBridgeHistoryQuery.getBridgeHistory( - accountInfo.bech32Address - ); - - return ( - { - analyticsStore.logEvent("back_click", { pageName: "Bridge History" }); - navigate(-1); - }} - showBottomMenu={false} - rightRenderer={ - { - e.preventDefault(); - bridgeHistory.fetch(); - }} - /> - } - > -
- {bridgeHistory.isFetching ? ( -
- -
- ) : bridgeHistory.history.length === 0 ? ( -
-

- -

-
- ) : ( - bridgeHistory.history - .reverse() - .map((history) => ( - - )) - )} -
-
- ); -}); - -const BridgeStatus: FunctionComponent<{ history: BridgeHistory }> = observer( - ({ history }) => { - const { chainStore, queriesStore } = useStore(); - const isEvm = chainStore.current.features?.includes("evm") ?? false; - const currentQueriesStore = queriesStore.get(chainStore.current.chainId); - - const counterChainSwapStatusQuery = isEvm - ? currentQueriesStore.cosmwasm.queryBridgeReverseSwapHash - : currentQueriesStore.evm.queryBridgeReverseSwapHash; - const reverseSwapHash = counterChainSwapStatusQuery.getReverseSwapHash( - history.swapId - ); - const fetCurrency = chainStore.current.currencies.find( - (c) => c.coinDenom === "FET" - ); - - return ( -
-
-

{`Swap id #${history.swapId}`}

-

{`Send ${ - fetCurrency - ? new CoinPretty(fetCurrency, history.amount) - .maxDecimals(2) - .toString() - : "0 FET" - }`}

-

- To: {Bech32Address.shortenAddress(history.to, 22, !isEvm)} -

-
- -
- {reverseSwapHash.isFetching ? ( - - ) : ( -
- - - -
- )} -
-
- ); - } -); diff --git a/packages/fetch-extension/src/pages/bridge/ethereum-bridge.tsx b/packages/fetch-extension/src/pages/bridge/ethereum-bridge.tsx deleted file mode 100644 index a36c91955a..0000000000 --- a/packages/fetch-extension/src/pages/bridge/ethereum-bridge.tsx +++ /dev/null @@ -1,544 +0,0 @@ -import React, { FunctionComponent, useState, useEffect } from "react"; -import { observer } from "mobx-react-lite"; -import { useNavigate, useLocation } from "react-router"; - -import style from "./style.module.scss"; -import { Button } from "reactstrap"; -import { AddressInput, CoinInput, FeeButtons, Input } from "@components/form"; -import { - IAmountConfig, - IFeeConfig, - IGasConfig, - IMemoConfig, - IRecipientConfig, - useGasSimulator, - useNativeBridgeConfig, -} from "@keplr-wallet/hooks"; -import { useStore } from "../../stores"; -import { useNotification } from "@components/notification"; -import { FormattedMessage, useIntl } from "react-intl"; -import { ExtensionKVStore } from "@keplr-wallet/common"; -import { AppCurrency } from "@keplr-wallet/types"; -import { Dec, DecUtils, IntPretty } from "@keplr-wallet/unit"; -import queryString from "querystring"; - -import { BigNumber } from "@ethersproject/bignumber"; - -export const EthereumBridge: FunctionComponent<{ - limit: string; - fee?: string; -}> = observer(({ limit, fee }) => { - const [phase, setPhase] = useState<"configure" | "approve" | "bridge">( - "configure" - ); - - let search = useLocation().search; - if (search.startsWith("?")) { - search = search.slice(1); - } - const query = queryString.parse(search) as { - defaultRecipient: string | undefined; - defaultAmount: string | undefined; - }; - - const { chainStore, accountStore, queriesStore } = useStore(); - const accountInfo = accountStore.getAccount(chainStore.current.chainId); - - const nativeBridgeConfig = useNativeBridgeConfig( - chainStore, - queriesStore, - chainStore.current.chainId, - accountInfo.bech32Address - ); - - useEffect(() => { - if (query.defaultRecipient) { - nativeBridgeConfig.recipientConfig.setRawRecipient( - query.defaultRecipient - ); - } - if (query.defaultAmount) { - nativeBridgeConfig.amountConfig.setAmount(query.defaultAmount); - } - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [query.defaultAmount, query.defaultRecipient]); - - if (accountInfo.txTypeInProgress === "nativeBridgeSend") { - return ( -

- Bridging in progress {" "} -

- ); - } - - return ( -
- {phase === "configure" ? ( - - ) : null} - {phase === "approve" ? ( - - ) : null} - {phase === "bridge" ? ( - - ) : null} -
- ); -}); - -export const Configure: FunctionComponent<{ - amountConfig: IAmountConfig; - recipientConfig: IRecipientConfig; - memoConfig: IMemoConfig; - setPhase: React.Dispatch< - React.SetStateAction<"configure" | "approve" | "bridge"> - >; - limit: string; - fee?: string; -}> = observer( - ({ amountConfig, recipientConfig, memoConfig, setPhase, limit, fee }) => { - const intl = useIntl(); - - const { chainStore, queriesStore, accountStore } = useStore(); - - const navigate = useNavigate(); - - const accountInfo = accountStore.getAccount(chainStore.current.chainId); - const allowanceQuery = queriesStore - .get(chainStore.current.chainId) - .evm.queryERC20Allowance.getQueryAllowance( - accountInfo.bech32Address, - queriesStore.get(chainStore.current.chainId).evm.queryNativeFetBridge - .nativeBridgeAddress, - "contractAddress" in amountConfig.sendCurrency - ? amountConfig.sendCurrency.contractAddress - : "" - ); - - const isValid = - recipientConfig.error == null && - memoConfig.error == null && - amountConfig.error == null && - !allowanceQuery.isFetching && - accountInfo.txTypeInProgress !== "approval"; - - return ( -
-
- ERC20 to Native Limit: {limit} FET -
-
- -
{ - e.preventDefault(); - recipientConfig.setRawRecipient( - accountStore.getAccount("fetchhub-4").bech32Address - ); - }} - > - Bridge to your Fetchhub address:{" "} - {accountStore.getAccount("fetchhub-4").bech32Address} -
- -
- - -
- {fee && ( -
- -
-
- )} - -
- - ); - } -); - -export const Approve: FunctionComponent<{ - amountConfig: IAmountConfig; - recipientConfig: IRecipientConfig; - feeConfig: IFeeConfig; - gasConfig: IGasConfig; - currency: AppCurrency; -}> = observer( - ({ amountConfig, recipientConfig, feeConfig, gasConfig, currency }) => { - const intl = useIntl(); - const notification = useNotification(); - - const isValid = feeConfig.error == null && gasConfig.error == null; - - const navigate = useNavigate(); - - const { - chainStore, - priceStore, - accountStore, - queriesStore, - analyticsStore, - } = useStore(); - - const approveGasSimulator = useGasSimulator( - new ExtensionKVStore("gas-simulator.native-bridge.approve"), - chainStore, - chainStore.current.chainId, - gasConfig, - feeConfig, - "bridge-approve", - () => { - return accountStore - .getAccount(chainStore.current.chainId) - .ethereum.makeApprovalTx( - amountConfig.amount, - queriesStore.get(chainStore.current.chainId).evm - .queryNativeFetBridge.nativeBridgeAddress, - currency - ); - } - ); - - return ( -
-

Approve

-
-
- Allow the bridge contract to spend{" "} - - {new IntPretty(amountConfig.amount).trim(true).toString()} FET - {" "} - on your behalf. -
- - - - -
-
- ); - } -); - -export const Bridge: FunctionComponent<{ - feeConfig: IFeeConfig; - gasConfig: IGasConfig; - bridgeAmount: string; - recipient: string; - currency: AppCurrency; -}> = observer(({ feeConfig, gasConfig, bridgeAmount, currency, recipient }) => { - const intl = useIntl(); - const isValid = feeConfig.error == null && gasConfig.error == null; - - const navigate = useNavigate(); - const notification = useNotification(); - - const { chainStore, priceStore, accountStore, analyticsStore } = useStore(); - - const bridgeGasSimulator = useGasSimulator( - new ExtensionKVStore("gas-simulator.native-bridge.bridge"), - chainStore, - chainStore.current.chainId, - gasConfig, - feeConfig, - "bridge", - () => { - return accountStore - .getAccount(chainStore.current.chainId) - .ethereum.makeNativeBridgeTx(bridgeAmount, recipient); - } - ); - - return ( -
-

Bridge

-
-

- Sending{" "} - - {new IntPretty(bridgeAmount).trim(true).toString()}{" "} - {currency.coinDenom} - {" "} - to {recipient} on Fetch - network. -

- - - -
-
- ); -}); diff --git a/packages/fetch-extension/src/pages/bridge/fetchhub-bridge.tsx b/packages/fetch-extension/src/pages/bridge/fetchhub-bridge.tsx deleted file mode 100644 index 98a2cc13f5..0000000000 --- a/packages/fetch-extension/src/pages/bridge/fetchhub-bridge.tsx +++ /dev/null @@ -1,258 +0,0 @@ -import React, { FunctionComponent } from "react"; -import { observer } from "mobx-react-lite"; -import { useNavigate } from "react-router"; - -import style from "./style.module.scss"; -import { Button } from "reactstrap"; -import { - AddressInput, - CoinInput, - FeeButtons, - Input, - MemoInput, -} from "@components/form"; -import { useGasSimulator, useNativeBridgeConfig } from "@keplr-wallet/hooks"; -import { useStore } from "../../stores"; -import { useNotification } from "@components/notification"; -import { FormattedMessage, useIntl } from "react-intl"; -import { ExtensionKVStore } from "@keplr-wallet/common"; - -export const FetchhubBridge: FunctionComponent<{ - limit: string; - fee?: string; -}> = observer(({ limit, fee }) => { - const navigate = useNavigate(); - const intl = useIntl(); - - const { - chainStore, - accountStore, - queriesStore, - keyRingStore, - analyticsStore, - priceStore, - } = useStore(); - const accountInfo = accountStore.getAccount(chainStore.current.chainId); - const notification = useNotification(); - - const nativeBridgeConfig = useNativeBridgeConfig( - chainStore, - queriesStore, - chainStore.current.chainId, - accountInfo.bech32Address - ); - const bridgeGasSimulator = useGasSimulator( - new ExtensionKVStore("gas-simulator.native-bridge.send"), - chainStore, - chainStore.current.chainId, - nativeBridgeConfig.gasConfig, - nativeBridgeConfig.feeConfig, - "bridge", - () => { - // Prefer not to use the gas config or fee config, - // because gas simulator can change the gas config and fee config from the result of reaction, - // and it can make repeated reaction. - if ( - nativeBridgeConfig.amountConfig.error != null || - nativeBridgeConfig.recipientConfig.error != null - ) { - throw new Error("Not ready to simulate tx"); - } - - return accountInfo.cosmwasm.makeNativeBridgeTx( - nativeBridgeConfig.amountConfig.amount, - nativeBridgeConfig.recipientConfig.recipient - ); - } - ); - - const isValid = - nativeBridgeConfig.recipientConfig.error == null && - nativeBridgeConfig.memoConfig.error == null && - nativeBridgeConfig.amountConfig.error == null && - nativeBridgeConfig.feeConfig.error == null && - nativeBridgeConfig.gasConfig.error == null; - - if (accountInfo.txTypeInProgress === "nativeBridgeSend") { - return ( -

- Bridging in progress {" "} -

- ); - } - - const onSubmit = async () => { - try { - analyticsStore.logEvent("bridge_txn_click", { - chainId: chainStore.current.chainId, - chainName: chainStore.current.chainName, - }); - const tx = accountInfo.cosmwasm.makeNativeBridgeTx( - nativeBridgeConfig.amountConfig.amount, - nativeBridgeConfig.recipientConfig.recipient - ); - - await tx.send( - nativeBridgeConfig.feeConfig.toStdFee(), - nativeBridgeConfig.memoConfig.memo, - { - preferNoSetFee: true, - preferNoSetMemo: true, - }, - { - onBroadcasted() { - navigate("/bridge"); - analyticsStore.logEvent("bridge_txn_broadcasted", { - chainId: chainStore.current.chainId, - chainName: chainStore.current.chainName, - feeType: nativeBridgeConfig.feeConfig.feeType, - }); - }, - onFulfill(tx) { - if (tx.code == null || tx.code === 0) { - notification.push({ - placement: "top-center", - type: "success", - duration: 2, - content: "Bridging Successful", - canDelete: true, - transition: { - duration: 0.25, - }, - }); - } else { - notification.push({ - placement: "top-center", - type: "danger", - duration: 2, - content: "Bridging Failed", - canDelete: true, - transition: { - duration: 0.25, - }, - }); - } - navigate("/"); - }, - } - ); - } catch (e) { - analyticsStore.logEvent("bridge_txn_broadcasted_fail", { - chainId: chainStore.current.chainId, - chainName: chainStore.current.chainName, - feeType: nativeBridgeConfig.feeConfig.feeType, - message: e?.message ?? "", - }); - navigate("/", { replace: true }); - notification.push({ - type: "warning", - placement: "top-center", - duration: 5, - content: `Fail to bridge token: ${e.message}`, - canDelete: true, - transition: { - duration: 0.25, - }, - }); - } - }; - - return ( -
-
- Native to ERC20 Limit: {limit} FET -
-
- - {keyRingStore.keyRingType !== "ledger" && ( -
{ - e.preventDefault(); - nativeBridgeConfig.recipientConfig.setRawRecipient( - accountStore.getAccount("1").ethereumHexAddress - ); - }} - > - Bridge to your Ethereum address:{" "} - {accountStore.getAccount("1").ethereumHexAddress} -
- )} - -
- - -
- {fee && ( -
- -
-
- )} - - - -
- - ); -}); diff --git a/packages/fetch-extension/src/pages/bridge/index.tsx b/packages/fetch-extension/src/pages/bridge/index.tsx deleted file mode 100644 index 1c7d35be78..0000000000 --- a/packages/fetch-extension/src/pages/bridge/index.tsx +++ /dev/null @@ -1,155 +0,0 @@ -import React, { FunctionComponent } from "react"; -import style from "./style.module.scss"; -import { useNavigate } from "react-router"; -import { observer } from "mobx-react-lite"; -import { useStore } from "../../stores"; -import { EthereumBridge } from "./ethereum-bridge"; -import { FetchhubBridge } from "./fetchhub-bridge"; -import { HeaderLayout } from "@layouts/header-layout"; -import { Dec, IntPretty } from "@keplr-wallet/unit"; -import { Button } from "reactstrap"; - -export const BridgePage: FunctionComponent = observer(() => { - const { chainStore, queriesStore, analyticsStore } = useStore(); - const navigate = useNavigate(); - - const bridgeEvmQuery = queriesStore.get(chainStore.current.chainId).evm - .queryNativeFetBridge; - const bridgeFetQuery = queriesStore.get(chainStore.current.chainId).cosmwasm - .queryNativeFetBridge; - - const isLoading = bridgeEvmQuery.isFetching || bridgeFetQuery.isFetching; - const isError = - bridgeEvmQuery.error || - bridgeFetQuery.error || - !bridgeEvmQuery.status || - !bridgeFetQuery.status; - const isPaused = - (bridgeEvmQuery.status?.paused ?? true) || - (bridgeFetQuery.status?.paused ?? true); - const isEvmCapReached = bridgeEvmQuery.status - ? new Dec(bridgeEvmQuery.status.supply).gte( - new Dec(bridgeEvmQuery.status.cap) - ) - : true; - const isFetCapReached = bridgeFetQuery.status - ? new Dec(bridgeFetQuery.status.supply).gte( - new Dec(bridgeFetQuery.status.cap) - ) - : true; - - const isEvm = chainStore.current.features?.includes("evm") ?? false; - return ( - { - analyticsStore.logEvent("back_click", { pageName: "Bridge" }); - navigate(-1); - }} - rightRenderer={ - - } - > - {isLoading ? ( -

- Fetching Bridge details {" "} -

- ) : isError ? ( -

- Error fetching bridge details, please try later{" "} -

- ) : isPaused ? ( -

- {" "} - Bridge is currently paused. Please try again later{" "} -

- ) : (!isEvm && isFetCapReached) || (isEvm && isEvmCapReached) ? ( -

- {" "} - Bridge cap reached. Please try again later{" "} -

- ) : isEvm ? ( -
- -
- ) : ( -
- -
- )} -
- ); -}); - -function minDec(...values: Dec[]): Dec { - const sorted = values.sort((lhs: Dec, rhs: Dec): number => { - if (lhs.gt(rhs)) { - return 1; - } else if (lhs.lt(rhs)) { - return -1; - } else { - return 0; - } - }); - - return sorted[0]; -} diff --git a/packages/fetch-extension/src/pages/bridge/style.module.scss b/packages/fetch-extension/src/pages/bridge/style.module.scss deleted file mode 100644 index fee8c7bd5e..0000000000 --- a/packages/fetch-extension/src/pages/bridge/style.module.scss +++ /dev/null @@ -1,167 +0,0 @@ -/// To add bottom space for send button -// .form-container { -// height: 100%; -// } - -.formInnerContainer { - height: 100%; - display: flex; - flex-direction: column; -} - -.chainSelector { - width: 100%; - height: 46px; - - button { - width: 100%; - } - - :global(.dropdown-menu.show) { - width: 100%; - } -} - -.alert { - display: flex; - border: solid 1px #9092b6; - background-color: #ffffff; - color: #32325d; - - i { - font-size: 24px; - margin-right: 8px; - } - - h1 { - font-size: 16px; - font-weight: bold; - color: #32325d; - margin-bottom: 4px; - } - - p { - font-size: 14px; - line-height: 1.57; - margin: 0; - } -} - -.bridgeLimit { - padding: 10px; - text-align: center; - background-color: rgb(223, 223, 223); - margin-bottom: 20px; -} - -.loaderScreen { - text-align: center; - position: relative; - top: 45%; -} - -.addressSelector { - overflow-wrap: anywhere; - font-size: small; - margin-top: -15px; - margin-bottom: 15px; - cursor: pointer; - text-decoration: underline; - color: #555555; -} - -.historyBtn { - display: flex; - align-items: center; - padding: 12px; - margin: 18px; -} - -.bHistory { - display: flex; - padding: 10px; - line-height: 20px; - justify-content: space-between; - margin: 12px 0; - background: #ffffff; - .hContent { - width: 83.5%; - .sId { - font-weight: 400; - font-size: 10px; - color: #808da0; - margin: 0; - line-height: 22px; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - } - - .hTitle { - font-weight: 400; - padding-bottom: 10px; - font-size: 16px; - color: #525f7f; - margin: 0; - line-height: 22px; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - margin-right: 10px; - &::first-letter { - text-transform: capitalize; - } - } - - .hDesc { - font-weight: 400; - font-size: 15px; - color: #808da0; - margin: 0; - line-height: 22px; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - } - } - - .hStatus { - display: flex; - width: 16.5%; - margin-top: 2px; - position: relative; - } - - .statusButton { - display: flex; - padding: 3px; - - .ethLogo { - height: 20px; - display: flex; - margin-right: 1px; - } - - .fetLogo { - height: 15px; - display: flex; - margin: 2px 4px 0 2px; - } - - .status { - display: flex; - height: 20px; - } - } - - .arrowIcon { - transform: rotate(90deg); - margin: -5px 0 0 15px; - } -} - -.refresh { - height: 20px; - margin: 22px; - cursor: pointer; -} diff --git a/packages/fetch-extension/src/pages/ibc-transfer/style.module.scss b/packages/fetch-extension/src/pages/ibc-transfer/style.module.scss deleted file mode 100644 index b4ed52268f..0000000000 --- a/packages/fetch-extension/src/pages/ibc-transfer/style.module.scss +++ /dev/null @@ -1,48 +0,0 @@ -/// To add bottom space for send button -// .form-container { -// height: 100%; -// } - -.formInnerContainer { - height: 100%; - display: flex; - flex-direction: column; -} - -.chainSelector { - width: 100%; - height: 46px; - - button { - width: 100%; - } - - :global(.dropdown-menu.show) { - width: 100%; - } -} - -.alert { - display: flex; - border: solid 1px #9092b6; - background-color: #ffffff; - color: #32325d; - - i { - font-size: 24px; - margin-right: 8px; - } - - h1 { - font-size: 16px; - font-weight: bold; - color: #32325d; - margin-bottom: 4px; - } - - p { - font-size: 14px; - line-height: 1.57; - margin: 0; - } -} diff --git a/packages/fetch-extension/src/pages/lock/index.tsx b/packages/fetch-extension/src/pages/lock/index.tsx deleted file mode 100644 index b2bc23a9d8..0000000000 --- a/packages/fetch-extension/src/pages/lock/index.tsx +++ /dev/null @@ -1,114 +0,0 @@ -import React, { FunctionComponent, useState } from "react"; - -import { PasswordInput } from "@components/form"; - -import { Button, Form } from "reactstrap"; - -import { observer } from "mobx-react-lite"; -import { useStore } from "../../stores"; -import { Banner } from "@components/banner"; -import { useForm } from "react-hook-form"; - -import { EmptyLayout } from "@layouts/empty-layout"; - -import style from "./style.module.scss"; - -import { FormattedMessage, useIntl } from "react-intl"; -import { useInteractionInfo } from "@keplr-wallet/hooks"; -import { useNavigate } from "react-router"; -import delay from "delay"; -import { StartAutoLockMonitoringMsg } from "@keplr-wallet/background"; -import { InExtensionMessageRequester } from "@keplr-wallet/router-extension"; -import { BACKGROUND_PORT } from "@keplr-wallet/router"; - -interface FormData { - password: string; -} - -export const LockPage: FunctionComponent = observer(() => { - const intl = useIntl(); - const navigate = useNavigate(); - - const { - register, - handleSubmit, - setError, - formState: { errors }, - } = useForm({ - defaultValues: { - password: "", - }, - }); - - const { keyRingStore, analyticsStore } = useStore(); - const [loading, setLoading] = useState(false); - - const interactionInfo = useInteractionInfo(() => { - keyRingStore.rejectAll(); - }); - - return ( - -
{ - setLoading(true); - try { - await keyRingStore.unlock(data.password); - - const msg = new StartAutoLockMonitoringMsg(); - const requester = new InExtensionMessageRequester(); - // Make sure to notify that auto lock service to start check locking after duration. - await requester.sendMessage(BACKGROUND_PORT, msg); - analyticsStore.logEvent("sign_in_click", { message: "success" }); - if (interactionInfo.interaction) { - if (!interactionInfo.interactionInternal) { - // XXX: If the connection doesn't have the permission, - // permission service tries to grant the permission right after unlocking. - // Thus, due to the yet uncertain reason, it requests new interaction for granting permission - // before the `window.close()`. And, it could make the permission page closed right after page changes. - // Unfortunately, I still don't know the exact cause. - // Anyway, for now, to reduce this problem, jsut wait small time, and close the window only if the page is not changed. - await delay(100); - if (window.location.href.includes("#/unlock")) { - window.close(); - } - } else { - navigate("/", { replace: true }); - } - } - } catch (e) { - analyticsStore.logEvent("sign_in_click", { message: "fail" }); - - console.log("Fail to decrypt: " + e.message); - setError("password", { - message: intl.formatMessage({ - id: "lock.input.password.error.invalid", - }), - }); - setLoading(false); - } - })} - > - - - - -
- ); -}); diff --git a/packages/fetch-extension/src/pages/lock/style.module.scss b/packages/fetch-extension/src/pages/lock/style.module.scss deleted file mode 100644 index 2e1508a39a..0000000000 --- a/packages/fetch-extension/src/pages/lock/style.module.scss +++ /dev/null @@ -1,9 +0,0 @@ -.formContainer { - display: flex; - flex-direction: column; - height: 100%; -} - -.capslockTooltipArrow { - left: 10px !important; -} diff --git a/packages/fetch-extension/src/pages/proposals/index.tsx b/packages/fetch-extension/src/pages/proposals/index.tsx deleted file mode 100644 index 10d67f8c7d..0000000000 --- a/packages/fetch-extension/src/pages/proposals/index.tsx +++ /dev/null @@ -1,215 +0,0 @@ -import { HeaderLayout } from "@layouts/header-layout"; -import React, { Fragment, FunctionComponent, useEffect, useState } from "react"; -import { useNavigate } from "react-router"; -import { SearchInput } from "@components/notification-search-input"; -import { GovStatusChip } from "@components/chips/gov-chip"; -import style from "./style.module.scss"; -import { Proposal } from "@components/proposal/proposal"; -import { fetchProposals, fetchVote } from "@utils/fetch-proposals"; -import { ProposalType } from "src/@types/proposal-type"; -import { useStore } from "../../stores"; -import { FormattedMessage, useIntl } from "react-intl"; - -export const proposalOptions = { - ProposalActive: "PROPOSAL_STATUS_VOTING_PERIOD", - ProposalPassed: "PROPOSAL_STATUS_PASSED", - ProposalRejected: "PROPOSAL_STATUS_REJECTED", - ProposalFailed: "PROPOSAL_STATUS_FAILED", -}; - -export const Proposals: FunctionComponent = () => { - const navigate = useNavigate(); - const intl = useIntl(); - const [inputVal, setInputVal] = useState(""); - const [selectedIndex, setSelectedIndex] = useState(0); - - const [isLoading, setIsLoading] = useState(false); - const { chainStore, accountStore, analyticsStore, proposalStore } = - useStore(); - const accountInfo = accountStore.getAccount(chainStore.current.chainId); - const [proposals, setProposals] = useState([]); - const storedProposals = proposalStore.proposals; - useEffect(() => { - if (storedProposals.closedProposals.length === 0) { - setIsLoading(true); - } - (async () => { - try { - const response = await fetchProposals(chainStore.current.chainId); - const votedProposals: ProposalType[] = []; - const allProposals = response.proposals.reverse(); - let activeProposals = allProposals.filter((proposal: ProposalType) => { - return proposal.status === proposalOptions.ProposalActive; - }); - - const promises = activeProposals.map(async (proposal: ProposalType) => { - try { - const vote = await fetchVote( - proposal.proposal_id, - accountInfo.bech32Address, - chainStore.current.rest - ); - if (vote.vote.option && vote.vote.option != "Unspecified") - return proposal.proposal_id; - } catch (e) {} - }); - const voteArray = await Promise.all(promises); - - activeProposals = activeProposals.filter((proposal: ProposalType) => { - if (voteArray.indexOf(proposal.proposal_id) != -1) { - votedProposals.push(proposal); - return false; - } - return true; - }); - const closedProposals = allProposals.filter( - (proposal: ProposalType) => { - return ( - proposal.status === proposalOptions.ProposalPassed || - proposal.status === proposalOptions.ProposalRejected || - proposal.status === proposalOptions.ProposalFailed - ); - } - ); - setIsLoading(false); - proposalStore.setProposalsInStore({ - activeProposals, - closedProposals, - votedProposals, - allProposals, - }); - - if (selectedIndex === 1) { - setProposals(activeProposals); - return; - } - if (selectedIndex === 2) { - setProposals(closedProposals); - return; - } - - if (selectedIndex === 3) { - setProposals(votedProposals); - return; - } - - setProposals(allProposals); - } catch (e) {} - })(); - }, []); - - useEffect(() => { - let newProposal: ProposalType[]; - - if (selectedIndex === 1) { - newProposal = storedProposals.activeProposals; - } else if (selectedIndex === 2) { - newProposal = storedProposals.closedProposals; - } else if (selectedIndex === 3) { - newProposal = storedProposals.votedProposals; - } else { - newProposal = storedProposals.allProposals; - } - - newProposal = newProposal.filter((proposal: ProposalType) => { - if ( - proposal.content.title - .toLowerCase() - .includes(inputVal.trim().toLowerCase()) || - proposal.proposal_id.includes(inputVal) - ) - return true; - }); - - setProposals(newProposal); - }, [selectedIndex, inputVal]); - const handleCheck = (id: number) => { - if (isLoading) return; - - if (selectedIndex === id) { - setSelectedIndex(0); - return; - } - setSelectedIndex(id); - }; - return ( - { - analyticsStore.logEvent("back_click", { pageName: "Proposals" }); - navigate(-1); - }} - showBottomMenu={false} - > - {}} - searchTitle="Search by title or Proposal ID" - /> - { - handleCheck(id); - analyticsStore.logEvent("active_tab_click"); - }} - filter={true} - /> - { - handleCheck(id); - analyticsStore.logEvent("voted_tab_click"); - }} - filter={true} - /> - { - handleCheck(id); - analyticsStore.logEvent("closed_tab_click"); - }} - filter={true} - /> - -
- {isLoading ? ( -
- -
- ) : proposals.length === 0 ? ( -
-

- - {inputVal !== "" && ( - -
- -
- )} -

-
- ) : ( - proposals.map((proposal: any) => ( - - )) - )} -
-
- ); -}; diff --git a/packages/fetch-extension/src/pages/proposals/proposal-detail/index.tsx b/packages/fetch-extension/src/pages/proposals/proposal-detail/index.tsx deleted file mode 100644 index 6f0dbc3d33..0000000000 --- a/packages/fetch-extension/src/pages/proposals/proposal-detail/index.tsx +++ /dev/null @@ -1,303 +0,0 @@ -import { HeaderLayout } from "@layouts/header-layout"; -import React, { useEffect, useState, Fragment } from "react"; -import { FunctionComponent } from "react"; -import { useNavigate, useParams } from "react-router"; -import style from "./style.module.scss"; -import { Button } from "reactstrap"; -import { ProposalSetup, ProposalType } from "src/@types/proposal-type"; -import { VoteBlock } from "@components/proposal/vote-block"; -import moment from "moment"; -import { useStore } from "../../../stores"; -import { useNotification } from "@components/notification"; -import classNames from "classnames"; -import { proposalOptions } from "../index"; -import { FormattedMessage, useIntl } from "react-intl"; -import ReactMarkdown from "react-markdown"; -import remarkGfm from "remark-gfm"; - -const voteArr = ["Unspecified", "Yes", "Abstain", "No", "NoWithVeto"]; - -export const ProposalDetail: FunctionComponent = () => { - const navigate = useNavigate(); - const notification = useNotification(); - const intl = useIntl(); - const { chainStore, accountStore, analyticsStore, proposalStore } = - useStore(); - const { id } = useParams<{ id?: string }>(); - const [proposal, setProposal] = useState(); - const [votedOn, setVotedOn] = useState(0); - const [isLoading, setIsLoading] = useState(true); - const [closed, setClosed] = useState(true); - const [isSendingTx, setIsSendingTx] = useState(false); - const storedProposals: ProposalSetup = proposalStore.proposals; - const [category, setCategory] = useState(1); - const current = chainStore.current; - const accountInfo = accountStore.getAccount(current.chainId); - useEffect(() => { - let proposalItem = storedProposals.activeProposals.find( - (proposal) => proposal.proposal_id === id - ); - if (!proposalItem) { - proposalItem = storedProposals.closedProposals.find( - (proposal) => proposal.proposal_id === id - ); - } - if (!proposalItem) { - proposalItem = storedProposals.votedProposals.find( - (proposal) => proposal.proposal_id === id - ); - } - setIsLoading(false); - setProposal(proposalItem); - const cat = storedProposals.votedProposals.find( - (proposal) => proposal.proposal_id === id - ) - ? 3 - : proposalItem?.status === proposalOptions.ProposalRejected || - proposalItem?.status === proposalOptions.ProposalPassed || - proposalItem?.status === proposalOptions.ProposalFailed - ? 2 - : 1; - setCategory(cat); - }, [id]); - - useEffect(() => { - const date = new Date(); - if ( - proposal && - moment(proposal?.voting_end_time).valueOf() > date.getTime() - ) { - setClosed(false); - } - }, [proposal]); - const handleClick = async () => { - const vote: any = voteArr[votedOn]; - if (!proposal) return; - if (vote !== "Unspecified" && accountInfo.isReadyToSendTx) { - analyticsStore.logEvent("vote_txn_click", { - action: vote, - }); - const tx = accountInfo.cosmos.makeGovVoteTx(proposal?.proposal_id, vote); - setIsSendingTx(true); - try { - let gas = accountInfo.cosmos.msgOpts.govVote.gas; - - // Gas adjustment is 1.5 - // Since there is currently no convenient way to adjust the gas adjustment on the UI, - // Use high gas adjustment to prevent failure. - try { - gas = (await tx.simulate()).gasUsed * 1.5; - } catch (e) { - // Some chain with older version of cosmos sdk (below @0.43 version) can't handle the simulation. - // Therefore, the failure is expected. If the simulation fails, simply use the default value. - console.log(e); - } - - await tx.send( - { amount: [], gas: gas.toString() }, - "", - {}, - { - onBroadcasted: () => { - analyticsStore.logEvent("vote_txn_broadcasted", { - chainId: chainStore.current.chainId, - chainName: chainStore.current.chainName, - }); - }, - } - ); - - navigate(`/proposal-vote-status/${votedOn}/${id}`, { replace: true }); - } catch (e: any) { - analyticsStore.logEvent("vote_txn_broadcasted_fail", { - chainId: chainStore.current.chainId, - chainName: chainStore.current.chainName, - message: e?.message ?? "", - }); - console.log(e); - if (e?.message === "Request rejected") { - notification.push({ - type: "warning", - placement: "top-center", - duration: 5, - content: `Failed to vote: ${e.message}`, - canDelete: true, - transition: { - duration: 0.25, - }, - }); - navigate("/", { replace: true }); - return; - } - notification.push({ - type: "warning", - placement: "top-center", - duration: 5, - content: `Failed to vote: ${e.message}`, - canDelete: true, - transition: { - duration: 0.25, - }, - }); - navigate(-2); - navigate(`/proposal?id=${category}`, { replace: true }); - } finally { - setIsSendingTx(false); - } - } - }; - - const handleVoteClick = (id: number) => { - if (closed) { - return; - } - setVotedOn(id); - }; - - return ( - { - analyticsStore.logEvent("back_click", { pageName: "Proposal Detail" }); - navigate(-1); - }} - showBottomMenu={false} - > -
- {isLoading ? ( -
- -
- ) : ( - -
-
-

{proposal?.content.title}

-

{proposal?.proposal_id}

-
-
-
-

- -

-

- {moment(proposal?.voting_start_time) - .utc() - .format("ddd, DD MMM YYYY hh:mm:ss ")} - GMT -

-
-
-

- -

-

- {moment(proposal?.voting_end_time) - .utc() - .format("ddd, DD MMM YYYY hh:mm:ss ")} - GMT -

-
-
-

- {proposal && ( - - {proposal.content.description} - - )} -

-
- -
-

{ - if (chainStore.current.govUrl) { - analyticsStore.logEvent( - "proposal_view_in_block_explorer_click" - ); - window.open(`${chainStore.current.govUrl}${id}`, "_blank"); - } - }} - > - - -

-
- - {!closed && ( -
-
- - - - - - - -
- -
- )} -
- )} -
-
- ); -}; diff --git a/packages/fetch-extension/src/pages/proposals/proposal-detail/style.module.scss b/packages/fetch-extension/src/pages/proposals/proposal-detail/style.module.scss deleted file mode 100644 index dbae3b5cf8..0000000000 --- a/packages/fetch-extension/src/pages/proposals/proposal-detail/style.module.scss +++ /dev/null @@ -1,121 +0,0 @@ -.pContentScroll { - max-height: 55vh; - overflow-y: scroll; - overflow-x: hidden; - - .pHeading { - display: flex; - justify-content: space-between; - - .pTitle { - font-weight: 600; - font-size: 20px; - line-height: 100%; - margin-bottom: 8px; - color: #525f7f; - &::first-letter { - text-transform: capitalize; - } - } - - .pId { - font-weight: 400; - font-size: 14px; - margin: -5px 0 0; - color: #525f7f; - } - } - - .pDesc { - font-size: 14px; - line-height: 20px; - margin-bottom: 8px; - color: #525f7f; - - .pAnchor { - text-decoration: underline; - } - } -} - -.closed { - max-height: 100%; -} - -.pLinkContainer { - margin-top: 8px; - - .pLink { - color: #3b82f6; - font-weight: 700; - font-size: 16px; - line-height: 22px; - text-align: center; - text-decoration-line: underline; - cursor: pointer; - margin: auto 0; - } -} - -.pVotingDate { - margin: 8px 0; - display: flex; - justify-content: space-between; - - .pVotingHead { - font-weight: 600; - color: #525f7f; - line-height: 16px; - font-size: 14px; - margin: 0 0 4px; - } - - .pVotingEnd { - font-weight: 400; - color: #525f7f; - line-height: 16px; - font-size: 14px; - } -} - -.voteContainer { - display: grid; - grid-template-columns: 1fr 1fr; - gap: 10px; - margin-top: auto; -} - -.endBody { - margin-top: auto; -} - -.button { - padding: 8px; - color: #fff; - text-align: center; - background-color: #3b82f6; - border: 1px solid #3b82f6; - border-radius: 4px; - flex-direction: row; - justify-content: center; - align-items: center; - font-size: 0.875rem; - line-height: 19px; - display: flex; - width: 100%; - margin: 16px 0 0; -} - -.pContainer { - height: 100%; - display: flex; - flex-direction: column; - padding: 0 4px; - - .isLoading { - display: flex; - justify-content: center; - align-items: center; - height: 60vh; - } -} diff --git a/packages/fetch-extension/src/pages/proposals/proposal-vote-status/index.tsx b/packages/fetch-extension/src/pages/proposals/proposal-vote-status/index.tsx deleted file mode 100644 index 3097817fa3..0000000000 --- a/packages/fetch-extension/src/pages/proposals/proposal-vote-status/index.tsx +++ /dev/null @@ -1,117 +0,0 @@ -import { HeaderLayout } from "@layouts/header-layout"; -import React, { FunctionComponent, useEffect, useState } from "react"; -import { useLocation, useNavigate, useParams } from "react-router"; -import { Button } from "reactstrap"; -import { ProposalSetup, ProposalType } from "src/@types/proposal-type"; -import style from "./style.module.scss"; -import classNames from "classnames"; -import { FormattedMessage, useIntl } from "react-intl"; -import { useStore } from "../../../stores"; -export const PropsalVoteStatus: FunctionComponent = () => { - const navigate = useNavigate(); - const location = useLocation(); - const { proposalStore, analyticsStore } = useStore(); - - const intl = useIntl(); - const { votedOn, id } = useParams<{ votedOn?: string; id?: string }>(); - const [proposal, setProposal] = useState(); - const storedProposals: ProposalSetup = proposalStore.proposals; - let icon: string; - let color: string; - let text: string; - - switch (votedOn) { - case "1": - icon = "gov-tick.svg"; - text = "Yes"; - color = "#6AB77A"; - break; - case "2": - icon = "gov-abstain.svg"; - text = "Abstain"; - color = "#ECAA5D"; - break; - case "3": - icon = "gov-cross-2.svg"; - text = "No"; - color = "#DC6461"; - break; - default: - icon = "gov-no-veto.svg"; - text = "No with veto"; - color = "#3E64C4"; - } - useEffect(() => { - let proposalItem = storedProposals.activeProposals.find( - (proposal) => proposal.proposal_id === id - ); - if (!proposalItem) { - proposalItem = storedProposals.closedProposals.find( - (proposal) => proposal.proposal_id === id - ); - } - if (!proposalItem) { - proposalItem = storedProposals.votedProposals.find( - (proposal) => proposal.proposal_id === id - ); - } - setProposal(proposalItem); - }, [id]); - - const handleReturnHome = () => { - navigate("/", { replace: true }); - }; - const handleChangeVote = () => { - if (location.search === "?true") { - navigate(`/proposal-detail/${id}`, { replace: true }); - return; - } - navigate(-1); - }; - return ( - { - analyticsStore.logEvent("back_click", { pageName: "Proposal Detail" }); - navigate(-1); - }} - showBottomMenu={false} - > -
-
-

{proposal?.content.title}

- {"Proposal_icon"} -

- {`Voted ${text}`} -

-
-
- - -
-
-
- ); -}; diff --git a/packages/fetch-extension/src/pages/proposals/proposal-vote-status/style.module.scss b/packages/fetch-extension/src/pages/proposals/proposal-vote-status/style.module.scss deleted file mode 100644 index 0004125776..0000000000 --- a/packages/fetch-extension/src/pages/proposals/proposal-vote-status/style.module.scss +++ /dev/null @@ -1,64 +0,0 @@ -.pButtonContainer { - .button { - width: 100%; - padding: 8px; - color: #fff; - text-align: center; - border: 1px solid #3b82f6; - border-radius: 4px; - flex-direction: row; - justify-content: center; - align-items: center; - font-size: 0.875rem; - line-height: 19px; - display: flex; - margin: 8px 0 0; - } - - .invertedButton { - color: #3b82f6; - border: 1px solid #3b82f6; - width: 100%; - padding: 8px; - &:hover { - background-color: #3b82f6; - color: #fff; - } - } -} - -.pContainer { - height: 100%; - display: flex; - flex-direction: column; - - .pCenter { - display: flex; - flex-direction: column; - margin: auto; - - .pImage { - height: 160px; - width: 160px; - margin: 0 auto; - } - - .pTitle { - color: #525f7f; - font-weight: 700; - font-size: 20px; - line-height: 100%; - text-align: center; - &::first-letter { - text-transform: capitalize; - } - } - .voteText { - text-align: center; - font-weight: 700; - font-size: 22px; - line-height: 30px; - margin-top: 8px; - } - } -} diff --git a/packages/fetch-extension/src/pages/proposals/style.module.scss b/packages/fetch-extension/src/pages/proposals/style.module.scss deleted file mode 100644 index 807f658986..0000000000 --- a/packages/fetch-extension/src/pages/proposals/style.module.scss +++ /dev/null @@ -1,31 +0,0 @@ -.isLoading { - display: flex; - justify-content: center; - align-items: center; - height: 60vh; -} - -.proposalContainer { - margin-top: 16px; - padding: 0 8px; - height: 380px; - overflow: scroll; - border: 1px solid #e5e7e6; - border-radius: 8px; - - .resultText { - color: #808da0; - font-weight: 400; - font-size: 15px; - margin: auto; - height: 100%; - display: flex; - flex-direction: column; - justify-content: center; - - p { - margin: 0; - text-align: center; - } - } -} diff --git a/packages/fetch-extension/src/pages/register/advanced-bip44.tsx b/packages/fetch-extension/src/pages/register/advanced-bip44.tsx deleted file mode 100644 index 7f96c5aaf6..0000000000 --- a/packages/fetch-extension/src/pages/register/advanced-bip44.tsx +++ /dev/null @@ -1,239 +0,0 @@ -import React, { FunctionComponent, useState } from "react"; -import { Button, FormGroup, Input, Label } from "reactstrap"; -import { useConfirm } from "@components/confirm"; -import { FormattedMessage, useIntl } from "react-intl"; -import { action, computed, makeObservable, observable } from "mobx"; -import { observer } from "mobx-react-lite"; -import { BIP44HDPath } from "@keplr-wallet/background"; - -export class BIP44Option { - @observable - protected _coinType?: number; - - @observable - protected _account: number = 0; - - @observable - protected _change: number = 0; - - @observable - protected _index: number = 0; - - constructor(coinType?: number) { - this._coinType = coinType; - - makeObservable(this); - } - - get coinType(): number | undefined { - return this._coinType; - } - - get account(): number { - return this._account; - } - - get change(): number { - return this._change; - } - - get index(): number { - return this._index; - } - - @computed - get bip44HDPath(): BIP44HDPath { - return { - account: this.account, - change: this.change, - addressIndex: this.index, - }; - } - - @action - setCoinType(coinType: number | undefined) { - this._coinType = coinType; - } - - @action - setAccount(account: number) { - this._account = account; - } - - @action - setChange(change: number) { - this._change = change; - } - - @action - setIndex(index: number) { - this._index = index; - } -} - -// CONTRACT: Use with `observer` -export const useBIP44Option = (coinType?: number) => { - const [bip44Option] = useState(() => new BIP44Option(coinType)); - - return bip44Option; -}; - -export const AdvancedBIP44Option: FunctionComponent<{ - bip44Option: BIP44Option; -}> = observer(({ bip44Option }) => { - const intl = useIntl(); - - const confirm = useConfirm(); - - const [isOpen, setIsOpen] = useState( - bip44Option.account !== 0 || - bip44Option.change !== 0 || - bip44Option.index !== 0 - ); - const toggleOpen = async () => { - if (isOpen) { - if ( - await confirm.confirm({ - paragraph: intl.formatMessage({ - id: "register.bip44.confirm.clear", - }), - }) - ) { - setIsOpen(false); - bip44Option.setAccount(0); - bip44Option.setChange(0); - bip44Option.setIndex(0); - } - } else { - setIsOpen(true); - } - }; - - return ( - - - {isOpen ? ( - - -
-
{`m/44'/${ - bip44Option.coinType != null ? bip44Option.coinType : "···" - }'/`}
- { - e.preventDefault(); - - let value = e.target.value; - if (value) { - if (value !== "0") { - // Remove leading zeros - for (let i = 0; i < value.length; i++) { - if (value[i] === "0") { - value = value.replace("0", ""); - } else { - break; - } - } - } - const parsed = parseFloat(value); - // Should be integer and positive. - if (Number.isInteger(parsed) && parsed >= 0) { - bip44Option.setAccount(parsed); - } - } else { - bip44Option.setAccount(0); - } - }} - /> -
{`'/`}
- { - e.preventDefault(); - - let value = e.target.value; - if (value) { - if (value !== "0") { - // Remove leading zeros - for (let i = 0; i < value.length; i++) { - if (value[i] === "0") { - value = value.replace("0", ""); - } else { - break; - } - } - } - const parsed = parseFloat(value); - // Should be integer and positive. - if ( - Number.isInteger(parsed) && - (parsed === 0 || parsed === 1) - ) { - bip44Option.setChange(parsed); - } - } else { - bip44Option.setChange(0); - } - }} - /> -
/
- { - e.preventDefault(); - - let value = e.target.value; - if (value) { - if (value !== "0") { - // Remove leading zeros - for (let i = 0; i < value.length; i++) { - if (value[i] === "0") { - value = value.replace("0", ""); - } else { - break; - } - } - } - const parsed = parseFloat(value); - // Should be integer and positive. - if (Number.isInteger(parsed) && parsed >= 0) { - bip44Option.setIndex(parsed); - } - } else { - bip44Option.setIndex(0); - } - }} - /> -
-
- ) : null} -
- ); -}); diff --git a/packages/fetch-extension/src/pages/register/auth/cosmos-rpc.ts b/packages/fetch-extension/src/pages/register/auth/cosmos-rpc.ts deleted file mode 100644 index ab6813d5a4..0000000000 --- a/packages/fetch-extension/src/pages/register/auth/cosmos-rpc.ts +++ /dev/null @@ -1,103 +0,0 @@ -import type { SafeEventEmitterProvider } from "@web3auth/base"; -import { SigningStargateClient, StargateClient } from "@cosmjs/stargate"; -import { - DirectSecp256k1Wallet, - OfflineDirectSigner, -} from "@cosmjs/proto-signing"; - -const rpc = "https://rpc.sentry-02.theta-testnet.polypore.xyz"; -// eslint-disable-next-line import/no-default-export -export default class CosmosRpc { - private provider: SafeEventEmitterProvider; - - constructor(provider: SafeEventEmitterProvider) { - this.provider = provider; - } - - async getChainId(): Promise { - try { - const client = await StargateClient.connect(rpc); - - // Get the connected Chain's ID - const chainId = await client.getChainId(); - - return chainId.toString(); - } catch (error) { - return error as string; - } - } - - async getAccounts(): Promise { - try { - const privateKey = Buffer.from(await this.getPrivateKey(), "hex"); - const walletPromise = await DirectSecp256k1Wallet.fromKey( - privateKey, - "cosmos" - ); - return (await walletPromise.getAccounts())[0].address; - } catch (error) { - return error; - } - } - - async getBalance(): Promise { - try { - const client = await StargateClient.connect(rpc); - - const privateKey = Buffer.from(await this.getPrivateKey(), "hex"); - const walletPromise = await DirectSecp256k1Wallet.fromKey( - privateKey, - "cosmos" - ); - const address = (await walletPromise.getAccounts())[0].address; - // Get user's balance in uAtom - return await client.getAllBalances(address); - } catch (error) { - return error as string; - } - } - - async sendTransaction( - fromAddress: string, - destination: string - ): Promise { - try { - await StargateClient.connect(rpc); - const privateKey = Buffer.from(await this.getPrivateKey(), "hex"); - const getSignerFromKey = async (): Promise => { - return DirectSecp256k1Wallet.fromKey(privateKey, "cosmos"); - }; - const signer: OfflineDirectSigner = await getSignerFromKey(); - - const signingClient = await SigningStargateClient.connectWithSigner( - rpc, - signer - ); - - const result = await signingClient.sendTokens( - fromAddress, - destination, - [{ denom: "uatom", amount: "250" }], - { - amount: [{ denom: "uatom", amount: "250" }], - gas: "100000", - } - ); - const transactionHash = result.transactionHash; - const height = result.height; - return { transactionHash, height }; - } catch (error) { - return error as string; - } - } - - async getPrivateKey(): Promise { - try { - return await this.provider.request({ - method: "private_key", - }); - } catch (error) { - return error as string; - } - } -} diff --git a/packages/fetch-extension/src/pages/register/auth/image.tsx b/packages/fetch-extension/src/pages/register/auth/image.tsx deleted file mode 100644 index 59db688fdc..0000000000 --- a/packages/fetch-extension/src/pages/register/auth/image.tsx +++ /dev/null @@ -1,26 +0,0 @@ -import React from "react"; - -export interface ImageProps { - hoverImageId?: string; - imageId: string; - isButton?: boolean; - height?: string; - width?: string; - image: string; -} - -export const Image = (props: ImageProps) => { - const { imageId, height = "auto", width = "auto", image } = props; - - return ( - - {imageId} - - ); -}; diff --git a/packages/fetch-extension/src/pages/register/auth/index.tsx b/packages/fetch-extension/src/pages/register/auth/index.tsx deleted file mode 100644 index abc0222acc..0000000000 --- a/packages/fetch-extension/src/pages/register/auth/index.tsx +++ /dev/null @@ -1,281 +0,0 @@ -import React, { FunctionComponent, useEffect, useState } from "react"; -import { Web3AuthNoModal as Web3Auth } from "@web3auth/no-modal"; -import { CommonPrivateKeyProvider } from "@web3auth/base-provider"; -import { CHAIN_NAMESPACES, WALLET_ADAPTERS } from "@web3auth/base"; -import { - OPENLOGIN_NETWORK, - OpenloginAdapter, -} from "@web3auth/openlogin-adapter"; -import style from "./style.module.scss"; -import { Image } from "./image"; -import classNames from "classnames"; -import { RegisterConfig } from "@keplr-wallet/hooks"; -import { observer } from "mobx-react-lite"; -import CosmosRpc from "./cosmos-rpc"; -import { Button, Form } from "reactstrap"; -import { FormattedMessage, useIntl } from "react-intl"; -import { BackButton } from ".."; -import { useForm } from "react-hook-form"; -import { Input, PasswordInput } from "@components/form"; -// eslint-disable-next-line import/no-extraneous-dependencies -import { AuthApiKey } from "../../../config.ui"; -import { useStore } from "../../../stores"; -// get from https://dashboard.web3auth.io - -export const AuthIntro: FunctionComponent<{ - registerConfig: RegisterConfig; -}> = observer(({ registerConfig }) => { - const { analyticsStore } = useStore(); - - const [web3auth, setWeb3auth] = useState(null); - const isEnvDevelopment = process.env.NODE_ENV !== "production"; - useEffect(() => { - if (!AuthApiKey) return; - const init = async () => { - try { - const chainConfig = { - chainNamespace: CHAIN_NAMESPACES.OTHER, - chainId: "fetchhub-4", - rpcTarget: "https://rpc-fetchhub.fetch-ai.com", - displayName: "fetch", - blockExplorer: "https://explore.fetch.ai/", - ticker: "FET", - tickerName: "Fetch Token", - }; - const web3auth = new Web3Auth({ - clientId: AuthApiKey, - chainConfig, - web3AuthNetwork: isEnvDevelopment - ? OPENLOGIN_NETWORK.TESTNET - : OPENLOGIN_NETWORK.CYAN, - }); - setWeb3auth(web3auth); - const privateKeyProvider = new CommonPrivateKeyProvider({ - config: { chainConfig }, - }); - const openloginAdapter = new OpenloginAdapter({ privateKeyProvider }); - web3auth.configureAdapter(openloginAdapter); - - await web3auth.init(); - } catch (error) { - console.error(error); - } - }; - - init(); - }, []); - - const login = async () => { - if (!web3auth) { - return; - } - return await web3auth.connectTo(WALLET_ADAPTERS.OPENLOGIN, { - loginProvider: "google", - }); - }; - - const logout = async () => { - if (!web3auth) { - return; - } - await web3auth.logout(); - }; - const getPrivateKey = async (provider: any) => { - if (!provider) { - return ""; - } - const rpc = new CosmosRpc(provider); - return await rpc.getPrivateKey(); - }; - - const getUserInfo = async () => { - if (!web3auth) { - return; - } - const user = await web3auth.getUserInfo(); - return user.email; - }; - - const imageId = `login-google-light`; - const hoverImage = `login-google-active`; - const [image, setImage] = useState(`login-google-light`); - return ( - - {AuthApiKey && ( -
setImage("login-google-active")} - onMouseLeave={() => setImage("login-google-light")} - onClick={async (e) => { - e.preventDefault(); - const target = e.target as HTMLElement; - if (target.tagName === "A") { - const url = target.getAttribute("href"); - if (url) { - window.open(url, "_blank"); // Open the URL in a new window - } - return; - } - try { - const data = await login(); - const privateKey = await getPrivateKey(data); - if (!privateKey) return; - registerConfig.setType("auth"); - registerConfig.setPrivateKey(privateKey); - const email = await getUserInfo(); - registerConfig.setEmail(email || ""); - await logout(); - } catch (e) { - } finally { - analyticsStore.logEvent("continue_with_google_click", { - registerType: "google", - }); - } - }} - > - -
- )} -
- ); -}); - -interface FormData { - name: string; - words: string; - password: string; - confirmPassword: string; -} -export const AuthPage: FunctionComponent<{ - registerConfig: RegisterConfig; -}> = observer(({ registerConfig }) => { - const intl = useIntl(); - const { analyticsStore } = useStore(); - - const { - register, - getValues, - handleSubmit, - formState: { errors }, - } = useForm({ - defaultValues: { - name: "", - password: "", - confirmPassword: "", - }, - }); - const privateKey = Buffer.from( - registerConfig.privateKey.trim().replace("0x", ""), - "hex" - ); - return ( - -
{ - registerConfig.createPrivateKey( - data.name, - privateKey, - data.password, - { email: registerConfig.email } - ); - analyticsStore.logEvent("register_next_click", { - registerType: "google", - }); - })} - > - - {registerConfig.mode === "create" ? ( - - { - if (password.length < 8) { - return intl.formatMessage({ - id: "register.create.input.password.error.too-short", - }); - } - }, - })} - error={errors.password && errors.password.message} - /> - { - if (confirmPassword !== getValues()["password"]) { - return intl.formatMessage({ - id: "register.create.input.confirm-password.error.unmatched", - }); - } - }, - })} - error={errors.confirmPassword && errors.confirmPassword.message} - /> - - ) : null} - -
- { - registerConfig.clear(); - analyticsStore.logEvent("back_click", { pageName: "Register" }); - }} - /> -
- ); -}); - -// eslint-disable-next-line import/no-default-export diff --git a/packages/fetch-extension/src/pages/register/auth/style.module.scss b/packages/fetch-extension/src/pages/register/auth/style.module.scss deleted file mode 100644 index e7e3a5f855..0000000000 --- a/packages/fetch-extension/src/pages/register/auth/style.module.scss +++ /dev/null @@ -1,63 +0,0 @@ -.card { - margin: 0.5rem; - padding: 0.7rem; - text-align: center; - color: #0070f3; - text-decoration: none; - border: 1px solid #0070f3; - border-radius: 10px; - transition: color 0.15s ease, border-color 0.15s ease; - width: 100%; -} - -.container { - padding: 0; - margin-bottom: 18px; -} - -.w3abutton { - border: 1px solid #f3f3f4; - box-shadow: none; - box-sizing: border-box; - border-radius: 24px; - height: 48px; - width: 100%; - padding: 8px; - position: relative; - display: flex; - align-items: center; - justify-content: center; - font-family: var(--text-body); - font-style: normal; - font-weight: 600; - cursor: pointer; - background-color: #0364ff; - color: #fff; - - &:hover { - transition: 200ms; - background-color: #0a49af; - } -} - -.gTitle { - position: relative; - display: flex; - align-items: center; - justify-content: center; - font-size: 16px; - margin-left: 10px; - margin-right: 10px; -} - -.authPoweredBy { - font-size: 10px; - position: absolute; - bottom: 2px; - right: 12px; - color: white; - &:hover { - color: white; - background-color: transparent; - } -} diff --git a/packages/fetch-extension/src/pages/register/index.tsx b/packages/fetch-extension/src/pages/register/index.tsx deleted file mode 100644 index eabbb5644c..0000000000 --- a/packages/fetch-extension/src/pages/register/index.tsx +++ /dev/null @@ -1,161 +0,0 @@ -// Shim ------------ -require("setimmediate"); -// Shim ------------ -import React, { FunctionComponent, useEffect } from "react"; - -import { EmptyLayout } from "@layouts/empty-layout"; - -import { observer } from "mobx-react-lite"; - -import style from "./style.module.scss"; - -import { Button } from "reactstrap"; - -import { FormattedMessage } from "react-intl"; - -import { useRegisterConfig } from "@keplr-wallet/hooks"; -import { useStore } from "../../stores"; -import { NewMnemonicIntro, NewMnemonicPage, TypeNewMnemonic } from "./mnemonic"; -import { - RecoverMnemonicIntro, - RecoverMnemonicPage, - TypeRecoverMnemonic, -} from "./mnemonic"; -import { - ImportLedgerIntro, - ImportLedgerPage, - TypeImportLedger, -} from "./ledger"; -import { WelcomePage } from "./welcome"; -import { AdditionalSignInPrepend } from "../../config.ui"; -import classnames from "classnames"; -import { - ImportKeystoneIntro, - ImportKeystonePage, - TypeImportKeystone, -} from "./keystone"; -import { - MigrateEthereumAddressIntro, - MigrateEthereumAddressPage, - TypeMigrateEth, -} from "./migration"; -import { AuthIntro, AuthPage } from "./auth"; -import { configure } from "mobx"; -configure({ - enforceActions: "always", // Make mobx to strict mode. -}); -export enum NunWords { - WORDS12, - WORDS24, -} - -export const BackButton: FunctionComponent<{ onClick: () => void }> = ({ - onClick, -}) => { - return ( -
- -
- ); -}; - -export const RegisterPage: FunctionComponent = observer(() => { - const { keyRingStore, uiConfigStore, analyticsStore } = useStore(); - - useEffect(() => { - analyticsStore.logEvent("register_page_viewed"); - document.documentElement.setAttribute("data-register-page", "true"); - - return () => { - document.documentElement.removeAttribute("data-register-page"); - }; - }, []); - - const registerConfig = useRegisterConfig(keyRingStore, [ - ...(AdditionalSignInPrepend ?? []), - { - type: "auth", - intro: AuthIntro, - page: AuthPage, - }, - { - type: TypeNewMnemonic, - intro: NewMnemonicIntro, - page: NewMnemonicPage, - }, - { - type: TypeRecoverMnemonic, - intro: RecoverMnemonicIntro, - page: RecoverMnemonicPage, - }, - // Currently, there is no way to use ledger with keplr on firefox. - // Temporarily, hide the ledger usage. - ...(uiConfigStore.platform !== "firefox" - ? [ - { - type: TypeImportLedger, - intro: ImportLedgerIntro, - page: ImportLedgerPage, - }, - ] - : []), - { - type: TypeImportKeystone, - intro: ImportKeystoneIntro, - page: ImportKeystonePage, - }, - // TODO: think about moving this into the configuration at some point - { - type: TypeMigrateEth, - intro: MigrateEthereumAddressIntro, - page: MigrateEthereumAddressPage, - }, - ]); - - return ( - -
-
-
- logo - logo -
-
- {registerConfig.render()} - {registerConfig.isFinalized ? : null} - {registerConfig.isIntro ? ( -
- , - }} - /> -
- ) : null} -
- - ); -}); diff --git a/packages/fetch-extension/src/pages/register/keystone/index.tsx b/packages/fetch-extension/src/pages/register/keystone/index.tsx deleted file mode 100644 index 43ef9b1e5e..0000000000 --- a/packages/fetch-extension/src/pages/register/keystone/index.tsx +++ /dev/null @@ -1,172 +0,0 @@ -import React, { FunctionComponent } from "react"; -import { RegisterConfig } from "@keplr-wallet/hooks"; -import { FormattedMessage, useIntl } from "react-intl"; -import { Button, Form } from "reactstrap"; -import { useForm } from "react-hook-form"; -import style from "../style.module.scss"; -import { Input, PasswordInput } from "@components/form"; -import { useBIP44Option } from "../advanced-bip44"; -import { BackButton } from "../index"; -import { observer } from "mobx-react-lite"; -import { useStore } from "../../../stores"; -import { KeystoneIntroduction } from "./introduction"; - -export const TypeImportKeystone = "import-keystone"; - -interface FormData { - name: string; - password: string; - confirmPassword: string; -} - -export const ImportKeystoneIntro: FunctionComponent<{ - registerConfig: RegisterConfig; -}> = observer(({ registerConfig }) => { - const { analyticsStore } = useStore(); - return ( - - ); -}); - -export const ImportKeystonePage: FunctionComponent<{ - registerConfig: RegisterConfig; -}> = observer(({ registerConfig }) => { - const intl = useIntl(); - - const bip44Option = useBIP44Option(); - - const { - register, - handleSubmit, - getValues, - formState: { errors }, - } = useForm({ - defaultValues: { - name: "", - password: "", - confirmPassword: "", - }, - }); - - const { analyticsStore } = useStore(); - - return ( -
-
- {intl.formatMessage({ - id: "register.name", - })} -
-
{ - analyticsStore.logEvent("register_next_click", { - registerType: "keystone", - }); - try { - await registerConfig.createKeystone( - data.name, - data.password, - bip44Option.bip44HDPath - ); - analyticsStore.setUserProperties({ - registerType: "keystone", - accountType: "keystone", - }); - } catch (e: any) { - alert(e.message ? e.message : e.toString()); - registerConfig.clear(); - } - })} - > - - {registerConfig.mode === "create" ? ( - - { - if (password.length < 8) { - return intl.formatMessage({ - id: "register.create.input.password.error.too-short", - }); - } - }, - })} - error={errors.password && errors.password.message} - /> - { - if (confirmPassword !== getValues()["password"]) { - return intl.formatMessage({ - id: "register.create.input.confirm-password.error.unmatched", - }); - } - }, - })} - error={errors.confirmPassword && errors.confirmPassword.message} - /> - - ) : null} - {/* */} - - - { - registerConfig.clear(); - analyticsStore.logEvent("back_click", { - pageName: "Keystone", - }); - }} - /> -
- ); -}); diff --git a/packages/fetch-extension/src/pages/register/keystone/introduction.tsx b/packages/fetch-extension/src/pages/register/keystone/introduction.tsx deleted file mode 100644 index e61ca703e8..0000000000 --- a/packages/fetch-extension/src/pages/register/keystone/introduction.tsx +++ /dev/null @@ -1,109 +0,0 @@ -import React, { useState } from "react"; -import { createPortal } from "react-dom"; -import { Button } from "reactstrap"; -import styles from "../style.module.scss"; - -function Introduction({ - isOpen, - onClose, -}: { - isOpen: boolean; - onClose: () => void; -}) { - return createPortal( -
e.stopPropagation()} - > -
-
- - - - - -
-
- Keystone is a top-notch hardware wallet for optimal security, - user-friendly interface and extensive compatibility. -
- - -
-
, - document.body - ); -} - -export function KeystoneIntroduction({ className }: { className: any }) { - const [isOpen, setIsOpen] = useState(false); - - const onClick = (e: any) => { - e.stopPropagation(); - setIsOpen(true); - }; - - return ( - - - - - - - - setIsOpen(false)} /> - - ); -} diff --git a/packages/fetch-extension/src/pages/register/ledger/index.tsx b/packages/fetch-extension/src/pages/register/ledger/index.tsx deleted file mode 100644 index fa93c59849..0000000000 --- a/packages/fetch-extension/src/pages/register/ledger/index.tsx +++ /dev/null @@ -1,233 +0,0 @@ -import React, { FunctionComponent } from "react"; -import { RegisterConfig } from "@keplr-wallet/hooks"; -import { FormattedMessage, useIntl } from "react-intl"; -import { Button, Form } from "reactstrap"; -import { useForm } from "react-hook-form"; -import style from "../style.module.scss"; -import { Input, PasswordInput } from "@components/form"; -import { AdvancedBIP44Option, useBIP44Option } from "../advanced-bip44"; -import { BackButton } from "../index"; -import { observer } from "mobx-react-lite"; -import { useStore } from "../../../stores"; -import { ledgerUSBVendorId } from "@ledgerhq/devices"; - -export const TypeImportLedger = "import-ledger"; - -interface FormData { - name: string; - password: string; - confirmPassword: string; -} - -export const ImportLedgerIntro: FunctionComponent<{ - registerConfig: RegisterConfig; -}> = observer(({ registerConfig }) => { - const { analyticsStore } = useStore(); - return ( - - ); -}); - -export const ImportLedgerPage: FunctionComponent<{ - registerConfig: RegisterConfig; -}> = observer(({ registerConfig }) => { - const intl = useIntl(); - - const bip44Option = useBIP44Option(118); - - const { - register, - handleSubmit, - getValues, - formState: { errors }, - } = useForm({ - defaultValues: { - name: "", - password: "", - confirmPassword: "", - }, - }); - - const { analyticsStore, ledgerInitStore } = useStore(); - - const ensureUSBPermission = async () => { - const anyNavigator = navigator as any; - if (ledgerInitStore.isWebHID) { - const device = await anyNavigator.hid.requestDevice({ - filters: [ - { - vendorId: ledgerUSBVendorId, - }, - ], - }); - if (!device || (Array.isArray(device) && device.length === 0)) { - throw new Error("No device selected"); - } - } else { - if ( - !(await anyNavigator.usb.requestDevice({ - filters: [ - { - vendorId: ledgerUSBVendorId, - }, - ], - })) - ) { - throw new Error("No device selected"); - } - } - }; - - return ( -
-
- {intl.formatMessage({ - id: "register.name", - })} -
-
{ - try { - await ensureUSBPermission(); - - await registerConfig.createLedger( - data.name, - data.password, - bip44Option.bip44HDPath, - "Cosmos" - ); - analyticsStore.logEvent("register_done_click", { - registerType: "ledger", - accountType: "ledger", - pageName: "Ledger Cosmos", - }); - } catch (e) { - alert(e.message ? e.message : e.toString()); - registerConfig.clear(); - } - })} - > - - {registerConfig.mode === "create" ? ( - - { - if (password.length < 8) { - return intl.formatMessage({ - id: "register.create.input.password.error.too-short", - }); - } - }, - })} - error={errors.password && errors.password.message} - /> - { - if (confirmPassword !== getValues()["password"]) { - return intl.formatMessage({ - id: "register.create.input.confirm-password.error.unmatched", - }); - } - }, - })} - error={errors.confirmPassword && errors.confirmPassword.message} - /> - - ) : null} - - - - - { - registerConfig.clear(); - analyticsStore.logEvent("back_click", { - pageName: "Ledger", - }); - }} - /> -
- ); -}); diff --git a/packages/fetch-extension/src/pages/register/migration/index.tsx b/packages/fetch-extension/src/pages/register/migration/index.tsx deleted file mode 100644 index 97381428b5..0000000000 --- a/packages/fetch-extension/src/pages/register/migration/index.tsx +++ /dev/null @@ -1,89 +0,0 @@ -import React, { FunctionComponent, useState } from "react"; -import { RegisterConfig } from "@keplr-wallet/hooks"; -import { observer } from "mobx-react-lite"; -import { FormattedMessage } from "react-intl"; -import { Button } from "reactstrap"; -import { BackButton } from "../index"; -import { MigrateMetamaskPrivateKeyPage } from "./metamask-privatekey"; -import { useStore } from "../../../stores"; - -export const TypeMigrateEth = "migrate-from-eth"; - -enum MigrationMode { - SELECT_MODE, - METAMASK_PRIVATE_KEY, -} - -export const MigrateEthereumAddressIntro: FunctionComponent<{ - registerConfig: RegisterConfig; -}> = observer(({ registerConfig }) => { - const { analyticsStore } = useStore(); - - return ( - - ); -}); - -const MigrationSelectionPage: FunctionComponent<{ - setMode: (mode: MigrationMode) => void; - onBack: () => void; -}> = (props) => { - const { analyticsStore } = useStore(); - return ( -
- - { - analyticsStore.logEvent("back_click", { - pageName: "Migrate a Metamask Private Key", - }); - props.onBack(); - }} - /> -
- ); -}; - -export const MigrateEthereumAddressPage: FunctionComponent<{ - registerConfig: RegisterConfig; -}> = observer(({ registerConfig }) => { - const [mode, setMode] = useState(MigrationMode.SELECT_MODE); - - switch (mode) { - case MigrationMode.SELECT_MODE: - return ( - registerConfig.clear()} - /> - ); - case MigrationMode.METAMASK_PRIVATE_KEY: - return ( - setMode(MigrationMode.SELECT_MODE)} - /> - ); - } -}); diff --git a/packages/fetch-extension/src/pages/register/migration/metamask-privatekey.tsx b/packages/fetch-extension/src/pages/register/migration/metamask-privatekey.tsx index a7d4e3d630..eb1f5cdf5b 100644 --- a/packages/fetch-extension/src/pages/register/migration/metamask-privatekey.tsx +++ b/packages/fetch-extension/src/pages/register/migration/metamask-privatekey.tsx @@ -1,5 +1,4 @@ import React, { FunctionComponent } from "react"; -import { BackButton } from "../index"; import { FormattedMessage, useIntl } from "react-intl"; import { Input, TextArea } from "@components/form"; import style from "../style.module.scss"; @@ -10,6 +9,19 @@ import { parseEthPrivateKey } from "@fetchai/eth-migration"; import { RegisterConfig } from "@keplr-wallet/hooks"; import { useStore } from "../../../stores"; +export const BackButton: FunctionComponent<{ onClick: () => void }> = ({ + onClick, +}) => { + return ( +
+ +
+ ); +}; + interface FormData { name: string; ethAddress: string; diff --git a/packages/fetch-extension/src/pages/register/mnemonic/hook.ts b/packages/fetch-extension/src/pages/register/mnemonic/hook.ts deleted file mode 100644 index 69e13a2e51..0000000000 --- a/packages/fetch-extension/src/pages/register/mnemonic/hook.ts +++ /dev/null @@ -1,96 +0,0 @@ -import { action, flow, makeObservable, observable } from "mobx"; -import { RegisterConfig } from "@keplr-wallet/hooks"; -import { useState } from "react"; -import { toGenerator } from "@keplr-wallet/common"; - -export type NewMnemonicMode = "generate" | "verify"; - -export enum NumWords { - WORDS12, - WORDS24, -} - -export class NewMnemonicConfig { - @observable - protected _mode: NewMnemonicMode = "generate"; - - @observable - protected _numWords: NumWords = NumWords.WORDS12; - - @observable - protected _mnemonic: string = ""; - - @observable - protected _name: string = ""; - - @observable - protected _password: string = ""; - - constructor(protected readonly registerConfig: RegisterConfig) { - makeObservable(this); - - this.setNumWords(this.numWords); - } - - get mode(): NewMnemonicMode { - return this._mode; - } - - @action - setMode(mode: NewMnemonicMode) { - this._mode = mode; - } - - get numWords(): NumWords { - return this._numWords; - } - - @flow - *setNumWords(numWords: NumWords) { - this._numWords = numWords; - if (numWords === NumWords.WORDS12) { - this._mnemonic = yield* toGenerator( - this.registerConfig.generateMnemonic(128) - ); - } else if (numWords === NumWords.WORDS24) { - this._mnemonic = yield* toGenerator( - this.registerConfig.generateMnemonic(256) - ); - } - } - - get mnemonic(): string { - return this._mnemonic; - } - - @action - setMnemonic(mnemonic: string) { - this._mnemonic = mnemonic; - } - - get name(): string { - return this._name; - } - - @action - setName(name: string) { - this._name = name; - } - - get password(): string { - return this._password; - } - - @action - setPassword(password: string) { - this._password = password; - } -} - -export const useNewMnemonicConfig = (registerConfig: RegisterConfig) => { - const [newMnemonicConfig] = useState( - () => new NewMnemonicConfig(registerConfig) - ); - - return newMnemonicConfig; -}; diff --git a/packages/fetch-extension/src/pages/register/mnemonic/index.ts b/packages/fetch-extension/src/pages/register/mnemonic/index.ts deleted file mode 100644 index 20b2c2d30e..0000000000 --- a/packages/fetch-extension/src/pages/register/mnemonic/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -export * from "./hook"; -export * from "./new-mnemonic"; -export * from "./recover-mnemonic"; diff --git a/packages/fetch-extension/src/pages/register/mnemonic/new-mnemonic.tsx b/packages/fetch-extension/src/pages/register/mnemonic/new-mnemonic.tsx deleted file mode 100644 index 321cb33ce5..0000000000 --- a/packages/fetch-extension/src/pages/register/mnemonic/new-mnemonic.tsx +++ /dev/null @@ -1,351 +0,0 @@ -import React, { FunctionComponent, useEffect, useMemo, useState } from "react"; -import { RegisterConfig } from "@keplr-wallet/hooks"; -import { observer } from "mobx-react-lite"; -import { FormattedMessage, useIntl } from "react-intl"; -import { useForm } from "react-hook-form"; -import { - AdvancedBIP44Option, - BIP44Option, - useBIP44Option, -} from "../advanced-bip44"; -import style from "../style.module.scss"; -import { Alert, Button, ButtonGroup, Form } from "reactstrap"; -import { Input, PasswordInput } from "@components/form"; -import { BackButton } from "../index"; -import { NewMnemonicConfig, NumWords, useNewMnemonicConfig } from "./hook"; -import { useStore } from "../../../stores"; - -export const TypeNewMnemonic = "new-mnemonic"; - -interface FormData { - name: string; - words: string; - password: string; - confirmPassword: string; -} - -export const NewMnemonicIntro: FunctionComponent<{ - registerConfig: RegisterConfig; -}> = observer(({ registerConfig }) => { - const { analyticsStore } = useStore(); - - return ( - - ); -}); - -export const NewMnemonicPage: FunctionComponent<{ - registerConfig: RegisterConfig; -}> = observer(({ registerConfig }) => { - const newMnemonicConfig = useNewMnemonicConfig(registerConfig); - const bip44Option = useBIP44Option(); - - return ( - - {newMnemonicConfig.mode === "generate" ? ( - - ) : null} - {newMnemonicConfig.mode === "verify" ? ( - - ) : null} - - ); -}); - -export const GenerateMnemonicModePage: FunctionComponent<{ - registerConfig: RegisterConfig; - newMnemonicConfig: NewMnemonicConfig; - bip44Option: BIP44Option; -}> = observer(({ registerConfig, newMnemonicConfig, bip44Option }) => { - const intl = useIntl(); - const { analyticsStore } = useStore(); - const { - register, - handleSubmit, - getValues, - formState: { errors }, - } = useForm({ - defaultValues: { - name: newMnemonicConfig.name, - words: newMnemonicConfig.mnemonic, - password: "", - confirmPassword: "", - }, - }); - - return ( -
- -

- -

-
    -
  • - -
  • -
  • - -
  • -
-
-
- {intl.formatMessage({ - id: "register.create.title", - })} -
- - - - -
-
-
{ - newMnemonicConfig.setName(data.name); - newMnemonicConfig.setPassword(data.password); - newMnemonicConfig.setMode("verify"); - analyticsStore.logEvent("register_next_click", { - pageName: "Create New Account", - registerType: "seed", - accountType: "mnemonic", - }); - })} - > -
{newMnemonicConfig.mnemonic}
- - {registerConfig.mode === "create" ? ( - - { - if (password.length < 8) { - return intl.formatMessage({ - id: "register.create.input.password.error.too-short", - }); - } - }, - })} - error={errors.password && errors.password.message} - /> - { - if (confirmPassword !== getValues()["password"]) { - return intl.formatMessage({ - id: "register.create.input.confirm-password.error.unmatched", - }); - } - }, - })} - error={errors.confirmPassword && errors.confirmPassword.message} - /> - - ) : null} - - - - { - registerConfig.clear(); - analyticsStore.logEvent("back_click", { - pageName: "Create New Account", - }); - }} - /> -
- ); -}); - -export const VerifyMnemonicModePage: FunctionComponent<{ - registerConfig: RegisterConfig; - newMnemonicConfig: NewMnemonicConfig; - bip44Option: BIP44Option; -}> = observer(({ registerConfig, newMnemonicConfig, bip44Option }) => { - const wordsSlice = useMemo(() => { - const words = newMnemonicConfig.mnemonic.split(" "); - for (let i = 0; i < words.length; i++) { - words[i] = words[i].trim(); - } - return words; - }, [newMnemonicConfig.mnemonic]); - - const [randomizedWords, setRandomizedWords] = useState([]); - const [suggestedWords, setSuggestedWords] = useState([]); - - useEffect(() => { - // Set randomized words. - const words = newMnemonicConfig.mnemonic.split(" "); - for (let i = 0; i < words.length; i++) { - words[i] = words[i].trim(); - } - words.sort((word1, word2) => { - // Sort alpahbetically. - return word1 > word2 ? 1 : -1; - }); - setRandomizedWords(words); - // Clear suggested words. - setSuggestedWords([]); - }, [newMnemonicConfig.mnemonic]); - - const { analyticsStore } = useStore(); - - return ( -
-
-
- {suggestedWords.map((word, i) => { - return ( - - ); - })} -
-
-
-
-
- {randomizedWords.map((word, i) => { - return ( - - ); - })} -
-
- - { - newMnemonicConfig.setMode("generate"); - analyticsStore.logEvent("back_click", { - pageName: "Verify New Account", - }); - }} - /> -
- ); -}); diff --git a/packages/fetch-extension/src/pages/register/mnemonic/recover-mnemonic.module.scss b/packages/fetch-extension/src/pages/register/mnemonic/recover-mnemonic.module.scss deleted file mode 100644 index cf24d0cc16..0000000000 --- a/packages/fetch-extension/src/pages/register/mnemonic/recover-mnemonic.module.scss +++ /dev/null @@ -1,108 +0,0 @@ -.container { - .title { - display: flex; - align-items: end; - } - - .dropdown { - min-width: 160px; - height: 46px; - - button { - min-width: 160px; - - text-align: left; - font-weight: normal; - } - - :global(.dropdown-toggle) { - background-color: white; - box-shadow: 0 1px 3px rgba(50, 50, 93, 0.15), 0 1px 0 rgba(0, 0, 0, 0.02) !important; - - &:not(:active) { - border: 1px solid #596e8d; - } - - &::after { - border-radius: 2px; - content: " "; - display: block; - height: 0.625em; - margin-top: -0.4375em; - pointer-events: none; - position: absolute; - top: 50%; - transform: rotate(-45deg); - transform-origin: center; - width: 0.625em; - border: 0 solid black; - border-bottom-width: 3px; - border-left-width: 3px; - right: 1.125em; - z-index: 4; - } - } - - :global(.dropdown-menu.show) { - min-width: 160px; - - z-index: 2000; - } - } - - .alert { - text-align: center; - - font-weight: 600; - font-size: 16px; - line-height: 22px; - color: #fd5778; - background: #fff7f8; - border: 1px solid #fd5778; - border-radius: 16px; - - padding: 16px 0; - - margin-bottom: 1.5rem; - } -} - -.mnemonicContainer { - display: grid; - - grid-template-columns: 1fr 1fr 1fr; - &.private-key { - grid-template-columns: 1fr; - - .mnemonicWordFormGroup { - flex: 1; - } - } - - column-gap: 30px; - row-gap: 20px; - - margin-bottom: 1.5rem; - - .mnemonicWordContainer { - display: flex; - align-items: center; - - .order { - width: 40px; - } - - .mnemonicWordFormGroup { - margin-bottom: 0; - } - - .mnemonicWord { - border-radius: 0.375rem !important; - padding-right: 38px; - } - } -} - -.formInnerContainer { - width: 420px; -} diff --git a/packages/fetch-extension/src/pages/register/mnemonic/recover-mnemonic.tsx b/packages/fetch-extension/src/pages/register/mnemonic/recover-mnemonic.tsx deleted file mode 100644 index dddbf50e05..0000000000 --- a/packages/fetch-extension/src/pages/register/mnemonic/recover-mnemonic.tsx +++ /dev/null @@ -1,622 +0,0 @@ -import React, { FunctionComponent, useState } from "react"; - -import { - Button, - ButtonDropdown, - DropdownItem, - DropdownMenu, - DropdownToggle, - Form, -} from "reactstrap"; - -import { FormattedMessage, useIntl } from "react-intl"; -import style from "../style.module.scss"; -import styleRecoverMnemonic from "./recover-mnemonic.module.scss"; -import { BackButton } from "../index"; -import { Input, PasswordInput } from "@components/form"; -import { useForm } from "react-hook-form"; -import { observer } from "mobx-react-lite"; -import { RegisterConfig } from "@keplr-wallet/hooks"; -import { AdvancedBIP44Option, useBIP44Option } from "../advanced-bip44"; - -import { Buffer } from "buffer/"; -import { useStore } from "../../../stores"; -import classnames from "classnames"; -import { NewMnemonicStep } from "src/pages-new/register/mnemonic"; - -// eslint-disable-next-line @typescript-eslint/no-var-requires -const bip39 = require("bip39"); - -export function isPrivateKey(str: string): boolean { - if (str.startsWith("0x")) { - return true; - } - - if (str.length === 64) { - try { - return Buffer.from(str, "hex").length === 32; - } catch { - return false; - } - } - return false; -} - -function validatePrivateKey(value: string): boolean { - if (isPrivateKey(value)) { - value = value.replace("0x", ""); - if (value.length !== 64) { - return false; - } - return ( - Buffer.from(value, "hex").toString("hex").toLowerCase() === - value.toLowerCase() - ); - } - return false; -} - -interface FormData { - name: string; - password: string; - confirmPassword: string; -} - -export const TypeRecoverMnemonic = "recover-mnemonic"; - -export const RecoverMnemonicIntro: FunctionComponent<{ - registerConfig: RegisterConfig; -}> = observer(({ registerConfig }) => { - const { analyticsStore } = useStore(); - - return ( - - ); -}); - -enum SeedType { - WORDS12 = "12words", - WORDS24 = "24words", - PRIVATE_KEY = "private_key", -} - -export const RecoverMnemonicPage: FunctionComponent<{ - registerConfig: RegisterConfig; -}> = observer(({ registerConfig }) => { - const intl = useIntl(); - - const bip44Option = useBIP44Option(); - - const { analyticsStore } = useStore(); - - const { - register, - handleSubmit, - getValues, - formState: { errors }, - } = useForm({ - defaultValues: { - name: "", - password: "", - confirmPassword: "", - }, - }); - - const [shownMnemonicIndex, setShownMnemonicIndex] = useState(-1); - - const [seedType, _setSeedType] = useState(SeedType.WORDS12); - const [seedWords, setSeedWords] = useState( - new Array(12).fill("") - ); - - const setSeedType = (seedType: SeedType) => { - _setSeedType(seedType); - setShownMnemonicIndex(-1); - - if (seedType === SeedType.WORDS12) { - setSeedWords((seedWords) => { - if (seedWords.length < 12) { - return seedWords.concat(new Array(12 - seedWords.length).fill("")); - } else { - return seedWords.slice(0, 12); - } - }); - } - if (seedType === SeedType.WORDS24) { - setSeedWords((seedWords) => { - if (seedWords.length < 24) { - return seedWords.concat(new Array(24 - seedWords.length).fill("")); - } else { - return seedWords.slice(0, 24); - } - }); - } - if (seedType === SeedType.PRIVATE_KEY) { - setSeedWords((seedWords) => seedWords.slice(0, 1)); - } - }; - const [showDropdown, setShowDropdown] = useState(false); - - const seedTypeToParagraph = (seedType: SeedType) => { - switch (seedType) { - case SeedType.WORDS12: { - return NewMnemonicStep.WORDS12; - } - case SeedType.WORDS24: { - return NewMnemonicStep.WORDS24; - } - case SeedType.PRIVATE_KEY: { - return NewMnemonicStep.PRIVATEKEY; - } - default: { - return "Unknown"; - } - } - }; - - const handlePaste = (index: number, value: string) => { - const words = value - .trim() - .split(" ") - .map((word) => word.trim()); - - if (words.length === 1) { - // If the length of pasted words is 1 and the word is guessed as a private key, - // set seed type as private key automatically. - if (isPrivateKey(words[0])) { - setSeedType(SeedType.PRIVATE_KEY); - setSeedWords([words[0]]); - return; - } - } - - if (words.length === 12 || words.length === 24) { - // 12/24 words are treated specially. - // Regardless of where it is pasted from, if it is a valid seed, it will be processed directly. - if (bip39.validateMnemonic(words.join(" "))) { - if (words.length === 12) { - setSeedType(SeedType.WORDS12); - } else { - setSeedType(SeedType.WORDS24); - } - - setSeedWords(words); - - return; - } - } - - let newSeedWords = seedWords.slice(); - const expectedLength = Math.min(index + words.length, 24); - - if (seedWords.length < expectedLength) { - newSeedWords = newSeedWords.concat( - new Array(expectedLength - seedWords.length).fill("") - ); - - if (expectedLength > 12) { - setSeedType(SeedType.WORDS24); - } else { - setSeedType(SeedType.WORDS12); - } - } - - for (let i = index; i < expectedLength; i++) { - newSeedWords[i] = words[i - index]; - } - - setSeedWords(newSeedWords); - }; - - const [seedWordsError, setSeedWordsError] = useState( - undefined - ); - - const validateSeedWords = (seedWords: string[]) => { - seedWords = seedWords.map((word) => word.trim()); - if (seedWords.join(" ").trim().length === 0) { - return "__required__"; - } - if (seedWords.length === 1 && isPrivateKey(seedWords[0])) { - if (!validatePrivateKey(seedWords[0])) { - return "__invalid__"; - } - return undefined; - } else { - // num words is the length to the last non-empty word. - let numWords = 0; - for (let i = 0; i < seedWords.length; i++) { - if (seedWords[i].length > 0) { - numWords = i + 1; - } - } - - seedWords = seedWords.slice(0, numWords); - // If an empty word exists in the middle of words, it is treated as an error. - if (seedWords.find((word) => word.length === 0)) { - return "__invalid__"; - } - - if (numWords < 9) { - return intl.formatMessage({ - id: "register.create.textarea.mnemonic.error.too-short", - }); - } - - if (!bip39.validateMnemonic(seedWords.join(" "))) { - return "__invalid__"; - } - - return undefined; - } - }; - - return ( - -
-
- {seedType === SeedType.PRIVATE_KEY - ? intl.formatMessage({ - id: "register.recover.alt.private-key.title", - }) - : intl.formatMessage({ - id: "register.recover.title", - })} -
-
- setShowDropdown((value) => !value)} - > - - {seedTypeToParagraph(seedType)} - - - { - e.preventDefault(); - - setSeedType(SeedType.WORDS12); - }} - > - {seedTypeToParagraph(SeedType.WORDS12)} - - { - e.preventDefault(); - - setSeedType(SeedType.WORDS24); - }} - > - {seedTypeToParagraph(SeedType.WORDS24)} - - { - e.preventDefault(); - - setSeedType(SeedType.PRIVATE_KEY); - }} - > - {seedTypeToParagraph(SeedType.PRIVATE_KEY)} - - - -
-
-
{ - e.preventDefault(); - - const seedWordsError = validateSeedWords(seedWords); - if (seedWordsError) { - setSeedWordsError(seedWordsError); - return; - } else { - setSeedWordsError(undefined); - } - - handleSubmit(async (data: FormData) => { - try { - if (seedWords.length === 1 && isPrivateKey(seedWords[0])) { - const privateKey = Buffer.from( - seedWords[0].replace("0x", ""), - "hex" - ); - await registerConfig.createPrivateKey( - data.name, - privateKey, - data.password - ); - analyticsStore.logEvent("register_done_click", { - registerType: "seed", - accountType: "privateKey", - pageName: "Verify New Account", - }); - } else { - await registerConfig.createMnemonic( - data.name, - // In logic, not 12/24 words can be handled. - // However, seed words have only a length of 12/24 when mnemonic. - // Since the rest has an empty string, additional spaces are created by the empty string after join. - // Therefore, trim should be done last. - seedWords.join(" ").trim(), - data.password, - bip44Option.bip44HDPath - ); - analyticsStore.logEvent("register_done_click", { - registerType: "seed", - accountType: "mnemonic", - pageName: "Verify New Account", - }); - } - } catch (e) { - alert(e.message ? e.message : e.toString()); - registerConfig.clear(); - } - })(e); - }} - > -
- {seedWords.map((word, index) => { - return ( -
- {seedType !== SeedType.PRIVATE_KEY ? ( -
- {index + 1}. -
- ) : null} - { - e.preventDefault(); - - handlePaste(index, e.clipboardData.getData("text")); - }} - onChange={(e) => { - e.preventDefault(); - - if ( - shownMnemonicIndex >= 0 && - shownMnemonicIndex !== index - ) { - setShownMnemonicIndex(-1); - } - - const newSeedWords = seedWords.slice(); - newSeedWords[index] = e.target.value.trim(); - setSeedWords(newSeedWords); - }} - value={word} - append={ -
{ - e.preventDefault(); - setShownMnemonicIndex((prev) => { - if (prev === index) { - return -1; - } - return index; - }); - }} - > - {shownMnemonicIndex === index ? ( - - ) : ( - - )} -
- } - /> -
- ); - })} -
- {seedWordsError ? ( -
- {(() => { - if (seedWordsError === "__required__") { - if (seedType === SeedType.PRIVATE_KEY) { - return intl.formatMessage({ - id: "register.import.textarea.private-key.error.required", - }); - } else { - return intl.formatMessage({ - id: "register.import.textarea.mnemonic.error.required", - }); - } - } - - if (seedWordsError === "__invalid__") { - if (seedType === SeedType.PRIVATE_KEY) { - return intl.formatMessage({ - id: "register.import.textarea.private-key.error.invalid", - }); - } else { - return intl.formatMessage({ - id: "register.import.textarea.mnemonic.error.invalid", - }); - } - } - - return seedWordsError; - })()} -
- ) : null} -
- - {registerConfig.mode === "create" ? ( - - { - if (password.length < 8) { - return intl.formatMessage({ - id: "register.create.input.password.error.too-short", - }); - } - }, - })} - error={errors.password && errors.password.message} - /> - { - if (confirmPassword !== getValues()["password"]) { - return intl.formatMessage({ - id: "register.create.input.confirm-password.error.unmatched", - }); - } - }, - })} - error={ - errors.confirmPassword && errors.confirmPassword.message - } - /> - - ) : null} -
- - -
- - { - registerConfig.clear(); - analyticsStore.logEvent("back_click", { - pageName: "Import Existing Account", - }); - }} - /> -
- - ); -}); - -const IconClosedEye: FunctionComponent<{ - width?: number; - height?: number; - color?: string; -}> = ({ width = 28, height = 29, color = "#C6C6CD" }) => { - return ( - - - - - ); -}; - -const IconOpenEye: FunctionComponent<{ - width?: number; - height?: number; - color?: string; -}> = ({ width = 28, height = 29, color = "#C6C6CD" }) => { - return ( - - - - - ); -}; diff --git a/packages/fetch-extension/src/pages/register/welcome.module.scss b/packages/fetch-extension/src/pages/register/welcome.module.scss deleted file mode 100644 index d8412546df..0000000000 --- a/packages/fetch-extension/src/pages/register/welcome.module.scss +++ /dev/null @@ -1,10 +0,0 @@ -.title { - font-size: 24px; - letter-spacing: -1.07px; -} - -.content { - font-size: 16px; - letter-spacing: -0.71px; - color: #6b6b6b; -} diff --git a/packages/fetch-extension/src/pages/register/welcome.tsx b/packages/fetch-extension/src/pages/register/welcome.tsx deleted file mode 100644 index 147b814f26..0000000000 --- a/packages/fetch-extension/src/pages/register/welcome.tsx +++ /dev/null @@ -1,51 +0,0 @@ -import React, { FunctionComponent } from "react"; - -import styleWelcome from "./welcome.module.scss"; -import { Button } from "reactstrap"; - -import { useIntl } from "react-intl"; - -export const WelcomePage: FunctionComponent = () => { - const intl = useIntl(); - - return ( -
-
- {intl.formatMessage({ - id: "register.welcome.title", - })} -
-
- {intl.formatMessage({ - id: "register.welcome.content", - })} -
- -
- ); -}; diff --git a/packages/fetch-extension/src/pages/send/index.tsx b/packages/fetch-extension/src/pages/send/index.tsx deleted file mode 100644 index 23eff48ed1..0000000000 --- a/packages/fetch-extension/src/pages/send/index.tsx +++ /dev/null @@ -1,451 +0,0 @@ -import React, { FunctionComponent, useEffect, useMemo } from "react"; -import { - AddressInput, - FeeButtons, - CoinInput, - MemoInput, -} from "@components/form"; -import { useStore } from "../../stores"; - -import { HeaderLayout } from "@layouts/index"; - -import { observer } from "mobx-react-lite"; - -import style from "./style.module.scss"; -import { useNotification } from "@components/notification"; - -import { useIntl } from "react-intl"; -import { Button } from "reactstrap"; - -import { useNavigate, useLocation } from "react-router"; -import queryString from "querystring"; - -import { useGasSimulator, useSendTxConfig } from "@keplr-wallet/hooks"; -import { - fitPopupWindow, - openPopupWindow, - PopupSize, -} from "@keplr-wallet/popup"; -import { DenomHelper, ExtensionKVStore } from "@keplr-wallet/common"; -import { TXNTYPE } from "../../config"; - -export const SendPage: FunctionComponent = observer(() => { - const navigate = useNavigate(); - let search = useLocation().search; - if (search.startsWith("?")) { - search = search.slice(1); - } - const query = queryString.parse(search) as { - defaultDenom: string | undefined; - defaultRecipient: string | undefined; - defaultAmount: string | undefined; - defaultMemo: string | undefined; - detached: string | undefined; - }; - - useEffect(() => { - // Scroll to top on page mounted. - if (window.scrollTo) { - window.scrollTo(0, 0); - } - }, []); - - const intl = useIntl(); - - const notification = useNotification(); - - const { - chainStore, - accountStore, - priceStore, - queriesStore, - analyticsStore, - uiConfigStore, - } = useStore(); - const current = chainStore.current; - - const accountInfo = accountStore.getAccount(current.chainId); - - const sendConfigs = useSendTxConfig( - chainStore, - queriesStore, - accountStore, - current.chainId, - accountInfo.bech32Address, - { - allowHexAddressOnEthermint: true, - icns: uiConfigStore.icnsInfo, - computeTerraClassicTax: true, - } - ); - - const gasSimulatorKey = useMemo(() => { - if (sendConfigs.amountConfig.sendCurrency) { - const denomHelper = new DenomHelper( - sendConfigs.amountConfig.sendCurrency.coinMinimalDenom - ); - - if (denomHelper.type !== "native") { - if (denomHelper.type === "cw20") { - // Probably, the gas can be different per cw20 according to how the contract implemented. - return `${denomHelper.type}/${denomHelper.contractAddress}`; - } - - return denomHelper.type; - } - } - - return "native"; - }, [sendConfigs.amountConfig.sendCurrency]); - - const gasSimulator = useGasSimulator( - new ExtensionKVStore("gas-simulator.main.send"), - chainStore, - current.chainId, - sendConfigs.gasConfig, - sendConfigs.feeConfig, - gasSimulatorKey, - () => { - if (!sendConfigs.amountConfig.sendCurrency) { - throw new Error("Send currency not set"); - } - - // Prefer not to use the gas config or fee config, - // because gas simulator can change the gas config and fee config from the result of reaction, - // and it can make repeated reaction. - if ( - sendConfigs.amountConfig.error != null || - sendConfigs.recipientConfig.error != null - ) { - throw new Error("Not ready to simulate tx"); - } - - const denomHelper = new DenomHelper( - sendConfigs.amountConfig.sendCurrency.coinMinimalDenom - ); - // I don't know why, but simulation does not work for secret20 - if (denomHelper.type === "secret20") { - throw new Error("Simulating secret wasm not supported"); - } - - return accountInfo.makeSendTokenTx( - sendConfigs.amountConfig.amount, - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - sendConfigs.amountConfig.sendCurrency!, - sendConfigs.recipientConfig.recipient - ); - } - ); - - useEffect(() => { - // To simulate secretwasm, we need to include the signature in the tx. - // With the current structure, this approach is not possible. - if ( - sendConfigs.amountConfig.sendCurrency && - new DenomHelper(sendConfigs.amountConfig.sendCurrency.coinMinimalDenom) - .type === "secret20" - ) { - gasSimulator.forceDisable( - new Error("Simulating secret20 is not supported") - ); - sendConfigs.gasConfig.setGas( - accountInfo.secret.msgOpts.send.secret20.gas - ); - } else { - gasSimulator.forceDisable(false); - gasSimulator.setEnabled(true); - } - }, [ - accountInfo.secret.msgOpts.send.secret20.gas, - gasSimulator, - sendConfigs.amountConfig.sendCurrency, - sendConfigs.gasConfig, - ]); - - useEffect(() => { - if ( - sendConfigs.feeConfig.chainInfo.features && - sendConfigs.feeConfig.chainInfo.features.includes("terra-classic-fee") - ) { - // When considering stability tax for terra classic. - // Simulation itself doesn't consider the stability tax send. - // Thus, it always returns fairly lower gas. - // To adjust this, for terra classic, increase the default gas adjustment - gasSimulator.setGasAdjustment(1.6); - } - }, [gasSimulator, sendConfigs.feeConfig.chainInfo]); - - useEffect(() => { - if (query.defaultDenom) { - const currency = current.currencies.find( - (cur) => cur.coinMinimalDenom === query.defaultDenom - ); - - if (currency) { - sendConfigs.amountConfig.setSendCurrency(currency); - } - } - }, [current.currencies, query.defaultDenom, sendConfigs.amountConfig]); - - const isDetachedPage = query.detached === "true"; - - useEffect(() => { - if (isDetachedPage) { - fitPopupWindow(); - } - }, [isDetachedPage]); - - useEffect(() => { - if (query.defaultRecipient) { - sendConfigs.recipientConfig.setRawRecipient(query.defaultRecipient); - } - if (query.defaultAmount) { - sendConfigs.amountConfig.setAmount(query.defaultAmount); - } - if (query.defaultMemo) { - sendConfigs.memoConfig.setMemo(query.defaultMemo); - } - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [query.defaultAmount, query.defaultMemo, query.defaultRecipient]); - - const sendConfigError = - sendConfigs.recipientConfig.error ?? - sendConfigs.amountConfig.error ?? - sendConfigs.memoConfig.error ?? - sendConfigs.gasConfig.error ?? - sendConfigs.feeConfig.error; - const txStateIsValid = sendConfigError == null; - - return ( - { - analyticsStore.logEvent("back_click", { pageName: "Send" }); - navigate(-1); - } - } - rightRenderer={ - isDetachedPage ? undefined : ( -
- { - e.preventDefault(); - - const windowInfo = await browser.windows.getCurrent(); - - let queryString = `?detached=true&defaultDenom=${sendConfigs.amountConfig.sendCurrency.coinMinimalDenom}`; - if (sendConfigs.recipientConfig.rawRecipient) { - queryString += `&defaultRecipient=${sendConfigs.recipientConfig.rawRecipient}`; - } - if (sendConfigs.amountConfig.amount) { - queryString += `&defaultAmount=${sendConfigs.amountConfig.amount}`; - } - if (sendConfigs.memoConfig.memo) { - queryString += `&defaultMemo=${sendConfigs.memoConfig.memo}`; - } - - await openPopupWindow( - browser.runtime.getURL(`/popup.html#/send${queryString}`), - undefined, - { - top: (windowInfo.top || 0) + 80, - left: - (windowInfo.left || 0) + - (windowInfo.width || 0) - - PopupSize.width - - 20, - } - ); - window.close(); - }} - /> -
- ) - } - > -
{ - e.preventDefault(); - analyticsStore.logEvent("send_txn_click"); - - if (accountInfo.isReadyToSendTx && txStateIsValid) { - try { - const stdFee = sendConfigs.feeConfig.toStdFee(); - - const tx = accountInfo.makeSendTokenTx( - sendConfigs.amountConfig.amount, - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - sendConfigs.amountConfig.sendCurrency!, - sendConfigs.recipientConfig.recipient - ); - - await tx.send( - stdFee, - sendConfigs.memoConfig.memo, - { - preferNoSetFee: true, - preferNoSetMemo: true, - }, - { - onBroadcastFailed: (e: any) => { - console.log(e); - }, - onBroadcasted: () => { - analyticsStore.logEvent("send_txn_broadcasted", { - chainId: chainStore.current.chainId, - chainName: chainStore.current.chainName, - feeType: sendConfigs.feeConfig.feeType, - }); - }, - } - ); - - if (!isDetachedPage) { - navigate("/", { replace: true }); - } - } catch (e) { - analyticsStore.logEvent("send_txn_broadcasted_fail", { - chainId: chainStore.current.chainId, - chainName: chainStore.current.chainName, - feeType: sendConfigs.feeConfig.feeType, - message: e?.message ?? "", - }); - if (!isDetachedPage) { - navigate("/", { replace: true }); - } - notification.push({ - type: "warning", - placement: "top-center", - duration: 5, - content: `Fail to send token: ${e.message}`, - canDelete: true, - transition: { - duration: 0.25, - }, - }); - } finally { - // XXX: If the page is in detached state, - // close the window without waiting for tx to commit. analytics won't work. - if (isDetachedPage) { - window.close(); - } - } - } - }} - > -
-
- - { - if ( - // In the case of terra classic, tax is applied in proportion to the amount. - // However, in this case, the tax itself changes the fee, - // so if you use the max function, it will fall into infinite repetition. - // We currently disable if chain is terra classic because we can't handle it properly. - sendConfigs.feeConfig.chainInfo.features && - sendConfigs.feeConfig.chainInfo.features.includes( - "terra-classic-fee" - ) - ) { - return true; - } - return false; - })()} - overrideSelectableCurrencies={(() => { - if ( - chainStore.current.features && - chainStore.current.features.includes("terra-classic-fee") - ) { - // At present, can't handle stability tax well if it is not registered native token. - // So, for terra classic, disable other tokens. - const currencies = - sendConfigs.amountConfig.sendableCurrencies; - return currencies.filter((cur) => { - const denom = new DenomHelper(cur.coinMinimalDenom); - if ( - denom.type !== "native" || - denom.denom.startsWith("ibc/") - ) { - return false; - } - - return true; - }); - } - - return undefined; - })()} - /> - - -
-
- -
- - - ); -}); diff --git a/packages/fetch-extension/src/pages/send/style.module.scss b/packages/fetch-extension/src/pages/send/style.module.scss deleted file mode 100644 index ff4827da5b..0000000000 --- a/packages/fetch-extension/src/pages/send/style.module.scss +++ /dev/null @@ -1,41 +0,0 @@ -@import "../../../../../node_modules/argon-dashboard-react/src/assets/scss/argon-dashboard/custom/functions"; -@import "../../../../../node_modules/argon-dashboard-react/src/assets/scss/argon-dashboard/custom/mixins"; -@import "../../../../../node_modules/argon-dashboard-react/src/assets/scss/argon-dashboard/custom/variables"; - -/// To add bottom space for send button -// .form-container { -// height: 100%; -// } - -.formInnerContainer { - height: 100%; - display: flex; - flex-direction: column; -} - -.fullModal { - width: 100%; - height: 100%; - max-width: none; - max-height: none; - border: 0; - margin: 0; - padding: 0; - - &:global(.modal-content) { - box-shadow: none; - } -} - -.addressBookButton { - background: white; - border-top-left-radius: 0; - border-bottom-left-radius: 0; - border-width: 0; - - box-shadow: $input-alternative-box-shadow !important; - - &:hover { - box-shadow: $input-focus-alternative-box-shadow !important; - } -} diff --git a/packages/fetch-extension/src/pages/setting/connections/basic-access.tsx b/packages/fetch-extension/src/pages/setting/connections/basic-access.tsx deleted file mode 100644 index 0713d1e15d..0000000000 --- a/packages/fetch-extension/src/pages/setting/connections/basic-access.tsx +++ /dev/null @@ -1,120 +0,0 @@ -import React, { FunctionComponent, useMemo, useState } from "react"; -import { HeaderLayout } from "@layouts/index"; - -import style from "../style.module.scss"; -import { useNavigate } from "react-router"; -import { observer } from "mobx-react-lite"; -import { useStore } from "../../../stores"; -import { PageButton } from "../page-button"; -import { - ButtonDropdown, - DropdownItem, - DropdownMenu, - DropdownToggle, -} from "reactstrap"; - -import styleConnections from "./style.module.scss"; -import { useIntl } from "react-intl"; -import { useConfirm } from "@components/confirm"; - -export const SettingConnectionsPage: FunctionComponent = observer(() => { - const navigate = useNavigate(); - const intl = useIntl(); - - const { chainStore, permissionStore, analyticsStore } = useStore(); - const [selectedChainId, setSelectedChainId] = useState( - chainStore.current.chainId - ); - const basicAccessInfo = permissionStore.getBasicAccessInfo(selectedChainId); - - const [dropdownOpen, setOpen] = useState(false); - const toggle = () => setOpen(!dropdownOpen); - - const confirm = useConfirm(); - - const xIcon = useMemo( - () => [], - [] - ); - - return ( - { - analyticsStore.logEvent("back_click", { - pageName: "Wallet Access Permissions", - }); - - navigate(-1); - }} - > -
- - - {chainStore.getChain(selectedChainId).chainName} - - -
- Get Chain Infos - {chainStore.chainInfos.map((chainInfo) => { - return ( - { - e.preventDefault(); - - setSelectedChainId(chainInfo.chainId); - }} - > - {chainInfo.chainName} - - ); - })} -
-
-
- {basicAccessInfo.origins.map((origin) => { - return ( - { - e.preventDefault(); - - if ( - await confirm.confirm({ - img: ( - unlink - ), - title: intl.formatMessage({ - id: "setting.connections.confirm.delete-connection.title", - }), - paragraph: intl.formatMessage({ - id: "setting.connections.confirm.delete-connection.paragraph", - }), - }) - ) { - await basicAccessInfo.removeOrigin(origin); - } - }} - icons={xIcon} - /> - ); - })} -
-
- ); -}); diff --git a/packages/fetch-extension/src/pages/setting/connections/index.tsx b/packages/fetch-extension/src/pages/setting/connections/index.tsx deleted file mode 100644 index bf28a1d21d..0000000000 --- a/packages/fetch-extension/src/pages/setting/connections/index.tsx +++ /dev/null @@ -1,2 +0,0 @@ -export * from "./basic-access"; -export * from "./viewing-key"; diff --git a/packages/fetch-extension/src/pages/setting/connections/style.module.scss b/packages/fetch-extension/src/pages/setting/connections/style.module.scss deleted file mode 100644 index caf238da94..0000000000 --- a/packages/fetch-extension/src/pages/setting/connections/style.module.scss +++ /dev/null @@ -1,10 +0,0 @@ -@import "../../../styles/var"; - -.dropdown { - margin-left: $layout-padding; - width: fit-content; -} -.dropdownWrapper { - height: 400px; - overflow-y: scroll; -} diff --git a/packages/fetch-extension/src/pages/setting/connections/viewing-key.tsx b/packages/fetch-extension/src/pages/setting/connections/viewing-key.tsx deleted file mode 100644 index 5f86d3aafe..0000000000 --- a/packages/fetch-extension/src/pages/setting/connections/viewing-key.tsx +++ /dev/null @@ -1,97 +0,0 @@ -import React, { FunctionComponent, useMemo } from "react"; -import { useNavigate, useParams } from "react-router"; -import { observer } from "mobx-react-lite"; -import { useStore } from "../../../stores"; -import style from "../style.module.scss"; -import { PageButton } from "../page-button"; -import { HeaderLayout } from "@layouts/index"; -import { useIntl } from "react-intl"; -import { useConfirm } from "@components/confirm"; -import { Secret20ViewingKeyPermissionInnerStore } from "@keplr-wallet/stores"; - -export const SettingSecret20ViewingKeyConnectionsPage: FunctionComponent = - observer(() => { - const { contractAddress } = useParams<{ contractAddress?: string }>(); - - const intl = useIntl(); - const navigate = useNavigate(); - const confirm = useConfirm(); - - const { chainStore, permissionStore, queriesStore, analyticsStore } = - useStore(); - - let tokenInfo; - let accessInfo: Secret20ViewingKeyPermissionInnerStore | undefined; - - if (contractAddress) { - tokenInfo = queriesStore - .get(chainStore.current.chainId) - .secret.querySecret20ContractInfo.getQueryContract(contractAddress); - - accessInfo = permissionStore.getSecret20ViewingKeyAccessInfo( - chainStore.current.chainId, - contractAddress - ); - } - - const xIcon = useMemo( - () => [], - [] - ); - - return ( - { - analyticsStore.logEvent("back_click", { pageName: "Connections" }); - navigate(-1); - }} - > -
-
{`${tokenInfo?.tokenInfo?.name} (${tokenInfo?.tokenInfo?.symbol})`}
- {accessInfo?.origins.map((origin) => { - return ( - { - e.preventDefault(); - - if ( - await confirm.confirm({ - img: ( - unlink - ), - title: intl.formatMessage({ - id: "setting.connections.viewing-key.confirm.delete-connection.title", - }), - paragraph: intl.formatMessage({ - id: "setting.connections.viewing-key.confirm.delete-connection.paragraph", - }), - }) - ) { - await accessInfo?.removeOrigin(origin); - } - }} - icons={xIcon} - /> - ); - })} -
-
- ); - }); diff --git a/packages/fetch-extension/src/pages/setting/export-to-mobile/index.tsx b/packages/fetch-extension/src/pages/setting/export-to-mobile/index.tsx deleted file mode 100644 index 77c498460f..0000000000 --- a/packages/fetch-extension/src/pages/setting/export-to-mobile/index.tsx +++ /dev/null @@ -1,464 +0,0 @@ -import React, { FunctionComponent, useEffect, useRef, useState } from "react"; -import { HeaderLayout } from "@layouts/index"; -import { useNavigate } from "react-router"; -import { FormattedMessage, useIntl } from "react-intl"; -// eslint-disable-next-line @typescript-eslint/ban-ts-comment -// @ts-ignore -import QRCode from "qrcode.react"; -import style from "./style.module.scss"; -import WalletConnect from "@walletconnect/client"; -import { Buffer } from "buffer/"; -import { Button, Form } from "reactstrap"; -import { observer } from "mobx-react-lite"; -import { useStore } from "../../../stores"; -import { useForm } from "react-hook-form"; -import { PasswordInput } from "@components/form"; -import { ExportKeyRingData } from "@keplr-wallet/background"; -import AES, { Counter } from "aes-js"; -import { AddressBookConfigMap, AddressBookData } from "@keplr-wallet/hooks"; -import { ExtensionKVStore } from "@keplr-wallet/common"; -import { toJS } from "mobx"; -import { useConfirm } from "@components/confirm"; - -export interface QRCodeSharedData { - // The uri for the wallet connect - wcURI: string; - // The temporary password for encrypt/descrypt the key datas. - // This must not be shared the other than the extension and mobile. - sharedPassword: string; -} - -export interface WCExportKeyRingDatasResponse { - encrypted: { - // ExportKeyRingData[] - // Json format and hex encoded - ciphertext: string; - // Hex encoded - iv: string; - }; - addressBooks: { [chainId: string]: AddressBookData[] | undefined }; -} - -export const ExportToMobilePage: FunctionComponent = () => { - const navigate = useNavigate(); - const intl = useIntl(); - const { analyticsStore } = useStore(); - - const [exportKeyRingDatas, setExportKeyRingDatas] = useState< - ExportKeyRingData[] - >([]); - - return ( - { - navigate(-1); - analyticsStore.logEvent("back_click", { - pageName: "Link ASI Mobile Wallet", - }); - }} - > - {exportKeyRingDatas.length === 0 ? ( - - ) : ( - { - setExportKeyRingDatas([]); - }} - /> - )} - - ); -}; - -interface FormData { - password: string; -} - -export const EnterPasswordToExportKeyRingView: FunctionComponent<{ - onSetExportKeyRingDatas: (datas: ExportKeyRingData[]) => void; -}> = observer(({ onSetExportKeyRingDatas }) => { - const { keyRingStore } = useStore(); - - const intl = useIntl(); - - const { - register, - handleSubmit, - setError, - formState: { errors }, - } = useForm({ - defaultValues: { - password: "", - }, - }); - - const [loading, setLoading] = useState(false); - - return ( -
-
- info -
-

- Only scan on ASI Mobile Wallet -

-
- Scanning the QR code outside of ASI Mobile Wallet can lead to loss - of funds -
-
-
-
- export-to-mobile -
- Scan QR code to export accounts to ASI Mobile Wallet -
- {keyRingStore.multiKeyStoreInfo.length > 2 ? ( -
- The process may take several minutes -
- ) : null} -
-
{ - setLoading(true); - try { - onSetExportKeyRingDatas( - await keyRingStore.exportKeyRingDatas(data.password) - ); - } catch (e) { - console.log("Fail to decrypt: " + e.message); - setError("password", { - message: intl.formatMessage({ - id: "setting.export-to-mobile.input.password.error.invalid", - }), - }); - } finally { - setLoading(false); - } - })} - > - - - -
- ); -}); - -const QRCodeView: FunctionComponent<{ - keyRingData: ExportKeyRingData[]; - - cancel: () => void; -}> = observer(({ keyRingData, cancel }) => { - const { chainStore } = useStore(); - - const navigate = useNavigate(); - const confirm = useConfirm(); - const intl = useIntl(); - - const [connector, setConnector] = useState(); - const [qrCodeData, setQRCodeData] = useState(); - - const cancelRef = useRef(cancel); - cancelRef.current = cancel; - const [isExpired, setIsExpired] = useState(false); - const processOnce = useRef(false); - - const [addressBookConfigMap] = useState( - () => - new AddressBookConfigMap(new ExtensionKVStore("address-book"), chainStore) - ); - - useEffect(() => { - const id = setTimeout(() => { - if (processOnce.current) { - return; - } - // Hide qr code after 30 seconds. - setIsExpired(true); - - confirm - .confirm({ - paragraph: intl.formatMessage( - { - id: "setting.export-to-mobile.qr-code-view.session-expired", - }, - { - forceYes: true, - } - ), - hideNoButton: true, - }) - .then(() => { - cancelRef.current(); - }); - }, 30000); - - return () => { - clearTimeout(id); - }; - }, [confirm, intl]); - - useEffect(() => { - (async () => { - const connector = new WalletConnect({ - bridge: "https://wc-bridge.keplr.app", - }); - - if (connector.connected) { - await connector.killSession(); - } - - setConnector(connector); - })(); - }, []); - - useEffect(() => { - if (connector) { - connector.on("display_uri", (error, payload) => { - if (error) { - console.log(error); - navigate("/"); - return; - } - - const bytes = new Uint8Array(32); - crypto.getRandomValues(bytes); - const password = Buffer.from(bytes).toString("hex"); - - const uri = payload.params[0] as string; - setQRCodeData({ - wcURI: uri, - sharedPassword: password, - }); - }); - - connector.createSession(); - } - }, [connector, navigate]); - - const onConnect = (error: any) => { - if (error) { - console.log(error); - navigate("/"); - } - }; - const onConnectRef = useRef(onConnect); - onConnectRef.current = onConnect; - - const onCallRequest = (error: any, payload: any) => { - if (!connector || !qrCodeData) { - return; - } - - if ( - isExpired || - error || - payload.method !== "keplr_request_export_keyring_datas_wallet_connect_v1" - ) { - console.log(error, payload?.method); - navigate("/"); - } else { - if (processOnce.current) { - return; - } - processOnce.current = true; - - const buf = Buffer.from(JSON.stringify(keyRingData)); - - const bytes = new Uint8Array(16); - crypto.getRandomValues(bytes); - const iv = Buffer.from(bytes); - - const counter = new Counter(0); - counter.setBytes(iv); - const aesCtr = new AES.ModeOfOperation.ctr( - Buffer.from(qrCodeData.sharedPassword, "hex"), - counter - ); - - (async () => { - const addressBooks: { - [chainId: string]: AddressBookData[] | undefined; - } = {}; - - if (payload.params && payload.params.length > 0) { - for (const chainId of payload.params[0].addressBookChainIds ?? []) { - const addressBookConfig = - addressBookConfigMap.getAddressBookConfig(chainId); - - await addressBookConfig.waitLoaded(); - - addressBooks[chainId] = toJS( - addressBookConfig.addressBookDatas - ) as AddressBookData[]; - } - } - - const response: WCExportKeyRingDatasResponse = { - encrypted: { - ciphertext: Buffer.from(aesCtr.encrypt(buf)).toString("hex"), - // Hex encoded - iv: iv.toString("hex"), - }, - addressBooks, - }; - - connector.approveRequest({ - id: payload.id, - result: [response], - }); - - navigate("/"); - })(); - } - }; - const onCallRequestRef = useRef(onCallRequest); - onCallRequestRef.current = onCallRequest; - - useEffect(() => { - if (connector && qrCodeData) { - connector.on("connect", (error) => { - onConnectRef.current(error); - }); - - connector.on("call_request", (error, payload) => { - onCallRequestRef.current(error, payload); - }); - } - }, [connector, qrCodeData]); - - useEffect(() => { - if (connector) { - return () => { - // Kill session after 5 seconds. - // Delay is needed because it is possible for wc to being processing the request. - setTimeout(() => { - connector.killSession().catch(console.log); - }, 5000); - }; - } - }, [connector]); - - return ( -
-
-
- { - if (isExpired) { - return intl.formatMessage({ - id: "setting.export-to-mobile.qr-code-view.expired", - }); - } - - if (qrCodeData) { - return JSON.stringify(qrCodeData); - } - - return ""; - })()} - /> -
- Scan this QR code on ASI Mobile Wallet to export your accounts. -
-
-
-
- ); -}); diff --git a/packages/fetch-extension/src/pages/setting/export-to-mobile/style.module.scss b/packages/fetch-extension/src/pages/setting/export-to-mobile/style.module.scss deleted file mode 100644 index 349ee1cd4d..0000000000 --- a/packages/fetch-extension/src/pages/setting/export-to-mobile/style.module.scss +++ /dev/null @@ -1,8 +0,0 @@ -@import "../../../styles/var"; - -.container { - display: flex; - flex-direction: column; - - height: 100%; -} diff --git a/packages/fetch-extension/src/pages/setting/export/index.tsx b/packages/fetch-extension/src/pages/setting/export/index.tsx deleted file mode 100644 index bdbc2ee112..0000000000 --- a/packages/fetch-extension/src/pages/setting/export/index.tsx +++ /dev/null @@ -1,135 +0,0 @@ -import React, { - FunctionComponent, - useCallback, - useEffect, - useState, -} from "react"; -import { HeaderLayout } from "@layouts/index"; - -import { useNavigate, useLocation, useParams } from "react-router"; -import { FormattedMessage, useIntl } from "react-intl"; -import { PasswordInput } from "@components/form"; -import { Button, Form } from "reactstrap"; -import { useForm } from "react-hook-form"; -import { WarningView } from "./warning-view"; - -import classnames from "classnames"; -import queryString from "query-string"; - -import style from "./style.module.scss"; -import { observer } from "mobx-react-lite"; -import { useStore } from "../../../stores"; -import { flowResult } from "mobx"; - -interface FormData { - password: string; -} - -export const ExportPage: FunctionComponent = observer(() => { - const navigate = useNavigate(); - const location = useLocation(); - const { index = "-1 " } = useParams<{ index: string; type?: string }>(); - - const intl = useIntl(); - - const { keyRingStore, analyticsStore } = useStore(); - - const query = queryString.parse(location.search); - - const type = query["type"] ?? "mnemonic"; - - const [loading, setLoading] = useState(false); - const [keyRing, setKeyRing] = useState(""); - - const { - register, - handleSubmit, - setError, - formState: { errors }, - } = useForm({ - defaultValues: { - password: "", - }, - }); - - useEffect(() => { - if (parseInt(index).toString() !== index) { - throw new Error("Invalid index"); - } - }, [index]); - - return ( - { - analyticsStore.logEvent("back_click", { - pageName: - type === "mnemonic" ? "View Mnemonic Seed" : "View Private Key", - }); - navigate(-1); - }, [navigate])} - > -
- {keyRing ? ( -
- {keyRing} -
- ) : ( - - -
{ - setLoading(true); - try { - setKeyRing( - await flowResult( - keyRingStore.showKeyRing(parseInt(index), data.password) - ) - ); - } catch (e) { - console.log("Fail to decrypt: " + e.message); - setError("password", { - message: intl.formatMessage({ - id: "setting.export.input.password.error.invalid", - }), - }); - } finally { - setLoading(false); - } - })} - > - - - -
- )} -
-
- ); -}); diff --git a/packages/fetch-extension/src/pages/setting/export/style.module.scss b/packages/fetch-extension/src/pages/setting/export/style.module.scss deleted file mode 100644 index ccd49d2b29..0000000000 --- a/packages/fetch-extension/src/pages/setting/export/style.module.scss +++ /dev/null @@ -1,32 +0,0 @@ -@import "../../../../../../node_modules/argon-dashboard-react/src/assets/scss/argon-dashboard/custom/functions"; -@import "../../../../../../node_modules/argon-dashboard-react/src/assets/scss/argon-dashboard/custom/mixins"; -@import "../../../../../../node_modules/argon-dashboard-react/src/assets/scss/argon-dashboard/custom/variables"; - -.container { - display: flex; - flex-direction: column; - - height: 100%; -} - -.mnemonic { - font-family: "Courier Prime", serif; - font-size: 16px; - letter-spacing: -0.36px; - - padding: 20px 30px; - text-align: center; - - background: white; - border-radius: 6px; - - box-shadow: $input-alternative-box-shadow !important; - - &.alt-hex { - word-break: break-all; - - &::before { - content: "0x"; - } - } -} diff --git a/packages/fetch-extension/src/pages/setting/export/warning-view.module.scss b/packages/fetch-extension/src/pages/setting/export/warning-view.module.scss deleted file mode 100644 index 9a57a454ab..0000000000 --- a/packages/fetch-extension/src/pages/setting/export/warning-view.module.scss +++ /dev/null @@ -1,20 +0,0 @@ -.innerContainer { - flex: 1; - - display: flex; - flex-direction: column; - justify-content: center; - align-items: center; - - .imgLock { - height: 96px; - } - - p { - margin-top: 18px; - - font-size: 16px; - letter-spacing: -0.3px; - color: #32325d; - } -} diff --git a/packages/fetch-extension/src/pages/setting/export/warning-view.tsx b/packages/fetch-extension/src/pages/setting/export/warning-view.tsx deleted file mode 100644 index 5c14ee2860..0000000000 --- a/packages/fetch-extension/src/pages/setting/export/warning-view.tsx +++ /dev/null @@ -1,19 +0,0 @@ -import React, { FunctionComponent } from "react"; - -import styleWarningView from "./warning-view.module.scss"; -import { FormattedMessage } from "react-intl"; - -export const WarningView: FunctionComponent = () => { - return ( -
- lock -

- -

-
- ); -}; diff --git a/packages/fetch-extension/src/pages/sign/adr-36.tsx b/packages/fetch-extension/src/pages/sign/adr-36.tsx deleted file mode 100644 index 145c0c9c9b..0000000000 --- a/packages/fetch-extension/src/pages/sign/adr-36.tsx +++ /dev/null @@ -1,148 +0,0 @@ -import React, { FunctionComponent, useMemo } from "react"; -import { SignDocWrapper } from "@keplr-wallet/cosmos"; -import { observer } from "mobx-react-lite"; -import { useStore } from "../../stores"; -import { Buffer } from "buffer/"; -import { MsgRender } from "./details-tab"; -import styleDetailsTab from "./details-tab.module.scss"; -import { Label } from "reactstrap"; -import { EthSignType } from "@keplr-wallet/types"; -import { renderEvmTxn } from "./evm"; -import { useIntl } from "react-intl"; -import { UnsignedTransaction } from "@ethersproject/transactions"; - -export const ADR36SignDocDetailsTab: FunctionComponent<{ - signDocWrapper: SignDocWrapper; - isADR36WithString?: boolean; - ethSignType?: EthSignType; - origin?: string; -}> = observer(({ signDocWrapper, isADR36WithString, ethSignType, origin }) => { - const { chainStore, accountStore } = useStore(); - const intl = useIntl(); - - const renderTitleText = () => { - if (ethSignType && ethSignType === EthSignType.TRANSACTION) { - return "Sign transaction for"; - } - return "Prove account ownership to"; - }; - - let evmRenderedMessage: React.ReactElement | undefined; - - const signValue = useMemo(() => { - if (signDocWrapper.aminoSignDoc.msgs.length !== 1) { - throw new Error("Sign doc is inproper ADR-36"); - } - - const msg = signDocWrapper.aminoSignDoc.msgs[0]; - if (msg.type !== "sign/MsgSignData") { - throw new Error("Sign doc is inproper ADR-36"); - } - - if (isADR36WithString) { - const str = Buffer.from(msg.value.data, "base64").toString(); - try { - // In case of json, it is displayed more easily to read. - return JSON.stringify(JSON.parse(str), null, 2); - } catch { - return str; - } - } else if (ethSignType === EthSignType.TRANSACTION) { - try { - const decoder = new TextDecoder(); - const str = decoder.decode(Buffer.from(msg.value.data, "base64")); - const txnParams: UnsignedTransaction = JSON.parse(str); - const msgContent = renderEvmTxn( - txnParams, - chainStore.current.feeCurrencies[0], - chainStore.current.currencies, - intl - ); - - evmRenderedMessage = ( - - - {msgContent.content} - -
- {txnParams.data && - accountStore.getAccount(chainStore.current.chainId).isNanoLedger ? ( -
-
- Before you click ‘Approve’ -
-
    -
  • - Connect your Ledger device and select the Ethereum app -
  • -
  • Enable ‘blind signing’ on your Ledger device
  • -
-
- ) : null} -
- ); - - return JSON.stringify(JSON.parse(str), null, 2); - } catch { - return msg.value.data; - } - } else { - return msg.value.data as string; - } - }, [signDocWrapper.aminoSignDoc.msgs, isADR36WithString, ethSignType]); - - // TODO: Add warning view to let users turn on blind signing option on ledger if EIP712 - - return ( -
-
- {evmRenderedMessage ? ( - evmRenderedMessage - ) : ( - - {origin ?? "Unknown"} - - )} -
- {!evmRenderedMessage && ( -
- -
-
-              {signValue}
-            
-
- -
-
{chainStore.current.chainName}
-
-
- )} -
- ); -}); diff --git a/packages/fetch-extension/src/pages/sign/amino.tsx b/packages/fetch-extension/src/pages/sign/amino.tsx deleted file mode 100644 index b7803e6038..0000000000 --- a/packages/fetch-extension/src/pages/sign/amino.tsx +++ /dev/null @@ -1,186 +0,0 @@ -/* eslint-disable react/display-name */ - -import { - CosmosMsgOpts, - CosmwasmMsgOpts, - SecretMsgOpts, -} from "@keplr-wallet/stores"; -import { Currency } from "@keplr-wallet/types"; -import { FormattedMessage, IntlShape } from "react-intl"; -import React from "react"; -import { Bech32Address } from "@keplr-wallet/cosmos"; -import { Hash } from "@keplr-wallet/crypto"; -import { - MessageObj, - MsgBeginRedelegate, - MsgDelegate, - MsgExecuteContract, - MsgInstantiateContract, - MsgLink, - MsgSend, - MsgTransfer, - MsgUndelegate, - MsgVote, - MsgWithdrawDelegatorReward, - renderMsgBeginRedelegate, - renderMsgDelegate, - renderMsgExecuteContract, - renderMsgInstantiateContract, - renderMsgSend, - renderMsgTransfer, - renderMsgUndelegate, - renderMsgVote, - renderMsgWithdrawDelegatorReward, - renderUnknownMessage, -} from "./messages"; - -export function renderAminoMessage( - msgOpts: { - readonly cosmos: { - readonly msgOpts: CosmosMsgOpts; - }; - readonly cosmwasm: { - readonly msgOpts: CosmwasmMsgOpts; - }; - readonly secret: { - readonly msgOpts: SecretMsgOpts; - }; - }, - msg: MessageObj, - currencies: Currency[], - intl: IntlShape -): { - icon: string | undefined; - title: string; - content: React.ReactElement; -} { - try { - if (msg.type === msgOpts.cosmos.msgOpts.send.native.type) { - const value = msg.value as MsgSend["value"]; - return renderMsgSend(currencies, intl, value.amount, value.to_address); - } - - if (msg.type === msgOpts.cosmos.msgOpts.ibcTransfer.type) { - const value = msg.value as MsgTransfer["value"]; - return renderMsgTransfer( - currencies, - intl, - value.token, - value.receiver, - value.source_channel - ); - } - - if (msg.type === msgOpts.cosmos.msgOpts.redelegate.type) { - const value = msg.value as MsgBeginRedelegate["value"]; - return renderMsgBeginRedelegate( - currencies, - intl, - value.amount, - value.validator_src_address, - value.validator_dst_address - ); - } - - if (msg.type === msgOpts.cosmos.msgOpts.undelegate.type) { - const value = msg.value as MsgUndelegate["value"]; - return renderMsgUndelegate( - currencies, - intl, - value.amount, - value.validator_address - ); - } - - if (msg.type === msgOpts.cosmos.msgOpts.delegate.type) { - const value = msg.value as MsgDelegate["value"]; - return renderMsgDelegate( - currencies, - intl, - value.amount, - value.validator_address - ); - } - - if (msg.type === msgOpts.cosmos.msgOpts.withdrawRewards.type) { - const value = msg.value as MsgWithdrawDelegatorReward["value"]; - return renderMsgWithdrawDelegatorReward(intl, value.validator_address); - } - - if (msg.type === msgOpts.cosmos.msgOpts.govVote.type) { - const value = msg.value as MsgVote["value"]; - return renderMsgVote(intl, value.proposal_id, value.option); - } - - if (msg.type === "wasm/MsgInstantiateContract") { - const value = msg.value as MsgInstantiateContract["value"]; - return renderMsgInstantiateContract( - currencies, - intl, - value.init_funds, - value.admin, - value.code_id, - value.label, - value.init_msg - ); - } - - if ( - msg.type === msgOpts.cosmwasm.msgOpts.executeWasm.type || - msg.type === msgOpts.secret.msgOpts.executeSecretWasm.type - ) { - const value = msg.value as MsgExecuteContract["value"]; - return renderMsgExecuteContract( - currencies, - intl, - value.funds ?? value.sent_funds ?? [], - value.callback_code_hash, - value.contract, - value.msg - ); - } - - if (msg.type === "cyber/Link") { - const value = msg.value as MsgLink["value"]; - - const cyberlinks: { from: string; to: string }[] = []; - - for (const link of value.links) { - cyberlinks.push({ - from: link.from, - to: link.to, - }); - } - - return { - icon: "fas fa-paper-plane", - title: intl.formatMessage({ - id: "sign.list.message.cyber/Link.title", - }), - content: ( - {chunks}, - br:
, - neuron: Bech32Address.shortenAddress(value.neuron, 20), - link: cyberlinks - .map((link) => { - return `${Hash.truncHashPortion( - link.from, - 7, - 7 - )} → ${Hash.truncHashPortion(link.to, 7, 7)}`; - }) - .join(", "), - }} - /> - ), - }; - } - } catch (e) { - console.log(e); - } - - return renderUnknownMessage(msg); -} diff --git a/packages/fetch-extension/src/pages/sign/data-tab.tsx b/packages/fetch-extension/src/pages/sign/data-tab.tsx deleted file mode 100644 index 049f18f1d3..0000000000 --- a/packages/fetch-extension/src/pages/sign/data-tab.tsx +++ /dev/null @@ -1,33 +0,0 @@ -import React, { FunctionComponent } from "react"; -import { observer } from "mobx-react-lite"; -import { SignDocHelper } from "@keplr-wallet/hooks"; - -import style from "./style.module.scss"; -import { EthSignType } from "@keplr-wallet/types"; - -export const DataTab: FunctionComponent<{ - signDocHelper: SignDocHelper; - ethSignType?: EthSignType; -}> = observer(({ signDocHelper, ethSignType }) => { - if ( - ethSignType === EthSignType.TRANSACTION && - signDocHelper.signDocWrapper && - signDocHelper.signDocWrapper.mode === "amino" && - signDocHelper.signDocWrapper.aminoSignDoc.msgs.length === 1 && - signDocHelper.signDocWrapper.aminoSignDoc.msgs[0].type === - "sign/MsgSignData" - ) { - const decoder = new TextDecoder(); - const jsonStr = decoder.decode( - Buffer.from( - signDocHelper.signDocWrapper.aminoSignDoc.msgs[0].value.data, - "base64" - ) - ); - const ethPayload = JSON.stringify(JSON.parse(jsonStr), undefined, 2); - return
{ethPayload}
; - } - - const content = JSON.stringify(signDocHelper.signDocJson, undefined, 2); - return
{content}
; -}); diff --git a/packages/fetch-extension/src/pages/sign/decimals.spec.ts b/packages/fetch-extension/src/pages/sign/decimals.spec.ts deleted file mode 100644 index 12a29beb84..0000000000 --- a/packages/fetch-extension/src/pages/sign/decimals.spec.ts +++ /dev/null @@ -1,42 +0,0 @@ -import { clearDecimals } from "./decimals"; - -describe("clearDecimals", () => { - it("should return the input string if it does not contain a decimal point", () => { - const input = "1234"; - expect(clearDecimals(input)).toBe(input); - }); - - it("should remove trailing zeros after the decimal point", () => { - const input = "1234.0000"; - const expected = "1234"; - expect(clearDecimals(input)).toBe(expected); - }); - - it("should remove the decimal point if the last character is a dot", () => { - const input = "1234."; - const expected = "1234"; - expect(clearDecimals(input)).toBe(expected); - }); - - it("should remove trailing zeros and the decimal point if both are present", () => { - const input = "12.340000"; - const expected = "12.34"; - expect(clearDecimals(input)).toBe(expected); - }); - - it("should handle decimals with no trailing zeros", () => { - const input = "12.34"; - expect(clearDecimals(input)).toBe(input); - }); - - it("should handle input with multiple decimal points", () => { - const input = "12.34.56.000"; - const expected = "12.34.56"; - expect(clearDecimals(input)).toBe(expected); - }); - - it("should handle an empty string input", () => { - const input = ""; - expect(clearDecimals(input)).toBe(input); - }); -}); diff --git a/packages/fetch-extension/src/pages/sign/decimals.ts b/packages/fetch-extension/src/pages/sign/decimals.ts deleted file mode 100644 index ee0f9aaa97..0000000000 --- a/packages/fetch-extension/src/pages/sign/decimals.ts +++ /dev/null @@ -1,18 +0,0 @@ -export function clearDecimals(dec: string): string { - if (!dec.includes(".")) { - return dec; - } - - for (let i = dec.length - 1; i >= 0; i--) { - if (dec[i] === "0") { - dec = dec.slice(0, dec.length - 1); - } else { - break; - } - } - if (dec.length > 0 && dec[dec.length - 1] === ".") { - dec = dec.slice(0, dec.length - 1); - } - - return dec; -} diff --git a/packages/fetch-extension/src/pages/sign/details-tab.module.scss b/packages/fetch-extension/src/pages/sign/details-tab.module.scss deleted file mode 100644 index 03f53c1053..0000000000 --- a/packages/fetch-extension/src/pages/sign/details-tab.module.scss +++ /dev/null @@ -1,76 +0,0 @@ -.hr { - background-color: gray; - margin: 0; - height: 1px; -} - -.container { - flex: 1; - display: flex; - flex-direction: column; -} - -.msgContainer { - flex: 1; - - hr { - margin: 8px 0; - } - - .msg { - display: flex; - flex-direction: row; - - .icon { - display: flex; - flex-direction: column; - margin: 0 10px 0 8px; - width: 24px; - text-align: center; - - i { - font-size: 20px; - line-height: 20px; - } - } - - .contentContainer { - display: flex; - flex: 1; - flex-direction: column; - - .contentTitle { - font-size: 16px; - font-weight: bold; - } - - .content { - font-size: 12px; - color: gray; - } - } - } -} - -.ethLedgerBlindSigningWarning { - padding: 20px 0; - background: #f7f9fc; - border-radius: 6px; - - .title { - font-weight: 600; - font-size: 14px; - line-height: 20px; - color: #323c4a; - margin-bottom: 10px; - margin-left: 28px; - } - - .list { - font-size: 14px; - line-height: 20px; - color: #566172; - padding-inline-start: 36px; - margin-bottom: 0; - } -} diff --git a/packages/fetch-extension/src/pages/sign/details-tab.tsx b/packages/fetch-extension/src/pages/sign/details-tab.tsx deleted file mode 100644 index 8528e99872..0000000000 --- a/packages/fetch-extension/src/pages/sign/details-tab.tsx +++ /dev/null @@ -1,252 +0,0 @@ -import React, { FunctionComponent } from "react"; - -import { observer } from "mobx-react-lite"; -import { useStore } from "../../stores"; - -import styleDetailsTab from "./details-tab.module.scss"; - -import { renderAminoMessage } from "./amino"; -import { Msg } from "@keplr-wallet/types"; -import { FormattedMessage, useIntl } from "react-intl"; -import { FeeButtons, MemoInput } from "@components/form"; -import { - IFeeConfig, - IGasConfig, - IMemoConfig, - SignDocHelper, -} from "@keplr-wallet/hooks"; -import { useLanguage } from "../../languages"; -import { Badge, Button, Label } from "reactstrap"; -import { renderDirectMessage } from "./direct"; -import { AnyWithUnpacked } from "@keplr-wallet/cosmos"; -import { CoinPretty } from "@keplr-wallet/unit"; - -export const DetailsTab: FunctionComponent<{ - signDocHelper: SignDocHelper; - memoConfig: IMemoConfig; - feeConfig: IFeeConfig; - gasConfig: IGasConfig; - - isInternal: boolean; - - preferNoSetFee: boolean; - preferNoSetMemo: boolean; - - isNeedLedgerEthBlindSigning: boolean; -}> = observer( - ({ - signDocHelper, - memoConfig, - feeConfig, - gasConfig, - isInternal, - preferNoSetFee, - preferNoSetMemo, - isNeedLedgerEthBlindSigning, - }) => { - const { chainStore, priceStore, accountStore } = useStore(); - const intl = useIntl(); - const language = useLanguage(); - - const mode = signDocHelper.signDocWrapper - ? signDocHelper.signDocWrapper.mode - : "none"; - const msgs = signDocHelper.signDocWrapper - ? signDocHelper.signDocWrapper.mode === "amino" - ? signDocHelper.signDocWrapper.aminoSignDoc.msgs - : signDocHelper.signDocWrapper.protoSignDoc.txMsgs - : []; - - const renderedMsgs = (() => { - if (mode === "amino") { - return (msgs as readonly Msg[]).map((msg, i) => { - const msgContent = renderAminoMessage( - accountStore.getAccount(chainStore.current.chainId), - msg, - chainStore.current.currencies, - intl - ); - return ( - - - {msgContent.content} - -
-
- ); - }); - } else if (mode === "direct") { - return (msgs as AnyWithUnpacked[]).map((msg, i) => { - const msgContent = renderDirectMessage( - msg, - chainStore.current.currencies, - intl - ); - return ( - - - {msgContent.content} - -
-
- ); - }); - } else { - return null; - } - })(); - - return ( -
- -
- {renderedMsgs} -
-
- {!preferNoSetMemo ? ( - - ) : ( - - -
-
- {memoConfig.memo - ? memoConfig.memo - : intl.formatMessage({ id: "sign.info.warning.empty-memo" })} -
-
-
- )} - {!preferNoSetFee || !feeConfig.isManual ? ( - - ) : ( - - -
-
- {(() => { - // To modify the gas in the current component composition, - // the fee buttons component should be shown. - // However, if the fee amount is an empty array, the UI to show is ambiguous. - // Therefore, if the fee amount is an empty array, it is displayed as 0 fee in some asset. - const feeOrZero = - feeConfig.fee ?? - (() => { - if (chainStore.current.feeCurrencies.length === 0) { - return new CoinPretty( - chainStore.current.stakeCurrency, - "0" - ); - } - - return new CoinPretty( - chainStore.current.feeCurrencies[0], - "0" - ); - })(); - - return ( - - {feeOrZero.maxDecimals(6).trim(true).toString()} - {priceStore.calculatePrice( - feeOrZero, - language.fiatCurrency - ) ? ( -
- {priceStore - .calculatePrice(feeOrZero, language.fiatCurrency) - ?.toString()} -
- ) : null} -
- ); - })()} -
-
- { - /* - Even if the "preferNoSetFee" option is turned on, it provides the way to edit the fee to users. - However, if the interaction is internal, you can be sure that the fee is set well inside Keplr. - Therefore, the button is not shown in this case. - */ - !isInternal ? ( -
- -
- ) : null - } -
- )} - {isNeedLedgerEthBlindSigning ? ( -
-
- Before you click ‘Approve’ -
-
    -
  • Connect your Ledger device and select the Ethereum app
  • -
  • Enable ‘blind signing’ on your Ledger device
  • -
-
- ) : null} -
- ); - } -); - -export const MsgRender: FunctionComponent<{ - icon?: string; - title: string; -}> = ({ icon = "fas fa-question", title, children }) => { - return ( -
-
-
- -
-
-
-
{title}
-
{children}
-
-
- ); -}; diff --git a/packages/fetch-extension/src/pages/sign/direct.tsx b/packages/fetch-extension/src/pages/sign/direct.tsx deleted file mode 100644 index 4f23cf915c..0000000000 --- a/packages/fetch-extension/src/pages/sign/direct.tsx +++ /dev/null @@ -1,197 +0,0 @@ -import { Currency } from "@keplr-wallet/types"; -import { IntlShape } from "react-intl"; -import { AnyWithUnpacked, UnknownMessage } from "@keplr-wallet/cosmos"; -import { - renderGenericMsgGrant, - renderMsgBeginRedelegate, - renderMsgDelegate, - renderMsgExecuteContract, - renderMsgInstantiateContract, - renderMsgRevoke, - renderMsgSend, - renderMsgTransfer, - renderMsgUndelegate, - renderMsgVote, - renderMsgWithdrawDelegatorReward, - renderSendMsgGrant, - renderStakeMsgGrant, - renderUnknownMessage, -} from "./messages"; -import { Buffer } from "buffer/"; -import { MsgSend } from "@keplr-wallet/proto-types/cosmos/bank/v1beta1/tx"; -import { - MsgBeginRedelegate, - MsgDelegate, - MsgUndelegate, -} from "@keplr-wallet/proto-types/cosmos/staking/v1beta1/tx"; -import { MsgVote } from "@keplr-wallet/proto-types/cosmos/gov/v1beta1/tx"; -import { MsgWithdrawDelegatorReward } from "@keplr-wallet/proto-types/cosmos/distribution/v1beta1/tx"; -import { - MsgExecuteContract, - MsgInstantiateContract, -} from "@keplr-wallet/proto-types/cosmwasm/wasm/v1/tx"; -import { MsgTransfer } from "@keplr-wallet/proto-types/ibc/applications/transfer/v1/tx"; -import { - MsgGrant, - MsgRevoke, -} from "@keplr-wallet/proto-types/cosmos/authz/v1beta1/tx"; -import { GenericAuthorization } from "@keplr-wallet/proto-types/cosmos/authz/v1beta1/authz"; -import { SendAuthorization } from "@keplr-wallet/proto-types/cosmos/bank/v1beta1/authz"; -import { StakeAuthorization } from "@keplr-wallet/proto-types/cosmos/staking/v1beta1/authz"; - -export function renderDirectMessage( - msg: AnyWithUnpacked, - currencies: Currency[], - intl: IntlShape -) { - try { - if (msg instanceof UnknownMessage) { - return renderUnknownMessage(msg.toJSON()); - } - - if ("unpacked" in msg) { - switch (msg.typeUrl) { - case "/cosmos.bank.v1beta1.MsgSend": { - const sendMsg = msg.unpacked as MsgSend; - return renderMsgSend( - currencies, - intl, - sendMsg.amount, - sendMsg.toAddress - ); - } - case "/cosmos.staking.v1beta1.MsgDelegate": { - const delegateMsg = msg.unpacked as MsgDelegate; - if (delegateMsg.amount) { - return renderMsgDelegate( - currencies, - intl, - delegateMsg.amount, - delegateMsg.validatorAddress - ); - } - break; - } - case "/cosmos.staking.v1beta1.MsgBeginRedelegate": { - const redelegateMsg = msg.unpacked as MsgBeginRedelegate; - if (redelegateMsg.amount) { - return renderMsgBeginRedelegate( - currencies, - intl, - redelegateMsg.amount, - redelegateMsg.validatorSrcAddress, - redelegateMsg.validatorDstAddress - ); - } - break; - } - case "/cosmos.staking.v1beta1.MsgUndelegate": { - const undelegateMsg = msg.unpacked as MsgUndelegate; - if (undelegateMsg.amount) { - return renderMsgUndelegate( - currencies, - intl, - undelegateMsg.amount, - undelegateMsg.validatorAddress - ); - } - break; - } - case "/cosmwasm.wasm.v1.MsgInstantiateContract": { - const instantiateContractMsg = msg.unpacked as MsgInstantiateContract; - return renderMsgInstantiateContract( - currencies, - intl, - instantiateContractMsg.funds, - instantiateContractMsg.admin, - instantiateContractMsg.codeId, - instantiateContractMsg.label, - JSON.parse(Buffer.from(instantiateContractMsg.msg).toString()) - ); - } - case "/cosmwasm.wasm.v1.MsgExecuteContract": { - const executeContractMsg = msg.unpacked as MsgExecuteContract; - return renderMsgExecuteContract( - currencies, - intl, - executeContractMsg.funds, - undefined, - executeContractMsg.contract, - JSON.parse(Buffer.from(executeContractMsg.msg).toString()) - ); - } - case "/cosmos.authz.v1beta1.MsgGrant": { - const grantMsg = msg.unpacked as MsgGrant; - - switch (grantMsg.grant?.authorization?.typeUrl) { - case "/cosmos.bank.v1beta1.SendAuthorization": - return renderSendMsgGrant( - currencies, - intl, - grantMsg.grantee, - grantMsg.grant.expiration, - SendAuthorization.decode(grantMsg.grant.authorization.value) - ); - - case "/cosmos.staking.v1beta1.StakeAuthorization": - return renderStakeMsgGrant( - currencies, - intl, - grantMsg.grantee, - grantMsg.grant.expiration, - StakeAuthorization.decode(grantMsg.grant?.authorization.value) - ); - - default: - return renderGenericMsgGrant( - intl, - grantMsg.grantee, - grantMsg.grant?.expiration, - grantMsg.grant?.authorization?.typeUrl === - "/cosmos.authz.v1beta1.GenericAuthorization" - ? GenericAuthorization.decode( - grantMsg.grant!.authorization!.value - ).msg - : grantMsg.grant!.authorization!.typeUrl - ); - } - } - case "/cosmos.authz.v1beta1.MsgRevoke": { - const revokeMsg = msg.unpacked as MsgRevoke; - return renderMsgRevoke(intl, revokeMsg.msgTypeUrl, revokeMsg.grantee); - } - case "/cosmos.distribution.v1beta1.MsgWithdrawDelegatorReward": { - const withdrawMsg = msg.unpacked as MsgWithdrawDelegatorReward; - return renderMsgWithdrawDelegatorReward( - intl, - withdrawMsg.validatorAddress - ); - } - case "/cosmos.gov.v1beta1.MsgVote": { - const voteMsg = msg.unpacked as MsgVote; - return renderMsgVote(intl, voteMsg.proposalId, voteMsg.option); - } - case "/ibc.applications.transfer.v1.MsgTransfer": { - const transferMsg = msg.unpacked as MsgTransfer; - if (transferMsg.token) { - return renderMsgTransfer( - currencies, - intl, - transferMsg.token, - transferMsg.receiver, - transferMsg.sourceChannel - ); - } - break; - } - } - } - } catch (e) { - console.log(e); - } - - return renderUnknownMessage({ - typeUrl: msg.typeUrl || "Unknown", - value: Buffer.from(msg.value).toString("base64"), - }); -} diff --git a/packages/fetch-extension/src/pages/sign/evm.tsx b/packages/fetch-extension/src/pages/sign/evm.tsx deleted file mode 100644 index abb6f8b30e..0000000000 --- a/packages/fetch-extension/src/pages/sign/evm.tsx +++ /dev/null @@ -1,90 +0,0 @@ -/* eslint-disable react/display-name */ - -import { erc20MetadataInterface } from "@keplr-wallet/stores"; -import { Currency } from "@keplr-wallet/types"; -import { IntlShape } from "react-intl"; -import React from "react"; -import { - renderMsgEvmExecuteContract, - renderMsgSend, - renderUnknownMessage, -} from "./messages"; -import { UnsignedTransaction } from "@ethersproject/transactions"; -import { BigNumber } from "@ethersproject/bignumber"; -import { DenomHelper } from "@keplr-wallet/common"; - -export function renderEvmTxn( - txnParams: UnsignedTransaction, - nativeCurrency: Currency, - currencies: Currency[], - intl: IntlShape -): { - icon: string | undefined; - title: string; - content: React.ReactElement; -} { - try { - if ( - txnParams.value && - BigNumber.from(txnParams.value).gt(0) && - !txnParams.data - ) { - return renderMsgSend( - currencies, - intl, - [ - { - amount: BigNumber.from(txnParams.value).toString(), - denom: nativeCurrency.coinMinimalDenom, - }, - ], - txnParams.to ?? "", - true - ); - } - - if (txnParams.data) { - const sendCurrency = currencies.find((c) => { - const coin = new DenomHelper(c.coinMinimalDenom); - return coin.type === "erc20" && coin.contractAddress === txnParams.to; - }); - - if (sendCurrency) { - const erc20TransferParams = erc20MetadataInterface.parseTransaction({ - data: txnParams.data.toString(), - value: txnParams.value, - }); - - if (erc20TransferParams.name === "transfer") { - return renderMsgSend( - currencies, - intl, - [ - { - amount: erc20TransferParams.args["_value"].toString(), - denom: sendCurrency.coinMinimalDenom, - }, - ], - erc20TransferParams.args["_to"], - true - ); - } - } - - return renderMsgEvmExecuteContract( - intl, - txnParams.value && BigNumber.from(txnParams.value).gt(0) - ? { - amount: BigNumber.from(txnParams.value).toString(), - denom: nativeCurrency.coinMinimalDenom, - } - : undefined, - txnParams - ); - } - } catch (e) { - console.log(e); - } - - return renderUnknownMessage(txnParams); -} diff --git a/packages/fetch-extension/src/pages/sign/index.tsx b/packages/fetch-extension/src/pages/sign/index.tsx deleted file mode 100644 index 4378822519..0000000000 --- a/packages/fetch-extension/src/pages/sign/index.tsx +++ /dev/null @@ -1,411 +0,0 @@ -import React, { FunctionComponent, useEffect, useMemo, useState } from "react"; -import { Button } from "reactstrap"; - -import { HeaderLayout } from "@layouts/index"; - -import style from "./style.module.scss"; - -import { useStore } from "../../stores"; - -import classnames from "classnames"; -import { DataTab } from "./data-tab"; -import { DetailsTab } from "./details-tab"; -import { FormattedMessage, useIntl } from "react-intl"; - -import { useNavigate } from "react-router"; -import { observer } from "mobx-react-lite"; -import { - useFeeConfig, - useInteractionInfo, - useMemoConfig, - useSignDocAmountConfig, - useSignDocHelper, - useZeroAllowedGasConfig, -} from "@keplr-wallet/hooks"; -import { ADR36SignDocDetailsTab } from "./adr-36"; -import { ChainIdHelper } from "@keplr-wallet/cosmos"; -import { unescapeHTML } from "@keplr-wallet/common"; -import { EthSignType } from "@keplr-wallet/types"; - -enum Tab { - Details, - Data, -} - -export const SignPage: FunctionComponent = observer(() => { - const navigate = useNavigate(); - - const [tab, setTab] = useState(Tab.Details); - - const intl = useIntl(); - - const { - chainStore, - keyRingStore, - signInteractionStore, - accountStore, - queriesStore, - analyticsStore, - } = useStore(); - - const [signer, setSigner] = useState(""); - const [origin, setOrigin] = useState(); - const [isADR36WithString, setIsADR36WithString] = useState< - boolean | undefined - >(); - const [ethSignType, setEthSignType] = useState(); - - const current = chainStore.current; - // There are services that sometimes use invalid tx to sign arbitrary data on the sign page. - // In this case, there is no obligation to deal with it, but 0 gas is favorably allowed. - const gasConfig = useZeroAllowedGasConfig(chainStore, current.chainId, 0); - const amountConfig = useSignDocAmountConfig( - chainStore, - accountStore, - current.chainId, - signer - ); - const feeConfig = useFeeConfig( - chainStore, - queriesStore, - current.chainId, - signer, - amountConfig, - gasConfig - ); - const memoConfig = useMemoConfig(chainStore, current.chainId); - - const signDocHelper = useSignDocHelper(feeConfig, memoConfig); - amountConfig.setSignDocHelper(signDocHelper); - - useEffect(() => { - if (signInteractionStore.waitingData) { - const data = signInteractionStore.waitingData; - chainStore.selectChain(data.data.chainId); - if (data.data.signDocWrapper.isADR36SignDoc) { - setIsADR36WithString(data.data.isADR36WithString); - } - if (data.data.ethSignType) { - setEthSignType(data.data.ethSignType); - } - setOrigin(data.data.msgOrigin); - if ( - !data.data.signDocWrapper.isADR36SignDoc && - data.data.chainId !== data.data.signDocWrapper.chainId - ) { - // Validate the requested chain id and the chain id in the sign doc are same. - // If the sign doc is for ADR-36, there is no chain id in the sign doc, so no need to validate. - throw new Error("Chain id unmatched"); - } - signDocHelper.setSignDocWrapper(data.data.signDocWrapper); - gasConfig.setGas(data.data.signDocWrapper.gas); - let memo = data.data.signDocWrapper.memo; - if (data.data.signDocWrapper.mode === "amino") { - // For amino-json sign doc, the memo is escaped by default behavior of golang's json marshaller. - // For normal users, show the escaped characters with unescaped form. - // Make sure that the actual sign doc's memo should be escaped. - // In this logic, memo should be escaped from account store or background's request signing function. - memo = unescapeHTML(memo); - } - memoConfig.setMemo(memo); - if ( - data.data.signOptions.preferNoSetFee && - data.data.signDocWrapper.fees[0] - ) { - feeConfig.setManualFee(data.data.signDocWrapper.fees[0]); - } - amountConfig.setDisableBalanceCheck( - !!data.data.signOptions.disableBalanceCheck - ); - feeConfig.setDisableBalanceCheck( - !!data.data.signOptions.disableBalanceCheck - ); - if ( - data.data.signDocWrapper.granter && - data.data.signDocWrapper.granter !== data.data.signer - ) { - feeConfig.setDisableBalanceCheck(true); - } - setSigner(data.data.signer); - } - }, [ - amountConfig, - chainStore, - gasConfig, - memoConfig, - feeConfig, - signDocHelper, - signInteractionStore.waitingData, - ]); - - // If the preferNoSetFee or preferNoSetMemo in sign options is true, - // don't show the fee buttons/memo input by default - // But, the sign options would be removed right after the users click the approve/reject button. - // Thus, without this state, the fee buttons/memo input would be shown after clicking the approve buttion. - const [isProcessing, setIsProcessing] = useState(false); - const needSetIsProcessing = - signInteractionStore.waitingData?.data.signOptions.preferNoSetFee === - true || - signInteractionStore.waitingData?.data.signOptions.preferNoSetMemo === true; - - const preferNoSetFee = - signInteractionStore.waitingData?.data.signOptions.preferNoSetFee === - true || isProcessing; - const preferNoSetMemo = - signInteractionStore.waitingData?.data.signOptions.preferNoSetMemo === - true || isProcessing; - - const interactionInfo = useInteractionInfo( - () => { - if (needSetIsProcessing) { - setIsProcessing(true); - } - - signInteractionStore.rejectAll(); - }, - { - enableScroll: true, - } - ); - - const currentChainId = chainStore.current.chainId; - const currentChainIdentifier = useMemo( - () => ChainIdHelper.parse(currentChainId).identifier, - [currentChainId] - ); - const selectedChainId = chainStore.selectedChainId; - const selectedChainIdentifier = useMemo( - () => ChainIdHelper.parse(selectedChainId).identifier, - [selectedChainId] - ); - - // Check that the request is delivered - // and the chain is selected properly. - // The chain store loads the saved chain infos including the suggested chain asynchronously on init. - // So, it can be different the current chain and the expected selected chain for a moment. - const isLoaded = (() => { - if (!signDocHelper.signDocWrapper) { - return false; - } - - return currentChainIdentifier === selectedChainIdentifier; - })(); - - // If this is undefined, show the chain name on the header. - // If not, show the alternative title. - const alternativeTitle = (() => { - if (!isLoaded) { - return ""; - } - - if ( - signDocHelper.signDocWrapper && - signDocHelper.signDocWrapper.isADR36SignDoc && - !ethSignType - ) { - return "Prove Ownership"; - } - - return undefined; - })(); - - const approveIsDisabled = (() => { - if (!isLoaded) { - return true; - } - - if (!signDocHelper.signDocWrapper) { - return true; - } - - // If the sign doc is for ADR-36, - // there is no error related to the fee or memo... - if (signDocHelper.signDocWrapper.isADR36SignDoc) { - return false; - } - - return memoConfig.error != null || feeConfig.error != null; - })(); - - return ( - { - analyticsStore.logEvent("back_click", { pageName: "Sign" }); - navigate(-1); - } - : undefined - } - style={{ background: "white", minHeight: "100%" }} - innerStyle={{ display: "flex", flexDirection: "column" }} - > - { - /* - Show the informations of tx when the sign data is delivered. - If sign data not delivered yet, show the spinner alternatively. - */ - isLoaded ? ( -
- -
- {tab === Tab.Data ? ( - - ) : null} - {tab === Tab.Details ? ( - signDocHelper.signDocWrapper?.isADR36SignDoc ? ( - - ) : ( - - ) - ) : null} -
-
- {keyRingStore.keyRingType === "ledger" && - signInteractionStore.isLoading ? ( - - ) : ( - - - - - )} -
-
- ) : ( -
- -
- ) - } -
- ); -}); diff --git a/packages/fetch-extension/src/pages/sign/messages.tsx b/packages/fetch-extension/src/pages/sign/messages.tsx deleted file mode 100644 index 508b82cf6e..0000000000 --- a/packages/fetch-extension/src/pages/sign/messages.tsx +++ /dev/null @@ -1,839 +0,0 @@ -/* eslint-disable react/display-name */ - -import React, { FunctionComponent, useEffect, useMemo, useState } from "react"; -import { Bech32Address } from "@keplr-wallet/cosmos"; -import { CoinUtils, Coin } from "@keplr-wallet/unit"; -import { IntlShape, FormattedMessage, useIntl } from "react-intl"; -import { Currency } from "@keplr-wallet/types"; -import { Button, Badge, Label } from "reactstrap"; -import { observer } from "mobx-react-lite"; -import { useStore } from "../../stores"; -import yaml from "js-yaml"; - -import { Buffer } from "buffer/"; -import { CoinPrimitive } from "@keplr-wallet/stores"; -import { clearDecimals } from "./decimals"; -import { Any } from "@keplr-wallet/proto-types/google/protobuf/any"; -import { Grant } from "@keplr-wallet/proto-types/cosmos/authz/v1beta1/authz"; -import { - AuthorizationType, - StakeAuthorization, -} from "@keplr-wallet/proto-types/cosmos/staking/v1beta1/authz"; -import { SendAuthorization } from "@keplr-wallet/proto-types/cosmos/bank/v1beta1/authz"; -import { UnsignedTransaction } from "@ethersproject/transactions"; - -export interface MessageObj { - readonly type: string; - readonly value: unknown; -} - -export interface MsgSend { - value: { - amount: [ - { - amount: string; - denom: string; - } - ]; - from_address: string; - to_address: string; - }; -} - -export interface MsgTransfer { - value: { - source_port: string; - source_channel: string; - token: { - denom: string; - amount: string; - }; - sender: string; - receiver: string; - timeout_height: { - revision_number: string | undefined; - revision_height: string; - }; - }; -} - -export interface MsgDelegate { - value: { - amount: { - amount: string; - denom: string; - }; - delegator_address: string; - validator_address: string; - }; -} - -export interface MsgUndelegate { - value: { - amount: { - amount: string; - denom: string; - }; - delegator_address: string; - validator_address: string; - }; -} - -export interface MsgWithdrawDelegatorReward { - value: { - delegator_address: string; - validator_address: string; - }; -} - -export interface MsgBeginRedelegate { - value: { - amount: { - amount: string; - denom: string; - }; - delegator_address: string; - validator_dst_address: string; - validator_src_address: string; - }; -} - -export interface MsgVote { - value: { - proposal_id: string; - voter: string; - // In the stargate, option would be the enum (0: empty, 1: yes, 2: abstain, 3: no, 4: no with veto). - option: string | number; - }; -} - -export interface MsgInstantiateContract { - value: { - // Admin field can be omitted. - admin?: string; - sender: string; - code_id: string; - label: string; - // eslint-disable-next-line @typescript-eslint/ban-types - init_msg: object; - init_funds: [ - { - amount: string; - denom: string; - } - ]; - }; -} - -// This message can be a normal cosmwasm message or a secret-wasm message. -export interface MsgExecuteContract { - value: { - contract: string; - // If message is for secret-wasm, msg will be the base64 encoded and encrypted string. - // eslint-disable-next-line @typescript-eslint/ban-types - msg: object | string; - sender: string; - // The field is for wasm message. - funds?: [ - { - amount: string; - denom: string; - } - ]; - // The bottom fields are for secret-wasm message. - sent_funds?: [ - { - amount: string; - denom: string; - } - ]; - callback_code_hash?: string; - callback_sig?: string | null; - }; -} - -export interface MsgLink { - value: { - links: [ - { - from: string; - to: string; - } - ]; - neuron: string; - }; -} - -// eslint-disable-next-line @typescript-eslint/ban-types -export function renderUnknownMessage(msg: object) { - return { - icon: undefined, - title: "Custom", - content: ( - - - - ), - }; -} - -export function renderMsgSend( - currencies: Currency[], - intl: IntlShape, - amount: CoinPrimitive[], - toAddress: string, - isEvm?: boolean -) { - const receives: CoinPrimitive[] = []; - for (const coinPrimitive of amount) { - const coin = new Coin(coinPrimitive.denom, coinPrimitive.amount); - const parsed = CoinUtils.parseDecAndDenomFromCoin(currencies, coin); - - receives.push({ - amount: clearDecimals(parsed.amount), - denom: parsed.denom, - }); - } - - return { - icon: "fas fa-paper-plane", - title: intl.formatMessage({ - id: "sign.list.message.cosmos-sdk/MsgSend.title", - }), - content: ( - {chunks}, - recipient: Bech32Address.shortenAddress(toAddress, 20, isEvm), - amount: receives - .map((coin) => { - return `${coin.amount} ${coin.denom}`; - }) - .join(","), - }} - /> - ), - }; -} - -export function renderMsgTransfer( - currencies: Currency[], - intl: IntlShape, - amount: CoinPrimitive, - receiver: string, - channelId: string -) { - const coin = new Coin(amount.denom, amount.amount); - const parsed = CoinUtils.parseDecAndDenomFromCoin(currencies, coin); - - amount = { - amount: clearDecimals(parsed.amount), - denom: parsed.denom, - }; - - return { - icon: "fas fa-link", - title: intl.formatMessage({ - id: "sign.list.message.cosmos-sdk/MsgTransfer.title", - }), - content: ( - {chunks}, - receiver: Bech32Address.shortenAddress(receiver, 20), - amount: `${amount.amount} ${amount.denom}`, - channel: channelId, - }} - /> - ), - }; -} - -export function renderMsgBeginRedelegate( - currencies: Currency[], - intl: IntlShape, - amount: CoinPrimitive, - validatorSrcAddress: string, - validatorDstAddress: string -) { - const parsed = CoinUtils.parseDecAndDenomFromCoin( - currencies, - new Coin(amount.denom, amount.amount) - ); - - return { - icon: "fas fa-layer-group", - title: intl.formatMessage({ - id: "sign.list.message.cosmos-sdk/MsgBeginRedelegate.title", - }), - content: ( - {chunks}, - fromValidator: Bech32Address.shortenAddress(validatorSrcAddress, 24), - toValidator: Bech32Address.shortenAddress(validatorDstAddress, 24), - amount: `${clearDecimals(parsed.amount)} ${parsed.denom}`, - }} - /> - ), - }; -} - -export function renderMsgUndelegate( - currencies: Currency[], - intl: IntlShape, - amount: CoinPrimitive, - validatorAddress: string -) { - const parsed = CoinUtils.parseDecAndDenomFromCoin( - currencies, - new Coin(amount.denom, amount.amount) - ); - - return { - icon: "fas fa-layer-group", - title: intl.formatMessage({ - id: "sign.list.message.cosmos-sdk/MsgUndelegate.title", - }), - content: ( - {chunks}, - br:
, - validator: Bech32Address.shortenAddress(validatorAddress, 24), - amount: `${clearDecimals(parsed.amount)} ${parsed.denom}`, - }} - /> - ), - }; -} - -export function renderMsgDelegate( - currencies: Currency[], - intl: IntlShape, - amount: CoinPrimitive, - validatorAddress: string -) { - const parsed = CoinUtils.parseDecAndDenomFromCoin( - currencies, - new Coin(amount.denom, amount.amount) - ); - - return { - icon: "fas fa-layer-group", - title: intl.formatMessage({ - id: "sign.list.message.cosmos-sdk/MsgDelegate.title", - }), - content: ( - {chunks}, - validator: Bech32Address.shortenAddress(validatorAddress, 24), - amount: `${clearDecimals(parsed.amount)} ${parsed.denom}`, - }} - /> - ), - }; -} - -export function renderMsgWithdrawDelegatorReward( - intl: IntlShape, - validatorAddress: string -) { - return { - icon: "fas fa-money-bill", - title: intl.formatMessage({ - id: "sign.list.message.cosmos-sdk/MsgWithdrawDelegatorReward.title", - }), - content: ( - {chunks}, - validator: Bech32Address.shortenAddress(validatorAddress, 34), - }} - /> - ), - }; -} - -export function renderMsgVote( - intl: IntlShape, - proposalId: string, - option: string | number -) { - const textualOption = (() => { - if (typeof option === "string") { - return option; - } - - switch (option) { - case 0: - return "Empty"; - case 1: - return "Yes"; - case 2: - return "Abstain"; - case 3: - return "No"; - case 4: - return "No with veto"; - default: - return "Unspecified"; - } - })(); - - return { - icon: "fas fa-vote-yea", - title: intl.formatMessage({ - id: "sign.list.message.cosmos-sdk/MsgVote.title", - }), - content: ( - {chunks}, - id: proposalId, - option: textualOption, - }} - /> - ), - }; -} - -export function renderMsgInstantiateContract( - currencies: Currency[], - intl: IntlShape, - initFunds: CoinPrimitive[], - admin: string | undefined, - codeId: string, - label: string, - // eslint-disable-next-line @typescript-eslint/ban-types - initMsg: object -) { - const funds: { amount: string; denom: string }[] = []; - for (const coinPrimitive of initFunds) { - const coin = new Coin(coinPrimitive.denom, coinPrimitive.amount); - const parsed = CoinUtils.parseDecAndDenomFromCoin(currencies, coin); - - funds.push({ - amount: clearDecimals(parsed.amount), - denom: parsed.denom, - }); - } - - return { - icon: "fas fa-cog", - title: intl.formatMessage({ - id: "sign.list.message.wasm/MsgInstantiateContract.title", - }), - content: ( - - {chunks}, - br:
, - admin: admin ? Bech32Address.shortenAddress(admin, 30) : "", - ["only-admin-exist"]: (...chunks: any[]) => (admin ? chunks : ""), - codeId: codeId, - label: label, - ["only-funds-exist"]: (...chunks: any[]) => - funds.length > 0 ? chunks : "", - funds: funds - .map((coin) => { - return `${coin.amount} ${coin.denom}`; - }) - .join(","), - }} - /> -
- -
- ), - }; -} - -export function renderMsgEvmExecuteContract( - intl: IntlShape, - sent: CoinPrimitive | undefined, - // eslint-disable-next-line @typescript-eslint/ban-types - txnParams: UnsignedTransaction -) { - return { - icon: "fas fa-cog", - title: intl.formatMessage({ - id: "sign.list.message.wasm/MsgExecuteContract.title", - }), - content: ( - - {chunks}, - br:
, - address: Bech32Address.shortenAddress(txnParams.to ?? "", 26, true), - ["only-sent-exist"]: (...chunks: any[]) => (sent ? chunks : ""), - sent: sent ? `${sent.amount} ${sent.denom}` : "", - }} - /> - -
-          {txnParams.data?.toString()}
-        
-
- ), - }; -} - -export function renderMsgExecuteContract( - currencies: Currency[], - intl: IntlShape, - sentFunds: CoinPrimitive[], - callbackCodeHash: string | undefined, - contract: string, - // eslint-disable-next-line @typescript-eslint/ban-types - msg: object | string -) { - const sent: { amount: string; denom: string }[] = []; - for (const coinPrimitive of sentFunds) { - const coin = new Coin(coinPrimitive.denom, coinPrimitive.amount); - const parsed = CoinUtils.parseDecAndDenomFromCoin(currencies, coin); - - sent.push({ - amount: clearDecimals(parsed.amount), - denom: parsed.denom, - }); - } - - const isSecretWasm = callbackCodeHash != null; - - return { - icon: "fas fa-cog", - title: intl.formatMessage({ - id: "sign.list.message.wasm/MsgExecuteContract.title", - }), - content: ( - - {chunks}, - br:
, - address: Bech32Address.shortenAddress(contract, 26), - ["only-sent-exist"]: (...chunks: any[]) => - sent.length > 0 ? chunks : "", - sent: sent - .map((coin) => { - return `${coin.amount} ${coin.denom}`; - }) - .join(","), - }} - /> - {isSecretWasm ? ( - -
- - - -
- ) : ( -
- )} - -
- ), - }; -} - -export function renderGenericMsgGrant( - intl: IntlShape, - granteeAddress: string, - expiration: Grant["expiration"], - grantTypeUrl: Any["typeUrl"] -) { - return { - icon: "fas fa-key", - title: intl.formatMessage({ - id: "sign.list.message.cosmos-sdk/MsgGrant.title", - }), - content: ( - {chunks}, - grantee: Bech32Address.shortenAddress(granteeAddress, 24), - grantType: grantTypeUrl - ? grantTypeUrl.split(".").slice(-1)[0] - : intl.formatMessage({ - id: "sign.list.message.cosmos-sdk/MsgGrant.unspecified", - }), - expirationDate: intl.formatDate(expiration), - }} - /> - ), - }; -} - -const stakingGrantTypes: Record = { - [AuthorizationType.AUTHORIZATION_TYPE_DELEGATE]: - "sign.list.message.cosmos-sdk/MsgDelegate.title", - [AuthorizationType.AUTHORIZATION_TYPE_REDELEGATE]: - "sign.list.message.cosmos-sdk/MsgBeginRedelegate.title", - [AuthorizationType.AUTHORIZATION_TYPE_UNDELEGATE]: - "sign.list.message.cosmos-sdk/MsgUndelegate.title", - [AuthorizationType.AUTHORIZATION_TYPE_UNSPECIFIED]: - "sign.list.message.cosmos-sdk/MsgGrant.unspecified", - [AuthorizationType.UNRECOGNIZED]: - "sign.list.message.cosmos-sdk/MsgGrant.unrecognized", -}; - -export function renderStakeMsgGrant( - currencies: Currency[], - intl: IntlShape, - grantee: string, - expiration: Grant["expiration"], - stakingSettings: StakeAuthorization -) { - const parsedMaxAmount = - stakingSettings.maxTokens && - CoinUtils.parseDecAndDenomFromCoin( - currencies, - new Coin( - stakingSettings.maxTokens.denom, - stakingSettings.maxTokens.amount - ) - ); - - return { - icon: "fas fa-key", - title: intl.formatMessage({ - id: "sign.list.message.cosmos-sdk/MsgGrant.title", - }), - content: ( - {chunks}, - br:
, - grantee: Bech32Address.shortenAddress(grantee, 24), - grantType: intl.formatMessage({ - id: stakingGrantTypes[stakingSettings.authorizationType], - }), - expirationDate: intl.formatDate(expiration), - validatorListType: intl.formatMessage({ - id: stakingSettings.allowList?.address.length - ? "sign.list.message.cosmos-sdk/MsgGrant.staking.validatorAllowedLabel" - : "sign.list.message.cosmos-sdk/MsgGrant.staking.validatorDeniedLabel", - }), - validators: intl.formatList( - ( - stakingSettings.allowList?.address || - stakingSettings.denyList?.address || - [] - ).map((valAddress) => Bech32Address.shortenAddress(valAddress, 24)) - ), - maxAmount: parsedMaxAmount - ? `${clearDecimals(parsedMaxAmount.amount)} ${ - parsedMaxAmount.denom - }` - : intl.formatMessage({ - id: "sign.list.message.cosmos-sdk/MsgGrant.unlimited", - }), - }} - /> - ), - }; -} - -export function renderSendMsgGrant( - currencies: Currency[], - intl: IntlShape, - granteeAddress: string, - expiration: Grant["expiration"], - sendSettings: SendAuthorization -) { - const maxAmount = - intl.formatList( - sendSettings.spendLimit - ?.map((amount) => - CoinUtils.parseDecAndDenomFromCoin( - currencies, - new Coin(amount.denom, amount.amount) - ) - ) - ?.map((coin) => `${clearDecimals(coin.amount)} ${coin.denom}`) - ) || - intl.formatMessage({ - id: "sign.list.message.cosmos-sdk/MsgGrant.unlimited", - }); - - return { - icon: "fas fa-key", - title: intl.formatMessage({ - id: "sign.list.message.cosmos-sdk/MsgGrant.title", - }), - content: ( - {chunks}, - br:
, - grantee: Bech32Address.shortenAddress(granteeAddress, 24), - maxAmount, - expirationDate: intl.formatDate(expiration), - }} - /> - ), - }; -} - -export function renderMsgRevoke( - intl: IntlShape, - revokeType: string, - granteeAddress: string -) { - return { - icon: "fas fa-lock", - title: intl.formatMessage({ - id: "sign.list.message.cosmos-sdk/MsgRevoke.title", - }), - content: ( - {chunks}, - revokeType: revokeType.split(".").slice(-1)[0], - grantee: Bech32Address.shortenAddress(granteeAddress, 24), - }} - /> - ), - }; -} - -export const WasmExecutionMsgView: FunctionComponent<{ - // eslint-disable-next-line @typescript-eslint/ban-types - msg: object | string; -}> = observer(({ msg }) => { - const { chainStore, accountStore } = useStore(); - - const [isOpen, setIsOpen] = useState(true); - const intl = useIntl(); - - const toggleOpen = () => setIsOpen((isOpen) => !isOpen); - - const [detailsMsg, setDetailsMsg] = useState(() => - JSON.stringify(msg, null, 2) - ); - const [warningMsg, setWarningMsg] = useState(""); - - useEffect(() => { - // If msg is string, it will be the message for secret-wasm. - // So, try to decrypt. - // But, if this msg is not encrypted via Keplr, Keplr cannot decrypt it. - // TODO: Handle the error case. If an error occurs, rather than rejecting the signing, it informs the user that Keplr cannot decrypt it and allows the user to choose. - if (typeof msg === "string") { - (async () => { - try { - let cipherText = Buffer.from(Buffer.from(msg, "base64")); - // Msg is start with 32 bytes nonce and 32 bytes public key. - const nonce = cipherText.slice(0, 32); - cipherText = cipherText.slice(64); - - const keplr = await accountStore - .getAccount(chainStore.current.chainId) - .getKeplr(); - if (!keplr) { - throw new Error("Can't get the keplr API"); - } - - const enigmaUtils = keplr.getEnigmaUtils(chainStore.current.chainId); - let plainText = Buffer.from( - await enigmaUtils.decrypt(cipherText, nonce) - ); - // Remove the contract code hash. - plainText = plainText.slice(64); - - setDetailsMsg( - JSON.stringify(JSON.parse(plainText.toString()), null, 2) - ); - setWarningMsg(""); - } catch { - setWarningMsg( - intl.formatMessage({ - id: "sign.list.message.wasm/MsgExecuteContract.content.warning.secret-wasm.failed-decryption", - }) - ); - } - })(); - } - }, [chainStore, chainStore.current.chainId, intl, msg]); - - return ( -
- {isOpen ? ( - -
{isOpen ? detailsMsg : ""}
- {warningMsg ?
{warningMsg}
: null} -
- ) : null} - -
- ); -}); - -// eslint-disable-next-line @typescript-eslint/ban-types -export const UnknownMsgView: FunctionComponent<{ msg: object }> = ({ msg }) => { - const prettyMsg = useMemo(() => { - try { - return yaml.dump(msg); - } catch (e) { - console.log(e); - return "Failed to decode the msg"; - } - }, [msg]); - - return ( -
-
{prettyMsg}
-
- ); -}; diff --git a/packages/fetch-extension/src/pages/sign/style.module.scss b/packages/fetch-extension/src/pages/sign/style.module.scss deleted file mode 100644 index d73383a3fb..0000000000 --- a/packages/fetch-extension/src/pages/sign/style.module.scss +++ /dev/null @@ -1,67 +0,0 @@ -@import "../../styles/var"; - -.tabs { - ul { - list-style: none; - display: flex; - flex: 1; - padding: 0; - - li { - flex: 1; - text-align: center; - border-bottom-color: #dbdbdb; - border-bottom-style: solid; - border-bottom-width: 1px; - padding-bottom: 8px; - - &:global(.active) { - border-bottom-color: #5e72e4; - color: #5e72e4; - } - } - } - - .tab { - cursor: pointer; - text-decoration: none; - } -} - -.buttons { - display: flex; - padding-top: 15px; -} - -.button { - flex: 1; -} - -.container { - flex: 1; - display: flex; - flex-direction: column; -} - -.tabContainer { - height: 342px; - overflow: auto; - display: flex; - flex-direction: column; - - &.data-tab { - overflow: auto; - } -} - -.message { - margin-bottom: 0px; - height: 400px; - font-size: 12px; - overflow: visible; - background: transparent; - word-wrap: break-word; - white-space: pre-wrap; - color: white; - font-size: Lexend; -} diff --git a/packages/fetch-extension/src/pages/validator-list/index.tsx b/packages/fetch-extension/src/pages/validator-list/index.tsx deleted file mode 100644 index 375b461ac8..0000000000 --- a/packages/fetch-extension/src/pages/validator-list/index.tsx +++ /dev/null @@ -1,179 +0,0 @@ -import searchIcon from "@assets/icon/search.png"; -import { Staking } from "@keplr-wallet/stores"; -import { CoinPretty } from "@keplr-wallet/unit"; -import { HeaderLayout } from "@layouts/header-layout"; -import { observer } from "mobx-react-lite"; -import React, { FunctionComponent, useEffect, useState } from "react"; -import { useLocation, useNavigate } from "react-router"; -import { useStore } from "../../stores"; -import { MyValidatorsList } from "./my-validators"; -import style from "./style.module.scss"; -import { ValidatorsList } from "./validators"; - -type ValidatorData = Staking.Validator & { amount: CoinPretty }; - -export enum ValidatorOperation { - VALIDATOR = "validator", - MY_STAKE = "myStake", -} - -export const ValidatorList: FunctionComponent = observer(() => { - const navigate = useNavigate(); - const location = useLocation(); - const operation = location.pathname.split("/")[2]; - const [validators, setValidators] = useState<{ - [key in string]: ValidatorData; - }>({}); - const [filteredValidators, setFilteredValidators] = useState( - [] - ); - const { analyticsStore } = useStore(); - const [loading, setLoading] = useState(true); - const [searchInput, setSearchInput] = useState(); - const { chainStore, queriesStore, accountStore } = useStore(); - const queries = queriesStore.get(chainStore.current.chainId); - const account = accountStore.getAccount(chainStore.current.chainId); - const queryDelegations = - queries.cosmos.queryDelegations.getQueryBech32Address( - account.bech32Address - ); - useEffect(() => { - const fetchValidators = async () => { - setLoading(true); - const bondedValidators = await queries.cosmos.queryValidators - .getQueryStatus(Staking.BondStatus.Bonded) - .waitFreshResponse(); - const unbondingValidators = await queries.cosmos.queryValidators - .getQueryStatus(Staking.BondStatus.Unbonding) - .waitFreshResponse(); - const unbondedValidators = await queries.cosmos.queryValidators - .getQueryStatus(Staking.BondStatus.Unbonded) - .waitFreshResponse(); - - const map: { - [key in string]: ValidatorData; - } = {}; - for (const val of [ - ...(bondedValidators?.data.validators || []), - ...(unbondingValidators?.data.validators || []), - ...(unbondedValidators?.data.validators || []), - ]) { - const amount = queryDelegations.getDelegationTo(val.operator_address); - - map[val.operator_address] = { ...val, amount }; - } - setValidators(map); - setFilteredValidators(Object.values(map)); - setLoading(false); - }; - fetchValidators(); - }, [queries.cosmos.queryValidators, queryDelegations]); - - useEffect(() => { - analyticsStore.logEvent( - operation == ValidatorOperation.VALIDATOR - ? "stake_validators_tab_click" - : "stake_mystake_tab_click" - ); - }, [operation]); - - const handleFilterValidators = (searchValue: string) => { - const filteredValidators = Object.values(validators).filter((validator) => - searchValue?.trim().length - ? validator.description.moniker - ?.toLowerCase() - .includes(searchValue.toLowerCase()) || - validator.operator_address - ?.toLowerCase() - .includes(searchValue.toLowerCase()) - : true - ); - setFilteredValidators(filteredValidators); - setSearchInput(searchValue); - }; - - return ( - { - analyticsStore.logEvent("back_click", { pageName: "Stake" }); - navigate("/"); - }} - > -
-
{ - localStorage.setItem("validatorTab", ValidatorOperation.VALIDATOR); - navigate(`/validators/${ValidatorOperation.VALIDATOR}`); - analyticsStore.logEvent("stake_validators_tab_click"); - }} - > - Validators -
- -
{ - localStorage.setItem("validatorTab", ValidatorOperation.MY_STAKE); - navigate(`/validators/${ValidatorOperation.MY_STAKE}`); - }} - > - My Stake -
-
-
-
- search - handleFilterValidators(e.target.value)} - /> -
-
- {loading && ( -
-
- - - -
-
- Loading Validators -
- )} - - {!loading && operation === ValidatorOperation.VALIDATOR && ( - - )} - {!loading && operation === ValidatorOperation.MY_STAKE && ( - - )} -
- ); -}); diff --git a/packages/fetch-extension/src/pages/validator-list/my-validator-card/index.tsx b/packages/fetch-extension/src/pages/validator-list/my-validator-card/index.tsx deleted file mode 100644 index 1f70122327..0000000000 --- a/packages/fetch-extension/src/pages/validator-list/my-validator-card/index.tsx +++ /dev/null @@ -1,87 +0,0 @@ -import { ToolTip } from "@components/tooltip"; -import { Staking } from "@keplr-wallet/stores"; -import { CoinPretty } from "@keplr-wallet/unit"; -import { formatAddress, shortenMintingNumber } from "@utils/format"; -import React from "react"; -import { useNavigate } from "react-router"; -import { CHAIN_ID_DORADO, CHAIN_ID_FETCHHUB } from "../../../config.ui.var"; -import styleValidators from "./validators.module.scss"; -import { useStore } from "../../../stores"; - -export const URL: { [key in string]: string } = { - [CHAIN_ID_DORADO]: "https://explore-dorado.fetch.ai/validators", - [CHAIN_ID_FETCHHUB]: "https://www.mintscan.io/fetchai/validators", -}; - -export const MyValidatorCard = ({ - validator, - chainID, -}: { - validator: Staking.Validator & { amount: CoinPretty }; - chainID: string; -}) => { - const navigate = useNavigate(); - const { analyticsStore } = useStore(); - const status = validator.status.split("_")[2].toLowerCase(); - const commisionRate = ( - parseFloat(validator.commission.commission_rates.rate) * 100 - ).toFixed(2); - return ( -
{ - analyticsStore.logEvent("stake_validator_click", { - pageName: "My Stake Tab", - }); - navigate(`/validators/${validator.operator_address}/stake`); - }} - > -
-
- {validator.description.moniker} -
- - {validator.operator_address} -
- } - > - - {formatAddress(validator.operator_address)} - - -
-
-
- Staked - - {shortenMintingNumber(validator.amount.toDec().toString(), 0)} - {validator.amount.currency.coinDenom} - -
-
- Commission - {commisionRate}% -
-
- Status - {status} -
-
- - View in Explorer - -
- ); -}; diff --git a/packages/fetch-extension/src/pages/validator-list/my-validator-card/validators.module.scss b/packages/fetch-extension/src/pages/validator-list/my-validator-card/validators.module.scss deleted file mode 100644 index d848d5ee07..0000000000 --- a/packages/fetch-extension/src/pages/validator-list/my-validator-card/validators.module.scss +++ /dev/null @@ -1,57 +0,0 @@ -.col { - text-align: center; - display: flex; - flex-direction: column; - gap: 4px; - font-size: 12px; - text-transform: capitalize; -} - -.row { - display: flex; - justify-content: space-between; - width: 100%; -} - -.label { - font-weight: bold; - text-transform: capitalize; -} - -.address { - font-style: italic; - font-size: 12px; -} - -.avatar { - width: 80px; - height: 80px; - line-height: initial; - text-align: center; - color: rgb(255, 255, 255); - border-radius: 100%; - background: rgb(214, 26, 127); -} -.item { - display: flex; - flex-direction: column; - gap: 8px; - width: 100%; - padding: 10px; - background: #ffffff; - border-radius: 6px; - cursor: pointer; - margin: 10px 0px; -} - -.item:hover { - box-shadow: 0 0 100px 30px #e0e0e0 inset; -} - -.tooltip { - font-weight: 400; - font-size: 10px; - line-height: 10px; - - padding: 2px 4px; -} diff --git a/packages/fetch-extension/src/pages/validator-list/my-validators/index.tsx b/packages/fetch-extension/src/pages/validator-list/my-validators/index.tsx deleted file mode 100644 index 362f33ba8d..0000000000 --- a/packages/fetch-extension/src/pages/validator-list/my-validators/index.tsx +++ /dev/null @@ -1,47 +0,0 @@ -import { Staking } from "@keplr-wallet/stores"; -import { CoinPretty } from "@keplr-wallet/unit"; -import React from "react"; -import { useStore } from "../../../stores"; -import { MyValidatorCard } from "../my-validator-card"; - -type ValidatorData = Staking.Validator & { amount: CoinPretty }; - -export const MyValidatorsList = ({ - filteredValidators, -}: { - filteredValidators: ValidatorData[]; -}) => { - const { chainStore } = useStore(); - - const filterValidators = (validator: ValidatorData) => { - return validator.amount - .toDec() - .gt(new CoinPretty(validator.amount.currency, "0").toDec()); - }; - - const sortValidators = (a: ValidatorData, b: ValidatorData) => { - return ( - parseFloat(b.amount.toDec().toString()) - - parseFloat(a.amount.toDec().toString()) - ); - }; - - return ( - - {filteredValidators.length ? ( - filteredValidators - .filter(filterValidators) - .sort(sortValidators) - .map((validator: ValidatorData) => ( - - )) - ) : ( -
No Validators Found
- )} -
- ); -}; diff --git a/packages/fetch-extension/src/pages/validator-list/style.module.scss b/packages/fetch-extension/src/pages/validator-list/style.module.scss deleted file mode 100644 index a6a464b2bf..0000000000 --- a/packages/fetch-extension/src/pages/validator-list/style.module.scss +++ /dev/null @@ -1,129 +0,0 @@ -.searchContainer { - margin: 12px 0px; - display: flex; - align-items: center; - .searchBox { - display: flex; - padding: 5px; - flex: 1; - background-color: #f2f3f6; - border-radius: 4px; - align-items: center; - gap: 10px; - img { - width: 16px; - height: 16px; - -webkit-user-drag: none; - -khtml-user-drag: none; - -moz-user-drag: none; - -o-user-drag: none; - } - input { - border: none; - outline: none; - background: transparent; - &::placeholder { - color: #525f7f; - } - flex-grow: 1; - } - } -} - -.loader { - display: inline-block; - margin: 0 16px; -} - -.loader { - --path: #2f3545; - --dot: #5628ee; - --duration: 2s; - width: 44px; - height: 44px; - position: relative; -} - -.loader:before { - content: ""; - width: 6px; - height: 6px; - border-radius: 50%; - position: absolute; - display: block; - background: var(--dot); - top: 37px; - left: 19px; - transform: translate(-18px, -18px); - animation: dotRect var(--duration) cubic-bezier(0.785, 0.135, 0.15, 0.86) - infinite; -} - -.loader svg { - display: block; - width: 100%; - height: 100%; -} - -.loader svg rect, -.loader svg polygon, -.loader svg circle { - fill: none; - stroke: var(--path); - stroke-width: 10px; - stroke-linejoin: round; - stroke-linecap: round; -} - -.loader svg rect { - stroke-dasharray: 192 64 192 64; - stroke-dashoffset: 0; - animation: pathRect 2s cubic-bezier(0.785, 0.135, 0.15, 0.86) infinite; -} - -.tabList { - display: flex; - flex-direction: row; -} - -.tab { - width: 50%; - text-align: center; - cursor: pointer; -} - -@keyframes pathRect { - 25% { - stroke-dashoffset: 64; - } - - 50% { - stroke-dashoffset: 128; - } - - 75% { - stroke-dashoffset: 192; - } - - 100% { - stroke-dashoffset: 256; - } -} - -@keyframes dotRect { - 25% { - transform: translate(0, 0); - } - - 50% { - transform: translate(18px, -18px); - } - - 75% { - transform: translate(0, -36px); - } - - 100% { - transform: translate(-18px, -18px); - } -} diff --git a/packages/fetch-extension/src/pages/validator-list/validator-card/validators.module.scss b/packages/fetch-extension/src/pages/validator-list/validator-card/validators.module.scss deleted file mode 100644 index d848d5ee07..0000000000 --- a/packages/fetch-extension/src/pages/validator-list/validator-card/validators.module.scss +++ /dev/null @@ -1,57 +0,0 @@ -.col { - text-align: center; - display: flex; - flex-direction: column; - gap: 4px; - font-size: 12px; - text-transform: capitalize; -} - -.row { - display: flex; - justify-content: space-between; - width: 100%; -} - -.label { - font-weight: bold; - text-transform: capitalize; -} - -.address { - font-style: italic; - font-size: 12px; -} - -.avatar { - width: 80px; - height: 80px; - line-height: initial; - text-align: center; - color: rgb(255, 255, 255); - border-radius: 100%; - background: rgb(214, 26, 127); -} -.item { - display: flex; - flex-direction: column; - gap: 8px; - width: 100%; - padding: 10px; - background: #ffffff; - border-radius: 6px; - cursor: pointer; - margin: 10px 0px; -} - -.item:hover { - box-shadow: 0 0 100px 30px #e0e0e0 inset; -} - -.tooltip { - font-weight: 400; - font-size: 10px; - line-height: 10px; - - padding: 2px 4px; -} diff --git a/packages/fetch-extension/src/pages/validator-list/validators/index.tsx b/packages/fetch-extension/src/pages/validator-list/validators/index.tsx deleted file mode 100644 index 1b2832ea58..0000000000 --- a/packages/fetch-extension/src/pages/validator-list/validators/index.tsx +++ /dev/null @@ -1,37 +0,0 @@ -import { Staking } from "@keplr-wallet/stores"; -import { CoinPretty } from "@keplr-wallet/unit"; -import React from "react"; -import { useStore } from "../../../stores"; -import { ValidatorCard } from "../validator-card"; - -type ValidatorData = Staking.Validator & { amount: CoinPretty }; - -export const ValidatorsList = ({ - filteredValidators, -}: { - filteredValidators: ValidatorData[]; -}) => { - const { chainStore } = useStore(); - - const sortValidators = (a: ValidatorData, b: ValidatorData) => { - return parseFloat(b.delegator_shares) - parseFloat(a.delegator_shares); - }; - - return ( - - {filteredValidators.length ? ( - filteredValidators - .sort((a, b) => sortValidators(a, b)) - .map((validator: ValidatorData) => ( - - )) - ) : ( -
No Validators Found
- )} -
- ); -}; diff --git a/packages/fetch-extension/src/pages/validator/index.tsx b/packages/fetch-extension/src/pages/validator/index.tsx deleted file mode 100644 index 9c0dbc3427..0000000000 --- a/packages/fetch-extension/src/pages/validator/index.tsx +++ /dev/null @@ -1,185 +0,0 @@ -import { Staking } from "@keplr-wallet/stores"; -import { HeaderLayout } from "@layouts/header-layout"; -import { observer } from "mobx-react-lite"; -import React, { FunctionComponent, useMemo } from "react"; -import { useLocation, useNavigate } from "react-router"; -import { useStore } from "../../stores"; -import { Stake } from "./stake"; -import style from "./style.module.scss"; -import { Transfer } from "./transfer"; -import { Unstake } from "./unstake"; -import { ValidatorDetails } from "./validator-details"; -import { Dec } from "@keplr-wallet/unit"; - -enum ValidatorOperation { - STAKE = "stake", - UNSTAKE = "unstake", - TRANSFER = "transfer", -} - -export const Validator: FunctionComponent = observer(() => { - const navigate = useNavigate(); - const location = useLocation(); - const validatorAddress = location.pathname.split("/")[2]; - const operation = location.pathname.split("/")[3]; - const validatorTab = localStorage.getItem("validatorTab") || "validator"; - const { chainStore, accountStore, queriesStore, analyticsStore } = useStore(); - const account = accountStore.getAccount(chainStore.current.chainId); - const queries = queriesStore.get(chainStore.current.chainId); - - const bondedValidators = queries.cosmos.queryValidators.getQueryStatus( - Staking.BondStatus.Bonded - ); - const unbondingValidators = queries.cosmos.queryValidators.getQueryStatus( - Staking.BondStatus.Unbonding - ); - const unbondedValidators = queries.cosmos.queryValidators.getQueryStatus( - Staking.BondStatus.Unbonded - ); - const queryDelegations = - queries.cosmos.queryDelegations.getQueryBech32Address( - account.bech32Address - ); - const queryRewards = queries.cosmos.queryRewards.getQueryBech32Address( - account.bech32Address - ); - const { validator, amount, rewards } = useMemo(() => { - const amount = queryDelegations.getDelegationTo(validatorAddress); - const validator = - bondedValidators.getValidator(validatorAddress) || - unbondingValidators.getValidator(validatorAddress) || - unbondedValidators.getValidator(validatorAddress); - const thumbnail = - bondedValidators.getValidatorThumbnail(validatorAddress) || - unbondingValidators.getValidatorThumbnail(validatorAddress) || - unbondedValidators.getValidatorThumbnail(validatorAddress); - const rewards = queryRewards.getRewardsOf(validatorAddress); - return { - validator, - thumbnail, - rewards, - amount: amount, - }; - }, [ - queryDelegations, - validatorAddress, - bondedValidators, - unbondingValidators, - unbondedValidators, - queryRewards, - ]); - const inflation = queries.cosmos.queryInflation; - const { inflation: ARR, isFetching } = inflation; - const validatorCom: any = parseFloat( - validator?.commission.commission_rates.rate || "0" - ); - const APR = ARR.mul(new Dec(1 - validatorCom)); - return ( - { - analyticsStore.logEvent("back_click", { pageName: "Validator Detail" }); - navigate(`/validators/${validatorTab}`); - }} - > -
- {validator && ( - - )} -
-
-
Current Staked Amount
-
- {amount.maxDecimals(4).trim(true).toString()} -
-
-
-
navigate(`/validators/${validatorAddress}/stake`)} - > - Stake -
- -
- navigate(`/validators/${validatorAddress}/unstake`) - } - > - Unstake -
-
- navigate(`/validators/${validatorAddress}/transfer`) - } - > - Redelegate -
-
- {operation == ValidatorOperation.STAKE && ( - - )} - {operation == ValidatorOperation.UNSTAKE && ( - - )} - {operation == ValidatorOperation.TRANSFER && ( - validator.operator_address != validatorAddress - )} - /> - )} -
-
-
- ); -}); diff --git a/packages/fetch-extension/src/pages/validator/stake-complete.tsx b/packages/fetch-extension/src/pages/validator/stake-complete.tsx deleted file mode 100644 index b2b986d59c..0000000000 --- a/packages/fetch-extension/src/pages/validator/stake-complete.tsx +++ /dev/null @@ -1,91 +0,0 @@ -import { HeaderLayout } from "@layouts/header-layout"; -import React, { FunctionComponent, useMemo } from "react"; -import { useLocation, useNavigate } from "react-router"; -import { Button } from "reactstrap"; -import activeStake from "@assets/icon/activeStake.png"; -import { Staking } from "@keplr-wallet/stores"; -import { useStore } from "../../stores"; -import { observer } from "mobx-react-lite"; - -export const StakeComplete: FunctionComponent = observer(() => { - const navigate = useNavigate(); - const validatorAddress = useLocation().pathname.split("/")[2]; - const validatorTab = localStorage.getItem("validatorTab"); - const { chainStore, queriesStore } = useStore(); - const queries = queriesStore.get(chainStore.current.chainId); - - const bondedValidators = queries.cosmos.queryValidators.getQueryStatus( - Staking.BondStatus.Bonded - ); - const unbondingValidators = queries.cosmos.queryValidators.getQueryStatus( - Staking.BondStatus.Unbonding - ); - const unbondedValidators = queries.cosmos.queryValidators.getQueryStatus( - Staking.BondStatus.Unbonded - ); - - const { validator } = useMemo(() => { - const validator = - bondedValidators.getValidator(validatorAddress) || - unbondingValidators.getValidator(validatorAddress) || - unbondedValidators.getValidator(validatorAddress); - return { - validator, - }; - }, [ - bondedValidators, - validatorAddress, - unbondingValidators, - unbondedValidators, - ]); - - return ( - -
- - {validator && ( -
- Amount processed with -
- {validator.description.moniker} -
-
- )} -
- - - - -
- ); -}); diff --git a/packages/fetch-extension/src/pages/validator/stake.tsx b/packages/fetch-extension/src/pages/validator/stake.tsx deleted file mode 100644 index 8277cd90a6..0000000000 --- a/packages/fetch-extension/src/pages/validator/stake.tsx +++ /dev/null @@ -1,202 +0,0 @@ -import activeStake from "@assets/icon/activeStake.png"; -import { useNotification } from "@components/notification"; -import { - EmptyAmountError, - InsufficientAmountError, - InvalidNumberAmountError, - NegativeAmountError, - ZeroAmountError, - useDelegateTxConfig, -} from "@keplr-wallet/hooks"; -import { CoinPretty, Int } from "@keplr-wallet/unit"; -import { observer } from "mobx-react-lite"; -import React, { FunctionComponent, useMemo } from "react"; -import { useIntl } from "react-intl"; -import { useNavigate } from "react-router"; -import { Button, FormGroup, Input, Label } from "reactstrap"; -import { useStore } from "../../stores"; -import style from "./style.module.scss"; -import { TXNTYPE } from "../../config"; - -export const Stake: FunctionComponent<{ validatorAddress: string }> = observer( - ({ validatorAddress }) => { - const navigate = useNavigate(); - const { chainStore, accountStore, queriesStore, analyticsStore } = - useStore(); - const account = accountStore.getAccount(chainStore.current.chainId); - - const sendConfigs = useDelegateTxConfig( - chainStore, - queriesStore, - accountStore, - chainStore.current.chainId, - account.bech32Address - ); - const { amountConfig, memoConfig, feeConfig } = sendConfigs; - - const intl = useIntl(); - const error = amountConfig.error; - - const queryBalances = queriesStore - .get(amountConfig.chainId) - .queryBalances.getQueryBech32Address(amountConfig.sender); - - const queryBalance = queryBalances.balances.find( - (bal) => - amountConfig.sendCurrency.coinMinimalDenom === - bal.currency.coinMinimalDenom - ); - const balance = queryBalance - ? queryBalance.balance - : new CoinPretty(amountConfig.sendCurrency, new Int(0)); - - const errorText: string | undefined = useMemo(() => { - if (error) { - switch (error.constructor) { - case EmptyAmountError: - // No need to show the error to user. - return; - case InvalidNumberAmountError: - return intl.formatMessage({ - id: "input.amount.error.invalid-number", - }); - case ZeroAmountError: - return intl.formatMessage({ - id: "input.amount.error.is-zero", - }); - case NegativeAmountError: - return intl.formatMessage({ - id: "input.amount.error.is-negative", - }); - case InsufficientAmountError: - return intl.formatMessage({ - id: "input.amount.error.insufficient", - }); - default: - return intl.formatMessage({ id: "input.amount.error.unknown" }); - } - } - }, [intl, error]); - - const notification = useNotification(); - - const txnResult = { - onBroadcasted: () => { - notification.push({ - type: "primary", - placement: "top-center", - duration: 2, - content: `Transaction broadcasted`, - canDelete: true, - transition: { - duration: 0.25, - }, - }); - analyticsStore.logEvent("stake_txn_broadcasted", { - chainId: chainStore.current.chainId, - chainName: chainStore.current.chainName, - feeType: feeConfig.feeType, - }); - }, - onFulfill: (tx: any) => { - const istxnSuccess = tx.code ? false : true; - notification.push({ - type: istxnSuccess ? "success" : "danger", - placement: "top-center", - duration: 5, - content: istxnSuccess - ? `Transaction Completed` - : `Transaction Failed: ${tx.log}`, - canDelete: true, - transition: { - duration: 0.25, - }, - }); - }, - }; - const stakeClicked = async () => { - try { - analyticsStore.logEvent("stake_txn_click"); - await account.cosmos - .makeDelegateTx(amountConfig.amount, validatorAddress) - .send(feeConfig.toStdFee(), memoConfig.memo, undefined, txnResult); - } catch (e) { - notification.push({ - type: "danger", - placement: "top-center", - duration: 5, - content: `Transaction Failed`, - canDelete: true, - transition: { - duration: 0.25, - }, - }); - analyticsStore.logEvent("stake_txn_broadcasted_fail", { - chainId: chainStore.current.chainId, - chainName: chainStore.current.chainName, - feeType: feeConfig.feeType, - message: e?.message ?? "", - }); - } finally { - navigate("/", { replace: true }); - } - }; - - return ( - - - - { - e.preventDefault(); - amountConfig.setAmount(e.target.value); - }} - style={{ borderRadius: "0%" }} - min={0} - autoComplete="off" - /> - {errorText != null ? ( -
{errorText}
- ) : null} - -
-
- ); - } -); diff --git a/packages/fetch-extension/src/pages/validator/style.module.scss b/packages/fetch-extension/src/pages/validator/style.module.scss deleted file mode 100644 index 19bfb491f4..0000000000 --- a/packages/fetch-extension/src/pages/validator/style.module.scss +++ /dev/null @@ -1,153 +0,0 @@ -.stakeContainer { - display: flex; - justify-content: space-between; - flex-direction: column; - height: 100%; -} - -.stakedAmount { - display: flex; - flex-direction: column; - align-items: center; - gap: 5px; - font-size: 14px; -} - -.tabList { - display: flex; - flex-direction: row; -} - -.tab { - width: 50%; - text-align: center; - cursor: pointer; -} - -.stakeValueInput { - padding: 8px; - border: none; - margin-bottom: 10px; -} - -.nextStakedValidatorName { - text-align: center; - color: #5090ff; - margin-bottom: 10px; -} - -.nextStakedInfo { - text-align: center; -} - -.balance { - text-align: right; - font-weight: normal; - color: #555555; - cursor: pointer; - - &:hover { - color: black; - text-decoration: underline; - } - - &.clicked { - color: black; - } -} - -.errorText { - color: #fb8c72; - font: 10px; -} - -.loader { - display: inline-block; - margin: 0 16px; -} - -.loader { - --path: #2f3545; - --dot: #5628ee; - --duration: 2s; - width: 44px; - height: 44px; - position: relative; -} - -.loader:before { - content: ""; - width: 6px; - height: 6px; - border-radius: 50%; - position: absolute; - display: block; - background: var(--dot); - top: 37px; - left: 19px; - transform: translate(-18px, -18px); - animation: dotRect var(--duration) cubic-bezier(0.785, 0.135, 0.15, 0.86) - infinite; -} - -.loader svg { - display: block; - width: 100%; - height: 100%; -} - -.loader svg rect, -.loader svg polygon, -.loader svg circle { - fill: none; - stroke: var(--path); - stroke-width: 10px; - stroke-linejoin: round; - stroke-linecap: round; -} - -.loader svg rect { - stroke-dasharray: 192 64 192 64; - stroke-dashoffset: 0; - animation: pathRect 2s cubic-bezier(0.785, 0.135, 0.15, 0.86) infinite; -} - -.dropdown:hover { - background: aliceblue !important; -} - -@keyframes pathRect { - 25% { - stroke-dashoffset: 64; - } - - 50% { - stroke-dashoffset: 128; - } - - 75% { - stroke-dashoffset: 192; - } - - 100% { - stroke-dashoffset: 256; - } -} - -@keyframes dotRect { - 25% { - transform: translate(0, 0); - } - - 50% { - transform: translate(18px, -18px); - } - - 75% { - transform: translate(0, -36px); - } - - 100% { - transform: translate(-18px, -18px); - } -} diff --git a/packages/fetch-extension/src/pages/validator/transfer.tsx b/packages/fetch-extension/src/pages/validator/transfer.tsx deleted file mode 100644 index 4b178eda09..0000000000 --- a/packages/fetch-extension/src/pages/validator/transfer.tsx +++ /dev/null @@ -1,259 +0,0 @@ -import activeStake from "@assets/icon/activeStake.png"; -import { useNotification } from "@components/notification"; -import { - EmptyAmountError, - InsufficientAmountError, - InvalidNumberAmountError, - NegativeAmountError, - ZeroAmountError, - useRedelegateTxConfig, -} from "@keplr-wallet/hooks"; -import { observer } from "mobx-react-lite"; -import React, { FunctionComponent, useMemo, useState } from "react"; -import { useIntl } from "react-intl"; -import { useNavigate } from "react-router"; -import { - Button, - ButtonDropdown, - DropdownItem, - DropdownMenu, - DropdownToggle, - FormGroup, - Input, - Label, -} from "reactstrap"; -import { useStore } from "../../stores"; -import style from "./style.module.scss"; -import { Staking } from "@keplr-wallet/stores"; -import { CoinPretty } from "@keplr-wallet/unit"; -import { TXNTYPE } from "../../config"; - -export const Transfer: FunctionComponent<{ - validatorAddress: string; - validatorsList: Staking.Validator[]; - balance: CoinPretty; -}> = observer(({ validatorAddress, validatorsList, balance }) => { - const navigate = useNavigate(); - const { chainStore, accountStore, queriesStore, analyticsStore } = useStore(); - const account = accountStore.getAccount(chainStore.current.chainId); - const [selectedValidator, setSelectedValidator] = useState( - validatorsList[0] - ); - const [showDropdown, setShowDropdown] = useState(false); - const sendConfigs = useRedelegateTxConfig( - chainStore, - queriesStore, - accountStore, - chainStore.current.chainId, - account.bech32Address, - validatorAddress - ); - const { amountConfig, memoConfig, feeConfig } = sendConfigs; - - const intl = useIntl(); - const error = amountConfig.error; - - const errorText: string | undefined = useMemo(() => { - if (error) { - switch (error.constructor) { - case EmptyAmountError: - // No need to show the error to user. - return; - case InvalidNumberAmountError: - return intl.formatMessage({ - id: "input.amount.error.invalid-number", - }); - case ZeroAmountError: - return intl.formatMessage({ - id: "input.amount.error.is-zero", - }); - case NegativeAmountError: - return intl.formatMessage({ - id: "input.amount.error.is-negative", - }); - case InsufficientAmountError: - return intl.formatMessage({ - id: "input.amount.error.insufficient", - }); - default: - return intl.formatMessage({ id: "input.amount.error.unknown" }); - } - } - }, [intl, error]); - - const notification = useNotification(); - - const txnResult = { - onBroadcasted: () => { - notification.push({ - type: "primary", - placement: "top-center", - duration: 2, - content: `Transaction broadcasted`, - canDelete: true, - transition: { - duration: 0.25, - }, - }); - analyticsStore.logEvent("redelegate_txn_broadcasted", { - chainId: chainStore.current.chainId, - chainName: chainStore.current.chainName, - feeType: feeConfig.feeType, - }); - }, - onFulfill: (tx: any) => { - const istxnSuccess = tx.code ? false : true; - notification.push({ - type: istxnSuccess ? "success" : "danger", - placement: "top-center", - duration: 5, - content: istxnSuccess - ? `Transaction Completed` - : `Transaction Failed: ${tx.log}`, - canDelete: true, - transition: { - duration: 0.25, - }, - }); - }, - }; - const stakeClicked = async () => { - try { - analyticsStore.logEvent("redelegate_txn_click"); - await account.cosmos - .makeBeginRedelegateTx( - amountConfig.amount, - validatorAddress, - selectedValidator.operator_address - ) - .send(feeConfig.toStdFee(), memoConfig.memo, undefined, txnResult); - } catch (e) { - notification.push({ - type: "danger", - placement: "top-center", - duration: 5, - content: `Transaction Failed`, - canDelete: true, - transition: { - duration: 0.25, - }, - }); - analyticsStore.logEvent("redelegate_txn_broadcasted_fail", { - chainId: chainStore.current.chainId, - chainName: chainStore.current.chainName, - feeType: feeConfig.feeType, - message: e?.message ?? "", - }); - } finally { - navigate("/", { replace: true }); - } - }; - - return ( - - - - setShowDropdown((value) => !value)} - style={{ float: "right" }} - > - - - {selectedValidator.description.moniker} - - - - -
- {validatorsList.map((validator) => { - return ( - { - analyticsStore.logEvent("stake_validator_click", { - pageName: "Validator Detail Page", - }); - setSelectedValidator(validator); - }} - > - {validator.description.moniker} - - ); - })} -
-
-
- - { - e.preventDefault(); - amountConfig.setAmount(e.target.value); - }} - style={{ borderRadius: "0%" }} - min={0} - autoComplete="off" - /> - {errorText != null ? ( -
{errorText}
- ) : null} - - -
-
- ); -}); diff --git a/packages/fetch-extension/src/pages/validator/unstake.tsx b/packages/fetch-extension/src/pages/validator/unstake.tsx deleted file mode 100644 index 63c57ffa81..0000000000 --- a/packages/fetch-extension/src/pages/validator/unstake.tsx +++ /dev/null @@ -1,199 +0,0 @@ -import activeStake from "@assets/icon/activeStake.png"; -import { useNotification } from "@components/notification"; -import { - EmptyAmountError, - InsufficientAmountError, - InvalidNumberAmountError, - NegativeAmountError, - ZeroAmountError, - useUndelegateTxConfig, -} from "@keplr-wallet/hooks"; -import { observer } from "mobx-react-lite"; -import React, { FunctionComponent, useMemo } from "react"; -import { useIntl } from "react-intl"; -import { useNavigate } from "react-router"; -import { Button, FormGroup, Input, Label } from "reactstrap"; -import { useStore } from "../../stores"; -import style from "./style.module.scss"; -import { TXNTYPE } from "../../config"; - -export const Unstake: FunctionComponent<{ - validatorAddress: string; -}> = observer(({ validatorAddress }) => { - const navigate = useNavigate(); - const { chainStore, accountStore, queriesStore, analyticsStore } = useStore(); - const account = accountStore.getAccount(chainStore.current.chainId); - - const sendConfigs = useUndelegateTxConfig( - chainStore, - queriesStore, - accountStore, - chainStore.current.chainId, - account.bech32Address, - validatorAddress - ); - const { amountConfig, memoConfig, feeConfig } = sendConfigs; - - const intl = useIntl(); - const error = amountConfig.error; - - const balance = queriesStore - .get(amountConfig.chainId) - .cosmos.queryDelegations.getQueryBech32Address(amountConfig.sender) - .getDelegationTo(validatorAddress); - - const errorText: string | undefined = useMemo(() => { - if (error) { - switch (error.constructor) { - case EmptyAmountError: - // No need to show the error to user. - return; - case InvalidNumberAmountError: - return intl.formatMessage({ - id: "input.amount.error.invalid-number", - }); - case ZeroAmountError: - return intl.formatMessage({ - id: "input.amount.error.is-zero", - }); - case NegativeAmountError: - return intl.formatMessage({ - id: "input.amount.error.is-negative", - }); - case InsufficientAmountError: - return intl.formatMessage({ - id: "input.amount.error.insufficient", - }); - default: - return intl.formatMessage({ id: "input.amount.error.unknown" }); - } - } - }, [intl, error]); - - const notification = useNotification(); - - const txnResult = { - onBroadcasted: () => { - notification.push({ - type: "primary", - placement: "top-center", - duration: 2, - content: `Transaction broadcasted`, - canDelete: true, - transition: { - duration: 0.25, - }, - }); - - analyticsStore.logEvent("unstake_txn_broadcasted", { - chainId: chainStore.current.chainId, - chainName: chainStore.current.chainName, - feeType: feeConfig.feeType, - }); - }, - onFulfill: (tx: any) => { - const istxnSuccess = tx.code ? false : true; - notification.push({ - type: istxnSuccess ? "success" : "danger", - placement: "top-center", - duration: 5, - content: istxnSuccess - ? `Transaction Completed` - : `Transaction Failed: ${tx.log}`, - canDelete: true, - transition: { - duration: 0.25, - }, - }); - }, - }; - - const stakeClicked = async () => { - try { - analyticsStore.logEvent("unstake_txn_click"); - await account.cosmos - .makeUndelegateTx(amountConfig.amount, validatorAddress) - .send(feeConfig.toStdFee(), memoConfig.memo, undefined, txnResult); - } catch (e) { - analyticsStore.logEvent("unstake_txn_broadcasted_fail", { - chainId: chainStore.current.chainId, - chainName: chainStore.current.chainName, - feeType: feeConfig.feeType, - message: e?.message ?? "", - }); - notification.push({ - type: "danger", - placement: "top-center", - duration: 5, - content: `Transaction Failed`, - canDelete: true, - transition: { - duration: 0.25, - }, - }); - } finally { - navigate("/", { replace: true }); - } - }; - - return ( - - - - { - e.preventDefault(); - amountConfig.setAmount(e.target.value); - }} - style={{ borderRadius: "0%" }} - min={0} - autoComplete="off" - /> - {errorText != null ? ( -
{errorText}
- ) : null} - - -
-
- ); -}); diff --git a/packages/fetch-extension/src/pages/validator/validator-details/index.tsx b/packages/fetch-extension/src/pages/validator/validator-details/index.tsx deleted file mode 100644 index 077928c9f9..0000000000 --- a/packages/fetch-extension/src/pages/validator/validator-details/index.tsx +++ /dev/null @@ -1,219 +0,0 @@ -import { ToolTip } from "@components/tooltip"; -import { Staking } from "@keplr-wallet/stores"; -import { formatAddress, shortenNumber } from "@utils/format"; -import React from "react"; -import { useStore } from "../../../stores"; -import { CHAIN_ID_DORADO, CHAIN_ID_FETCHHUB } from "../../../config.ui.var"; -import styleValidators from "./validatordetails.module.scss"; -import { useNavigate } from "react-router"; -import { useNotification } from "@components/notification"; - -export const URL: { [key in string]: string } = { - [CHAIN_ID_DORADO]: "https://explore-dorado.fetch.ai/validators", - [CHAIN_ID_FETCHHUB]: "https://www.mintscan.io/fetchai/validators", -}; - -export const ValidatorDetails = ({ - validator, - chainID, - rewards, - APR, - isFetching, -}: { - validator: Staking.Validator; - chainID: string; - rewards: any; - APR: any; - isFetching: boolean; -}) => { - const { chainStore, accountStore } = useStore(); - const account = accountStore.getAccount(chainStore.current.chainId); - const navigate = useNavigate(); - const notification = useNotification(); - const { analyticsStore } = useStore(); - const status = validator.status.split("_")[2].toLowerCase(); - - const commisionRate = ( - parseFloat(validator.commission.commission_rates.rate) * 100 - ).toFixed(2); - const maxCommisionRate = ( - parseFloat(validator.commission.commission_rates.max_rate) * 100 - ).toFixed(2); - - const handleClaim = async () => { - try { - analyticsStore.logEvent("claim_click", { - pageName: "Validator Detail", - }); - await account.cosmos.sendWithdrawDelegationRewardMsgs( - [validator.operator_address], - "", - undefined, - undefined, - { - onBroadcasted() { - notification.push({ - type: "primary", - placement: "top-center", - duration: 5, - content: `Transaction Broadcasted`, - canDelete: true, - transition: { - duration: 0.25, - }, - }); - analyticsStore.logEvent("claim_txn_broadcasted", { - chainId: chainStore.current.chainId, - chainName: chainStore.current.chainName, - }); - }, - onFulfill: (tx: any) => { - const istxnSuccess = tx.code ? false : true; - notification.push({ - type: istxnSuccess ? "success" : "danger", - placement: "top-center", - duration: 5, - content: istxnSuccess - ? `Transaction Completed` - : `Transaction Failed`, - canDelete: true, - transition: { - duration: 0.25, - }, - }); - }, - } - ); - navigate(`/validators/${validator.operator_address}/stake`); - } catch (err) { - console.error(err); - if (err.toString().includes("Error: Request rejected")) { - navigate(`/validators/${validator.operator_address}/stake`); - } - analyticsStore.logEvent("claim_txn_broadcasted_fail", { - chainId: chainStore.current.chainId, - chainName: chainStore.current.chainName, - message: err?.message ?? "", - }); - } - }; - return ( -
-
-
- {validator.description.website ? ( - - {validator.description.moniker} - - ) : ( - {validator.description.moniker} - )} -
- - {validator.operator_address} -
- } - > - - {formatAddress(validator.operator_address)} - - -
- {validator.description.details && ( -
- Description - {validator.description.details} -
- )} -
-
- Commission Rate - - {commisionRate}% ({maxCommisionRate}% Max) - -
-
- Delegated - {shortenNumber(validator.delegator_shares)} -
-
- Status - {status} -
-
- -
-
- APR - - {!isFetching ? ( -
{APR.maxDecimals(2).trim(true).toString()}%
- ) : ( - - - - )} -
-
-
- Earned Rewards -
- {!isFetching ? ( -
- {!rewards || - rewards.length === 0 || - parseFloat( - rewards[0]?.maxDecimals(4).toString().split(" ")[0] - ) < 0.00001 ? ( - 0 - ) : ( - rewards[0]?.maxDecimals(4).toString() - )} -
- ) : ( - - - - )} - {(!rewards || - rewards.length !== 0 || - parseFloat(rewards[0]?.maxDecimals(4).toString().split(" ")[0]) > - 0.00001) && ( - - )} -
-
-
- - View in Explorer for more Details - - {validator.jailed && ( -
- This validator is currently jailed. Redelegate your tokens. -
- )} -
- ); -}; diff --git a/packages/fetch-extension/src/pages/validator/validator-details/validatordetails.module.scss b/packages/fetch-extension/src/pages/validator/validator-details/validatordetails.module.scss deleted file mode 100644 index 2d5000d514..0000000000 --- a/packages/fetch-extension/src/pages/validator/validator-details/validatordetails.module.scss +++ /dev/null @@ -1,74 +0,0 @@ -.col { - text-align: center; - display: flex; - flex-direction: column; - gap: 4px; - font-size: 12px; -} - -.title { - display: flex; - flex-direction: column; - justify-content: space-between; - width: 100%; - border-bottom: 1px solid lightgray; - font-size: 14px; -} - -.label { - font-size: 14px; - font-weight: bold; - text-transform: capitalize; -} - -.address { - font-style: italic; - font-size: smaller; -} - -.description { - font-size: 14px; - display: flex; - flex-direction: column; - width: 100%; - border-bottom: 1px solid lightgray; -} - -.details { - display: flex; - justify-content: space-between; - width: 100%; - border-bottom: 1px solid lightgray; -} - -.item { - display: flex; - flex-direction: column; - gap: 8px; - width: 100%; - padding: 10px; - background: #ffffff; - border-radius: 6px; -} - -.tooltip { - font-weight: 400; - font-size: 10px; - line-height: 10px; - - padding: 2px 4px; -} -.jailed { - color: red; - text-align: center; - font-size: 10px; -} -.claimButton { - font-weight: bold; - cursor: pointer; - padding: 0px 13px; - text-decoration: underline; - color: #3b82f6; - border: none; - background: transparent; -}