Skip to content

Commit

Permalink
Merge pull request #99 from dezswap/feat/pool-simulation
Browse files Browse the repository at this point in the history
feat: pool simulation
  • Loading branch information
jhlee-young authored Jan 9, 2023
2 parents 803a50e + a66473d commit d069891
Show file tree
Hide file tree
Showing 8 changed files with 1,211 additions and 788 deletions.
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@
"@esbuild-plugins/node-globals-polyfill": "^0.1.1",
"@rollup/plugin-inject": "^4.0.4",
"@tippyjs/react": "^4.2.6",
"@xpla/wallet-provider": "^0.3.4",
"@xpla/xpla.js": "^0.2.1",
"@xpla/wallet-provider": "^0.3.9",
"@xpla/xpla.js": "^0.2.3",
"axios": "^1.1.3",
"buffer": "^6.0.3",
"decimal.js": "^10.2.1",
Expand Down
6 changes: 3 additions & 3 deletions src/hooks/useAPI.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import {
Amount,
generateReverseSimulationMsg,
generateSimulationMsg,
generatePairsMsg,
queryMessages,
} from "utils/dezswap";
import { Pairs } from "types/factory";
import axios from "axios";
Expand Down Expand Up @@ -38,14 +38,14 @@ export const useAPI = () => {
);

const getPairs = useCallback(
(options: Parameters<typeof generatePairsMsg>[0]) => {
(options?: Parameters<typeof queryMessages.getPairs>[0]) => {
const contractAddress = contractAddresses[network.name]?.factory;
if (!contractAddress) {
return undefined;
}
const res = lcd.wasm.contractQuery<Pairs>(
contractAddress,
generatePairsMsg(options),
queryMessages.getPairs(options),
);

return res;
Expand Down
4 changes: 2 additions & 2 deletions src/hooks/usePair.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { useCallback, useEffect, useMemo, useRef } from "react";
import { useAPI } from "hooks/useAPI";
import { NetworkName } from "types/common";
import { useAtom, useSetAtom } from "jotai";
import { generatePairsMsg } from "utils/dezswap";
import { queryMessages } from "utils/dezswap";
import pairsAtom, { isPairsLoadingAtom } from "stores/pairs";
import assetsAtom from "stores/assets";
import { useNetwork } from "hooks/useNetwork";
Expand All @@ -18,7 +18,7 @@ const usePairs = () => {
const api = useAPI();

const fetchPairs = useCallback(
async (options: Parameters<typeof generatePairsMsg>[0]) => {
async (options?: Parameters<typeof queryMessages.getPairs>[0]) => {
try {
if (!network.name || !window.navigator.onLine) {
return;
Expand Down
29 changes: 29 additions & 0 deletions src/hooks/usePool.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { useEffect, useMemo, useState } from "react";
import { useLCDClient } from "@xpla/wallet-provider";
import { Pool } from "types/pair";
import { queryMessages } from "utils/dezswap";

const usePool = (contractAddress?: string) => {
const lcd = useLCDClient();
const [pool, setPool] = useState<Pool>();

useEffect(() => {
const fetchPool = async () => {
if (!contractAddress) {
setPool(undefined);
return;
}
const res = await lcd?.wasm.contractQuery<Pool>(
contractAddress,
queryMessages.getPool(),
);
setPool(res);
};

fetchPool();
}, [contractAddress, lcd]);

return useMemo(() => pool, [pool]);
};

export default usePool;
91 changes: 89 additions & 2 deletions src/pages/Pool/Provide/useSimulate.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,92 @@
const useSimulate = () => {
/* TODO: implement */
import useAssets from "hooks/useAssets";
import { useEffect, useMemo, useState } from "react";
import usePool from "hooks/usePool";
import { Numeric } from "@xpla/xpla.js";

export interface ProvideSimulationResult {
estimatedAmount: string;
poolAssets: { address: string; amount: string }[];
percentageOfShare: string;
share: string;
}

const useSimulate = (
pairAddress: string,
assetAddress: string,
assetAmount: string,
) => {
const pool = usePool(pairAddress);
const { getAsset } = useAssets();
const [isLoading, setIsLoading] = useState(false);
const [isFailed, setIsFailed] = useState(false);
const [result, setResult] = useState<ProvideSimulationResult>();

useEffect(() => {
setIsLoading(true);
setIsFailed(false);
const fetchProvideInfos = async () => {
try {
if (pool) {
const poolAssets = pool.assets.map((asset) => ({
address:
"token" in asset.info
? asset.info.token.contract_addr
: asset.info.native_token.denom,
amount: asset.amount,
}));

if (poolAssets.length > 1) {
const [poolAsset1, poolAsset2] = poolAssets.sort((a) =>
a?.address === assetAddress ? -1 : 1,
);

const depositAmount = Numeric.parse(assetAmount);
if (Numeric.parse(pool.total_share).gt(0) && depositAmount.gt(0)) {
const share = depositAmount
.mul(pool.total_share)
.div(poolAsset1.amount)
.ceil();
const estimated = share
.mul(poolAsset2.amount)
.div(pool.total_share)
.ceil();

setResult({
estimatedAmount: estimated.toString(),
poolAssets,
percentageOfShare: share
.mul(100)
.div(share.plus(pool.total_share))
.toString(),
share: share.toString(),
});
return;
}
}
}
setIsFailed(true);
setResult(undefined);
} catch (error) {
console.error(error);
setIsFailed(true);
setResult(undefined);
} finally {
setIsLoading(false);
}
};
const timerId = setTimeout(() => {
fetchProvideInfos();
}, 1000);

return () => {
clearTimeout(timerId);
};
}, [assetAddress, getAsset, assetAmount]);

return useMemo(
() => ({ ...result, isLoading, isFailed }),
[isFailed, isLoading, result],
);
};

export default useSimulate;
93 changes: 91 additions & 2 deletions src/pages/Pool/Withdraw/useSimulate.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,94 @@
const useSimulate = () => {
/* TODO: implement */
import { Numeric } from "@xpla/xpla.js";
import { useEffect, useMemo, useState } from "react";
import usePool from "hooks/usePool";
import { useNetwork } from "hooks/useNetwork";
import useAssets from "hooks/useAssets";

export interface WithdrawSimulationResult {
estimatedAmount1: string;
estimatedAmount2: string;
poolAssets: { address: string; amount: string }[];
percentageOfShare: string;
}

const useSimulate = (
pairAddress: string,
liquidityTokenAddress: string,
amount: string,
) => {
const { name: networkName } = useNetwork();
const pool = usePool(pairAddress);
const { getAsset } = useAssets();
const [isLoading, setIsLoading] = useState(false);
const [isFailed, setIsFailed] = useState(false);
const [result, setResult] = useState<WithdrawSimulationResult>();

useEffect(() => {
setIsLoading(true);
setIsFailed(false);
let isAborted = false;

const fetchPool = async () => {
try {
if (isAborted) {
return;
}

if (pool) {
const poolAssets = pool.assets.map((asset) => ({
address:
"token" in asset.info
? asset.info.token.contract_addr
: asset.info.native_token.denom,
amount: asset.amount,
}));

if (
poolAssets &&
poolAssets.length > 1 &&
Numeric.parse(pool.total_share).gt(0) &&
Numeric.parse(amount).gt(0)
) {
const amountInNumeric = Numeric.parse(amount);
setResult({
estimatedAmount1: amountInNumeric
.mul(poolAssets[0].amount)
.div(pool.total_share)
.floor()
.toString(),
estimatedAmount2: amountInNumeric
.mul(poolAssets[1].amount)
.div(pool.total_share)
.floor()
.toString(),
poolAssets,
percentageOfShare: amountInNumeric.mul(100).toString(),
});
return;
}
}
setIsFailed(true);
setResult(undefined);
} catch (error) {
console.log(error);
setIsFailed(true);
setResult(undefined);
} finally {
setIsLoading(false);
}
};

fetchPool();

return () => {
isAborted = true;
};
}, [pairAddress, liquidityTokenAddress, amount, getAsset, networkName, pool]);

return useMemo(
() => ({ ...result, isLoading, isFailed }),
[isFailed, isLoading, pool, result],
);
};

export default useSimulate;
19 changes: 14 additions & 5 deletions src/utils/dezswap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,20 @@ import { contractAddresses } from "constants/dezswap";

export type Amount = string | number;

export const generatePairsMsg = (options: {
limit?: number;
start_after?: [Asset | NativeAsset, Asset | NativeAsset];
}) => {
return { pairs: options };
export const queryMessages = {
getPairs(
options: {
limit?: number;
start_after?: [Asset | NativeAsset, Asset | NativeAsset];
} = {},
) {
return {
pairs: options,
};
},
getPool() {
return { pool: {} };
},
};

const assetMsg = (
Expand Down
Loading

0 comments on commit d069891

Please sign in to comment.