Skip to content

Commit

Permalink
feat: bridge history (#332)
Browse files Browse the repository at this point in the history
  • Loading branch information
agent-dominatrix authored Sep 25, 2023
1 parent 099645f commit 0af0eae
Show file tree
Hide file tree
Showing 26 changed files with 1,003 additions and 77 deletions.
33 changes: 29 additions & 4 deletions packages/background/src/keyring/service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -265,9 +265,16 @@ export class KeyRingService {
const ethereumKeyFeatures =
await this.chainsService.getChainEthereumKeyFeatures(chainId);

const isEvm =
(await this.chainsService.getChainInfo(chainId)).features?.includes(
"evm"
) ?? false;

if (ethereumKeyFeatures.address || ethereumKeyFeatures.signing) {
// Check the comment on the method itself.
this.keyRing.throwErrorIfEthermintWithLedgerButNotSupported(chainId);
if (!isEvm) {
this.keyRing.throwErrorIfEthermintWithLedgerButNotSupported(chainId);
}
}

return this.keyRing.getKey(
Expand Down Expand Up @@ -308,10 +315,16 @@ export class KeyRingService {
const coinType = await this.chainsService.getChainCoinType(chainId);
const ethereumKeyFeatures =
await this.chainsService.getChainEthereumKeyFeatures(chainId);
const isEvm =
(await this.chainsService.getChainInfo(chainId)).features?.includes(
"evm"
) ?? false;

if (ethereumKeyFeatures.address || ethereumKeyFeatures.signing) {
// Check the comment on the method itself.
this.keyRing.throwErrorIfEthermintWithLedgerButNotSupported(chainId);
if (!isEvm) {
this.keyRing.throwErrorIfEthermintWithLedgerButNotSupported(chainId);
}
}

const key = await this.keyRing.getKey(
Expand Down Expand Up @@ -476,10 +489,16 @@ export class KeyRingService {
const coinType = await this.chainsService.getChainCoinType(chainId);
const ethereumKeyFeatures =
await this.chainsService.getChainEthereumKeyFeatures(chainId);
const isEvm =
(await this.chainsService.getChainInfo(chainId)).features?.includes(
"evm"
) ?? false;

if (ethereumKeyFeatures.address || ethereumKeyFeatures.signing) {
// Check the comment on the method itself.
this.keyRing.throwErrorIfEthermintWithLedgerButNotSupported(chainId);
if (!isEvm) {
this.keyRing.throwErrorIfEthermintWithLedgerButNotSupported(chainId);
}
}

const key = await this.keyRing.getKey(
Expand Down Expand Up @@ -567,10 +586,16 @@ export class KeyRingService {
const coinType = await this.chainsService.getChainCoinType(chainId);
const ethereumKeyFeatures =
await this.chainsService.getChainEthereumKeyFeatures(chainId);
const isEvm =
(await this.chainsService.getChainInfo(chainId)).features?.includes(
"evm"
) ?? false;

if (ethereumKeyFeatures.address || ethereumKeyFeatures.signing) {
// Check the comment on the method itself.
this.keyRing.throwErrorIfEthermintWithLedgerButNotSupported(chainId);
if (!isEvm) {
this.keyRing.throwErrorIfEthermintWithLedgerButNotSupported(chainId);
}
}

const key = await this.keyRing.getKey(
Expand Down
5 changes: 5 additions & 0 deletions packages/fetch-extension/src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ import { PropsalVoteStatus } from "./pages/proposals/proposal-vote-status";
import { FetchnameService } from "./pages/fetch-name-service";
import { DomainDetails } from "./pages/fetch-name-service/domain-details";
import { BridgePage } from "./pages/bridge";
import { BridgeHistoryView } from "./pages/bridge/bridge-history";

window.keplr = new Keplr(
manifest.version,
Expand Down Expand Up @@ -211,6 +212,10 @@ ReactDOM.render(
element={<IBCTransferPage />}
/>
<Route path="/bridge" element={<BridgePage />} />
<Route
path="/bridge-history"
element={<BridgeHistoryView />}
/>
<Route path="/setting" element={<SettingPage />} />
<Route
path="/keystone/import-pubkey"
Expand Down
2 changes: 1 addition & 1 deletion packages/fetch-extension/src/languages/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -339,7 +339,7 @@
"sign.list.message.wasm.button.close": "Close",
"sign.list.message.wasm/MsgInstantiateContract.title": "Instantiate Wasm Contract",
"sign.list.message.wasm/MsgInstantiateContract.content": "Instantiate code ID <b>{codeId}</b> contract with<only-admin-exist> <b>{admin}</b> admin account and</only-admin-exist> <b>{label}</b> label<only-funds-exist> by funding <b>{funds}</b></only-funds-exist>",
"sign.list.message.wasm/MsgExecuteContract.title": "Execute Wasm Contract",
"sign.list.message.wasm/MsgExecuteContract.title": "Execute Contract",
"sign.list.message.wasm/MsgExecuteContract.content": "Execute contract <b>{address}</b><only-sent-exist> by sending <b>{sent}</b></only-sent-exist>",
"sign.list.message.wasm/MsgExecuteContract.content.badge.secret-wasm": "Encrypted",
"sign.list.message.wasm/MsgExecuteContract.content.warning.secret-wasm.failed-decryption": "Failed to decrypt Secret message. This may be due to Fetch Wallet viewing key not matching the transaction viewing key.",
Expand Down
209 changes: 209 additions & 0 deletions packages/fetch-extension/src/pages/bridge/bridge-history.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,209 @@
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://fetchstation.azoyalabs.com/mainnet/explorer/transactions/";
const ETHERSCAN_TXN_URL = "https://etherscan.io/tx/";

export const BridgeHistoryView: FunctionComponent = observer(() => {
const navigate = useNavigate();

const { chainStore, accountStore, queriesStore } = 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 (
<HeaderLayout
showChainName={false}
canChangeChainInfo={false}
alternativeTitle={"Bridge History"}
onBackButton={() => {
navigate(-1);
}}
showBottomMenu={false}
rightRenderer={
<img
src={restartIcon}
className={style["refresh"]}
onClick={(e) => {
e.preventDefault();

bridgeHistory.fetch();
}}
/>
}
>
<div className={style["proposalContainer"]}>
{bridgeHistory.isFetching ? (
<div className={style["loaderScreen"]}>
<i className="fa fa-spinner fa-spin fa-fw" />
</div>
) : bridgeHistory.history.length === 0 ? (
<div className={style["loaderScreen"]}>
<p>
<FormattedMessage id="search.no-result-found" />
</p>
</div>
) : (
bridgeHistory.history
.reverse()
.map((history) => (
<BridgeStatus key={history.swapId} history={history} />
))
)}
</div>
</HeaderLayout>
);
});

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 (
<div className={style["bHistory"]}>
<div className={style["hContent"]}>
<p className={style["sId"]}>{`Swap id #${history.swapId}`}</p>
<p className={style["hTitle"]}>{`Send ${
fetCurrency
? new CoinPretty(fetCurrency, history.amount)
.maxDecimals(2)
.toString()
: "0 FET"
}`}</p>
<p className={style["hDesc"]}>
To: {Bech32Address.shortenAddress(history.to, 22, !isEvm)}
</p>
</div>

<div className={style["hStatus"]}>
{reverseSwapHash.isFetching ? (
<i
style={{ position: "absolute", top: "35%" }}
className="fa fa-spinner fa-spin fa-fw"
/>
) : (
<div>
<Button
disabled={!history.transactionHash}
color="darkgrey"
className={style["statusButton"]}
onClick={() => {
window.open(
`${isEvm ? ETHERSCAN_TXN_URL : FETCHSTATION_TXN_URL}${
history.transactionHash
}`,
"_blank",
"noreferrer"
);
}}
>
{isEvm ? (
<img
draggable={false}
src={require("@assets/img/ethereum.svg")}
className={style["ethLogo"]}
/>
) : (
<img
draggable={false}
src={require("@assets/svg/fetch_logo_black.svg")}
className={style["fetLogo"]}
/>
)}
<img
draggable={false}
className={style["status"]}
src={require("@assets/svg/" +
`${
history.transactionHash ? "gov-tick.svg" : "gov-clock.svg"
}`)}
/>
</Button>
<img
className={style["arrowIcon"]}
src={require("@assets/svg/arrow-right-outline.svg")}
alt=""
draggable={false}
/>
<Button
disabled={!reverseSwapHash.hash}
color="darkgrey"
className={style["statusButton"]}
onClick={() => {
window.open(
`${!isEvm ? ETHERSCAN_TXN_URL : FETCHSTATION_TXN_URL}${
reverseSwapHash.hash
}`,
"_blank",
"noreferrer"
);
}}
>
{!isEvm ? (
<img
draggable={false}
src={require("@assets/img/ethereum.svg")}
className={style["ethLogo"]}
/>
) : (
<img
draggable={false}
src={require("@assets/svg/fetch_logo_black.svg")}
className={style["fetLogo"]}
/>
)}
<img
draggable={false}
className={style["status"]}
src={require("@assets/svg/" +
`${
reverseSwapHash.hash ? "gov-tick.svg" : "gov-clock.svg"
}`)}
/>
</Button>
</div>
)}
</div>
</div>
);
}
);
Original file line number Diff line number Diff line change
Expand Up @@ -153,9 +153,7 @@ export const Configure: FunctionComponent<{
</div>
<div className={style["formInnerContainer"]}>
<AddressInput
label={intl.formatMessage({
id: "send.input.recipient",
})}
label="Recipient (Fetchhub address)"
recipientConfig={recipientConfig}
disableAddressBook
value={""}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -164,9 +164,7 @@ export const FetchhubBridge: FunctionComponent<{
</div>
<div className={style["formInnerContainer"]}>
<AddressInput
label={intl.formatMessage({
id: "send.input.recipient",
})}
label={"Recipient (Ethereum address)"}
recipientConfig={nativeBridgeConfig.recipientConfig}
// memoConfig={nativeBridgeConfig.memoConfig}
// ibcChannelConfig={nativeBridgeConfig.channelConfig}
Expand Down
15 changes: 15 additions & 0 deletions packages/fetch-extension/src/pages/bridge/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ 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 } = useStore();
Expand Down Expand Up @@ -46,6 +47,20 @@ export const BridgePage: FunctionComponent = observer(() => {
onBackButton={() => {
navigate(-1);
}}
rightRenderer={
<Button
className={style["historyBtn"]}
color="primary"
outline
onClick={(e) => {
e.preventDefault();

navigate("/bridge-history");
}}
>
History
</Button>
}
>
{isLoading ? (
<p className={style["loaderScreen"]}>
Expand Down
Loading

0 comments on commit 0af0eae

Please sign in to comment.