Skip to content

Commit 30b567e

Browse files
feat: shielded swaps (#1980)
Co-authored-by: neocybereth <sean@arrowburn.co.nz>
1 parent 3444d4b commit 30b567e

File tree

92 files changed

+3064
-471
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

92 files changed

+3064
-471
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,5 +36,8 @@ yarn-error.log*
3636
!.yarn/sdks
3737
!.yarn/versions
3838

39+
.yalc
40+
yalc.lock
41+
3942
# Local Netlify folder
4043
.netlify

apps/extension/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@
3535
"@dao-xyz/borsh": "^5.1.5",
3636
"@ledgerhq/hw-transport": "^6.31.4",
3737
"@ledgerhq/hw-transport-webusb": "^6.29.4",
38-
"@namada/sdk": "0.22.0",
38+
"@namada/sdk": "0.23.0-beta.1",
3939
"@zondax/ledger-namada": "^2.0.0",
4040
"bignumber.js": "^9.1.1",
4141
"buffer": "^6.0.3",
@@ -54,7 +54,7 @@
5454
},
5555
"devDependencies": {
5656
"@babel/plugin-transform-modules-commonjs": "^7.20.11",
57-
"@namada/sdk-node": "^0.22.0",
57+
"@namada/sdk-node": "0.23.0-beta.1",
5858
"@svgr/webpack": "^6.3.1",
5959
"@types/chrome": "^0.0.237",
6060
"@types/firefox-webext-browser": "^94.0.1",

apps/extension/src/Approvals/Commitment.tsx

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { TxType } from "@namada/sdk";
1+
import { IbcTransferProps, TxType } from "@namada/sdk";
22
import {
33
BondProps,
44
ClaimRewardsProps,
@@ -12,13 +12,17 @@ import {
1212
} from "@namada/types";
1313
import { shortenAddress } from "@namada/utils";
1414
import { NamCurrency } from "App/Common/NamCurrency";
15+
import * as J from "fp-ts/Json";
16+
import { pipe } from "fp-ts/lib/function";
17+
import * as O from "fp-ts/Option";
1518
import { ReactNode } from "react";
1619
import { FaVoteYea } from "react-icons/fa";
1720
import { FaRegEye, FaWallet } from "react-icons/fa6";
1821
import { GoStack } from "react-icons/go";
1922
import { PiDotsNineBold } from "react-icons/pi";
2023
import { isShieldedPool, parseTransferType, ShieldedPoolLabel } from "utils";
2124
import { TransactionCard } from "./TransactionCard";
25+
import { OsmosisSwapMemo } from "./types";
2226

2327
type CommitmentProps = {
2428
commitment: CommitmentDetailProps;
@@ -37,6 +41,7 @@ const IconMap: Record<TxType, React.ReactNode> = {
3741
[TxType.VoteProposal]: <FaVoteYea />,
3842
[TxType.Batch]: <PiDotsNineBold />,
3943
[TxType.ClaimRewards]: <GoStack />,
44+
[TxType.OsmosisSwap]: <FaWallet />,
4045
};
4146

4247
const TitleMap: Record<TxType, string> = {
@@ -51,6 +56,7 @@ const TitleMap: Record<TxType, string> = {
5156
[TxType.VoteProposal]: "Vote",
5257
[TxType.Batch]: "Batch",
5358
[TxType.ClaimRewards]: "Claim Rewards",
59+
[TxType.OsmosisSwap]: "Shielded Swap",
5460
};
5561

5662
const formatAddress = (address: string): string =>
@@ -147,6 +153,27 @@ export const Commitment = ({
147153
wrapperFeePayer
148154
);
149155
title = `${type} ${title}`;
156+
} else if (commitment.txType === TxType.IBCTransfer) {
157+
const ibcTx = commitment as CommitmentDetailProps<IbcTransferProps>;
158+
159+
// It's fine not to handle errors here as memo can be optional and not JSON at all
160+
const maybeMemo = pipe(
161+
O.fromNullable(ibcTx.memo),
162+
O.map((memo) => J.parse(memo)),
163+
O.map(O.fromEither),
164+
O.flatten
165+
);
166+
167+
const maybeOsmosisSwapMemo = pipe(
168+
maybeMemo,
169+
O.map(OsmosisSwapMemo.decode),
170+
O.map(O.fromEither),
171+
O.flatten
172+
);
173+
174+
if (O.isSome(maybeOsmosisSwapMemo)) {
175+
title = TitleMap[TxType.OsmosisSwap];
176+
}
150177
}
151178

152179
return (

apps/extension/src/Approvals/types.ts

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import * as t from "io-ts";
12
import { Message } from "router";
23

34
export enum TopLevelRoute {
@@ -40,3 +41,63 @@ export enum Status {
4041
Pending,
4142
Failed,
4243
}
44+
45+
const NamadaOsmosisSwap = t.type({
46+
overflow_receiver: t.string,
47+
shielded_amount: t.string,
48+
shielding_data: t.string,
49+
});
50+
51+
const FinalMemoNamada = t.type({
52+
osmosis_swap: NamadaOsmosisSwap,
53+
});
54+
55+
const FinalMemo = t.type({
56+
namada: FinalMemoNamada,
57+
});
58+
59+
const OnFailedDelivery = t.type({
60+
local_recovery_addr: t.string,
61+
});
62+
63+
const RouteItem = t.type({
64+
pool_id: t.string,
65+
token_out_denom: t.string,
66+
});
67+
68+
const Slippage = t.type({
69+
min_output_amount: t.string,
70+
});
71+
72+
const OsmosisSwapMsg = t.type({
73+
final_memo: FinalMemo,
74+
on_failed_delivery: OnFailedDelivery,
75+
output_denom: t.string,
76+
receiver: t.string,
77+
route: t.array(RouteItem),
78+
slippage: Slippage,
79+
});
80+
81+
const Msg = t.type({
82+
osmosis_swap: OsmosisSwapMsg,
83+
});
84+
85+
const Wasm = t.type({
86+
contract: t.string,
87+
msg: Msg,
88+
});
89+
90+
export const OsmosisSwapMemo = t.type({
91+
wasm: Wasm,
92+
});
93+
94+
export type NamadaOsmosisSwap = t.TypeOf<typeof NamadaOsmosisSwap>;
95+
export type FinalMemoNamada = t.TypeOf<typeof FinalMemoNamada>;
96+
export type FinalMemo = t.TypeOf<typeof FinalMemo>;
97+
export type OnFailedDelivery = t.TypeOf<typeof OnFailedDelivery>;
98+
export type RouteItem = t.TypeOf<typeof RouteItem>;
99+
export type Slippage = t.TypeOf<typeof Slippage>;
100+
export type OsmosisSwapMsg = t.TypeOf<typeof OsmosisSwapMsg>;
101+
export type Msg = t.TypeOf<typeof Msg>;
102+
export type Wasm = t.TypeOf<typeof Wasm>;
103+
export type OsmosisSwapMemo = t.TypeOf<typeof OsmosisSwapMemo>;

apps/namadillo/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
"@keplr-wallet/types": "^0.12.136",
1313
"@namada/chain-registry": "^1.5.2",
1414
"@namada/indexer-client": "4.0.5",
15-
"@namada/sdk-multicore": "0.22.0",
15+
"@namada/sdk-multicore": "0.23.0-beta.1",
1616
"@tailwindcss/container-queries": "^0.1.1",
1717
"@tanstack/query-core": "^5.40.0",
1818
"@tanstack/react-query": "^5.40.0",
@@ -79,7 +79,7 @@
7979
},
8080
"devDependencies": {
8181
"@eslint/js": "^9.9.1",
82-
"@namada/sdk-node": "^0.22.0",
82+
"@namada/sdk-node": "0.23.0-beta.1",
8383
"@namada/vite-esbuild-plugin": "^1.0.1",
8484
"@playwright/test": "^1.24.1",
8585
"@svgr/webpack": "^6.5.1",

apps/namadillo/src/App/AppRoutes.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ import { StakingOverview } from "./Staking/StakingOverview";
3636
import { StakingRewards } from "./Staking/StakingRewards";
3737
import { StakingWithdrawModal } from "./Staking/StakingWithdrawModal";
3838
import { Unstake } from "./Staking/Unstake";
39+
import { SwapModule } from "./Swap/SwapModule";
3940
import { SwitchAccountPanel } from "./SwitchAccount/SwitchAccountPanel";
4041
import { TransactionDetails } from "./Transactions/TransactionDetails";
4142
import { TransactionHistory } from "./Transactions/TransactionHistory";
@@ -99,6 +100,9 @@ export const MainRoutes = (): JSX.Element => {
99100
<Route path={routes.unshield} element={<div />} />
100101
</Route>
101102

103+
{/* Swapping */}
104+
<Route path={routes.swap} element={<SwapModule />} />
105+
102106
{/* Transaction History */}
103107
{(features.namTransfersEnabled || features.ibcTransfersEnabled) && (
104108
<Route>

apps/namadillo/src/App/Transfer/AvailableAmountFooter.tsx renamed to apps/namadillo/src/App/Common/AvailableAmountFooter.tsx

File renamed without changes.

apps/namadillo/src/App/Transfer/ConnectProviderButton.tsx renamed to apps/namadillo/src/App/Common/ConnectProviderButton.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,13 @@ import { ActionButton } from "@namada/components";
33
type ConnectProviderButtonProps = {
44
onClick?: () => void;
55
disabled?: boolean;
6+
text?: string;
67
};
78

89
export const ConnectProviderButton = ({
910
onClick,
1011
disabled,
12+
text,
1113
}: ConnectProviderButtonProps): JSX.Element => {
1214
return (
1315
<ActionButton
@@ -18,7 +20,7 @@ export const ConnectProviderButton = ({
1820
size="xs"
1921
backgroundColor="white"
2022
>
21-
Select Address
23+
{text || "Select Address"}
2224
</ActionButton>
2325
);
2426
};
File renamed without changes.
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import { routes } from "App/routes";
2+
import { BsQuestionCircleFill } from "react-icons/bs";
3+
import { Link, useNavigate } from "react-router-dom";
4+
import { IconTooltip } from "./IconTooltip";
5+
6+
export const LedgerDeviceTooltip = (): JSX.Element => {
7+
const navigate = useNavigate();
8+
return (
9+
<IconTooltip
10+
className="absolute w-4 h-4 top-0 right-0 mt-4 mr-5"
11+
icon={<BsQuestionCircleFill className="w-4 h-4 text-yellow" />}
12+
text={
13+
<span>
14+
If your device is connected and the app is open, please go to{" "}
15+
<Link
16+
onClick={(e) => {
17+
e.preventDefault();
18+
navigate(routes.settingsLedger, {
19+
state: { backgroundLocation: location },
20+
});
21+
}}
22+
to={routes.settingsLedger}
23+
className="text-yellow"
24+
>
25+
Settings
26+
</Link>{" "}
27+
and pair your device with Namadillo.
28+
</span>
29+
}
30+
/>
31+
);
32+
};

0 commit comments

Comments
 (0)