diff --git a/dapp-oeth/abis/CurveRegistryExchange.json b/dapp-oeth/abis/CurveRegistryExchange.json index 53ac79560a..b7ce9a4c66 100644 --- a/dapp-oeth/abis/CurveRegistryExchange.json +++ b/dapp-oeth/abis/CurveRegistryExchange.json @@ -6,41 +6,27 @@ { "name": "TokenExchange", "inputs": [ - { - "name": "buyer", - "type": "address", - "indexed": true - }, - { - "name": "receiver", - "type": "address", - "indexed": true - }, - { - "name": "pool", - "type": "address", - "indexed": true - }, - { - "name": "token_sold", - "type": "address", - "indexed": false - }, - { - "name": "token_bought", - "type": "address", - "indexed": false - }, - { - "name": "amount_sold", - "type": "uint256", - "indexed": false - }, - { - "name": "amount_bought", - "type": "uint256", - "indexed": false - } + { "name": "buyer", "type": "address", "indexed": true }, + { "name": "receiver", "type": "address", "indexed": true }, + { "name": "pool", "type": "address", "indexed": true }, + { "name": "token_sold", "type": "address", "indexed": false }, + { "name": "token_bought", "type": "address", "indexed": false }, + { "name": "amount_sold", "type": "uint256", "indexed": false }, + { "name": "amount_bought", "type": "uint256", "indexed": false } + ], + "anonymous": false, + "type": "event" + }, + { + "name": "ExchangeMultiple", + "inputs": [ + { "name": "buyer", "type": "address", "indexed": true }, + { "name": "receiver", "type": "address", "indexed": true }, + { "name": "route", "type": "address[9]", "indexed": false }, + { "name": "swap_params", "type": "uint256[3][4]", "indexed": false }, + { "name": "pools", "type": "address[4]", "indexed": false }, + { "name": "amount_sold", "type": "uint256", "indexed": false }, + { "name": "amount_bought", "type": "uint256", "indexed": false } ], "anonymous": false, "type": "event" @@ -49,180 +35,116 @@ "stateMutability": "nonpayable", "type": "constructor", "inputs": [ - { - "name": "_address_provider", - "type": "address" - }, - { - "name": "_calculator", - "type": "address" - } + { "name": "_address_provider", "type": "address" }, + { "name": "_calculator", "type": "address" }, + { "name": "_weth", "type": "address" } ], "outputs": [] }, + { "stateMutability": "payable", "type": "fallback" }, { "stateMutability": "payable", - "type": "fallback" + "type": "function", + "name": "exchange_with_best_rate", + "inputs": [ + { "name": "_from", "type": "address" }, + { "name": "_to", "type": "address" }, + { "name": "_amount", "type": "uint256" }, + { "name": "_expected", "type": "uint256" } + ], + "outputs": [{ "name": "", "type": "uint256" }] }, { "stateMutability": "payable", "type": "function", "name": "exchange_with_best_rate", "inputs": [ - { - "name": "_from", - "type": "address" - }, - { - "name": "_to", - "type": "address" - }, - { - "name": "_amount", - "type": "uint256" - }, - { - "name": "_expected", - "type": "uint256" - } + { "name": "_from", "type": "address" }, + { "name": "_to", "type": "address" }, + { "name": "_amount", "type": "uint256" }, + { "name": "_expected", "type": "uint256" }, + { "name": "_receiver", "type": "address" } ], - "outputs": [ - { - "name": "", - "type": "uint256" - } - ] + "outputs": [{ "name": "", "type": "uint256" }] }, { "stateMutability": "payable", "type": "function", - "name": "exchange_with_best_rate", + "name": "exchange", "inputs": [ - { - "name": "_from", - "type": "address" - }, - { - "name": "_to", - "type": "address" - }, - { - "name": "_amount", - "type": "uint256" - }, - { - "name": "_expected", - "type": "uint256" - }, - { - "name": "_receiver", - "type": "address" - } + { "name": "_pool", "type": "address" }, + { "name": "_from", "type": "address" }, + { "name": "_to", "type": "address" }, + { "name": "_amount", "type": "uint256" }, + { "name": "_expected", "type": "uint256" } ], - "outputs": [ - { - "name": "", - "type": "uint256" - } - ] + "outputs": [{ "name": "", "type": "uint256" }] }, { "stateMutability": "payable", "type": "function", "name": "exchange", "inputs": [ - { - "name": "_pool", - "type": "address" - }, - { - "name": "_from", - "type": "address" - }, - { - "name": "_to", - "type": "address" - }, - { - "name": "_amount", - "type": "uint256" - }, - { - "name": "_expected", - "type": "uint256" - } + { "name": "_pool", "type": "address" }, + { "name": "_from", "type": "address" }, + { "name": "_to", "type": "address" }, + { "name": "_amount", "type": "uint256" }, + { "name": "_expected", "type": "uint256" }, + { "name": "_receiver", "type": "address" } ], - "outputs": [ - { - "name": "", - "type": "uint256" - } - ] + "outputs": [{ "name": "", "type": "uint256" }] }, { "stateMutability": "payable", "type": "function", - "name": "exchange", + "name": "exchange_multiple", "inputs": [ - { - "name": "_pool", - "type": "address" - }, - { - "name": "_from", - "type": "address" - }, - { - "name": "_to", - "type": "address" - }, - { - "name": "_amount", - "type": "uint256" - }, - { - "name": "_expected", - "type": "uint256" - }, - { - "name": "_receiver", - "type": "address" - } + { "name": "_route", "type": "address[9]" }, + { "name": "_swap_params", "type": "uint256[3][4]" }, + { "name": "_amount", "type": "uint256" }, + { "name": "_expected", "type": "uint256" } ], - "outputs": [ - { - "name": "", - "type": "uint256" - } - ] + "outputs": [{ "name": "", "type": "uint256" }] + }, + { + "stateMutability": "payable", + "type": "function", + "name": "exchange_multiple", + "inputs": [ + { "name": "_route", "type": "address[9]" }, + { "name": "_swap_params", "type": "uint256[3][4]" }, + { "name": "_amount", "type": "uint256" }, + { "name": "_expected", "type": "uint256" }, + { "name": "_pools", "type": "address[4]" } + ], + "outputs": [{ "name": "", "type": "uint256" }] + }, + { + "stateMutability": "payable", + "type": "function", + "name": "exchange_multiple", + "inputs": [ + { "name": "_route", "type": "address[9]" }, + { "name": "_swap_params", "type": "uint256[3][4]" }, + { "name": "_amount", "type": "uint256" }, + { "name": "_expected", "type": "uint256" }, + { "name": "_pools", "type": "address[4]" }, + { "name": "_receiver", "type": "address" } + ], + "outputs": [{ "name": "", "type": "uint256" }] }, { "stateMutability": "view", "type": "function", "name": "get_best_rate", "inputs": [ - { - "name": "_from", - "type": "address" - }, - { - "name": "_to", - "type": "address" - }, - { - "name": "_amount", - "type": "uint256" - } + { "name": "_from", "type": "address" }, + { "name": "_to", "type": "address" }, + { "name": "_amount", "type": "uint256" } ], "outputs": [ - { - "name": "", - "type": "address" - }, - { - "name": "", - "type": "uint256" - } + { "name": "", "type": "address" }, + { "name": "", "type": "uint256" } ] }, { @@ -230,32 +152,14 @@ "type": "function", "name": "get_best_rate", "inputs": [ - { - "name": "_from", - "type": "address" - }, - { - "name": "_to", - "type": "address" - }, - { - "name": "_amount", - "type": "uint256" - }, - { - "name": "_exclude_pools", - "type": "address[8]" - } + { "name": "_from", "type": "address" }, + { "name": "_to", "type": "address" }, + { "name": "_amount", "type": "uint256" }, + { "name": "_exclude_pools", "type": "address[8]" } ], "outputs": [ - { - "name": "", - "type": "address" - }, - { - "name": "", - "type": "uint256" - } + { "name": "", "type": "address" }, + { "name": "", "type": "uint256" } ] }, { @@ -263,238 +167,141 @@ "type": "function", "name": "get_exchange_amount", "inputs": [ - { - "name": "_pool", - "type": "address" - }, - { - "name": "_from", - "type": "address" - }, - { - "name": "_to", - "type": "address" - }, - { - "name": "_amount", - "type": "uint256" - } + { "name": "_pool", "type": "address" }, + { "name": "_from", "type": "address" }, + { "name": "_to", "type": "address" }, + { "name": "_amount", "type": "uint256" } ], - "outputs": [ - { - "name": "", - "type": "uint256" - } - ] + "outputs": [{ "name": "", "type": "uint256" }] }, { "stateMutability": "view", "type": "function", "name": "get_input_amount", "inputs": [ - { - "name": "_pool", - "type": "address" - }, - { - "name": "_from", - "type": "address" - }, - { - "name": "_to", - "type": "address" - }, - { - "name": "_amount", - "type": "uint256" - } + { "name": "_pool", "type": "address" }, + { "name": "_from", "type": "address" }, + { "name": "_to", "type": "address" }, + { "name": "_amount", "type": "uint256" } ], - "outputs": [ - { - "name": "", - "type": "uint256" - } - ] + "outputs": [{ "name": "", "type": "uint256" }] }, { "stateMutability": "view", "type": "function", "name": "get_exchange_amounts", "inputs": [ - { - "name": "_pool", - "type": "address" - }, - { - "name": "_from", - "type": "address" - }, - { - "name": "_to", - "type": "address" - }, - { - "name": "_amounts", - "type": "uint256[100]" - } + { "name": "_pool", "type": "address" }, + { "name": "_from", "type": "address" }, + { "name": "_to", "type": "address" }, + { "name": "_amounts", "type": "uint256[100]" } ], - "outputs": [ - { - "name": "", - "type": "uint256[100]" - } - ] + "outputs": [{ "name": "", "type": "uint256[100]" }] }, { "stateMutability": "view", "type": "function", - "name": "get_calculator", + "name": "get_exchange_multiple_amount", "inputs": [ - { - "name": "_pool", - "type": "address" - } + { "name": "_route", "type": "address[9]" }, + { "name": "_swap_params", "type": "uint256[3][4]" }, + { "name": "_amount", "type": "uint256" } ], - "outputs": [ - { - "name": "", - "type": "address" - } - ] + "outputs": [{ "name": "", "type": "uint256" }] + }, + { + "stateMutability": "view", + "type": "function", + "name": "get_exchange_multiple_amount", + "inputs": [ + { "name": "_route", "type": "address[9]" }, + { "name": "_swap_params", "type": "uint256[3][4]" }, + { "name": "_amount", "type": "uint256" }, + { "name": "_pools", "type": "address[4]" } + ], + "outputs": [{ "name": "", "type": "uint256" }] + }, + { + "stateMutability": "view", + "type": "function", + "name": "get_calculator", + "inputs": [{ "name": "_pool", "type": "address" }], + "outputs": [{ "name": "", "type": "address" }] }, { "stateMutability": "nonpayable", "type": "function", "name": "update_registry_address", "inputs": [], - "outputs": [ - { - "name": "", - "type": "bool" - } - ] + "outputs": [{ "name": "", "type": "bool" }] }, { "stateMutability": "nonpayable", "type": "function", "name": "set_calculator", "inputs": [ - { - "name": "_pool", - "type": "address" - }, - { - "name": "_calculator", - "type": "address" - } + { "name": "_pool", "type": "address" }, + { "name": "_calculator", "type": "address" } ], - "outputs": [ - { - "name": "", - "type": "bool" - } - ] + "outputs": [{ "name": "", "type": "bool" }] }, { "stateMutability": "nonpayable", "type": "function", "name": "set_default_calculator", - "inputs": [ - { - "name": "_calculator", - "type": "address" - } - ], - "outputs": [ - { - "name": "", - "type": "bool" - } - ] + "inputs": [{ "name": "_calculator", "type": "address" }], + "outputs": [{ "name": "", "type": "bool" }] }, { "stateMutability": "nonpayable", "type": "function", "name": "claim_balance", - "inputs": [ - { - "name": "_token", - "type": "address" - } - ], - "outputs": [ - { - "name": "", - "type": "bool" - } - ] + "inputs": [{ "name": "_token", "type": "address" }], + "outputs": [{ "name": "", "type": "bool" }] }, { "stateMutability": "nonpayable", "type": "function", "name": "set_killed", - "inputs": [ - { - "name": "_is_killed", - "type": "bool" - } - ], - "outputs": [ - { - "name": "", - "type": "bool" - } - ] + "inputs": [{ "name": "_is_killed", "type": "bool" }], + "outputs": [{ "name": "", "type": "bool" }] }, { "stateMutability": "view", "type": "function", "name": "registry", "inputs": [], - "outputs": [ - { - "name": "", - "type": "address" - } - ] + "outputs": [{ "name": "", "type": "address" }] }, { "stateMutability": "view", "type": "function", "name": "factory_registry", "inputs": [], - "outputs": [ - { - "name": "", - "type": "address" - } - ] + "outputs": [{ "name": "", "type": "address" }] + }, + { + "stateMutability": "view", + "type": "function", + "name": "crypto_registry", + "inputs": [], + "outputs": [{ "name": "", "type": "address" }] }, { "stateMutability": "view", "type": "function", "name": "default_calculator", "inputs": [], - "outputs": [ - { - "name": "", - "type": "address" - } - ] + "outputs": [{ "name": "", "type": "address" }] }, { "stateMutability": "view", "type": "function", "name": "is_killed", "inputs": [], - "outputs": [ - { - "name": "", - "type": "bool" - } - ] + "outputs": [{ "name": "", "type": "bool" }] } ], "linkReferences": {}, "deployedLinkReferences": {} -} \ No newline at end of file +} diff --git a/dapp-oeth/next.config.js b/dapp-oeth/next.config.js index 43f4b08352..7d5b47affb 100644 --- a/dapp-oeth/next.config.js +++ b/dapp-oeth/next.config.js @@ -59,7 +59,7 @@ const config = { if (!isServer) { config.resolve.alias['@sentry/node'] = '@sentry/browser' - } + } return config }, @@ -71,22 +71,22 @@ const config = { { source: '/swap', destination: '/', - permanent: true + permanent: true, }, { source: '/dapp', destination: '/', - permanent: true + permanent: true, }, { source: '/mint', destination: '/', - permanent: true + permanent: true, }, { source: '/stake', destination: '/earn', - permanent: true + permanent: true, }, ] }, @@ -112,7 +112,7 @@ const config = { }, { key: 'Content-Security-Policy', - value: "frame-ancestors https://*.ledger.com", + value: 'frame-ancestors https://*.ledger.com', }, ], }, diff --git a/dapp-oeth/pages/_app.js b/dapp-oeth/pages/_app.js index 36ece05e2f..753707716d 100644 --- a/dapp-oeth/pages/_app.js +++ b/dapp-oeth/pages/_app.js @@ -43,11 +43,11 @@ function App({ Component, pageProps, err }) { ).split('?')[0] useEffect(() => { - router.events.on("routeChangeComplete", pageview); + router.events.on('routeChangeComplete', pageview) return () => { - router.events.off("routeChangeComplete", pageview); - }; - }, [router.events]); + router.events.off('routeChangeComplete', pageview) + } + }, [router.events]) useEffect(() => { // Update account info when connection already established diff --git a/dapp-oeth/src/components/GetOUSD.js b/dapp-oeth/src/components/GetOUSD.js index f8db112422..eb98f9ba7b 100644 --- a/dapp-oeth/src/components/GetOUSD.js +++ b/dapp-oeth/src/components/GetOUSD.js @@ -59,7 +59,7 @@ const GetOUSD = ({ style={style} onClick={() => { if (process.browser) { - event({'event': 'connect_click'}) + event({ event: 'connect_click' }) if (ledgerLive) { activate(ledgerLiveConnector, undefined, true) } else { diff --git a/dapp-oeth/src/components/IPFSDappLink.js b/dapp-oeth/src/components/IPFSDappLink.js index 2456f0b0ad..e0f31084f7 100644 --- a/dapp-oeth/src/components/IPFSDappLink.js +++ b/dapp-oeth/src/components/IPFSDappLink.js @@ -5,13 +5,11 @@ export default function IPFSDappLink({ css }) { const [displayIpfsLink, setDisplayIpfsLink] = useState(false) useEffect(() => { - setDisplayIpfsLink( - process.env.DEPLOY_MODE !== 'ipfs' - ) + setDisplayIpfsLink(process.env.DEPLOY_MODE !== 'ipfs') }, []) if (!displayIpfsLink) { - return null; + return null } return ( diff --git a/dapp-oeth/src/components/Nav.js b/dapp-oeth/src/components/Nav.js index af41394c37..50a485395c 100644 --- a/dapp-oeth/src/components/Nav.js +++ b/dapp-oeth/src/components/Nav.js @@ -152,7 +152,7 @@ const TransactionActivityDropdown = () => { animationHash.current = setTimeout(() => { setTxHashesToAnimate([]) animationHash.current = null - }, 8000) + }, 13000) } const sortedTx = [...transactions] diff --git a/dapp-oeth/src/components/WalletSelectContent.js b/dapp-oeth/src/components/WalletSelectContent.js index f00a5401e1..b59a9dbef5 100644 --- a/dapp-oeth/src/components/WalletSelectContent.js +++ b/dapp-oeth/src/components/WalletSelectContent.js @@ -39,8 +39,8 @@ const WalletSelectContent = ({ isMobile }) => { if (active) { closeWalletSelectModal() event({ - 'event': 'connect', - 'connect_address': account?.slice(2) + event: 'connect', + connect_address: account?.slice(2), }) } }, [active]) @@ -70,8 +70,8 @@ const WalletSelectContent = ({ isMobile }) => { const onConnect = async (name) => { event({ - 'event': 'connect_modal_click', - 'connect_modal_wallet': name.toLowerCase() + event: 'connect_modal_click', + connect_modal_wallet: name.toLowerCase(), }) setError(null) diff --git a/dapp-oeth/src/components/buySell/ApproveSwap.js b/dapp-oeth/src/components/buySell/ApproveSwap.js index 3ec8aa9e7f..db134b2012 100644 --- a/dapp-oeth/src/components/buySell/ApproveSwap.js +++ b/dapp-oeth/src/components/buySell/ApproveSwap.js @@ -12,7 +12,7 @@ import { walletLogin } from 'utils/account' import { event } from '../../../lib/gtm' const ApproveSwap = ({ - stableCoinToApprove, + coinToApprove, needsApproval, selectedSwap, inputAmount, @@ -36,12 +36,10 @@ const ApproveSwap = ({ const [isApproving, setIsApproving] = useState({}) const web3react = useWeb3React() const { library, account, activate, active } = web3react - const coinApproved = stableCoinToApprove === 'eth' || stage === 'done' + const coinApproved = coinToApprove === 'eth' || stage === 'done' const isWrapped = - selectedSwap && - selectedSwap.name === 'woeth' && - stableCoinToApprove === 'oeth' + selectedSwap && selectedSwap.name === 'woeth' && coinToApprove === 'oeth' const approvalNeeded = (selectedSwap && @@ -59,15 +57,8 @@ const ApproveSwap = ({ const { vault, - uniV3SwapRouter, - uniV2Router, - sushiRouter, - curveOUSDMetaPool, curveOETHPool, - usdt, - dai, - usdc, - ousd, + curveRegistryExchange, weth, reth, steth, @@ -78,6 +69,8 @@ const ApproveSwap = ({ zapper, } = useStoreState(ContractStore, (s) => s.contracts || {}) + const curveRegistryCoins = ['steth', 'weth', 'reth', 'frxeth'] + const routeConfig = { vault: { contract: vault, @@ -93,39 +86,25 @@ const ApproveSwap = ({ done: 'Zap + Vault', }, }, - // uniswap: { - // contract: uniV3SwapRouter, - // name: { - // approving: 'Uniswap', - // done: 'Uniswap', - // }, - // }, curve: { - contract: curveOETHPool, + contract: + // Use router address for LSDs, and if OETH is going to LSD via curve + curveRegistryCoins.includes(coinToApprove) || + (coinToApprove === 'oeth' && + curveRegistryCoins.includes(selectedSwap?.coinToSwap) && + selectedSwap.name === 'curve') + ? curveRegistryExchange + : curveOETHPool, name: { approving: 'Curve', done: 'Curve', }, }, - // uniswapV2: { - // contract: uniV2Router, - // name: { - // approving: 'Uniswap', - // done: 'Uniswap', - // }, - // }, - // sushiswap: { - // contract: sushiRouter, - // name: { - // approving: 'Sushi Swap', - // done: 'Sushi Swap', - // }, - // }, woeth: { contract: woeth, name: { - approving: 'wOETH', - done: 'wOETH', + approving: 'wOETH contract', + done: 'wOETH contract', }, }, } @@ -134,26 +113,26 @@ const ApproveSwap = ({ if (selectedSwap) { if ( isApproving.contract === selectedSwap.name && - isApproving.coin === stableCoinToApprove + isApproving.coin === coinToApprove ) { setStage('waiting-network') return } } setStage('approve') - }, [selectedSwap]) + }, [JSON.stringify(selectedSwap), JSON.stringify(isApproving)]) useEffect(() => { const coinToContract = { weth, reth, steth, sfrxeth, oeth, frxeth, woeth } - if (Object.keys(coinToContract).includes(stableCoinToApprove)) { - setContract(coinToContract[stableCoinToApprove]) + if (Object.keys(coinToContract).includes(coinToApprove)) { + setContract(coinToContract[coinToApprove]) } - }, [stableCoinToApprove, reth, weth, steth, oeth, frxeth, woeth]) + }, [coinToApprove, reth, weth, steth, oeth, frxeth, woeth]) const ApprovalMessage = ({ stage, selectedSwap, - stableCoinToApprove, + coinToApprove, isMobile, }) => { if (stage === 'waiting-user') { @@ -182,7 +161,7 @@ const ApproveSwap = ({ const route = `${ routeConfig[selectedSwap.name].name.approving - } to use your ${stableCoinToApprove.toUpperCase()}` + } to use your ${coinToApprove.toUpperCase()}` const routeMobile = `${routeConfig[selectedSwap.name].name.approving}` return ( @@ -199,16 +178,14 @@ const ApproveSwap = ({ const SwapMessage = ({ balanceError, - stableCoinToApprove, + coinToApprove, swapsLoaded, selectedSwap, swappingGloballyDisabled, active, }) => { const coin = - stableCoinToApprove === 'woeth' - ? 'wOETH' - : stableCoinToApprove.toUpperCase() + coinToApprove === 'woeth' ? 'wOETH' : coinToApprove.toUpperCase() const noSwapRouteAvailable = swapsLoaded && !selectedSwap if (swappingGloballyDisabled) { return process.env.NEXT_PUBLIC_DISABLE_SWAP_BUTTON_MESSAGE @@ -223,7 +200,7 @@ const ApproveSwap = ({ return fbt('Insufficient liquidity', 'Insufficient liquidity') } else if (isWrapped) { return fbt('Wrap', 'Wrap') - } else if (stableCoinToApprove === 'woeth') { + } else if (coinToApprove === 'woeth') { return fbt('Unwrap', 'Unwrap') } else { return fbt('Swap', 'Swap') @@ -235,7 +212,7 @@ const ApproveSwap = ({ event({ event: 'approve_started', approval_type: isWrapped ? 'wrap' : 'swap', - approval_token: stableCoinToApprove, + approval_token: coinToApprove, }) setStage('waiting-user') try { @@ -248,18 +225,18 @@ const ApproveSwap = ({ storeTransaction( result, isWrapped ? 'approveWrap' : 'approve', - stableCoinToApprove + coinToApprove ) setStage('waiting-network') setIsApproving({ contract: needsApproval, - coin: stableCoinToApprove, + coin: coinToApprove, }) await rpcProvider.waitForTransaction(result.hash) event({ event: 'approve_complete', approval_type: isWrapped ? 'wrap' : 'swap', - approval_token: stableCoinToApprove, + approval_token: coinToApprove, approval_address: '', approval_tx: '', }) @@ -270,11 +247,11 @@ const ApproveSwap = ({ console.error('Exception happened: ', e) setStage('approve') if (e.code !== 4001) { - await storeTransactionError('approve', stableCoinToApprove) + await storeTransactionError('approve', coinToApprove) event({ event: 'approve_failed', approval_type: isWrapped ? 'wrap' : 'swap', - approval_token: stableCoinToApprove, + approval_token: coinToApprove, approval_address: '', approval_tx: '', }) @@ -282,7 +259,7 @@ const ApproveSwap = ({ event({ event: 'approve_rejected', approval_type: isWrapped ? 'wrap' : 'swap', - approval_token: stableCoinToApprove, + approval_token: coinToApprove, }) } } @@ -341,7 +318,7 @@ const ApproveSwap = ({ )} @@ -370,7 +347,7 @@ const ApproveSwap = ({ > { const coinsToRender = - coin === 'mix' ? ['weth', 'reth', 'steth', 'frxeth'] : coin.split(',') + coin === 'mix' ? ['weth', 'retFh', 'steth', 'frxeth'] : coin.split(',') const size = 24 return ( <> diff --git a/dapp-oeth/src/components/wrap/WrapHomepage.js b/dapp-oeth/src/components/wrap/WrapHomepage.js index a66df43ea4..e93f5aa253 100644 --- a/dapp-oeth/src/components/wrap/WrapHomepage.js +++ b/dapp-oeth/src/components/wrap/WrapHomepage.js @@ -309,7 +309,7 @@ const WrapHomepage = ({ LP token "exchange" (actually `add_liquidity`), + 12-14 for LP token -> wrapped coin (underlying for lending or fake pool) "exchange" (actually `remove_liquidity_one_coin`) + 15 for WETH -> ETH "exchange" (actually deposit/withdraw) + @param _amount The amount of `_route[0]` token to be sent. + @param _pools Array of pools for swaps via zap contracts. This parameter is only needed for + Polygon meta-factories underlying swaps. + @return Expected amount of the final output token +``` +*/ + +const curveRoutes = { + // stETH -> OETH Mint + '0xae7ab96520DE3A18E5e111B5EaAb095312D7fE84': { + '0x856c4Efb76C1D1AE02e20CEB03A2A6a08b0b8dC3': { + routes: [ + '0xae7ab96520DE3A18E5e111B5EaAb095312D7fE84', + '0x21E27a5E5513D6e65C4f830167390997aA84843a', + '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE', + '0x94B17476A93b3262d87B9a326965D1E91f9c13E7', + '0x856c4Efb76C1D1AE02e20CEB03A2A6a08b0b8dC3', + '0x0000000000000000000000000000000000000000', + '0x0000000000000000000000000000000000000000', + '0x0000000000000000000000000000000000000000', + '0x0000000000000000000000000000000000000000', + ], + swapParams: [ + // 1 for a stableswap `exchange`, + [BigNumber.from(1), BigNumber.from(0), BigNumber.from(1)], + // 1 for a stableswap `exchange`, + [BigNumber.from(0), BigNumber.from(1), BigNumber.from(1)], + [BigNumber.from(0), BigNumber.from(0), BigNumber.from(0)], + [BigNumber.from(0), BigNumber.from(0), BigNumber.from(0)], + ], + }, + }, + // WETH -> OETH Mint + '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2': { + '0x856c4Efb76C1D1AE02e20CEB03A2A6a08b0b8dC3': { + routes: [ + '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', + '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', + '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE', + '0x94B17476A93b3262d87B9a326965D1E91f9c13E7', + '0x856c4Efb76C1D1AE02e20CEB03A2A6a08b0b8dC3', + '0x0000000000000000000000000000000000000000', + '0x0000000000000000000000000000000000000000', + '0x0000000000000000000000000000000000000000', + '0x0000000000000000000000000000000000000000', + ], + swapParams: [ + // 15 for WETH -> ETH "exchange" (actually deposit/withdraw) + [BigNumber.from(0), BigNumber.from(0), BigNumber.from(15)], + // 1 for a stableswap `exchange`, + [BigNumber.from(0), BigNumber.from(1), BigNumber.from(1)], + [BigNumber.from(0), BigNumber.from(0), BigNumber.from(0)], + [BigNumber.from(0), BigNumber.from(0), BigNumber.from(0)], + ], + }, + }, + // rETH -> OETH Mint + '0xae78736Cd615f374D3085123A210448E74Fc6393': { + '0x856c4Efb76C1D1AE02e20CEB03A2A6a08b0b8dC3': { + routes: [ + '0xae78736Cd615f374D3085123A210448E74Fc6393', + '0x0f3159811670c117c372428D4E69AC32325e4D0F', + '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE', + '0x94B17476A93b3262d87B9a326965D1E91f9c13E7', + '0x856c4Efb76C1D1AE02e20CEB03A2A6a08b0b8dC3', + '0x0000000000000000000000000000000000000000', + '0x0000000000000000000000000000000000000000', + '0x0000000000000000000000000000000000000000', + '0x0000000000000000000000000000000000000000', + ], + swapParams: [ + // 3 for a cryptoswap `exchange`, + [BigNumber.from(1), BigNumber.from(0), BigNumber.from(3)], + // 1 for a stableswap `exchange`, + [BigNumber.from(0), BigNumber.from(1), BigNumber.from(1)], + [BigNumber.from(0), BigNumber.from(0), BigNumber.from(0)], + [BigNumber.from(0), BigNumber.from(0), BigNumber.from(0)], + ], + }, + }, + // frxETH -> OETH Mint + '0x5e8422345238f34275888049021821e8e08caa1f': { + '0x856c4Efb76C1D1AE02e20CEB03A2A6a08b0b8dC3': { + routes: [ + '0x5E8422345238F34275888049021821E8E08CAa1f', + '0xa1F8A6807c402E4A15ef4EBa36528A3FED24E577', + '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE', + '0x94B17476A93b3262d87B9a326965D1E91f9c13E7', + '0x856c4Efb76C1D1AE02e20CEB03A2A6a08b0b8dC3', + '0x0000000000000000000000000000000000000000', + '0x0000000000000000000000000000000000000000', + '0x0000000000000000000000000000000000000000', + '0x0000000000000000000000000000000000000000', + ], + swapParams: [ + // 1 for a stableswap `exchange`, + [BigNumber.from(1), BigNumber.from(0), BigNumber.from(1)], + // 1 for a stableswap `exchange`, + [BigNumber.from(0), BigNumber.from(1), BigNumber.from(1)], + [BigNumber.from(0), BigNumber.from(0), BigNumber.from(0)], + [BigNumber.from(0), BigNumber.from(0), BigNumber.from(0)], + ], + }, + }, + // OETH Redeem + '0x856c4Efb76C1D1AE02e20CEB03A2A6a08b0b8dC3': { + // OETH -> frxETH + '0x5e8422345238f34275888049021821e8e08caa1f': { + routes: [ + '0x856c4Efb76C1D1AE02e20CEB03A2A6a08b0b8dC3', + '0x94B17476A93b3262d87B9a326965D1E91f9c13E7', + '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE', + '0xa1F8A6807c402E4A15ef4EBa36528A3FED24E577', + '0x5E8422345238F34275888049021821E8E08CAa1f', + '0x0000000000000000000000000000000000000000', + '0x0000000000000000000000000000000000000000', + '0x0000000000000000000000000000000000000000', + '0x0000000000000000000000000000000000000000', + ], + swapParams: [ + // 1 for a stableswap `exchange`, + [BigNumber.from(1), BigNumber.from(0), BigNumber.from(1)], + // 1 for a stableswap `exchange`, + [BigNumber.from(0), BigNumber.from(1), BigNumber.from(1)], + [BigNumber.from(0), BigNumber.from(0), BigNumber.from(0)], + [BigNumber.from(0), BigNumber.from(0), BigNumber.from(0)], + ], + }, + // OETH -> WETH + '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2': { + routes: [ + '0x856c4Efb76C1D1AE02e20CEB03A2A6a08b0b8dC3', + '0x94B17476A93b3262d87B9a326965D1E91f9c13E7', + '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE', + '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', + '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', + '0x0000000000000000000000000000000000000000', + '0x0000000000000000000000000000000000000000', + '0x0000000000000000000000000000000000000000', + '0x0000000000000000000000000000000000000000', + ], + swapParams: [ + // 1 for a stableswap `exchange`, + [BigNumber.from(1), BigNumber.from(0), BigNumber.from(1)], + // 15 for WETH -> ETH "exchange" (actually deposit/withdraw) + [BigNumber.from(0), BigNumber.from(0), BigNumber.from(15)], + [BigNumber.from(0), BigNumber.from(0), BigNumber.from(0)], + [BigNumber.from(0), BigNumber.from(0), BigNumber.from(0)], + ], + }, + // OETH -> rETH + '0xae78736Cd615f374D3085123A210448E74Fc6393': { + routes: [ + '0x856c4Efb76C1D1AE02e20CEB03A2A6a08b0b8dC3', + '0x94B17476A93b3262d87B9a326965D1E91f9c13E7', + '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE', + '0x0f3159811670c117c372428D4E69AC32325e4D0F', + '0xae78736Cd615f374D3085123A210448E74Fc6393', + '0x0000000000000000000000000000000000000000', + '0x0000000000000000000000000000000000000000', + '0x0000000000000000000000000000000000000000', + '0x0000000000000000000000000000000000000000', + ], + swapParams: [ + // 1 for a stableswap `exchange`, + [BigNumber.from(1), BigNumber.from(0), BigNumber.from(1)], + // 3 for a cryptoswap `exchange`, + [BigNumber.from(0), BigNumber.from(1), BigNumber.from(3)], + [BigNumber.from(0), BigNumber.from(0), BigNumber.from(0)], + [BigNumber.from(0), BigNumber.from(0), BigNumber.from(0)], + ], + }, + // OETH -> stETH + '0xae7ab96520DE3A18E5e111B5EaAb095312D7fE84': { + routes: [ + '0x856c4Efb76C1D1AE02e20CEB03A2A6a08b0b8dC3', + '0x94B17476A93b3262d87B9a326965D1E91f9c13E7', + '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE', + '0x21E27a5E5513D6e65C4f830167390997aA84843a', + '0xae7ab96520DE3A18E5e111B5EaAb095312D7fE84', + '0x0000000000000000000000000000000000000000', + '0x0000000000000000000000000000000000000000', + '0x0000000000000000000000000000000000000000', + '0x0000000000000000000000000000000000000000', + ], + swapParams: [ + // 1 for a stableswap `exchange`, + [BigNumber.from(1), BigNumber.from(0), BigNumber.from(1)], + // 1 for a stableswap `exchange`, + [BigNumber.from(0), BigNumber.from(1), BigNumber.from(1)], + [BigNumber.from(0), BigNumber.from(0), BigNumber.from(0)], + [BigNumber.from(0), BigNumber.from(0), BigNumber.from(0)], + ], + }, + }, +} + +module.exports = curveRoutes diff --git a/dapp-oeth/src/hooks/useCurrencySwapper.js b/dapp-oeth/src/hooks/useCurrencySwapper.js index 8700fd4fd4..5b95b41825 100644 --- a/dapp-oeth/src/hooks/useCurrencySwapper.js +++ b/dapp-oeth/src/hooks/useCurrencySwapper.js @@ -1,7 +1,6 @@ import React, { useEffect, useState } from 'react' import { ethers, BigNumber } from 'ethers' import { useStoreState } from 'pullstate' - import ContractStore from 'stores/ContractStore' import AccountStore from 'stores/AccountStore' import { @@ -15,8 +14,8 @@ import { NullAddress, } from 'utils/constants' import { useWeb3React } from '@web3-react/core' -import { find } from 'lodash' import addresses from 'constants/contractAddresses' +import curveRoutes from 'constants/curveRoutes' import { calculateSwapAmounts } from 'utils/math' @@ -124,11 +123,28 @@ const useCurrencySwapper = ({ ) } + const curveRegistryCoins = ['steth', 'weth', 'reth', 'frxeth'] + + let allowanceCheckKey = nameMaps[selectedSwap.name] + + if (selectedSwap.name === 'curve') { + allowanceCheckKey = + (swapMode === 'mint' && + selectedCoin === 'oeth' && + curveRegistryCoins.includes(coinNeedingApproval)) || + (swapMode === 'redeem' && + coinNeedingApproval === 'oeth' && + curveRegistryCoins.includes(selectedCoin)) + ? 'curve_registry' + : 'curve' + } + + const allowance = parseFloat( + allowances[coinNeedingApproval][allowanceCheckKey] + ) + setNeedsApproval( - Object.keys(allowances).length > 0 && - parseFloat( - allowances[coinNeedingApproval][nameMaps[selectedSwap.name]] - ) < amount + Object.keys(allowances).length > 0 && allowance < amount ? selectedSwap.name : false ) @@ -338,45 +354,76 @@ const useCurrencySwapper = ({ } const _swapCurve = async (swapAmount, minSwapAmount, isGasEstimate) => { - const nullAddress = NullAddress?.toLowerCase() - const fromAddress = coinContract?.address?.toLowerCase() || nullAddress - const toAddress = - coinToReceiveContract?.address?.toLowerCase() || nullAddress - - const swapParams = [ - curveUnderlyingCoins.indexOf(fromAddress), - curveUnderlyingCoins.indexOf(toAddress), - swapAmount, - minSwapAmount, - ] + // Handle stETH, rETH, WETH, frxETH + if (coinContract?.address && coinToReceiveContract?.address) { + const { routes, swapParams } = + curveRoutes[coinContract?.address]?.[coinToReceiveContract?.address] - const overrides = - fromAddress === nullAddress - ? { - value: swapAmount, - } - : {} + if (!routes) { + throw new Error('No curve route found for contract address pair') + } - const estimatedGasLimit = await curveOETHPool.estimateGas.exchange( - ...swapParams, - { + const estimatedGasLimit = await curveRegistryExchange.estimateGas[ + 'exchange_multiple(address[9],uint256[3][4],uint256,uint256)' + ](routes, swapParams, swapAmount, minSwapAmount, { from: account, - ...overrides, - } - ) + }) - const gasLimit = increaseGasLimitByBuffer( - estimatedGasLimit, - curveGasLimitBuffer - ) + const gasLimit = increaseGasLimitByBuffer( + estimatedGasLimit, + curveGasLimitBuffer + ) - if (isGasEstimate) { - return gasLimit + if (isGasEstimate) { + return gasLimit + } else { + return await connSigner(curveRegistryExchange)[ + 'exchange_multiple(address[9],uint256[3][4],uint256,uint256)' + ](routes, swapParams, swapAmount, minSwapAmount, { + gasLimit, + }) + } } else { - return await connSigner(curveOETHPool).exchange(...swapParams, { - gasLimit, - ...overrides, - }) + const nullAddress = NullAddress?.toLowerCase() + const fromAddress = coinContract?.address?.toLowerCase() || nullAddress + const toAddress = + coinToReceiveContract?.address?.toLowerCase() || nullAddress + + const swapParams = [ + curveUnderlyingCoins.indexOf(fromAddress), + curveUnderlyingCoins.indexOf(toAddress), + swapAmount, + minSwapAmount, + ] + + const overrides = + fromAddress === nullAddress + ? { + value: swapAmount, + } + : {} + + const estimatedGasLimit = await curveOETHPool.estimateGas.exchange( + ...swapParams, + { + from: account, + ...overrides, + } + ) + + const gasLimit = increaseGasLimitByBuffer( + estimatedGasLimit, + curveGasLimitBuffer + ) + + if (isGasEstimate) { + return gasLimit + } else { + return await connSigner(curveOETHPool).exchange(...swapParams, { + gasLimit, + ...overrides, + }) + } } } @@ -399,16 +446,33 @@ const useCurrencySwapper = ({ } const quoteCurve = async (swapAmount) => { - return curveRegistryExchange.get_exchange_amount( - addresses.mainnet.CurveOETHPool, - // For Eth support - coinContract?.address || NullAddress, - coinToReceiveContract?.address || NullAddress, - swapAmount, - { - gasLimit: 1000000, + // Not a ETH/OETH swap + if (coinContract?.address && coinToReceiveContract?.address) { + const { routes, swapParams } = + curveRoutes[coinContract?.address]?.[coinToReceiveContract?.address] + + if (!routes) { + throw new Error('No curve route found for contract address pair') } - ) + + return curveRegistryExchange[ + 'get_exchange_multiple_amount(address[9],uint256[3][4],uint256)' + ](routes, swapParams, swapAmount, { + gasLimit: 1000000, + }) + } else { + // ETH + return curveRegistryExchange['get_exchange_amount']( + addresses.mainnet.CurveOETHPool, + // For Eth support + coinContract?.address || NullAddress, + coinToReceiveContract?.address || NullAddress, + swapAmount, + { + gasLimit: 1000000, + } + ) + } } const _swapUniswap = async (swapAmount, minSwapAmount, isGasEstimate) => { diff --git a/dapp-oeth/src/hooks/useSwapEstimator.js b/dapp-oeth/src/hooks/useSwapEstimator.js index f10b44bb9b..dee14b15dc 100644 --- a/dapp-oeth/src/hooks/useSwapEstimator.js +++ b/dapp-oeth/src/hooks/useSwapEstimator.js @@ -79,17 +79,10 @@ const useSwapEstimator = ({ const account = useStoreState(AccountStore, (s) => s.account) const [estimationCallback, setEstimationCallback] = useState(null) + const { mintVaultGasEstimate, - swapUniswapGasEstimate, swapCurveGasEstimate, - swapUniswapV2GasEstimate, - swapUniswapV2, - swapCurve, - quoteUniswap, - quoteUniswapV2, - quoteSushiSwap, - swapSushiswapGasEstimate, quoteCurve, redeemVaultGasEstimate, } = useCurrencySwapper({ @@ -208,9 +201,6 @@ const useSwapEstimator = ({ ? estimateMintSuitabilityVault() : estimateRedeemSuitabilityVault(), estimateSwapSuitabilityZapper(), - // estimateSwapSuitabilityUniswapV3(), - // estimateSwapSuitabilityUniswapV2(), - // estimateSwapSuitabilitySushiSwap(), estimateSwapSuitabilityCurve(), fetchEthPrice(), ]) @@ -408,10 +398,11 @@ const useSwapEstimator = ({ */ const estimateSwapSuitabilityCurve = async () => { const isRedeem = swapMode === 'redeem' + const curveRegistryCoins = ['steth', 'reth', 'weth', 'frxeth'] if ( (isRedeem && selectedCoin === 'mix') || - !['eth', 'oeth'].includes(selectedCoin) + !['eth', 'oeth', ...curveRegistryCoins].includes(selectedCoin) ) { return { canDoSwap: false, @@ -453,15 +444,28 @@ const useSwapEstimator = ({ } } - const approveAllowanceNeeded = allowancesLoaded - ? parseFloat(allowances[coinToSwap].curve) < parseFloat(inputAmountRaw) - : true - /* Check if Curve router has allowance to spend coin. If not we can not run gas estimation and need * to guess the gas usage. * * We don't check if positive amount is large enough: since we always approve max_int allowance. */ + + const allowanceCheckKey = + (swapMode === 'mint' && + selectedCoin === 'oeth' && + curveRegistryCoins.includes(coinToSwap)) || + (swapMode === 'redeem' && + coinToSwap === 'oeth' && + curveRegistryCoins.includes(selectedCoin)) + ? 'curve_registry' + : 'curve' + + // ETH / OETH mint flow + const approveAllowanceNeeded = allowancesLoaded + ? parseFloat(allowances[coinToSwap]?.[allowanceCheckKey]) < + parseFloat(inputAmountRaw) + : true + const hasEnoughBalance = userHasEnoughStablecoin( coinToSwap, parseFloat(inputAmountRaw) @@ -472,6 +476,7 @@ const useSwapEstimator = ({ const approveGasUsage = approveAllowanceNeeded ? gasLimitForApprovingCoin(coinToSwap) : 0 + return { canDoSwap: true, /* This estimate is from the few ones observed on the mainnet: @@ -479,7 +484,6 @@ const useSwapEstimator = ({ * https://etherscan.io/tx/0xbf033ffbaf01b808953ca1904d3b0110b50337d60d89c96cd06f3f9a6972d3ca * https://etherscan.io/tx/0x77d98d0307b53e81f50b39132e038a1c6ef87a599a381675ce44038515a04738 * https://etherscan.io/tx/0xbce1a2f1e76d4b4f900b3952f34f5f53f8be4a65ccff348661d19b9a3827aa04 - * */ gasUsed: swapGasUsage + approveGasUsage, swapGasUsage, @@ -522,274 +526,6 @@ const useSwapEstimator = ({ } } - const estimateSwapSuitabilityUniswapV2 = async () => { - return _estimateSwapSuitabilityUniswapV2Variant(false) - } - - const estimateSwapSuitabilitySushiSwap = async () => { - return _estimateSwapSuitabilityUniswapV2Variant(true) - } - - // Gives information on suitability of uniswapV2 / SushiSwap for this swap - const _estimateSwapSuitabilityUniswapV2Variant = async ( - isSushiSwap = false - ) => { - const isRedeem = swapMode === 'redeem' - if (isRedeem && selectedCoin === 'mix') { - return { - canDoSwap: false, - error: 'unsupported', - } - } - - try { - const priceQuoteValues = isSushiSwap - ? await quoteSushiSwap(swapAmount) - : await quoteUniswapV2(swapAmount) - const priceQuoteBn = priceQuoteValues[priceQuoteValues.length - 1] - - // 18 because ousd has 18 decimals - const amountReceived = ethers.utils.formatUnits( - priceQuoteBn, - isRedeem ? coinToReceiveDecimals : 18 - ) - - if ( - ethers.utils.formatUnits(swapAmount, decimals) / amountReceived > - max_price - ) { - return { - canDoSwap: false, - error: 'price_too_high', - } - } - - /* Check if Uniswap router has allowance to spend coin. If not we can not run gas estimation and need - * to guess the gas usage. - * - * We don't check if positive amount is large enough: since we always approve max_int allowance. - */ - const requiredAllowance = allowancesLoaded - ? allowances[coinToSwap][ - isSushiSwap ? 'sushiRouter' : 'uniswapV2Router' - ] - : 0 - - if (requiredAllowance === undefined) { - throw new Error('Can not find correct allowance for coin') - } - - const approveAllowanceNeeded = parseFloat(requiredAllowance) === 0 - - const hasEnoughBalance = userHasEnoughStablecoin( - coinToSwap, - parseFloat(inputAmountRaw) - ) - - if (approveAllowanceNeeded || !hasEnoughBalance) { - const swapGasUsage = selectedCoin === 'usdt' ? 175000 : 230000 - const approveGasUsage = approveAllowanceNeeded - ? gasLimitForApprovingCoin(coinToSwap) - : 0 - return { - canDoSwap: true, - /* Some example Uniswap transactions. When 2 swaps are done: - * - https://etherscan.io/tx/0x436ef157435c93241257fb0b347db7cc1b2c4f73d749c7e5c1181393f3d0aa26 - * - https://etherscan.io/tx/0x504799fecb64a0452f5635245ca313aa5612132dc6fe66c441b61fd98a0e0766 - * - https://etherscan.io/tx/0x2e3429fb9f04819a55f85cfdbbaf78dfbb049bff85be84a324650d77ff98dfc3 - * - * And Uniswap when 1 swap: - * - https://etherscan.io/tx/0x6ceca6c6c2a829928bbf9cf97a018b431def8e475577fcc7cc97ed6bd35f9f7b - * - https://etherscan.io/tx/0x02c1fffb94b06d54e0c6d47da460cb6e5e736e43f928b7e9b2dcd964b1390188 - * - https://etherscan.io/tx/0xe5a35025ec3fe71ece49a4311319bdc16302b7cc16b3e7a95f0d8e45baa922c7 - * - * Some example Sushiswap transactions. When 2 swaps are done: - * - https://etherscan.io/tx/0x8e66d8d682b8028fd44c916d4318fee7e69704e9f8e386dd7debbfe3157375c5 - * - https://etherscan.io/tx/0xbb837c5f001a0d71c75db49ddc22bd75b7800e426252ef1f1135e8e543769bea - * - https://etherscan.io/tx/0xe00ab2125b55fd398b00e361e2fd22f6fc9225e609fb2bb2b712586523c89824 - * - https://etherscan.io/tx/0x5c26312ac2bab17aa8895592faa8dc8607f15912de953546136391ee2e955e92 - * - * And Sushiswap when 1 swap: - * - https://etherscan.io/tx/0xa8a0c5d2433bcb6ddbfdfb1db7c55c674714690e353f305e4f3c72878ab6a3a7 - * - https://etherscan.io/tx/0x8d2a273d0451ab48c554f8a97d333f7f62b40804946cbd546dc57e2c009514f0 - * - * Both contracts have very similar gas usage (since they share a lot of the code base) - */ - gasUsed: swapGasUsage + approveGasUsage, - swapGasUsage, - approveGasUsage, - approveAllowanceNeeded, - inputAmount: parseFloat(inputAmountRaw), - amountReceived, - hasEnoughBalance, - } - } - - const { - swapAmount: swapAmountQuoted, - minSwapAmount: minSwapAmountQuoted, - } = calculateSwapAmounts( - amountReceived, - coinToReceiveDecimals, - priceToleranceValue - ) - - let gasEstimate - - if (isSushiSwap) { - gasEstimate = await swapSushiswapGasEstimate( - swapAmount, - minSwapAmountQuoted - ) - } else { - gasEstimate = await swapUniswapV2GasEstimate( - swapAmount, - minSwapAmountQuoted - ) - } - - return { - canDoSwap: true, - gasUsed: gasEstimate, - inputAmount: parseFloat(inputAmountRaw), - amountReceived, - } - } catch (e) { - console.error( - `Unexpected error estimating ${ - isSushiSwap ? 'sushiSwap' : 'uniswap v2' - } swap suitability: ${e?.message}` - ) - - if ( - (e.data && - e.data.message && - e.data.message.includes('INSUFFICIENT_OUTPUT_AMOUNT')) || - e.message.includes('INSUFFICIENT_OUTPUT_AMOUNT') - ) { - return { - canDoSwap: false, - error: 'price_too_high', - } - } - - return { - canDoSwap: false, - error: 'unexpected_error', - } - } - } - - /* Gives information on suitability of uniswap for this swap - */ - const estimateSwapSuitabilityUniswapV3 = async () => { - const isRedeem = swapMode === 'redeem' - if (isRedeem && selectedCoin === 'mix') { - return { - canDoSwap: false, - error: 'unsupported', - } - } - - try { - const priceQuote = await quoteUniswap(swapAmount) - const priceQuoteBn = BigNumber.from(priceQuote) - // 18 because ousd has 18 decimals - const amountReceived = ethers.utils.formatUnits( - priceQuoteBn, - isRedeem ? coinToReceiveDecimals : 18 - ) - - if ( - ethers.utils.formatUnits(swapAmount, decimals) / amountReceived > - max_price - ) { - return { - canDoSwap: false, - error: 'price_too_high', - } - } - - /* Check if Uniswap router has allowance to spend coin. If not we can not run gas estimation and need - * to guess the gas usage. - * - * We don't check if positive amount is large enough: since we always approve max_int allowance. - */ - - if ( - !allowancesLoaded || - parseFloat(allowances[coinToSwap].uniswapV3Router) === 0 || - !userHasEnoughStablecoin(coinToSwap, parseFloat(inputAmountRaw)) - ) { - const approveAllowanceNeeded = allowancesLoaded - ? parseFloat(allowances[coinToSwap].uniswapV3Router) === 0 - : true - const approveGasUsage = approveAllowanceNeeded - ? gasLimitForApprovingCoin(coinToSwap) - : 0 - const swapGasUsage = 165000 - return { - canDoSwap: true, - /* This estimate is over the maximum one appearing on mainnet: https://etherscan.io/tx/0x6b1163b012570819e2951fa95a8287ce16be96b8bf18baefb6e738d448188ed5 - * Swap gas costs are usually between 142k - 162k - * - * Other transactions here: https://etherscan.io/tokentxns?a=0x129360c964e2e13910d603043f6287e5e9383374&p=6 - */ - // TODO: if usdc / dai are selected it will cost more gas - gasUsed: swapGasUsage + approveGasUsage, - approveAllowanceNeeded, - swapGasUsage, - approveGasUsage, - inputAmount: parseFloat(inputAmountRaw), - amountReceived, - } - } - - const { - swapAmount: swapAmountQuoted, - minSwapAmount: minSwapAmountQuoted, - } = calculateSwapAmounts( - amountReceived, - coinToReceiveDecimals, - priceToleranceValue - ) - - const gasEstimate = await swapUniswapGasEstimate( - swapAmount, - minSwapAmountQuoted - ) - - return { - canDoSwap: true, - gasUsed: gasEstimate, - inputAmount: parseFloat(inputAmountRaw), - amountReceived, - } - } catch (e) { - console.error( - `Unexpected error estimating uniswap v3 swap suitability: ${e.message}` - ) - - // local node and mainnet return errors in different formats, this handles both cases - if ( - (e.data && - e.data.message && - e.data.message.includes('Too little received')) || - e.message.includes('Too little received') - ) { - return { - canDoSwap: false, - error: 'price_too_high', - } - } - - return { - canDoSwap: false, - error: 'unexpected_error', - } - } - } - /* Gives information on suitability of vault mint */ const estimateMintSuitabilityVault = async () => { @@ -1116,7 +852,6 @@ const useSwapEstimator = ({ estimateSwapSuitabilityZapper, estimateMintSuitabilityVault, estimateRedeemSuitabilityVault, - estimateSwapSuitabilityUniswapV3, estimateSwapSuitabilityCurve, } } diff --git a/dapp-oeth/src/services/allowances.service.js b/dapp-oeth/src/services/allowances.service.js index 7b3c9da032..a51cfdba62 100644 --- a/dapp-oeth/src/services/allowances.service.js +++ b/dapp-oeth/src/services/allowances.service.js @@ -14,6 +14,7 @@ export default class AllowancesService { oeth, woeth, curveOETHPool, + curveRegistryExchange, } = contracts const [ @@ -40,13 +41,45 @@ export default class AllowancesService { ]) let oethAllowanceCurvePool + let oethRegistryAllowanceCurvePool + let stethAllowanceCurvePool + let wethAllowanceCurvePool + let rethAllowanceCurvePool + let frxethAllowanceCurvePool if (curveOETHPool) { - ;[oethAllowanceCurvePool] = await Promise.all([ + ;[ + oethAllowanceCurvePool, + oethRegistryAllowanceCurvePool, + stethAllowanceCurvePool, + wethAllowanceCurvePool, + rethAllowanceCurvePool, + frxethAllowanceCurvePool, + ] = await Promise.all([ displayCurrency( await oeth.allowance(account, curveOETHPool.address), oeth ), + displayCurrency( + await oeth.allowance(account, curveRegistryExchange.address), + oeth + ), + displayCurrency( + await steth.allowance(account, curveRegistryExchange.address), + steth + ), + displayCurrency( + await weth.allowance(account, curveRegistryExchange.address), + weth + ), + displayCurrency( + await reth.allowance(account, curveRegistryExchange.address), + reth + ), + displayCurrency( + await frxeth.allowance(account, curveRegistryExchange.address), + frxeth + ), ]) } @@ -59,16 +92,20 @@ export default class AllowancesService { oeth: { vault: oethAllowanceVault, curve: oethAllowanceCurvePool, + curve_registry: oethRegistryAllowanceCurvePool, woeth: woethAllowance, }, weth: { vault: wethAllowanceVault, + curve: wethAllowanceCurvePool, }, reth: { vault: rethAllowanceVault, + curve: rethAllowanceCurvePool, }, frxeth: { vault: frxethAllowanceVault, + curve: frxethAllowanceCurvePool, }, sfrxeth: { vault: sfrxethAllowanceVault, @@ -76,6 +113,7 @@ export default class AllowancesService { }, steth: { vault: stethAllowanceVault, + curve: stethAllowanceCurvePool, }, } } diff --git a/dapp-oeth/src/utils/connectors.js b/dapp-oeth/src/utils/connectors.js index 713a9121ee..1efd8bfffb 100644 --- a/dapp-oeth/src/utils/connectors.js +++ b/dapp-oeth/src/utils/connectors.js @@ -71,7 +71,7 @@ export const defiWalletConnector = process.browser : {} export const ledgerLiveConnector = new LedgerHQFrameConnector({ - targetOrigin: "https://dapp-browser.apps.ledger.com", + targetOrigin: 'https://dapp-browser.apps.ledger.com', timeoutMilliseconds: 10000, }) diff --git a/dapp-oeth/src/utils/contracts.js b/dapp-oeth/src/utils/contracts.js index e8610b31be..6c363aca4c 100644 --- a/dapp-oeth/src/utils/contracts.js +++ b/dapp-oeth/src/utils/contracts.js @@ -17,6 +17,7 @@ import ognAbi from 'constants/mainnetAbi/ogn.json' import ogvAbi from 'constants/mainnetAbi/ogv.json' import veogvAbi from 'constants/mainnetAbi/veogv.json' import sfrxethAbi from 'constants/mainnetAbi/sfrxeth.json' +import registryExchangeJson from '../../abis/CurveRegistryExchange.json' const curveFactoryMiniAbi = [ { @@ -570,6 +571,11 @@ const setupCurve = async (curveAddressProvider, getContract, chainId) => { const registryExchangeAddress = await curveAddressProvider.get_address(2) const registryExchangeJson = require('../../abis/CurveRegistryExchange.json') + const curveRegistryExchange = getContract( + registryExchangeAddress, + registryExchangeJson.abi + ) + const factoryAddress = await curveAddressProvider.get_address(3) const factory = getContract(factoryAddress, curveFactoryMiniAbi) @@ -582,11 +588,7 @@ const setupCurve = async (curveAddressProvider, getContract, chainId) => { curvePoolMiniAbi ) - return [ - getContract(registryExchangeAddress, registryExchangeJson.abi), - curveOETHPool, - curveUnderlyingCoins, - ] + return [curveRegistryExchange, curveOETHPool, curveUnderlyingCoins] } // calls to be executed only once after setup diff --git a/dapp-oeth/src/utils/hooks.js b/dapp-oeth/src/utils/hooks.js index 86a4afb76b..5827c57d41 100644 --- a/dapp-oeth/src/utils/hooks.js +++ b/dapp-oeth/src/utils/hooks.js @@ -63,7 +63,7 @@ export function useEagerConnect() { setTriedLedgerLive(true) return } - + AccountStore.update((s) => { s.connectorName = 'Ledger' }) diff --git a/dapp-oeth/src/utils/web3.js b/dapp-oeth/src/utils/web3.js index 767f0c9105..318c686d67 100644 --- a/dapp-oeth/src/utils/web3.js +++ b/dapp-oeth/src/utils/web3.js @@ -8,8 +8,8 @@ export function isCorrectNetwork(chainId) { return chainId === 1 } else { return ( - chainId === - (parseInt(process.env.NEXT_PUBLIC_ETHEREUM_RPC_CHAIN_ID)) || 1337 + chainId === parseInt(process.env.NEXT_PUBLIC_ETHEREUM_RPC_CHAIN_ID) || + 1337 ) } } diff --git a/package.json b/package.json index a259c2e4e1..9baadec94d 100644 --- a/package.json +++ b/package.json @@ -13,6 +13,6 @@ "react-use": "^17.4.0" }, "engines": { - "node": ">=16" + "node": "16" } }