@ant-design/icons#RetweetOutlined JavaScript Examples
The following examples show how to use
@ant-design/icons#RetweetOutlined.
You can vote up the ones you like or vote down the ones you don't like,
and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: Swap.jsx From Tai-Shang-NFT-Wallet with MIT License | 4 votes |
function Swap({ selectedProvider, tokenListURI }) {
const [tokenIn, setTokenIn] = useState(defaultToken);
const [tokenOut, setTokenOut] = useState(defaultTokenOut);
const [exact, setExact] = useState();
const [amountIn, setAmountIn] = useState();
const [amountInMax, setAmountInMax] = useState();
const [amountOut, setAmountOut] = useState();
const [amountOutMin, setAmountOutMin] = useState();
const [trades, setTrades] = useState();
const [routerAllowance, setRouterAllowance] = useState();
const [balanceIn, setBalanceIn] = useState();
const [balanceOut, setBalanceOut] = useState();
const [slippageTolerance, setSlippageTolerance] = useState(
new Percent(Math.round(defaultSlippage * 100).toString(), "10000"),
);
const [timeLimit, setTimeLimit] = useState(defaultTimeLimit);
const [swapping, setSwapping] = useState(false);
const [approving, setApproving] = useState(false);
const [settingsVisible, setSettingsVisible] = useState(false);
const [swapModalVisible, setSwapModalVisible] = useState(false);
const [tokenList, setTokenList] = useState([]);
const [tokens, setTokens] = useState();
const [invertPrice, setInvertPrice] = useState(false);
const blockNumber = useBlockNumber(selectedProvider, 3000);
const signer = selectedProvider.getSigner();
const routerContract = new ethers.Contract(ROUTER_ADDRESS, IUniswapV2Router02ABI, signer);
const _tokenListUri = tokenListURI || "https://gateway.ipfs.io/ipns/tokens.uniswap.org";
const debouncedAmountIn = useDebounce(amountIn, 500);
const debouncedAmountOut = useDebounce(amountOut, 500);
const activeChainId = process.env.REACT_APP_NETWORK === "kovan" ? ChainId.KOVAN : ChainId.MAINNET;
useEffect(() => {
const getTokenList = async () => {
console.log(_tokenListUri);
try {
const tokenList = await fetch(_tokenListUri);
const tokenListJson = await tokenList.json();
const filteredTokens = tokenListJson.tokens.filter(function (t) {
return t.chainId === activeChainId;
});
const ethToken = WETH[activeChainId];
ethToken.name = "Ethereum";
ethToken.symbol = "ETH";
ethToken.logoURI =
"https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/ethereum/assets/0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2/logo.png";
const _tokenList = [ethToken, ...filteredTokens];
setTokenList(_tokenList);
const _tokens = tokenListToObject(_tokenList);
setTokens(_tokens);
} catch (e) {
console.log(e);
}
};
getTokenList();
}, [tokenListURI]);
const getTrades = async () => {
if (tokenIn && tokenOut && (amountIn || amountOut)) {
const pairs = arr => arr.map((v, i) => arr.slice(i + 1).map(w => [v, w])).flat();
const baseTokens = tokenList
.filter(function (t) {
return ["DAI", "USDC", "USDT", "COMP", "ETH", "MKR", "LINK", tokenIn, tokenOut].includes(t.symbol);
})
.map(el => {
return new Token(el.chainId, el.address, el.decimals, el.symbol, el.name);
});
const listOfPairwiseTokens = pairs(baseTokens);
const getPairs = async list => {
const listOfPromises = list.map(item => Fetcher.fetchPairData(item[0], item[1], selectedProvider));
return Promise.all(listOfPromises.map(p => p.catch(() => undefined)));
};
const listOfPairs = await getPairs(listOfPairwiseTokens);
let bestTrade;
if (exact === "in") {
setAmountInMax();
bestTrade = Trade.bestTradeExactIn(
listOfPairs.filter(item => item),
new TokenAmount(tokens[tokenIn], ethers.utils.parseUnits(amountIn.toString(), tokens[tokenIn].decimals)),
tokens[tokenOut],
{ maxNumResults: 3, maxHops: 1 },
);
if (bestTrade[0]) {
setAmountOut(bestTrade[0].outputAmount.toSignificant(6));
} else {
setAmountOut();
}
} else if (exact === "out") {
setAmountOutMin();
bestTrade = Trade.bestTradeExactOut(
listOfPairs.filter(item => item),
tokens[tokenIn],
new TokenAmount(tokens[tokenOut], ethers.utils.parseUnits(amountOut.toString(), tokens[tokenOut].decimals)),
{ maxNumResults: 3, maxHops: 1 },
);
if (bestTrade[0]) {
setAmountIn(bestTrade[0].inputAmount.toSignificant(6));
} else {
setAmountIn();
}
}
setTrades(bestTrade);
console.log(bestTrade);
}
};
useEffect(() => {
getTrades();
}, [tokenIn, tokenOut, debouncedAmountIn, debouncedAmountOut, slippageTolerance, selectedProvider]);
useEffect(() => {
if (trades && trades[0]) {
if (exact === "in") {
setAmountOutMin(trades[0].minimumAmountOut(slippageTolerance));
} else if (exact === "out") {
setAmountInMax(trades[0].maximumAmountIn(slippageTolerance));
}
}
}, [slippageTolerance, amountIn, amountOut, trades]);
const getBalance = async (_token, _account, _contract) => {
let newBalance;
if (_token === "ETH") {
newBalance = await selectedProvider.getBalance(_account);
} else {
newBalance = await makeCall("balanceOf", _contract, [_account]);
}
return newBalance;
};
const getAccountInfo = async () => {
if (tokens) {
const accountList = await selectedProvider.listAccounts();
if (tokenIn) {
const tempContractIn = new ethers.Contract(tokens[tokenIn].address, erc20Abi, selectedProvider);
const newBalanceIn = await getBalance(tokenIn, accountList[0], tempContractIn);
setBalanceIn(newBalanceIn);
let allowance;
if (tokenIn === "ETH") {
setRouterAllowance();
} else {
allowance = await makeCall("allowance", tempContractIn, [accountList[0], ROUTER_ADDRESS]);
setRouterAllowance(allowance);
}
}
if (tokenOut) {
const tempContractOut = new ethers.Contract(tokens[tokenOut].address, erc20Abi, selectedProvider);
const newBalanceOut = await getBalance(tokenOut, accountList[0], tempContractOut);
setBalanceOut(newBalanceOut);
}
}
};
usePoller(getAccountInfo, 6000);
const route = trades
? trades.length > 0
? trades[0].route.path.map(function (item) {
return item.symbol;
})
: []
: [];
const updateRouterAllowance = async newAllowance => {
setApproving(true);
try {
const tempContract = new ethers.Contract(tokens[tokenIn].address, erc20Abi, signer);
const result = await makeCall("approve", tempContract, [ROUTER_ADDRESS, newAllowance]);
console.log(result);
setApproving(false);
return true;
} catch (e) {
notification.open({
message: "Approval unsuccessful",
description: `Error: ${e.message}`,
});
}
};
const approveRouter = async () => {
const approvalAmount =
exact === "in"
? ethers.utils.hexlify(ethers.utils.parseUnits(amountIn.toString(), tokens[tokenIn].decimals))
: amountInMax.raw.toString();
console.log(approvalAmount);
const approval = updateRouterAllowance(approvalAmount);
if (approval) {
notification.open({
message: "Token transfer approved",
description: `You can now swap up to ${amountIn} ${tokenIn}`,
});
}
};
const removeRouterAllowance = async () => {
const approvalAmount = ethers.utils.hexlify(0);
console.log(approvalAmount);
const removal = updateRouterAllowance(approvalAmount);
if (removal) {
notification.open({
message: "Token approval removed",
description: `The router is no longer approved for ${tokenIn}`,
});
}
};
const executeSwap = async () => {
setSwapping(true);
try {
let args;
const metadata = {};
let call;
const deadline = Math.floor(Date.now() / 1000) + timeLimit;
const path = trades[0].route.path.map(function (item) {
return item.address;
});
console.log(path);
const accountList = await selectedProvider.listAccounts();
const address = accountList[0];
if (exact === "in") {
const _amountIn = ethers.utils.hexlify(ethers.utils.parseUnits(amountIn.toString(), tokens[tokenIn].decimals));
const _amountOutMin = ethers.utils.hexlify(ethers.BigNumber.from(amountOutMin.raw.toString()));
if (tokenIn === "ETH") {
call = "swapExactETHForTokens";
args = [_amountOutMin, path, address, deadline];
metadata.value = _amountIn;
} else {
call = tokenOut === "ETH" ? "swapExactTokensForETH" : "swapExactTokensForTokens";
args = [_amountIn, _amountOutMin, path, address, deadline];
}
} else if (exact === "out") {
const _amountOut = ethers.utils.hexlify(
ethers.utils.parseUnits(amountOut.toString(), tokens[tokenOut].decimals),
);
const _amountInMax = ethers.utils.hexlify(ethers.BigNumber.from(amountInMax.raw.toString()));
if (tokenIn === "ETH") {
call = "swapETHForExactTokens";
args = [_amountOut, path, address, deadline];
metadata.value = _amountInMax;
} else {
call = tokenOut === "ETH" ? "swapTokensForExactETH" : "swapTokensForExactTokens";
args = [_amountOut, _amountInMax, path, address, deadline];
}
}
console.log(call, args, metadata);
const result = await makeCall(call, routerContract, args, metadata);
console.log(result);
notification.open({
message: "Swap complete ?",
description: (
<>
<Text>{`Swapped ${tokenIn} for ${tokenOut}, transaction: `}</Text>
<Text copyable>{result.hash}</Text>
</>
),
});
setSwapping(false);
} catch (e) {
console.log(e);
setSwapping(false);
notification.open({
message: "Swap unsuccessful",
description: `Error: ${e.message}`,
});
}
};
const showSwapModal = () => {
setSwapModalVisible(true);
};
const handleSwapModalOk = () => {
setSwapModalVisible(false);
executeSwap();
};
const handleSwapModalCancel = () => {
setSwapModalVisible(false);
};
const insufficientBalance = balanceIn
? parseFloat(ethers.utils.formatUnits(balanceIn, tokens[tokenIn].decimals)) < amountIn
: null;
const inputIsToken = tokenIn !== "ETH";
const insufficientAllowance = !inputIsToken
? false
: routerAllowance
? parseFloat(ethers.utils.formatUnits(routerAllowance, tokens[tokenIn].decimals)) < amountIn
: null;
const formattedBalanceIn = balanceIn
? parseFloat(ethers.utils.formatUnits(balanceIn, tokens[tokenIn].decimals)).toPrecision(6)
: null;
const formattedBalanceOut = balanceOut
? parseFloat(ethers.utils.formatUnits(balanceOut, tokens[tokenOut].decimals)).toPrecision(6)
: null;
const metaIn =
tokens && tokenList && tokenIn
? tokenList.filter(function (t) {
return t.address === tokens[tokenIn].address;
})[0]
: null;
const metaOut =
tokens && tokenList && tokenOut
? tokenList.filter(function (t) {
return t.address === tokens[tokenOut].address;
})[0]
: null;
const cleanIpfsURI = uri => {
try {
return uri.replace("ipfs://", "https://ipfs.io/ipfs/");
} catch (e) {
console.log(e, uri);
return uri;
}
};
const logoIn = metaIn ? cleanIpfsURI(metaIn.logoURI) : null;
const logoOut = metaOut ? cleanIpfsURI(metaOut.logoURI) : null;
const rawPrice = trades && trades[0] ? trades[0].executionPrice : null;
const price = rawPrice ? rawPrice.toSignificant(7) : null;
const priceDescription = rawPrice
? invertPrice
? `${rawPrice.invert().toSignificant(7)} ${tokenIn} per ${tokenOut}`
: `${price} ${tokenOut} per ${tokenIn}`
: null;
const priceWidget = (
<Space>
<Text type="secondary">{priceDescription}</Text>
<Button
type="text"
onClick={() => {
setInvertPrice(!invertPrice);
}}
>
<RetweetOutlined />
</Button>
</Space>
);
const swapModal = (
<Modal title="Confirm swap" visible={swapModalVisible} onOk={handleSwapModalOk} onCancel={handleSwapModalCancel}>
<Row>
<Space>
<img src={logoIn} alt={tokenIn} width="30" />
{amountIn}
{tokenIn}
</Space>
</Row>
<Row justify="center" align="middle" style={{ width: 30 }}>
<span>↓</span>
</Row>
<Row>
<Space>
<img src={logoOut} alt={tokenOut} width="30" />
{amountOut}
{tokenOut}
</Space>
</Row>
<Divider />
<Row>{priceWidget}</Row>
<Row>
{trades && ((amountOutMin && exact === "in") || (amountInMax && exact === "out"))
? exact === "in"
? `Output is estimated. You will receive at least ${amountOutMin.toSignificant(
6,
)} ${tokenOut} or the transaction will revert.`
: `Input is estimated. You will sell at most ${amountInMax.toSignificant(
6,
)} ${tokenIn} or the transaction will revert.`
: null}
</Row>
</Modal>
);
return (
<Card
title={
<Space>
<img src="https://ipfs.io/ipfs/QmXttGpZrECX5qCyXbBQiqgQNytVGeZW5Anewvh2jc4psg" width="40" alt="uniswapLogo" />
<Typography>Uniswapper</Typography>
</Space>
}
extra={
<Button
type="text"
onClick={() => {
setSettingsVisible(true);
}}
>
<SettingOutlined />
</Button>
}
>
<Space direction="vertical">
<Row justify="center" align="middle">
<Card
size="small"
type="inner"
title={`From${exact === "out" && tokenIn && tokenOut ? " (estimate)" : ""}`}
extra={
<>
<img src={logoIn} alt={tokenIn} width="30" />
<Button
type="link"
onClick={() => {
setAmountOut();
setAmountIn(ethers.utils.formatUnits(balanceIn, tokens[tokenIn].decimals));
setAmountOutMin();
setAmountInMax();
setExact("in");
}}
>
{formattedBalanceIn}
</Button>
</>
}
style={{ width: 400, textAlign: "left" }}
>
<InputNumber
style={{ width: "160px" }}
min={0}
size="large"
value={amountIn}
onChange={e => {
setAmountOut();
setTrades();
setAmountIn(e);
setExact("in");
}}
/>
<Select
showSearch
value={tokenIn}
style={{ width: "120px" }}
size="large"
bordered={false}
defaultValue={defaultToken}
onChange={value => {
console.log(value);
if (value === tokenOut) {
console.log("switch!", tokenIn);
setTokenOut(tokenIn);
setAmountOut(amountIn);
setBalanceOut(balanceIn);
}
setTokenIn(value);
setTrades();
setAmountIn();
setExact("out");
setBalanceIn();
}}
filterOption={(input, option) => option.children.toLowerCase().indexOf(input.toLowerCase()) >= 0}
optionFilterProp="children"
>
{tokenList.map(token => (
<Option key={token.symbol} value={token.symbol}>
{token.symbol}
</Option>
))}
</Select>
</Card>
</Row>
<Row justify="center" align="middle">
<Tooltip title={route.join("->")}>
<span>↓</span>
</Tooltip>
</Row>
<Row justify="center" align="middle">
<Card
size="small"
type="inner"
title={`To${exact === "in" && tokenIn && tokenOut ? " (estimate)" : ""}`}
extra={
<>
<img src={logoOut} width="30" alt={tokenOut} />
<Button type="text">{formattedBalanceOut}</Button>
</>
}
style={{ width: 400, textAlign: "left" }}
>
<InputNumber
style={{ width: "160px" }}
size="large"
min={0}
value={amountOut}
onChange={e => {
setAmountOut(e);
setAmountIn();
setTrades();
setExact("out");
}}
/>
<Select
showSearch
value={tokenOut}
style={{ width: "120px" }}
size="large"
bordered={false}
onChange={value => {
console.log(value, tokenIn, tokenOut);
if (value === tokenIn) {
console.log("switch!", tokenOut);
setTokenIn(tokenOut);
setAmountIn(amountOut);
setBalanceIn(balanceOut);
}
setTokenOut(value);
setExact("in");
setAmountOut();
setTrades();
setBalanceOut();
}}
filterOption={(input, option) => option.children.toLowerCase().indexOf(input.toLowerCase()) >= 0}
optionFilterProp="children"
>
{tokenList.map(token => (
<Option key={token.symbol} value={token.symbol}>
{token.symbol}
</Option>
))}
</Select>
</Card>
</Row>
<Row justify="center" align="middle">
{priceDescription ? priceWidget : null}
</Row>
<Row justify="center" align="middle">
<Space>
{inputIsToken ? (
<Button size="large" loading={approving} disabled={!insufficientAllowance} onClick={approveRouter}>
{!insufficientAllowance && amountIn && amountOut ? "Approved" : "Approve"}
</Button>
) : null}
<Button
size="large"
loading={swapping}
disabled={insufficientAllowance || insufficientBalance || !amountIn || !amountOut}
onClick={showSwapModal}
>
{insufficientBalance ? "Insufficient balance" : "Swap!"}
</Button>
{swapModal}
</Space>
</Row>
</Space>
<Drawer
visible={settingsVisible}
onClose={() => {
setSettingsVisible(false);
}}
width={500}
>
<Descriptions title="Details" column={1} style={{ textAlign: "left" }}>
<Descriptions.Item label="blockNumber">{blockNumber}</Descriptions.Item>
<Descriptions.Item label="routerAllowance">
<Space>
{routerAllowance ? ethers.utils.formatUnits(routerAllowance, tokens[tokenIn].decimals) : null}
{routerAllowance > 0 ? <Button onClick={removeRouterAllowance}>Remove Allowance</Button> : null}
</Space>
</Descriptions.Item>
<Descriptions.Item label="route">{route.join("->")}</Descriptions.Item>
<Descriptions.Item label="exact">{exact}</Descriptions.Item>
<Descriptions.Item label="bestPrice">
{trades ? (trades.length > 0 ? trades[0].executionPrice.toSignificant(6) : null) : null}
</Descriptions.Item>
<Descriptions.Item label="nextMidPrice">
{trades ? (trades.length > 0 ? trades[0].nextMidPrice.toSignificant(6) : null) : null}
</Descriptions.Item>
<Descriptions.Item label="priceImpact">
{trades ? (trades.length > 0 ? trades[0].priceImpact.toSignificant(6) : null) : null}
</Descriptions.Item>
<Descriptions.Item label="slippageTolerance">
<InputNumber
defaultValue={defaultSlippage}
min={0}
max={100}
precision={2}
formatter={value => `${value}%`}
parser={value => value.replace("%", "")}
onChange={value => {
console.log(value);
const slippagePercent = new Percent(Math.round(value * 100).toString(), "10000");
setSlippageTolerance(slippagePercent);
}}
/>
</Descriptions.Item>
<Descriptions.Item label="amountInMax">{amountInMax ? amountInMax.toExact() : null}</Descriptions.Item>
<Descriptions.Item label="amountOutMin">{amountOutMin ? amountOutMin.toExact() : null}</Descriptions.Item>
<Descriptions.Item label="timeLimitInSeconds">
<InputNumber
min={0}
max={3600}
defaultValue={defaultTimeLimit}
onChange={value => {
console.log(value);
setTimeLimit(value);
}}
/>
</Descriptions.Item>
</Descriptions>
</Drawer>
</Card>
);
}
Example #2
Source File: Swap.jsx From moonshot with MIT License | 4 votes |
function Swap({ selectedProvider, tokenListURI }) {
const [tokenIn, setTokenIn] = useState(defaultToken)
const [tokenOut, setTokenOut] = useState(defaultTokenOut)
const [exact, setExact] = useState()
const [amountIn, setAmountIn] = useState()
const [amountInMax, setAmountInMax] = useState()
const [amountOut, setAmountOut] = useState()
const [amountOutMin, setAmountOutMin] = useState()
const [trades, setTrades] = useState()
const [routerAllowance, setRouterAllowance] = useState()
const [balanceIn, setBalanceIn] = useState()
const [balanceOut, setBalanceOut] = useState()
const [slippageTolerance, setSlippageTolerance] = useState(new Percent(Math.round(defaultSlippage*100).toString(), "10000"))
const [timeLimit, setTimeLimit] = useState(defaultTimeLimit)
const [swapping, setSwapping] = useState(false)
const [approving, setApproving] = useState(false)
const [settingsVisible, setSettingsVisible] = useState(false)
const [swapModalVisible, setSwapModalVisible] = useState(false)
const [tokenList, setTokenList] = useState([])
const [tokens, setTokens] = useState()
const [invertPrice, setInvertPrice] = useState(false)
let blockNumber = useBlockNumber(selectedProvider, 3000)
let signer = selectedProvider.getSigner()
let routerContract = new ethers.Contract(ROUTER_ADDRESS, IUniswapV2Router02ABI, signer);
let _tokenListUri = tokenListURI ? tokenListURI : 'https://gateway.ipfs.io/ipns/tokens.uniswap.org'
const debouncedAmountIn = useDebounce(amountIn, 500);
const debouncedAmountOut = useDebounce(amountOut, 500);
const activeChainId = (process.env.REACT_APP_NETWORK === 'kovan' ? ChainId.KOVAN : ChainId.MAINNET)
useEffect(() => {
const getTokenList = async () => {
console.log(_tokenListUri)
try {
let tokenList = await fetch(_tokenListUri)
let tokenListJson = await tokenList.json()
let filteredTokens = tokenListJson.tokens.filter(function (t) {
return t.chainId === activeChainId
})
let ethToken = WETH[activeChainId]
ethToken.name = 'Ethereum'
ethToken.symbol = 'ETH'
ethToken.logoURI = "https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/ethereum/assets/0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2/logo.png"
let _tokenList = [ethToken, ...filteredTokens]
setTokenList(_tokenList)
let _tokens = tokenListToObject(_tokenList)
setTokens(_tokens)
} catch (e) {
console.log(e)
}
}
getTokenList()
},[tokenListURI])
const getTrades = async () => {
if(tokenIn && tokenOut && (amountIn || amountOut)) {
let pairs = (arr) => arr.map( (v, i) => arr.slice(i + 1).map(w => [v,w]) ).flat();
let baseTokens = tokenList.filter(function (t) {
return ['DAI', 'USDC', 'USDT', 'COMP', 'ETH', 'MKR', 'LINK', tokenIn, tokenOut].includes(t.symbol)
}).map((el) => {
return new Token(el.chainId, el.address, el.decimals, el.symbol, el.name)
})
let listOfPairwiseTokens = pairs(baseTokens)
const getPairs = async (list) => {
let listOfPromises = list.map(item => Fetcher.fetchPairData(item[0], item[1], selectedProvider))
return Promise.all(listOfPromises.map(p => p.catch(() => undefined)));
}
let listOfPairs = await getPairs(listOfPairwiseTokens)
let bestTrade
if(exact === 'in') {
setAmountInMax()
bestTrade = Trade.bestTradeExactIn(
listOfPairs.filter(item => item),
new TokenAmount(tokens[tokenIn], parseUnits(amountIn.toString(), tokens[tokenIn].decimals)),
tokens[tokenOut], { maxNumResults: 3, maxHops: 1 })
if(bestTrade[0]) {
setAmountOut(bestTrade[0].outputAmount.toSignificant(6))
} else { setAmountOut() }
} else if (exact === 'out') {
setAmountOutMin()
bestTrade = Trade.bestTradeExactOut(
listOfPairs.filter(item => item),
tokens[tokenIn],
new TokenAmount(tokens[tokenOut], parseUnits(amountOut.toString(), tokens[tokenOut].decimals)),
{ maxNumResults: 3, maxHops: 1 })
if(bestTrade[0]) {
setAmountIn(bestTrade[0].inputAmount.toSignificant(6))
} else { setAmountIn() }
}
setTrades(bestTrade)
console.log(bestTrade)
}
}
useEffect(() => {
getTrades()
},[tokenIn, tokenOut, debouncedAmountIn, debouncedAmountOut, slippageTolerance, selectedProvider])
useEffect(() => {
if(trades && trades[0]) {
if(exact === 'in') {
setAmountOutMin(trades[0].minimumAmountOut(slippageTolerance))
} else if (exact === 'out') {
setAmountInMax(trades[0].maximumAmountIn(slippageTolerance))
}
}
}, [slippageTolerance, amountIn, amountOut, trades])
const getBalance = async (_token, _account, _contract) => {
let newBalance
if(_token === 'ETH') {
newBalance = await selectedProvider.getBalance(_account)
} else {
newBalance = await makeCall('balanceOf', _contract, [_account])
}
return newBalance
}
const getAccountInfo = async () => {
if(tokens) {
let accountList = await selectedProvider.listAccounts()
if(tokenIn) {
let tempContractIn = new ethers.Contract(tokens[tokenIn].address, erc20Abi, selectedProvider);
let newBalanceIn = await getBalance(tokenIn, accountList[0], tempContractIn)
setBalanceIn(newBalanceIn)
let allowance
if(tokenIn === 'ETH') {
setRouterAllowance()
} else {
allowance = await makeCall('allowance',tempContractIn,[accountList[0],ROUTER_ADDRESS])
setRouterAllowance(allowance)
}
}
if(tokenOut) {
let tempContractOut = new ethers.Contract(tokens[tokenOut].address, erc20Abi, selectedProvider);
let newBalanceOut = await getBalance(tokenOut, accountList[0], tempContractOut)
setBalanceOut(newBalanceOut)
}
}
}
usePoller(getAccountInfo, 6000)
let route = trades ? (trades.length > 0 ? trades[0].route.path.map(function(item) {
return item['symbol'];
}) : []) : []
const updateRouterAllowance = async (newAllowance) => {
setApproving(true)
try {
let tempContract = new ethers.Contract(tokens[tokenIn].address, erc20Abi, signer);
let result = await makeCall('approve', tempContract, [ROUTER_ADDRESS, newAllowance])
console.log(result)
setApproving(false)
return true
} catch(e) {
notification.open({
message: 'Approval unsuccessful',
description:
`Error: ${e.message}`,
});
}
}
const approveRouter = async () => {
let approvalAmount = exact === 'in' ? ethers.utils.hexlify(parseUnits(amountIn.toString(), tokens[tokenIn].decimals)) : amountInMax.raw.toString()
console.log(approvalAmount)
let approval = updateRouterAllowance(approvalAmount)
if(approval) {
notification.open({
message: 'Token transfer approved',
description:
`You can now swap up to ${amountIn} ${tokenIn}`,
});
}
}
const removeRouterAllowance = async () => {
let approvalAmount = ethers.utils.hexlify(0)
console.log(approvalAmount)
let removal = updateRouterAllowance(approvalAmount)
if(removal) {
notification.open({
message: 'Token approval removed',
description:
`The router is no longer approved for ${tokenIn}`,
});
}
}
const executeSwap = async () => {
setSwapping(true)
try {
let args
let metadata = {}
let call
let deadline = Math.floor(Date.now() / 1000) + timeLimit
let path = trades[0].route.path.map(function(item) {
return item['address'];
})
console.log(path)
let accountList = await selectedProvider.listAccounts()
let address = accountList[0]
if (exact === 'in') {
let _amountIn = ethers.utils.hexlify(parseUnits(amountIn.toString(), tokens[tokenIn].decimals))
let _amountOutMin = ethers.utils.hexlify(ethers.BigNumber.from(amountOutMin.raw.toString()))
if (tokenIn === 'ETH') {
call = 'swapExactETHForTokens'
args = [_amountOutMin, path, address, deadline]
metadata['value'] = _amountIn
} else {
call = tokenOut === 'ETH' ? 'swapExactTokensForETH' : 'swapExactTokensForTokens'
args = [_amountIn, _amountOutMin, path, address, deadline]
}
} else if (exact === 'out') {
let _amountOut = ethers.utils.hexlify(parseUnits(amountOut.toString(), tokens[tokenOut].decimals))
let _amountInMax = ethers.utils.hexlify(ethers.BigNumber.from(amountInMax.raw.toString()))
if (tokenIn === 'ETH') {
call = 'swapETHForExactTokens'
args = [_amountOut, path, address, deadline]
metadata['value'] = _amountInMax
} else {
call = tokenOut === 'ETH' ? 'swapTokensForExactETH' : 'swapTokensForExactTokens'
args = [_amountOut, _amountInMax, path, address, deadline]
}
}
console.log(call, args, metadata)
let result = await makeCall(call, routerContract, args, metadata)
console.log(result)
notification.open({
message: 'Swap complete ?',
description:
<><Text>{`Swapped ${tokenIn} for ${tokenOut}, transaction: `}</Text><Text copyable>{result.hash}</Text></>,
});
setSwapping(false)
} catch (e) {
console.log(e)
setSwapping(false)
notification.open({
message: 'Swap unsuccessful',
description:
`Error: ${e.message}`,
});
}
}
const showSwapModal = () => {
setSwapModalVisible(true);
};
const handleSwapModalOk = () => {
setSwapModalVisible(false);
executeSwap()
};
const handleSwapModalCancel = () => {
setSwapModalVisible(false);
};
let insufficientBalance = balanceIn ? parseFloat(formatUnits(balanceIn,tokens[tokenIn].decimals)) < amountIn : null
let inputIsToken = tokenIn !== 'ETH'
let insufficientAllowance = !inputIsToken ? false : routerAllowance ? parseFloat(formatUnits(routerAllowance,tokens[tokenIn].decimals)) < amountIn : null
let formattedBalanceIn = balanceIn?parseFloat(formatUnits(balanceIn,tokens[tokenIn].decimals)).toPrecision(6):null
let formattedBalanceOut = balanceOut?parseFloat(formatUnits(balanceOut,tokens[tokenOut].decimals)).toPrecision(6):null
let metaIn = tokens && tokenList && tokenIn ? tokenList.filter(function (t) {
return t.address === tokens[tokenIn].address
})[0] : null
let metaOut = tokens && tokenList && tokenOut ? tokenList.filter(function (t) {
return t.address === tokens[tokenOut].address
})[0] : null
const cleanIpfsURI = (uri) => {
try {
return (uri).replace('ipfs://','https://ipfs.io/ipfs/')
} catch(e) {
console.log(e, uri)
return uri
}
}
let logoIn = metaIn?cleanIpfsURI(metaIn.logoURI):null
let logoOut = metaOut?cleanIpfsURI(metaOut.logoURI):null
let rawPrice = trades&&trades[0]?trades[0].executionPrice:null
let price = rawPrice?rawPrice.toSignificant(7):null
let priceDescription = rawPrice ? (invertPrice ? `${(rawPrice.invert()).toSignificant(7)} ${tokenIn} per ${tokenOut}` : `${price} ${tokenOut} per ${tokenIn}`) : null
let priceWidget = (
<Space>
<Text type="secondary">{priceDescription}</Text>
<Button type="text" onClick={() => {setInvertPrice(!invertPrice)}}><RetweetOutlined /></Button>
</Space>
)
let swapModal = (
<Modal title="Confirm swap" visible={swapModalVisible} onOk={handleSwapModalOk} onCancel={handleSwapModalCancel}>
<Row><Space><img src={logoIn} alt={tokenIn} width='30'/>{amountIn}{tokenIn}</Space></Row>
<Row justify='center' align='middle' style={{width:30}}><span>↓</span></Row>
<Row><Space><img src={logoOut} alt={tokenOut} width='30'/>{amountOut}{tokenOut}</Space></Row>
<Divider/>
<Row>{priceWidget}</Row>
<Row>{trades&&((amountOutMin && exact==='in') || (amountInMax && exact==='out'))?(exact==='in'?`Output is estimated. You will receive at least ${amountOutMin.toSignificant(6)} ${tokenOut} or the transaction will revert.`:`Input is estimated. You will sell at most ${amountInMax.toSignificant(6)} ${tokenIn} or the transaction will revert.`):null}</Row>
</Modal>
)
return (
<Card title={<Space><img src="https://ipfs.io/ipfs/QmXttGpZrECX5qCyXbBQiqgQNytVGeZW5Anewvh2jc4psg" width='40' alt='uniswapLogo'/><Typography>Uniswapper</Typography></Space>} extra={<Button type="text" onClick={() => {setSettingsVisible(true)}}><SettingOutlined /></Button>}>
<Space direction="vertical">
<Row justify="center" align="middle">
<Card size="small" type="inner" title={`From${exact==='out' && tokenIn && tokenOut?' (estimate)':''}`} extra={<><img src={logoIn} alt={tokenIn} width='30'/><Button type="link" onClick={() => {
setAmountOut()
setAmountIn(formatUnits(balanceIn,tokens[tokenIn].decimals))
setAmountOutMin()
setAmountInMax()
setExact('in')
}}>{formattedBalanceIn}</Button></>} style={{ width: 400, textAlign: 'left' }}>
<InputNumber style={{width: '160px'}} min={0} size={'large'} value={amountIn} onChange={(e) => {
setAmountOut()
setTrades()
setAmountIn(e)
setExact('in')
}}/>
<Select showSearch value={tokenIn} style={{width: '120px'}} size={'large'} bordered={false} defaultValue={defaultToken} onChange={(value) => {
console.log(value)
if(value===tokenOut) {
console.log('switch!', tokenIn)
setTokenOut(tokenIn)
setAmountOut(amountIn)
setBalanceOut(balanceIn)
}
setTokenIn(value)
setTrades()
setAmountIn()
setExact('out')
setBalanceIn()
}} filterOption={(input, option) =>
option.children.toLowerCase().indexOf(input.toLowerCase()) >= 0
} optionFilterProp="children">
{tokenList.map(token => (
<Option key={token.symbol} value={token.symbol}>{token.symbol}</Option>
))}
</Select>
</Card>
</Row>
<Row justify="center" align="middle">
<Tooltip title={route.join("->")}><span>↓</span></Tooltip>
</Row>
<Row justify="center" align="middle">
<Card size="small" type="inner" title={`To${exact==='in' && tokenIn && tokenOut?' (estimate)':''}`} extra={<><img src={logoOut} width='30' alt={tokenOut}/><Button type="text">{formattedBalanceOut}</Button></>} style={{ width: 400, textAlign: 'left' }}>
<InputNumber style={{width: '160px'}} size={'large'} min={0} value={amountOut} onChange={(e) => {
setAmountOut(e)
setAmountIn()
setTrades()
setExact('out')
}}/>
<Select showSearch value={tokenOut} style={{width: '120px'}} size={'large'} bordered={false} onChange={(value) => {
console.log(value, tokenIn, tokenOut)
if(value===tokenIn) {
console.log('switch!', tokenOut)
setTokenIn(tokenOut)
setAmountIn(amountOut)
setBalanceIn(balanceOut)
}
setTokenOut(value)
setExact('in')
setAmountOut()
setTrades()
setBalanceOut()
}} filterOption={(input, option) =>
option.children.toLowerCase().indexOf(input.toLowerCase()) >= 0
} optionFilterProp="children">
{tokenList.map(token => (
<Option key={token.symbol} value={token.symbol}>{token.symbol}</Option>
))}
</Select>
</Card>
</Row>
<Row justify="center" align="middle">
{priceDescription?priceWidget:null}
</Row>
<Row justify="center" align="middle">
<Space>
{inputIsToken?<Button size="large" loading={approving} disabled={!insufficientAllowance} onClick={approveRouter}>{(!insufficientAllowance&&amountIn&&amountOut)?'Approved':'Approve'}</Button>:null}
<Button size="large" loading={swapping} disabled={insufficientAllowance || insufficientBalance || !amountIn || !amountOut} onClick={showSwapModal}>{insufficientBalance?'Insufficient balance':'Swap!'}</Button>
{swapModal}
</Space>
</Row>
</Space>
<Drawer visible={settingsVisible} onClose={() => { setSettingsVisible(false) }} width={500}>
<Descriptions title="Details" column={1} style={{textAlign: 'left'}}>
<Descriptions.Item label="blockNumber">{blockNumber}</Descriptions.Item>
<Descriptions.Item label="routerAllowance"><Space>{routerAllowance?formatUnits(routerAllowance,tokens[tokenIn].decimals):null}{routerAllowance>0?<Button onClick={removeRouterAllowance}>Remove Allowance</Button>:null}</Space></Descriptions.Item>
<Descriptions.Item label="route">{route.join("->")}</Descriptions.Item>
<Descriptions.Item label="exact">{exact}</Descriptions.Item>
<Descriptions.Item label="bestPrice">{trades ? (trades.length > 0 ? trades[0].executionPrice.toSignificant(6) : null) : null}</Descriptions.Item>
<Descriptions.Item label="nextMidPrice">{trades ? (trades.length > 0 ? trades[0].nextMidPrice.toSignificant(6) : null) : null}</Descriptions.Item>
<Descriptions.Item label="priceImpact">{trades ? (trades.length > 0 ? trades[0].priceImpact.toSignificant(6) : null) : null}</Descriptions.Item>
<Descriptions.Item label="slippageTolerance">{<InputNumber
defaultValue={defaultSlippage}
min={0}
max={100}
precision={2}
formatter={value => `${value}%`}
parser={value => value.replace('%', '')}
onChange={(value) => {
console.log(value)
let slippagePercent = new Percent(Math.round(value*100).toString(), "10000")
setSlippageTolerance(slippagePercent)
}}
/>}</Descriptions.Item>
<Descriptions.Item label="amountInMax">{amountInMax?amountInMax.toExact():null}</Descriptions.Item>
<Descriptions.Item label="amountOutMin">{amountOutMin?amountOutMin.toExact():null}</Descriptions.Item>
<Descriptions.Item label="timeLimitInSeconds">{<InputNumber
min={0}
max={3600}
defaultValue={defaultTimeLimit}
onChange={(value) => {
console.log(value)
setTimeLimit(value)
}}
/>}</Descriptions.Item>
</Descriptions>
</Drawer>
</Card>
)
}
Example #3
Source File: index.js From gobench with Apache License 2.0 | 4 votes |
DefaultPage = ({ list, loading, total, dispatch }) => {
const history = useHistory()
const [fetching, setFetching] = useState(false)
const [pagination, setPagination] = useState({
current: 1,
pageSize: 10,
total: 0,
showTotal: (total, range) => `${range[0]}-${range[1]} of ${total} scenarios`
})
const columns = [
{
title: 'ID',
dataIndex: 'id',
key: 'id',
sorter: (a, b) => a.name.length - b.name.length
},
{
title: 'Status',
dataIndex: 'status',
key: 'status',
sorter: (a, b) => a.name.length - b.name.length,
render: (text, item) => (
<>
<Link key={item.id} to={`/applications/${item.id}`}>
<Tag color={statusColors[text]} key={item.id}>
{text.toUpperCase()}
</Tag>
</Link>
</>
)
},
{
title: 'Name',
dataIndex: 'name',
key: 'name',
sorter: (a, b) => a.name.length - b.name.length,
render: (text, item) => <Link key={item.id} to={`/applications/${item.id}`}>{text}</Link>
},
{
title: 'Tags',
dataIndex: 'tags',
key: 'tags',
render: (text) => {
return (
<>
{formatTag(text).map(x => (
<Tag color={x.color} key={x.index}>
{x.text}
</Tag>
))}
</>
)
}
},
{
title: 'Started at',
dataIndex: 'started_at',
key: 'started_at',
sorter: (a, b) => a.name.length - b.name.length,
render: x => {
return moment(x).utc().format()
}
},
{
title: 'Duration',
dataIndex: 'duration',
key: 'duration',
render: (x, item) => {
const { started_at: startedAt, updated_at: updated } = item
const start = moment(startedAt).utc()
if (['provisioning', 'pending', 'error'].includes(item.status)) {
return <span />
}
if (['finished', 'cancel'].includes(item.status)) {
const end = moment(updated).utc()
const diff = end.diff(start)
const duration = moment.utc(diff).format('HH:mm:ss.SSS')
return <span>{duration}</span>
}
const diff = moment.utc().diff(start)
const duration = moment.utc(diff).format('HH:mm:ss.SSS')
return <span>{duration}</span>
}
},
{
title: 'Action',
dataIndex: 'action',
key: 'action',
render: (x, application) => {
return (
<div style={{ float: 'right' }} key={application.id}>
<Button
style={{ marginLeft: 5 }}
type='default'
onClick={() => clone(application)}
>
Clone
</Button>
{['running', 'pending'].includes(application.status) && (
<Popconfirm
title={`Are you sure cancel application ${application.name}?`}
onConfirm={() => cancel(application.id)}
okText='Yes'
cancelText='No'
>
<Button
type='dashed'
style={{ marginLeft: 5 }}
danger
>
Cancel
</Button>
</Popconfirm>
)}
{['finished', 'pending', 'error', 'cancel'].includes(application.status) && (
<Popconfirm
title={`Are you sure delete application ${application.name}?`}
onConfirm={() => destroy(application.id)}
okText='Yes'
cancelText='No'
>
<Button
type='primary'
className='delete-button'
style={{ marginLeft: 5, color: 'white', backgroundColor: '#f5222d!important' }}
danger
>
Delete
</Button>
</Popconfirm>
)}
</div>
)
}
}
]
useEffect(() => {
if (!fetching) {
dispatch({
type: 'application/LIST',
payload: { offset: (pagination.current - 1) * pagination.pageSize, limit: pagination.pageSize }
})
setFetching(true)
}
}, [list, total])
useEffect(() => {
if (total > 0 && total !== pagination.total) {
setPagination({ ...pagination, total })
}
}, [total])
const onTableChange = (pagination, filters, sorter, extra) => {
setPagination(pagination)
dispatch({
type: 'application/LIST',
payload: { offset: (pagination.current - 1) * pagination.pageSize, limit: pagination.pageSize, pagination, filters, sorter }
})
}
const onSearch = (keyword) => {
dispatch({
type: 'application/LIST',
payload: { offset: 0, limit: pagination.pageSize, keyword }
})
}
const clone = (data) => {
dispatch({
type: 'application/CLONE',
payload: { data }
})
}
const cancel = (id) => {
dispatch({
type: 'application/CANCEL',
payload: { id }
})
}
const destroy = (id) => {
dispatch({
type: 'application/DELETE',
payload: { id }
})
}
return (
<>
<div className='application'>
<Helmet title='Applications' />
<div className='card'>
<div className='card-header row'>
<div className='col-md-6'>
<div className='cui__utils__heading mb-0'>
<h2>Benchmark Application</h2>
</div>
<div className='text-muted'>A distributed benchmark tool with Golang</div>
</div>
<div className='col-md-6'>
<div className='text-right'>
<Tooltip title='Refresh'>
<Button
icon={<RetweetOutlined />}
style={{ marginRight: 5 }}
onClick={onSearch}
/>
</Tooltip>
<Button type='primary' onClick={() => history.push('/applications/create')}>Create Application</Button>
</div>
</div>
</div>
<div className='card-body'>
<div className='application-header'>
<div className='search-bar row'>
<div className='col-md-6 col-xs-12' />
<div className='col-md-6 col-xs-12'>
<Search
placeholder='input application name or tags'
enterButton='Search'
onSearch={value => onSearch(value)}
/>
</div>
</div>
</div>
<Table
dataSource={list}
pagination={pagination}
loading={loading}
columns={columns}
onChange={onTableChange}
ellipsis
/>
</div>
</div>
</div>
</>
)
}
Example #4
Source File: Swap.jsx From nft-e2e-example with MIT License | 4 votes |
function Swap({ selectedProvider, tokenListURI }) {
const [tokenIn, setTokenIn] = useState(defaultToken);
const [tokenOut, setTokenOut] = useState(defaultTokenOut);
const [exact, setExact] = useState();
const [amountIn, setAmountIn] = useState();
const [amountInMax, setAmountInMax] = useState();
const [amountOut, setAmountOut] = useState();
const [amountOutMin, setAmountOutMin] = useState();
const [trades, setTrades] = useState();
const [routerAllowance, setRouterAllowance] = useState();
const [balanceIn, setBalanceIn] = useState();
const [balanceOut, setBalanceOut] = useState();
const [slippageTolerance, setSlippageTolerance] = useState(
new Percent(Math.round(defaultSlippage * 100).toString(), "10000"),
);
const [timeLimit, setTimeLimit] = useState(defaultTimeLimit);
const [swapping, setSwapping] = useState(false);
const [approving, setApproving] = useState(false);
const [settingsVisible, setSettingsVisible] = useState(false);
const [swapModalVisible, setSwapModalVisible] = useState(false);
const [tokenList, setTokenList] = useState([]);
const [tokens, setTokens] = useState();
const [invertPrice, setInvertPrice] = useState(false);
const blockNumber = useBlockNumber(selectedProvider, 3000);
const signer = selectedProvider.getSigner();
const routerContract = new ethers.Contract(ROUTER_ADDRESS, IUniswapV2Router02ABI, signer);
const _tokenListUri = tokenListURI || "https://gateway.ipfs.io/ipns/tokens.uniswap.org";
const debouncedAmountIn = useDebounce(amountIn, 500);
const debouncedAmountOut = useDebounce(amountOut, 500);
const activeChainId = process.env.REACT_APP_NETWORK === "kovan" ? ChainId.KOVAN : ChainId.MAINNET;
useEffect(() => {
const getTokenList = async () => {
console.log(_tokenListUri);
try {
const tokenList = await fetch(_tokenListUri);
const tokenListJson = await tokenList.json();
const filteredTokens = tokenListJson.tokens.filter(function (t) {
return t.chainId === activeChainId;
});
const ethToken = WETH[activeChainId];
ethToken.name = "Ethereum";
ethToken.symbol = "ETH";
ethToken.logoURI =
"https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/ethereum/assets/0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2/logo.png";
const _tokenList = [ethToken, ...filteredTokens];
setTokenList(_tokenList);
const _tokens = tokenListToObject(_tokenList);
setTokens(_tokens);
} catch (e) {
console.log(e);
}
};
getTokenList();
}, [tokenListURI]);
const getTrades = async () => {
if (tokenIn && tokenOut && (amountIn || amountOut)) {
const pairs = arr => arr.map((v, i) => arr.slice(i + 1).map(w => [v, w])).flat();
const baseTokens = tokenList
.filter(function (t) {
return ["DAI", "USDC", "USDT", "COMP", "ETH", "MKR", "LINK", tokenIn, tokenOut].includes(t.symbol);
})
.map(el => {
return new Token(el.chainId, el.address, el.decimals, el.symbol, el.name);
});
const listOfPairwiseTokens = pairs(baseTokens);
const getPairs = async list => {
const listOfPromises = list.map(item => Fetcher.fetchPairData(item[0], item[1], selectedProvider));
return Promise.all(listOfPromises.map(p => p.catch(() => undefined)));
};
const listOfPairs = await getPairs(listOfPairwiseTokens);
let bestTrade;
if (exact === "in") {
setAmountInMax();
bestTrade = Trade.bestTradeExactIn(
listOfPairs.filter(item => item),
new TokenAmount(tokens[tokenIn], parseUnits(amountIn.toString(), tokens[tokenIn].decimals)),
tokens[tokenOut],
{ maxNumResults: 3, maxHops: 1 },
);
if (bestTrade[0]) {
setAmountOut(bestTrade[0].outputAmount.toSignificant(6));
} else {
setAmountOut();
}
} else if (exact === "out") {
setAmountOutMin();
bestTrade = Trade.bestTradeExactOut(
listOfPairs.filter(item => item),
tokens[tokenIn],
new TokenAmount(tokens[tokenOut], parseUnits(amountOut.toString(), tokens[tokenOut].decimals)),
{ maxNumResults: 3, maxHops: 1 },
);
if (bestTrade[0]) {
setAmountIn(bestTrade[0].inputAmount.toSignificant(6));
} else {
setAmountIn();
}
}
setTrades(bestTrade);
console.log(bestTrade);
}
};
useEffect(() => {
getTrades();
}, [tokenIn, tokenOut, debouncedAmountIn, debouncedAmountOut, slippageTolerance, selectedProvider]);
useEffect(() => {
if (trades && trades[0]) {
if (exact === "in") {
setAmountOutMin(trades[0].minimumAmountOut(slippageTolerance));
} else if (exact === "out") {
setAmountInMax(trades[0].maximumAmountIn(slippageTolerance));
}
}
}, [slippageTolerance, amountIn, amountOut, trades]);
const getBalance = async (_token, _account, _contract) => {
let newBalance;
if (_token === "ETH") {
newBalance = await selectedProvider.getBalance(_account);
} else {
newBalance = await makeCall("balanceOf", _contract, [_account]);
}
return newBalance;
};
const getAccountInfo = async () => {
if (tokens) {
const accountList = await selectedProvider.listAccounts();
if (tokenIn) {
const tempContractIn = new ethers.Contract(tokens[tokenIn].address, erc20Abi, selectedProvider);
const newBalanceIn = await getBalance(tokenIn, accountList[0], tempContractIn);
setBalanceIn(newBalanceIn);
let allowance;
if (tokenIn === "ETH") {
setRouterAllowance();
} else {
allowance = await makeCall("allowance", tempContractIn, [accountList[0], ROUTER_ADDRESS]);
setRouterAllowance(allowance);
}
}
if (tokenOut) {
const tempContractOut = new ethers.Contract(tokens[tokenOut].address, erc20Abi, selectedProvider);
const newBalanceOut = await getBalance(tokenOut, accountList[0], tempContractOut);
setBalanceOut(newBalanceOut);
}
}
};
usePoller(getAccountInfo, 6000);
const route = trades
? trades.length > 0
? trades[0].route.path.map(function (item) {
return item.symbol;
})
: []
: [];
const updateRouterAllowance = async newAllowance => {
setApproving(true);
try {
const tempContract = new ethers.Contract(tokens[tokenIn].address, erc20Abi, signer);
const result = await makeCall("approve", tempContract, [ROUTER_ADDRESS, newAllowance]);
console.log(result);
setApproving(false);
return true;
} catch (e) {
notification.open({
message: "Approval unsuccessful",
description: `Error: ${e.message}`,
});
}
};
const approveRouter = async () => {
const approvalAmount =
exact === "in"
? ethers.utils.hexlify(parseUnits(amountIn.toString(), tokens[tokenIn].decimals))
: amountInMax.raw.toString();
console.log(approvalAmount);
const approval = updateRouterAllowance(approvalAmount);
if (approval) {
notification.open({
message: "Token transfer approved",
description: `You can now swap up to ${amountIn} ${tokenIn}`,
});
}
};
const removeRouterAllowance = async () => {
const approvalAmount = ethers.utils.hexlify(0);
console.log(approvalAmount);
const removal = updateRouterAllowance(approvalAmount);
if (removal) {
notification.open({
message: "Token approval removed",
description: `The router is no longer approved for ${tokenIn}`,
});
}
};
const executeSwap = async () => {
setSwapping(true);
try {
let args;
const metadata = {};
let call;
const deadline = Math.floor(Date.now() / 1000) + timeLimit;
const path = trades[0].route.path.map(function (item) {
return item.address;
});
console.log(path);
const accountList = await selectedProvider.listAccounts();
const address = accountList[0];
if (exact === "in") {
const _amountIn = ethers.utils.hexlify(parseUnits(amountIn.toString(), tokens[tokenIn].decimals));
const _amountOutMin = ethers.utils.hexlify(ethers.BigNumber.from(amountOutMin.raw.toString()));
if (tokenIn === "ETH") {
call = "swapExactETHForTokens";
args = [_amountOutMin, path, address, deadline];
metadata.value = _amountIn;
} else {
call = tokenOut === "ETH" ? "swapExactTokensForETH" : "swapExactTokensForTokens";
args = [_amountIn, _amountOutMin, path, address, deadline];
}
} else if (exact === "out") {
const _amountOut = ethers.utils.hexlify(parseUnits(amountOut.toString(), tokens[tokenOut].decimals));
const _amountInMax = ethers.utils.hexlify(ethers.BigNumber.from(amountInMax.raw.toString()));
if (tokenIn === "ETH") {
call = "swapETHForExactTokens";
args = [_amountOut, path, address, deadline];
metadata.value = _amountInMax;
} else {
call = tokenOut === "ETH" ? "swapTokensForExactETH" : "swapTokensForExactTokens";
args = [_amountOut, _amountInMax, path, address, deadline];
}
}
console.log(call, args, metadata);
const result = await makeCall(call, routerContract, args, metadata);
console.log(result);
notification.open({
message: "Swap complete ?",
description: (
<>
<Text>{`Swapped ${tokenIn} for ${tokenOut}, transaction: `}</Text>
<Text copyable>{result.hash}</Text>
</>
),
});
setSwapping(false);
} catch (e) {
console.log(e);
setSwapping(false);
notification.open({
message: "Swap unsuccessful",
description: `Error: ${e.message}`,
});
}
};
const showSwapModal = () => {
setSwapModalVisible(true);
};
const handleSwapModalOk = () => {
setSwapModalVisible(false);
executeSwap();
};
const handleSwapModalCancel = () => {
setSwapModalVisible(false);
};
const insufficientBalance = balanceIn
? parseFloat(formatUnits(balanceIn, tokens[tokenIn].decimals)) < amountIn
: null;
const inputIsToken = tokenIn !== "ETH";
const insufficientAllowance = !inputIsToken
? false
: routerAllowance
? parseFloat(formatUnits(routerAllowance, tokens[tokenIn].decimals)) < amountIn
: null;
const formattedBalanceIn = balanceIn
? parseFloat(formatUnits(balanceIn, tokens[tokenIn].decimals)).toPrecision(6)
: null;
const formattedBalanceOut = balanceOut
? parseFloat(formatUnits(balanceOut, tokens[tokenOut].decimals)).toPrecision(6)
: null;
const metaIn =
tokens && tokenList && tokenIn
? tokenList.filter(function (t) {
return t.address === tokens[tokenIn].address;
})[0]
: null;
const metaOut =
tokens && tokenList && tokenOut
? tokenList.filter(function (t) {
return t.address === tokens[tokenOut].address;
})[0]
: null;
const cleanIpfsURI = uri => {
try {
return uri.replace("ipfs://", "https://ipfs.io/ipfs/");
} catch (e) {
console.log(e, uri);
return uri;
}
};
const logoIn = metaIn ? cleanIpfsURI(metaIn.logoURI) : null;
const logoOut = metaOut ? cleanIpfsURI(metaOut.logoURI) : null;
const rawPrice = trades && trades[0] ? trades[0].executionPrice : null;
const price = rawPrice ? rawPrice.toSignificant(7) : null;
const priceDescription = rawPrice
? invertPrice
? `${rawPrice.invert().toSignificant(7)} ${tokenIn} per ${tokenOut}`
: `${price} ${tokenOut} per ${tokenIn}`
: null;
const priceWidget = (
<Space>
<Text type="secondary">{priceDescription}</Text>
<Button
type="text"
onClick={() => {
setInvertPrice(!invertPrice);
}}
>
<RetweetOutlined />
</Button>
</Space>
);
const swapModal = (
<Modal title="Confirm swap" visible={swapModalVisible} onOk={handleSwapModalOk} onCancel={handleSwapModalCancel}>
<Row>
<Space>
<img src={logoIn} alt={tokenIn} width="30" />
{amountIn}
{tokenIn}
</Space>
</Row>
<Row justify="center" align="middle" style={{ width: 30 }}>
<span>↓</span>
</Row>
<Row>
<Space>
<img src={logoOut} alt={tokenOut} width="30" />
{amountOut}
{tokenOut}
</Space>
</Row>
<Divider />
<Row>{priceWidget}</Row>
<Row>
{trades && ((amountOutMin && exact === "in") || (amountInMax && exact === "out"))
? exact === "in"
? `Output is estimated. You will receive at least ${amountOutMin.toSignificant(
6,
)} ${tokenOut} or the transaction will revert.`
: `Input is estimated. You will sell at most ${amountInMax.toSignificant(
6,
)} ${tokenIn} or the transaction will revert.`
: null}
</Row>
</Modal>
);
return (
<Card
title={
<Space>
<img src="https://ipfs.io/ipfs/QmXttGpZrECX5qCyXbBQiqgQNytVGeZW5Anewvh2jc4psg" width="40" alt="uniswapLogo" />
<Typography>Uniswapper</Typography>
</Space>
}
extra={
<Button
type="text"
onClick={() => {
setSettingsVisible(true);
}}
>
<SettingOutlined />
</Button>
}
>
<Space direction="vertical">
<Row justify="center" align="middle">
<Card
size="small"
type="inner"
title={`From${exact === "out" && tokenIn && tokenOut ? " (estimate)" : ""}`}
extra={
<>
<img src={logoIn} alt={tokenIn} width="30" />
<Button
type="link"
onClick={() => {
setAmountOut();
setAmountIn(formatUnits(balanceIn, tokens[tokenIn].decimals));
setAmountOutMin();
setAmountInMax();
setExact("in");
}}
>
{formattedBalanceIn}
</Button>
</>
}
style={{ width: 400, textAlign: "left" }}
>
<InputNumber
style={{ width: "160px" }}
min={0}
size="large"
value={amountIn}
onChange={e => {
setAmountOut();
setTrades();
setAmountIn(e);
setExact("in");
}}
/>
<Select
showSearch
value={tokenIn}
style={{ width: "120px" }}
size="large"
bordered={false}
defaultValue={defaultToken}
onChange={value => {
console.log(value);
if (value === tokenOut) {
console.log("switch!", tokenIn);
setTokenOut(tokenIn);
setAmountOut(amountIn);
setBalanceOut(balanceIn);
}
setTokenIn(value);
setTrades();
setAmountIn();
setExact("out");
setBalanceIn();
}}
filterOption={(input, option) => option.children.toLowerCase().indexOf(input.toLowerCase()) >= 0}
optionFilterProp="children"
>
{tokenList.map(token => (
<Option key={token.symbol} value={token.symbol}>
{token.symbol}
</Option>
))}
</Select>
</Card>
</Row>
<Row justify="center" align="middle">
<Tooltip title={route.join("->")}>
<span>↓</span>
</Tooltip>
</Row>
<Row justify="center" align="middle">
<Card
size="small"
type="inner"
title={`To${exact === "in" && tokenIn && tokenOut ? " (estimate)" : ""}`}
extra={
<>
<img src={logoOut} width="30" alt={tokenOut} />
<Button type="text">{formattedBalanceOut}</Button>
</>
}
style={{ width: 400, textAlign: "left" }}
>
<InputNumber
style={{ width: "160px" }}
size="large"
min={0}
value={amountOut}
onChange={e => {
setAmountOut(e);
setAmountIn();
setTrades();
setExact("out");
}}
/>
<Select
showSearch
value={tokenOut}
style={{ width: "120px" }}
size="large"
bordered={false}
onChange={value => {
console.log(value, tokenIn, tokenOut);
if (value === tokenIn) {
console.log("switch!", tokenOut);
setTokenIn(tokenOut);
setAmountIn(amountOut);
setBalanceIn(balanceOut);
}
setTokenOut(value);
setExact("in");
setAmountOut();
setTrades();
setBalanceOut();
}}
filterOption={(input, option) => option.children.toLowerCase().indexOf(input.toLowerCase()) >= 0}
optionFilterProp="children"
>
{tokenList.map(token => (
<Option key={token.symbol} value={token.symbol}>
{token.symbol}
</Option>
))}
</Select>
</Card>
</Row>
<Row justify="center" align="middle">
{priceDescription ? priceWidget : null}
</Row>
<Row justify="center" align="middle">
<Space>
{inputIsToken ? (
<Button size="large" loading={approving} disabled={!insufficientAllowance} onClick={approveRouter}>
{!insufficientAllowance && amountIn && amountOut ? "Approved" : "Approve"}
</Button>
) : null}
<Button
size="large"
loading={swapping}
disabled={insufficientAllowance || insufficientBalance || !amountIn || !amountOut}
onClick={showSwapModal}
>
{insufficientBalance ? "Insufficient balance" : "Swap!"}
</Button>
{swapModal}
</Space>
</Row>
</Space>
<Drawer
visible={settingsVisible}
onClose={() => {
setSettingsVisible(false);
}}
width={500}
>
<Descriptions title="Details" column={1} style={{ textAlign: "left" }}>
<Descriptions.Item label="blockNumber">{blockNumber}</Descriptions.Item>
<Descriptions.Item label="routerAllowance">
<Space>
{routerAllowance ? formatUnits(routerAllowance, tokens[tokenIn].decimals) : null}
{routerAllowance > 0 ? <Button onClick={removeRouterAllowance}>Remove Allowance</Button> : null}
</Space>
</Descriptions.Item>
<Descriptions.Item label="route">{route.join("->")}</Descriptions.Item>
<Descriptions.Item label="exact">{exact}</Descriptions.Item>
<Descriptions.Item label="bestPrice">
{trades ? (trades.length > 0 ? trades[0].executionPrice.toSignificant(6) : null) : null}
</Descriptions.Item>
<Descriptions.Item label="nextMidPrice">
{trades ? (trades.length > 0 ? trades[0].nextMidPrice.toSignificant(6) : null) : null}
</Descriptions.Item>
<Descriptions.Item label="priceImpact">
{trades ? (trades.length > 0 ? trades[0].priceImpact.toSignificant(6) : null) : null}
</Descriptions.Item>
<Descriptions.Item label="slippageTolerance">
<InputNumber
defaultValue={defaultSlippage}
min={0}
max={100}
precision={2}
formatter={value => `${value}%`}
parser={value => value.replace("%", "")}
onChange={value => {
console.log(value);
const slippagePercent = new Percent(Math.round(value * 100).toString(), "10000");
setSlippageTolerance(slippagePercent);
}}
/>
</Descriptions.Item>
<Descriptions.Item label="amountInMax">{amountInMax ? amountInMax.toExact() : null}</Descriptions.Item>
<Descriptions.Item label="amountOutMin">{amountOutMin ? amountOutMin.toExact() : null}</Descriptions.Item>
<Descriptions.Item label="timeLimitInSeconds">
<InputNumber
min={0}
max={3600}
defaultValue={defaultTimeLimit}
onChange={value => {
console.log(value);
setTimeLimit(value);
}}
/>
</Descriptions.Item>
</Descriptions>
</Drawer>
</Card>
);
}