Skip to content

Commit

Permalink
'Swap' form: fix Kalamint exchanging + implement selecting another in…
Browse files Browse the repository at this point in the history
…itial asset than TEZ (#356)

* Add a new quipuswap contracts factory

* Implement choosing the initial asset which the user viewed before
  • Loading branch information
keshan3262 authored Jun 7, 2021
1 parent cce0140 commit 1eb3b26
Show file tree
Hide file tree
Showing 7 changed files with 124 additions and 58 deletions.
5 changes: 4 additions & 1 deletion src/app/PageRouter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,10 @@ const ROUTE_MAP = Woozie.Router.createMap<RouteContext>([
"/send/:assetSlug?",
onlyReady(({ assetSlug }) => <Send assetSlug={assetSlug} />),
],
["/swap", onlyReady(() => <Swap />)],
[
"/swap/:assetSlug?",
onlyReady(({ assetSlug }) => <Swap assetSlug={assetSlug} />),
],
["/delegate", onlyReady(() => <Delegate />)],
["/dapps", onlyReady(() => <DApps />)],
["/manage-assets", onlyReady(() => <ManageAssets />)],
Expand Down
2 changes: 1 addition & 1 deletion src/app/pages/Explore.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ const Explore: FC<ExploreProps> = ({ assetSlug }) => {
<ActionButton
label={<T id="swap" />}
Icon={SwapIcon}
href="/swap"
href={asset ? `/swap/${getAssetKey(asset)}` : "/swap"}
disabled={!canSend}
tippyProps={tippyProps}
/>
Expand Down
8 changes: 6 additions & 2 deletions src/app/pages/Swap.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,11 @@ import PageLayout from "app/layouts/PageLayout";
import SwapForm from "app/templates/SwapForm";
import { t } from "lib/i18n/react";

const Swap: React.FC = () => (
type SwapProps = {
assetSlug?: string | null;
};

const Swap: React.FC<SwapProps> = ({ assetSlug }) => (
<PageLayout
pageTitle={
<>
Expand All @@ -15,7 +19,7 @@ const Swap: React.FC = () => (
>
<div className="py-4">
<div className="w-full max-w-sm mx-auto">
<SwapForm />
<SwapForm assetSlug={assetSlug} />
</div>
</div>
</PageLayout>
Expand Down
28 changes: 24 additions & 4 deletions src/app/templates/SwapForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ import {
TEZ_ASSET,
assetAmountToUSD,
ExchangerType,
useAssetBySlug,
TempleAsset,
} from "lib/temple/front";
import useTippy from "lib/ui/useTippy";

Expand All @@ -58,7 +60,12 @@ type SwapFormValues = {

const maxTolerancePercentage = 30;

const SwapFormWrapper: React.FC = () => {
type SwapFormWrapperProps = {
assetSlug?: string | null;
};

const SwapFormWrapper: React.FC<SwapFormWrapperProps> = ({ assetSlug }) => {
const defaultAsset = useAssetBySlug(assetSlug) ?? undefined;
const { isSupportedNetwork } = useSwappableAssets();

if (!isSupportedNetwork) {
Expand All @@ -69,14 +76,18 @@ const SwapFormWrapper: React.FC = () => {
);
}

return <SwapForm />;
return <SwapForm defaultAsset={defaultAsset} />;
};

export default SwapFormWrapper;

const feeLabel = `${toLocalFixed(new BigNumber("0.3"))}%`;

const SwapForm: React.FC = () => {
type SwapFormProps = {
defaultAsset?: TempleAsset;
};

const SwapForm: React.FC<SwapFormProps> = ({ defaultAsset }) => {
const { assets, quipuswapTokensWhitelist, tokensExchangeData, tezUsdPrice } =
useSwappableAssets();
const { getInputAssetAmount, getOutputAssetAmounts } = useSwapCalculations();
Expand All @@ -94,10 +105,19 @@ const SwapForm: React.FC = () => {
)
? "quipuswap"
: "dexter";
const initialAsset = useMemo(() => {
if (
defaultAsset &&
assets.some((asset) => assetsAreSame(asset, defaultAsset))
) {
return defaultAsset;
}
return assets[0];
}, [assets, defaultAsset]);
const formContextValues = useForm<SwapFormValues>({
defaultValues: {
exchanger: defaultExchanger,
input: { asset: assets[0] },
input: { asset: initialAsset },
output: {},
tolerancePercentage: 1,
},
Expand Down
95 changes: 59 additions & 36 deletions src/app/templates/SwapForm/useSwappableAssets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -152,13 +152,21 @@ function getTokenId(token: TempleToken, replacer?: number) {
return token.type === TempleAssetType.FA2 ? token.id : replacer;
}

async function getTokensToExchange(
contractAddress: string,
async function getTokensToExchangeBigmaps(
contractsAddresses: string[],
tezos: TezosToolkit
): Promise<BigMapAbstraction> {
const tokenListContract = await loadContract(tezos, contractAddress, false);
const tokenListStorage = await tokenListContract.storage<any>();
return tokenListStorage.token_to_exchange;
): Promise<BigMapAbstraction[]> {
return Promise.all(
contractsAddresses.map(async (contractAddress) => {
const tokenListContract = await loadContract(
tezos,
contractAddress,
false
);
const tokenListStorage = await tokenListContract.storage<any>();
return tokenListStorage.token_to_exchange;
})
);
}

export const getAssetExchangeData = (
Expand Down Expand Up @@ -361,14 +369,14 @@ export default function useSwappableAssets(
const result: Record<string, Record<number, string>> = {};
const whitelist = quipuswapTokenWhitelists?.get(chainId) ?? [];
const quipuswapContracts = QUIPUSWAP_CONTRACTS.get(chainId)!;
const fa12FactoryAddress = quipuswapContracts.fa12Factory;
const fa2FactoryAddress = quipuswapContracts.fa2Factory;
const fa2TokensToExchange = fa2FactoryAddress
? await getTokensToExchange(fa2FactoryAddress, tezos)
: undefined;
const fa12TokensToExchange = fa12FactoryAddress
? await getTokensToExchange(fa12FactoryAddress, tezos)
: undefined;
const fa12FactoriesAddresses = quipuswapContracts.fa12Factory;
const fa2FactoriesAddresses = quipuswapContracts.fa2Factory;
const fa2TokensToExchangeBigmaps = fa2FactoriesAddresses
? await getTokensToExchangeBigmaps(fa2FactoriesAddresses, tezos)
: [];
const fa12TokensToExchangeBigmaps = fa12FactoriesAddresses
? await getTokensToExchangeBigmaps(fa12FactoriesAddresses, tezos)
: [];
const initialExchangableTokens = [
...whitelist,
...qsStoredTokens.filter(
Expand All @@ -383,14 +391,21 @@ export default function useSwappableAssets(
const tokenId = getTokenId(token);
let exchangeContractAddress: string | undefined;
if (token.type === TempleAssetType.FA2) {
// @ts-ignore
exchangeContractAddress =
fa2TokensToExchange &&
(await fa2TokensToExchange.get([token.address, token.id]))!;
exchangeContractAddress = (
await Promise.all(
fa2TokensToExchangeBigmaps.map((bigMap) =>
bigMap.get<string | undefined>([token.address, token.id])
)
)
).find((value) => value !== undefined);
} else {
exchangeContractAddress =
fa12TokensToExchange &&
((await fa12TokensToExchange.get(token.address))! as string);
exchangeContractAddress = (
await Promise.all(
fa12TokensToExchangeBigmaps.map((bigMap) =>
bigMap.get<string | undefined>(token.address)
)
)
).find((value) => value !== undefined);
}
if (!result[token.address]) {
result[token.address] = {};
Expand Down Expand Up @@ -497,21 +512,23 @@ export default function useSwappableAssets(
let isFA2Token = false;
let fa2IdIsCorrect = false;
const quipuswapContracts = QUIPUSWAP_CONTRACTS.get(chainId)!;
const fa2FactoryAddress = quipuswapContracts.fa2Factory;
const fa12FactoryAddress = quipuswapContracts.fa12Factory;
const fa2TokensList = fa2FactoryAddress
? await getTokensToExchange(fa2FactoryAddress, tezos)
: undefined;
const fa2FactoriesAddresses = quipuswapContracts.fa2Factory;
const fa12FactoriesAddresses = quipuswapContracts.fa12Factory;
const fa2TokensToExchangeBigmaps = fa2FactoriesAddresses
? await getTokensToExchangeBigmaps(fa2FactoriesAddresses, tezos)
: [];
let exchangeContractAddress: string | undefined;
try {
await assertFA2TokenContract(contract);
isFA2Token = true;
if (tokenId !== undefined) {
// @ts-ignore
exchangeContractAddress = await fa2TokensList.get([
searchStr,
tokenId,
]);
exchangeContractAddress = (
await Promise.all(
fa2TokensToExchangeBigmaps.map((bigMap) =>
bigMap.get<string | undefined>([searchStr, tokenId])
)
)
).find((value) => value !== undefined);
fa2IdIsCorrect = !!exchangeContractAddress;
}
} catch (e) {}
Expand All @@ -523,11 +540,17 @@ export default function useSwappableAssets(
}
if (!isFA2Token) {
try {
const tokensList = fa12FactoryAddress
? await getTokensToExchange(fa12FactoryAddress, tezos)
: undefined;
if (tokensList) {
exchangeContractAddress = await tokensList.get(searchStr);
const fa12TokensToExchangeBigmaps = fa12FactoriesAddresses
? await getTokensToExchangeBigmaps(fa12FactoriesAddresses, tezos)
: [];
if (fa12TokensToExchangeBigmaps.length > 0) {
exchangeContractAddress = (
await Promise.all(
fa12TokensToExchangeBigmaps.map((bigMap) =>
bigMap.get<string | undefined>(searchStr)
)
)
).find((value) => value !== undefined);
}
} catch (e) {}
}
Expand Down
18 changes: 11 additions & 7 deletions src/lib/analytics/use-page-router-analytics.hook.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,24 @@
import { useEffect } from 'react';
import { useEffect } from "react";

import { useAnalytics } from './use-analytics.hook';
import { useAnalytics } from "./use-analytics.hook";

const pageRoutesWithToken = ['/explore', '/send'];
const pageRoutesWithToken = ["/explore", "/send", "/swap"];

export const usePageRouterAnalytics = (pathname: string, search: string, isContextReady: boolean) => {
export const usePageRouterAnalytics = (
pathname: string,
search: string,
isContextReady: boolean
) => {
const { pageEvent } = useAnalytics();

useEffect(() => {
if (pathname === "/" && !isContextReady) {
return void pageEvent("/welcome", search);
}

if (pageRoutesWithToken.some(route => pathname.startsWith(route))) {
const [, route = '', tokenSlug = 'tez'] = pathname.split('/');
const [tokenAddress, tokenId = '0'] = tokenSlug.split('_');
if (pageRoutesWithToken.some((route) => pathname.startsWith(route))) {
const [, route = "", tokenSlug = "tez"] = pathname.split("/");
const [tokenAddress, tokenId = "0"] = tokenSlug.split("_");

return void pageEvent(`/${route}`, search, tokenAddress, tokenId);
}
Expand Down
26 changes: 19 additions & 7 deletions src/lib/temple/front/swap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,27 +75,39 @@ export const DEXTER_EXCHANGE_CONTRACTS = new Map<

export const QUIPUSWAP_CONTRACTS = new Map<
string,
Partial<Record<"fa12Factory" | "fa2Factory", string>>
Partial<Record<"fa12Factory" | "fa2Factory", string[]>>
>([
[
TempleChainId.Edo2net,
{
fa12Factory: "KT1WEcbPNGZNe6d5pm3eNufqe7cHS77DBG2G",
fa2Factory: "KT1KGdYTfLdzTKpyQbKkHJ2ASmBYa84hnCiQ",
fa12Factory: ["KT1WEcbPNGZNe6d5pm3eNufqe7cHS77DBG2G"],
fa2Factory: ["KT1KGdYTfLdzTKpyQbKkHJ2ASmBYa84hnCiQ"],
},
],
[
TempleChainId.Florencenet,
{
fa12Factory: "KT1We4CHneKjnCkovTDV34qc4W7xzWbn5LwY",
fa2Factory: "KT1SQX24W2v6D5sgihznax1eBykEGQNc7UpD",
fa12Factory: [
"KT195gyo5G7pay2tYweWDeYFkGLqcvQTXoCW",
"KT1We4CHneKjnCkovTDV34qc4W7xzWbn5LwY",
],
fa2Factory: [
"KT1HjLwPC3sbh6W5HjaKBsiVPTgptcNbnXnc",
"KT1SQX24W2v6D5sgihznax1eBykEGQNc7UpD",
],
},
],
[
TempleChainId.Mainnet,
{
fa12Factory: "KT1Lw8hCoaBrHeTeMXbqHPG4sS4K1xn7yKcD",
fa2Factory: "KT1SwH9P1Tx8a58Mm6qBExQFTcy2rwZyZiXS",
fa12Factory: [
"KT1FWHLMk5tHbwuSsp31S4Jum4dTVmkXpfJw",
"KT1Lw8hCoaBrHeTeMXbqHPG4sS4K1xn7yKcD",
],
fa2Factory: [
"KT1PvEyN1xCFCgorN92QCfYjw3axS6jawCiJ",
"KT1SwH9P1Tx8a58Mm6qBExQFTcy2rwZyZiXS",
],
},
],
]);
Expand Down

0 comments on commit 1eb3b26

Please sign in to comment.