Skip to content

Commit 1636c3d

Browse files
committed
feat: ui
1 parent 54debea commit 1636c3d

File tree

5 files changed

+478
-242
lines changed

5 files changed

+478
-242
lines changed

apps/namadillo/src/App/Ibc/OsmosisSwap.tsx

Lines changed: 142 additions & 195 deletions
Original file line numberDiff line numberDiff line change
@@ -1,109 +1,102 @@
11
import { Panel } from "@namada/components";
22
import { AccountType } from "@namada/types";
3-
import { MaspSyncCover } from "App/Common/MaspSyncCover";
4-
import { params } from "App/routes";
5-
import { TransferModule } from "App/Transfer/TransferModule";
3+
import { SwapModule } from "App/Transfer/SwapModule";
64
import { allDefaultAccountsAtom } from "atoms/accounts";
5+
import { namadaShieldedAssetsAtom } from "atoms/balance";
76
import {
8-
lastCompletedShieldedSyncAtom,
9-
namadaShieldedAssetsAtom,
10-
} from "atoms/balance";
11-
import { chainParametersAtom } from "atoms/chain";
12-
import { namadaChainRegistryAtom } from "atoms/integrations";
13-
import { ledgerStatusDataAtom } from "atoms/ledger";
14-
import { rpcUrlAtom } from "atoms/settings";
7+
getChainRegistryByChainId,
8+
ibcChannelsFamily,
9+
namadaRegistryChainAssetsMapAtom,
10+
} from "atoms/integrations";
11+
import { SwapResponse, SwapResponseError, SwapResponseOk } from "atoms/swaps";
12+
import { createOsmosisSwapTxAtom } from "atoms/transfer/atoms";
1513
import BigNumber from "bignumber.js";
16-
import { useRequiresNewShieldedSync } from "hooks/useRequiresNewShieldedSync";
17-
import { useTransactionActions } from "hooks/useTransactionActions";
18-
import { useTransfer } from "hooks/useTransfer";
19-
import { useUrlState } from "hooks/useUrlState";
20-
import { wallets } from "integrations";
21-
import { useAtom, useAtomValue } from "jotai";
22-
import { useState } from "react";
14+
import { useTransactionFee } from "hooks";
15+
import invariant from "invariant";
16+
import { useAtomValue } from "jotai";
17+
import { useEffect, useState } from "react";
18+
import { Asset, NamadaAssetWithAmount } from "types";
2319

2420
const SLIPPAGE = 0.005;
2521
const SWAP_CONTRACT_ADDRESS =
2622
"osmo14q5zmg3fp774kpz2j8c52q7gqjn0dnm3vcj3guqpj4p9xylqpc7s2ezh0h";
2723

2824
export const OsmosisSwap: React.FC = () => {
29-
//const { mutateAsync: performOsmosisSwap } = useAtomValue(
30-
// createOsmosisSwapTxAtom
31-
//);
32-
//const { data: availableAssets, isLoading: _isLoadingAssets } = useAtomValue(
33-
// namadaShieldedAssetsAtom
34-
//);
25+
const { mutateAsync: performOsmosisSwap } = useAtomValue(
26+
createOsmosisSwapTxAtom
27+
);
28+
const { data: availableAssets, isLoading: _isLoadingAssets } = useAtomValue(
29+
namadaShieldedAssetsAtom
30+
);
3531

36-
//const chainAssetsMapAtom = useAtomValue(namadaRegistryChainAssetsMapAtom);
37-
//const namadaAssets =
38-
// chainAssetsMapAtom.isSuccess ? Object.values(chainAssetsMapAtom.data) : [];
32+
const chainAssetsMapAtom = useAtomValue(namadaRegistryChainAssetsMapAtom);
33+
const namadaAssets =
34+
chainAssetsMapAtom.isSuccess ? Object.values(chainAssetsMapAtom.data) : [];
3935

40-
//const osmosisAssets =
41-
// getChainRegistryByChainId("osmosis-1")?.assets.assets || [];
36+
const osmosisAssets =
37+
getChainRegistryByChainId("osmosis-1")?.assets.assets || [];
4238

43-
//const [from, setFrom] = useState<NamadaAssetWithAmount | undefined>();
44-
//const [to, setTo] = useState<Asset | undefined>();
45-
//const [amount, setAmount] = useState<string>("");
46-
//const [recipient, setRecipient] = useState<string>(
47-
// "znam17drxewzvge966gzcl0u6tr4j90traepujm2vd8ptwwkgrftnhs2hdtnyzgl5freyjsdnchn4ddy"
48-
//);
49-
//const [localRecoveryAddr, setLocalRecoveryAddress] = useState<string>(
50-
// "osmo18st0wqx84av8y6xdlss9d6m2nepyqwj6n3q7js"
51-
//);
52-
//const [quote, setQuote] = useState<
53-
// (SwapResponseOk & { minAmount: string }) | null
54-
//>(null);
39+
const [from, setFrom] = useState<NamadaAssetWithAmount | undefined>();
40+
const [to, setTo] = useState<Asset | undefined>();
41+
const [amount, setAmount] = useState<string>("");
42+
const [recipient, setRecipient] = useState<string>(
43+
"znam17drxewzvge966gzcl0u6tr4j90traepujm2vd8ptwwkgrftnhs2hdtnyzgl5freyjsdnchn4ddy"
44+
);
45+
const [localRecoveryAddr, setLocalRecoveryAddress] = useState<string>(
46+
"osmo18st0wqx84av8y6xdlss9d6m2nepyqwj6n3q7js"
47+
);
48+
const [quote, setQuote] = useState<
49+
(SwapResponseOk & { minAmount: string }) | null
50+
>(null);
5551

56-
//const { data: ibcChannels } = useAtomValue(ibcChannelsFamily("osmosis"));
52+
const { data: ibcChannels } = useAtomValue(ibcChannelsFamily("osmosis"));
5753

58-
//const feeProps = useTransactionFee(["IbcTransfer"], true);
54+
const feeProps = useTransactionFee(["IbcTransfer"], true);
5955

60-
//useEffect(() => {
61-
// const call = async (): Promise<void> => {
62-
// invariant(from, "No from asset selected");
63-
// invariant(to, "No to asset selected");
64-
// // We have to map namada assets to osmosis assets to get correct base
65-
// const fromOsmosis = osmosisAssets.find(
66-
// (assets) => assets.symbol === from.asset.symbol
67-
// );
68-
// const toOsmosis = osmosisAssets.find(
69-
// (assets) => assets.symbol === to.symbol
70-
// );
56+
useEffect(() => {
57+
const call = async (): Promise<void> => {
58+
invariant(from, "No from asset selected");
59+
invariant(to, "No to asset selected");
60+
// We have to map namada assets to osmosis assets to get correct base
61+
const fromOsmosis = osmosisAssets.find(
62+
(assets) => assets.symbol === from.asset.symbol
63+
);
64+
const toOsmosis = osmosisAssets.find(
65+
(assets) => assets.symbol === to.symbol
66+
);
7167

72-
// invariant(fromOsmosis, "From asset is not found in Osmosis assets");
73-
// invariant(toOsmosis, "To asset is not found in Osmosis assets");
68+
invariant(fromOsmosis, "From asset is not found in Osmosis assets");
69+
invariant(toOsmosis, "To asset is not found in Osmosis assets");
7470

75-
// const quote = await fetch(
76-
// "https://sqs.osmosis.zone/router/quote?" +
77-
// new URLSearchParams({
78-
// tokenIn: `${amount}${fromOsmosis.base}`,
79-
// tokenOutDenom: toOsmosis.base,
80-
// humanDenoms: "false",
81-
// }).toString()
82-
// );
83-
// const response: SwapResponse = await quote.json();
71+
const quote = await fetch(
72+
"https://sqs.osmosis.zone/router/quote?" +
73+
new URLSearchParams({
74+
tokenIn: `${amount}${fromOsmosis.base}`,
75+
tokenOutDenom: toOsmosis.base,
76+
humanDenoms: "false",
77+
}).toString()
78+
);
79+
const response: SwapResponse = await quote.json();
8480

85-
// if (!(response as SwapResponseError).message) {
86-
// const r = response as SwapResponseOk;
87-
// const minAmount = BigNumber(r.amount_out)
88-
// .times(BigNumber(1).minus(SLIPPAGE))
89-
// .toString();
90-
// setQuote({ ...(response as SwapResponseOk), minAmount });
91-
// } else {
92-
// setQuote(null);
93-
// }
94-
// };
95-
// if (from && to && amount) {
96-
// call();
97-
// }
98-
//}, [from?.asset.address, to?.address, amount]);
81+
if (!(response as SwapResponseError).message) {
82+
const r = response as SwapResponseOk;
83+
const minAmount = BigNumber(r.amount_out)
84+
.times(BigNumber(1).minus(SLIPPAGE))
85+
.toString();
86+
setQuote({ ...(response as SwapResponseOk), minAmount });
87+
} else {
88+
setQuote(null);
89+
}
90+
};
91+
if (from && to && amount) {
92+
call();
93+
}
94+
}, [from?.asset.address, to?.address, amount]);
9995

100-
//const defaultAccounts = useAtomValue(allDefaultAccountsAtom);
101-
//const shieldedAccount = defaultAccounts.data?.find(
102-
// (account) => account.type === AccountType.ShieldedKeys
103-
//);
104-
//const transparentAccount = defaultAccounts.data?.find(
105-
// (account) => account.type !== AccountType.ShieldedKeys
106-
//);
96+
const defaultAccounts = useAtomValue(allDefaultAccountsAtom);
97+
const shieldedAccount = defaultAccounts.data?.find(
98+
(account) => account.type === AccountType.ShieldedKeys
99+
);
107100

108101
//const handleOsmosisSwap = useCallback(async () => {
109102
// invariant(transparentAccount, "No transparent account is found");
@@ -189,127 +182,81 @@ export const OsmosisSwap: React.FC = () => {
189182
// }
190183
//}, [transparentAccount, shieldedAccount, quote]);
191184

192-
/// New shiz below
193-
194-
const [displayAmount, setDisplayAmount] = useState<BigNumber | undefined>();
195-
const [generalErrorMessage, setGeneralErrorMessage] = useState("");
196-
const [currentStatus, setCurrentStatus] = useState("");
197-
const [currentStatusExplanation, setCurrentStatusExplanation] = useState("");
198-
const requiresNewSync = useRequiresNewShieldedSync();
199-
200-
const rpcUrl = useAtomValue(rpcUrlAtom);
201-
const chainParameters = useAtomValue(chainParametersAtom);
202-
const defaultAccounts = useAtomValue(allDefaultAccountsAtom);
203-
const [ledgerStatus, setLedgerStatusStop] = useAtom(ledgerStatusDataAtom);
204-
const { data: availableAssets, isLoading: isLoadingAssets } = useAtomValue(
205-
namadaShieldedAssetsAtom
206-
);
207-
const namadaChainRegistry = useAtomValue(namadaChainRegistryAtom);
208-
const chain = namadaChainRegistry.data?.chain;
209-
210-
const { storeTransaction } = useTransactionActions();
211-
212-
const ledgerAccountInfo = ledgerStatus && {
213-
deviceConnected: ledgerStatus.connected,
214-
errorMessage: ledgerStatus.errorMessage,
215-
};
216-
const chainId = chainParameters.data?.chainId;
217-
const account = defaultAccounts.data?.find(
218-
(account) => account.type === AccountType.ShieldedKeys
219-
);
220-
const sourceAddress = account?.address;
221-
const destinationAddress = defaultAccounts.data?.find(
222-
(account) => account.type !== AccountType.ShieldedKeys
223-
)?.address;
224-
225-
const [selectedAssetAddress, setSelectedAssetAddress] = useUrlState(
226-
params.asset
227-
);
228-
const lastSync = useAtomValue(lastCompletedShieldedSyncAtom);
229-
const selectedAsset =
230-
selectedAssetAddress ? availableAssets?.[selectedAssetAddress] : undefined;
231-
232-
const {
233-
execute: performTransfer,
234-
isPending: isPerformingTransfer,
235-
isSuccess,
236-
txKind,
237-
feeProps,
238-
completedAt,
239-
redirectToTransactionPage,
240-
} = useTransfer({
241-
source: sourceAddress ?? "",
242-
target: destinationAddress ?? "",
243-
token: selectedAsset?.asset.address ?? "",
244-
displayAmount: displayAmount ?? new BigNumber(0),
245-
onBeforeBuildTx: () => {
246-
setCurrentStatus("Generating MASP Parameters...");
247-
setCurrentStatusExplanation(
248-
"Generating MASP parameters can take a few seconds. Please wait..."
249-
);
250-
},
251-
onBeforeSign: () => {
252-
setCurrentStatus("Waiting for signature...");
253-
},
254-
onBeforeBroadcast: async () => {
255-
setCurrentStatus("Broadcasting unshielding transaction...");
256-
},
257-
onError: async (originalError) => {
258-
setCurrentStatus("");
259-
setCurrentStatusExplanation("");
260-
setGeneralErrorMessage((originalError as Error).message);
261-
},
262-
asset: selectedAsset?.asset,
263-
});
264-
265-
// We stop the ledger status check when the transfer is in progress
266-
setLedgerStatusStop(isPerformingTransfer);
185+
//TODO: sucks
186+
const toAmount = quote ? BigNumber(quote.amount_out) : undefined;
267187

268188
return (
269189
<Panel className="relative rounded-sm flex flex-col flex-1 pt-9">
270190
<header className="flex flex-col items-center text-center mb-8 gap-6">
271191
<h1 className="text-yellow"> Shielded Swaps </h1>
272192
</header>
273-
274-
<TransferModule
193+
<SwapModule
194+
feeProps={feeProps}
195+
walletAddress={shieldedAccount?.address}
275196
source={{
276-
isLoadingAssets: isLoadingAssets,
197+
amount: amount ? BigNumber(amount) : undefined,
198+
availableAmount: from?.amount,
199+
selectedAssetAddress: from?.asset.address,
277200
availableAssets,
278-
selectedAssetAddress,
279-
availableAmount: selectedAsset?.amount,
280-
chain,
281-
availableWallets: [wallets.namada],
282-
wallet: wallets.namada,
283-
walletAddress: sourceAddress,
284-
isShieldedAddress: true,
285-
onChangeSelectedAsset: setSelectedAssetAddress,
286-
amount: displayAmount,
287-
onChangeAmount: setDisplayAmount,
288-
ledgerAccountInfo,
289-
hideChainSelector: true,
290-
label: "Sell",
201+
onChangeAmount: (a) => setAmount(a ? a.toString() : ""),
202+
onChangeSellSelectedAsset: (address) => {
203+
setFrom(address ? availableAssets?.[address] : undefined);
204+
setQuote(null);
205+
},
291206
}}
292-
destination={{
293-
chain,
294-
availableWallets: [wallets.namada],
295-
wallet: wallets.namada,
296-
walletAddress: destinationAddress,
297-
isShieldedAddress: false,
298-
}}
299-
feeProps={feeProps}
300-
isShieldedTx={true}
301-
isSubmitting={isPerformingTransfer || isSuccess}
302-
errorMessage={generalErrorMessage}
303-
onSubmitTransfer={() => {}}
304-
currentStatus={currentStatus}
305-
currentStatusExplanation={currentStatusExplanation}
306-
completedAt={completedAt}
307-
onComplete={redirectToTransactionPage}
308-
buttonTextErrors={{
309-
NoAmount: "Define an amount to unshield",
207+
target={{
208+
amount: toAmount,
209+
selectedAssetAddress: to?.address,
210+
availableAssets,
211+
onChangeBuySelectedAsset: (address) => {
212+
setTo(address ? availableAssets?.[address].asset : undefined);
213+
setQuote(null);
214+
},
310215
}}
311216
/>
312-
{requiresNewSync && <MaspSyncCover longSync={lastSync === undefined} />}
217+
218+
{quote && (
219+
<div>
220+
<div>
221+
Amount in: {quote.amount_in.amount}
222+
{from?.asset.denom_units[0].aliases?.[0]}
223+
</div>
224+
<div>
225+
Amount out: {quote.amount_out}
226+
{to?.denom_units[0].aliases?.[0]}
227+
</div>
228+
<div>
229+
Min amount out: {quote.minAmount}
230+
{to?.denom_units[0].aliases?.[0]}
231+
</div>
232+
<div>Slippage: {SLIPPAGE * 100}%</div>
233+
<div>Routes: </div>
234+
<div>Effective fee: {BigNumber(quote.effective_fee).toString()}</div>
235+
<div>
236+
Price: 1 {from?.asset.symbol}{" "}
237+
{BigNumber(quote.amount_out).div(BigNumber(amount)).toString()}{" "}
238+
{to?.symbol}
239+
</div>
240+
<div>
241+
Price impact: {BigNumber(quote.price_impact).dp(3).toString()}
242+
</div>
243+
<ul className="list-disc list-inside">
244+
{quote.route.map((r, i) => (
245+
<li key={i}>
246+
Route{i + 1}
247+
<ul className="list-disc list-inside pl-4">
248+
{r.pools.map((p, i) => (
249+
<li key={i}>
250+
{p.id}: {p.token_out_denom}
251+
(Fee: {BigNumber(p.taker_fee).toString()})
252+
</li>
253+
))}
254+
</ul>
255+
</li>
256+
))}
257+
</ul>
258+
</div>
259+
)}
313260
</Panel>
314261
// <div className="text-white">
315262
// <div>From:</div>

0 commit comments

Comments
 (0)