const { factoryAddress, routerAddress, wethAddress, title, defaultCurrencies } = props; Storage.privateSet("config", { ROUTER_ADDRESS: routerAddress, FACTORY_ADDRESS: factoryAddress, WETH_ADDRESS: wethAddress, dexName: title, }); State.init({ inputCurrency: defaultCurrencies?.input, outputCurrency: defaultCurrencies?.output, inputCurrencyAmount: "", outputCurrencyAmount: "", maxInputBalance: "0", maxOutputBalance: "0", tradeType: "in", targetUnitAmount: 0, noPair: false, updateInputTokenBalance: false, updateOutputTokenBalance: false, loading: false, displayCurrencySelect: false, selectedTokenAddress: "", currencySelectType: 0, }); // styled area const BaseSwap = styled.div``; const Title = styled.div` color: #3d76ff; font-size: 18px; font-weight: 500; line-height: 22px; padding-left: 30px; padding-bottom: 10px; `; const Panel = styled.div` width: 560px; border-radius: 16px; border: 1px solid #2c334b; padding: 30px; background-color: #181a27; `; const ExchangeIcon = styled.div` width: 60px; margin: 20px auto; svg { color: #82a7ff; } `; const PanelLabel = styled.div` color: #82a7ff; font-size: 18px; font-weight: 500; line-height: 22px; `; const Price = styled.div` font-size: 14px; color: #4f5375; text-align: right; margin-bottom: 30px; margin-top: 20px; `; const SwapButton = styled.button` width: 100%; height: 60px; border-radius: 10px; background-color: #004bfc; color: #fff; font-size: 18px; line-height: 22px; border: none; transition: 0.5s; cursor: pointer; :hover { opacity: 0.8; } &:disabled { opacity: 0.5; pointer-events: none; } `; // styled area end const RouterContract = new ethers.Contract( routerAddress, Storage.privateGet("routerAbi"), Ethers.provider().getSigner() ); const FactoryContract = new ethers.Contract( factoryAddress, Storage.privateGet("factoryAbi"), Ethers.provider().getSigner() ); const getPairContract = (_pairAddress) => new ethers.Contract( _pairAddress, Storage.privateGet("pairAbi"), Ethers.provider().getSigner() ); function debounce(fn, wait) { let timer; return () => { clearTimeout(timer); timer = setTimeout(fn, wait); }; } const getBestTrade = () => { const wrapType = state.inputCurrency.address === "native" && state.outputCurrency.symbol === "WETH" ? 1 : state.inputCurrency.symbol === "WETH" && state.outputCurrency.address === "native" ? 2 : 0; if (wrapType) { State.update( state.tradeType === "in" ? { outputCurrencyAmount: state.inputCurrencyAmount, loading: false } : { inputCurrencyAmount: state.outputCurrencyAmount, loading: false } ); return; } FactoryContract.getPair( state.inputCurrency.address === "native" ? wethAddress : state.inputCurrency.address, state.outputCurrency.address === "native" ? wethAddress : state.outputCurrency.address ) .then((_pairAddress) => { if ( !_pairAddress || !ethers.utils.isAddress(_pairAddress) || _pairAddress === "0x0000000000000000000000000000000000000000" ) { throw Error; } const PairContract = getPairContract(_pairAddress); PairContract["token0"]().then((_token0) => { PairContract.getReserves().then((res) => { const [reserve0, reserve1] = res; const currentCurrency = state.tradeType === "in" ? state.inputCurrency : state.outputCurrency; const currentAmount = state.tradeType === "in" ? state.inputCurrencyAmount : state.outputCurrencyAmount; const type = _token0 === (currentCurrency.address === "native" ? wethAddress : currentCurrency.address) ? "in" : "out"; RouterContract[type === "in" ? "getAmountOut" : "getAmountIn"]( ethers.utils.parseUnits(currentAmount, currentCurrency.decimals), reserve0, reserve1 ).then((_outAmount) => { const outCurrency = state.tradeType === "in" ? state.outputCurrency : state.inputCurrency; const outAmount = Big( ethers.utils.formatUnits(_outAmount, outCurrency.decimals) ).toFixed(4); State.update( state.tradeType === "in" ? { outputCurrencyAmount: outAmount, loading: false } : { inputCurrencyAmount: outAmount, loading: false } ); }); }); }); }) .catch((err) => { State.update({ noPair: false, loading: false, }); }); }; const debouncedGetBestTrade = debounce(getBestTrade, 500); const getUnitAmount = () => { const bigInputAmount = Big(state.inputCurrencyAmount || 0); const bigOutputAmount = Big(state.outputCurrencyAmount || 0); if (bigInputAmount.eq(0) || bigOutputAmount.eq(0)) return "-"; const unitAmount = bigOutputAmount.div(bigInputAmount); if (unitAmount.lt(0.001)) return unitAmount.toPrecision(1); return unitAmount.toFixed(3); }; return ( <BaseSwap> <Title>{title}</Title> <Panel> <PanelLabel>Swap From</PanelLabel> <Widget src="bluebiu.near/widget/Base.BaseCurrencyInput" props={{ currency: state.inputCurrency, amount: state.inputCurrencyAmount, updateTokenBalance: state.updateInputTokenBalance, onCurrencySelectOpen: () => { State.update({ displayCurrencySelect: true, currencySelectType: 0, selectedTokenAddress: state.inputCurrency.address, }); }, onUpdateCurrencyBalance: (balance) => { State.update({ maxInputBalance: ethers.utils.formatUnits( balance, state.inputCurrency.decimals ), updateInputTokenBalance: false, }); }, onAmountChange: (val) => { State.update({ inputCurrencyAmount: val, tradeType: "in", loading: val && Number(val) && state.inputCurrency.address && state.outputCurrency.address, }); if (val && Number(val)) debouncedGetBestTrade(); }, }} /> <ExchangeIcon onClick={() => { const [inputCurrency, outputCurrency, inputCurrencyAmount] = [ state.outputCurrency, state.inputCurrency, state.outputCurrencyAmount, ]; State.update({ inputCurrency, outputCurrency, inputCurrencyAmount, outputCurrencyAmount: "", tradeType: "in", updateInputTokenBalance: true, updateOutputTokenBalance: true, loading: true, }); if (Big(inputCurrencyAmount || 0).gt(0)) getBestTrade(); }} > <Widget src="bluebiu.near/widget/Base.BaseExchangeIcon" /> </ExchangeIcon> <PanelLabel>To</PanelLabel> <Widget src="bluebiu.near/widget/Base.BaseCurrencyInput" props={{ currency: state.outputCurrency, amount: state.outputCurrencyAmount, updateTokenBalance: state.updateOutputTokenBalance, onCurrencySelectOpen: () => { State.update({ displayCurrencySelect: true, currencySelectType: 1, selectedTokenAddress: state.outputCurrency.address, }); }, onUpdateCurrencyBalance: () => { State.update({ updateOutputTokenBalance: false, }); }, onAmountChange: (val) => { State.update({ outputCurrencyAmount: val, tradeType: "out", loading: val && Number(val) && state.inputCurrency.address && state.outputCurrency.address, }); if (val && Number(val)) debouncedGetBestTrade(); }, }} /> <Price> 1 {state.inputCurrency.symbol}≈ {getUnitAmount()}{" "} {state.outputCurrency.symbol} </Price> <Widget src="bluebiu.near/widget/Base.BaseSwapButton" props={{ inputCurrency: state.inputCurrency, outputCurrency: state.outputCurrency, inputCurrencyAmount: state.inputCurrencyAmount, outputCurrencyAmount: state.outputCurrencyAmount, maxInputBalance: state.maxInputBalance, onSuccess: () => { State.update({ updateInputTokenBalance: true, updateOutputTokenBalance: true, }); }, noPair: state.noPair, loading: state.loading, }} /> </Panel> {state.displayCurrencySelect && ( <Widget src="bluebiu.near/widget/Base.BaseCurrencySelect" props={{ display: state.displayCurrencySelect, selectedTokenAddress: state.selectedTokenAddress, onClose: () => { State.update({ displayCurrencySelect: false, }); }, onSelect: (currency) => { const updatedParams = state.currencySelectType === 0 ? { inputCurrency: currency, inputCurrencyAmount: "", noPair: false, tradeType: "out", updateInputTokenBalance: true, } : { outputCurrency: currency, outputCurrencyAmount: "", noPair: false, tradeType: "in", updateOutputTokenBalance: true, }; if ( state.currencySelectType === 0 && currency.address === state.outputCurrency.address ) { updatedParams.outputCurrency = null; updatedParams.outputCurrencyAmount = ""; } if ( state.currencySelectType === 1 && currency.address === state.inputCurrency.address ) { updatedParams.inputCurrency = null; updatedParams.inputCurrencyAmount = ""; } if ( (state.currencySelectType === 0 && state.outputCurrencyAmount && Number(state.outputCurrencyAmount) && state.outputCurrency?.address) || (state.currencySelectType === 1 && state.inputCurrencyAmount && Number(state.inputCurrencyAmount) && state.inputCurrency?.address) ) { updatedParams.loading = true; } State.update(updatedParams); if (updatedParams.loading) getBestTrade(); }, }} /> )} </BaseSwap> );