diff --git a/packages/fetch-extension/src/index.tsx b/packages/fetch-extension/src/index.tsx
index 186bf25c6a..a60d3d5354 100644
--- a/packages/fetch-extension/src/index.tsx
+++ b/packages/fetch-extension/src/index.tsx
@@ -376,7 +376,10 @@ ReactDOM.render(
path="/setting/chat/readRecipt"
element={}
/>
- } />
+ }
+ />
}
diff --git a/packages/fetch-extension/src/pages/main/stake.tsx b/packages/fetch-extension/src/pages/main/stake.tsx
index 339467e500..9fbdf769b3 100644
--- a/packages/fetch-extension/src/pages/main/stake.tsx
+++ b/packages/fetch-extension/src/pages/main/stake.tsx
@@ -211,7 +211,7 @@ export const StakeView: FunctionComponent = observer(() => {
chainId: chainStore.current.chainId,
chainName: chainStore.current.chainName,
});
- navigate("/validators");
+ navigate("/validators/validator");
}}
>
diff --git a/packages/fetch-extension/src/pages/main/tx-button.tsx b/packages/fetch-extension/src/pages/main/tx-button.tsx
index 284a3f2c7f..1063d7726e 100644
--- a/packages/fetch-extension/src/pages/main/tx-button.tsx
+++ b/packages/fetch-extension/src/pages/main/tx-button.tsx
@@ -199,7 +199,7 @@ export const TxButtonView: FunctionComponent = observer(() => {
{
onMouseLeave={() => {
setIsActiveStake(false);
}}
+ data-loading={["undelegate", "redelegate", "delegate"].includes(
+ accountInfo.txTypeInProgress
+ )}
>
{
return memoConfig.error != null || feeConfig.error != null;
})();
- console.log("@@@@#!3", signDocHelper.signDocWrapper?.isADR36SignDoc);
-
return (
{
const navigate = useNavigate();
-
+ const location = useLocation();
+ const operation = location.pathname.split("/")[2];
const [validators, setValidators] = useState<{
[key in string]: ValidatorData;
}>({});
@@ -62,10 +68,6 @@ export const ValidatorList: FunctionComponent = observer(() => {
fetchValidators();
}, [queries.cosmos.queryValidators, queryDelegations]);
- const sortValidators = (a: ValidatorData, b: ValidatorData) => {
- return parseFloat(b.delegator_shares) - parseFloat(a.delegator_shares);
- };
-
const handleFilterValidators = (searchValue: string) => {
const filteredValidators = Object.values(validators).filter((validator) =>
searchValue?.trim().length
@@ -88,9 +90,39 @@ export const ValidatorList: FunctionComponent = observer(() => {
alternativeTitle="Stake"
onBackButton={() => navigate("/")}
>
-
- Validators
-
+
+
+ navigate(`/validators/${ValidatorOperation.VALIDATOR}`)
+ }
+ >
+ Validators
+
+
+
navigate(`/validators/${ValidatorOperation.MY_STAKE}`)}
+ >
+ My Stake
+
+
@@ -102,8 +134,7 @@ export const ValidatorList: FunctionComponent = observer(() => {
/>
-
- {loading ? (
+ {loading && (
{
Loading Validators
- ) : filteredValidators.length ? (
- filteredValidators
- .sort((a, b) => sortValidators(a, b))
- .map((validator: ValidatorData) => (
-
- ))
- ) : (
- No Validators Found
+ )}
+
+ {!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
new file mode 100644
index 0000000000..79c86ef9ff
--- /dev/null
+++ b/packages/fetch-extension/src/pages/validator-list/my-validator-card/index.tsx
@@ -0,0 +1,83 @@
+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";
+
+export const URL: { [key in string]: string } = {
+ [CHAIN_ID_DORADO]: "https://fetchstation.azoyalabs.com/dorado/validators",
+ [CHAIN_ID_FETCHHUB]: "https://fetchstation.azoyalabs.com/mainnet/validators",
+};
+
+export const MyValidatorCard = ({
+ 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)}
+
+
+
+
+
+ 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
new file mode 100644
index 0000000000..d848d5ee07
--- /dev/null
+++ b/packages/fetch-extension/src/pages/validator-list/my-validator-card/validators.module.scss
@@ -0,0 +1,57 @@
+.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
new file mode 100644
index 0000000000..362f33ba8d
--- /dev/null
+++ b/packages/fetch-extension/src/pages/validator-list/my-validators/index.tsx
@@ -0,0 +1,47 @@
+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
index 570013b901..a6a464b2bf 100644
--- a/packages/fetch-extension/src/pages/validator-list/style.module.scss
+++ b/packages/fetch-extension/src/pages/validator-list/style.module.scss
@@ -81,6 +81,17 @@
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;
diff --git a/packages/fetch-extension/src/pages/validator-list/validators/index.tsx b/packages/fetch-extension/src/pages/validator-list/validators/index.tsx
new file mode 100644
index 0000000000..1b2832ea58
--- /dev/null
+++ b/packages/fetch-extension/src/pages/validator-list/validators/index.tsx
@@ -0,0 +1,37 @@
+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
index 5ef06cec70..b450caaf55 100644
--- a/packages/fetch-extension/src/pages/validator/index.tsx
+++ b/packages/fetch-extension/src/pages/validator/index.tsx
@@ -1,13 +1,20 @@
+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 style from "./style.module.scss";
-import { Staking } from "@keplr-wallet/stores";
import { useStore } from "../../stores";
-import { ValidatorDetails } from "./validator-details";
-import { observer } from "mobx-react-lite";
import { Stake } from "./stake";
+import style from "./style.module.scss";
+import { Transfer } from "./transfer";
import { Unstake } from "./unstake";
+import { ValidatorDetails } from "./validator-details";
+
+enum ValidatorOperation {
+ STAKE = "stake",
+ UNSTAKE = "unstake",
+ TRANSFER = "transfer",
+}
export const Validator: FunctionComponent = observer(() => {
const navigate = useNavigate();
@@ -60,8 +67,8 @@ export const Validator: FunctionComponent = observer(() => {
navigate("/validators")}
+ alternativeTitle={operation.toLocaleUpperCase()}
+ onBackButton={() => navigate(-1)}
>
{validator && (
@@ -86,8 +93,12 @@ export const Validator: FunctionComponent = observer(() => {
navigate(`/validators/${validatorAddress}/stake`)}
>
@@ -97,8 +108,14 @@ export const Validator: FunctionComponent = observer(() => {
navigate(`/validators/${validatorAddress}/unstake`)
@@ -106,12 +123,44 @@ export const Validator: FunctionComponent = observer(() => {
>
Unstake
+
+ navigate(`/validators/${validatorAddress}/transfer`)
+ }
+ >
+ Transfer
+
- {operation == "stake" ? (
+ {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
index 9818e28e6b..d45a4262da 100644
--- a/packages/fetch-extension/src/pages/validator/stake-complete.tsx
+++ b/packages/fetch-extension/src/pages/validator/stake-complete.tsx
@@ -73,7 +73,7 @@ export const StakeComplete: FunctionComponent = observer(() => {