# CODE- EthereansOS farm Component breakdown **Note** this is the entire component broken down by function. We want to mirror the logic related to Univ3 pools for our farm starter kit. **How to Help**: Help by using a function as the input for chatgpt4 and asking it to explain it for you. Paste the input as **CHATGPT ANALYSIS** under a new subtitle (Use ## for the subtitle heading) # HTMLRender ``` return (<> <div className={style.ActionInfoSection}> {content && <div className={style.FarmingAsideInfoLP}>{content}</div>} <a className={style.ActionInfoSectionSettings} onClick={() => setSettings(!settings)}> <figure> <img src={`${process.env.PUBLIC_URL}/img/settings.svg`}/> </figure> </a> </div> {settings && <div className={style.SettingFB}> {renderSlippage && <div> <label className={style.SettingBLabPerch}> <p>Slippage: {slippage}%</p> <input type="range" min="0" max="99" step="0.05" value={slippage} onChange={e => setSlippage(parseFloat(e.currentTarget.value))}/> </label> </div>} {renderFeeType && <div className={style.FarmProtocolFees}> <p>Protocol Fees:</p> <label className={style.FarmProtocolFee}> <span><b>🧮 Transaction</b></span> {setupTokens && manageStatus && manageStatus.additionalFees && feeData && feeData.feePercentageForTransacted && <span>{calculateTransactedFee(feeData.feePercentageForTransacted, element.generation === 'gen1' ? manageStatus.tokenAmounts[0] : manageStatus.additionalFees[0], setupTokens[0])} {setupTokens[0].symbol} - {calculateTransactedFee(feeData.feePercentageForTransacted, element.generation === 'gen1' ? manageStatus.tokenAmounts[1] : manageStatus.additionalFees[1], setupTokens[1])} {setupTokens[1].symbol}</span>} <input type="radio" name={"feeType" + postfix} checked={feeType === 'percentage'} onClick={() => setFeeType("percentage")}/> </label> {!dualChainId && contracts.indexOf(web3Utils.toChecksumAddress(element.address)) === -1 && <label className={style.FarmProtocolFee}> <span><b>🔥 Burn</b></span> {feeData && feeData.tokenToTransferOrBurnInApplication && feeData.transferOrBurnAmountInApplication && <span>{formatMoney(fromDecimals(feeData.transferOrBurnAmountInApplication, feeData.tokenToTransferOrBurnInApplication.decimals, true), 6)} {feeData.tokenToTransferOrBurnInApplication.symbol}</span>} <input type="radio" name={"feeType" + postfix} checked={feeType === 'burn'} onClick={() => setFeeType("burn")}/> </label>} </div>} {renderAddress && <div> <label className={style.SettingBLabRegular}> <p>Receiver:</p> <input type="text" value={receiver} onChange={e => setReceiver(e.currentTarget.value)}/> </label> </div>} </div>} </>) } const getManageAdvanced = () => { const RemoveButton = <ActionAWeb3Button onSuccess={reloadData} onClick={removeLiquidity}>Remove</ActionAWeb3Button> if (withdrawOpen && currentPosition && setupInfo.free) { return ( <div> {(!setupInfo || setupInfo.minStakeable === '0') && <div className={style.RemoveLiquiditytools}> <input type="range" value={removalAmount} onChange={(e) => setRemovalAmount(parseInt(e.target.value))} id="formControlRange" /> <a className={style.RegularButtonDuo} onClick={() => setRemovalAmount(100)} >MAX</a> {renderSettings(true, true)} <p><b>{removalAmount}%</b></p> <p>{manageStatus.tokens.map((token, i) => <span key={token.address}> {formatMoneyUniV3(fromDecimals(parseInt(manageStatus.tokenAmounts[i].full || manageStatus.tokenAmounts[i]) * removalAmount / 100, token.decimals, true), 4)} {token.symbol} </span>)}</p> </div>} <div className={style.LiqiudityAffairs}> {setupInfo && setupInfo.minStakeable === '0' && RemoveButton} {setupInfo && setupInfo.minStakeable !== '0' && renderSettings(true, true, undefined, RemoveButton)} </div> </div> ) } return ( <div className={style.FarmingDynamics}> {setupTokens.map((setupToken, i) => { return <div className={style.FarmToken} key={setupToken.address}> {(i === 1 ? tickData.cursorNumber !== 100 : tickData.cursorNumber !== 0) && <TokenInputRegular selected={setupToken} tokens={[setupToken]} onElement={(t, _, value) => onUpdateTokenAmount(fromDecimals(value, t.decimals, true), i) } outputValue={tokenAmounts[i].value || fromDecimals(tokenAmounts[i].full || tokenAmounts[i], setupToken.decimals, true)}/>} </div> })} {minimumStakingError && <div> <p>{minimumStakingError}</p> </div>} {renderSettings(true, false, !currentPosition, (setupInfo.free && rewardTokenInfo && lpTokenAmount !== undefined && lpTokenAmount !== null && lpTokenAmount !== '' && lpTokenAmount !== '0' && (!lpTokenAmount.full || lpTokenAmount.full !== '0')) && <div> <p> Estimated reward per day: <br/> <b>{formatMoneyUniV3(freeEstimatedReward, rewardTokenInfo.decimals)} {rewardTokenInfo.symbol}</b> </p> </div>)} <div className={style.timeToFarm}> {tokensApprovals.some(value => !value) && approveButton} <ActionAWeb3Button onSuccess={reloadData} onClick={addLiquidity} disabled={tokensApprovals.some(value => !value) || tokenAmounts.some(value => value === 0)}>Add Liquidity</ActionAWeb3Button> </div> </div> ) } if (!setupTokens || setupTokens.length === 0 || !setup) { return <OurCircularProgress/> } return ( <div className={style.FarmSetupV3}> <div className={style.FarmSetupMain}> <div className={style.SetupFarmingInstructions}> <div className={style.SetupFarmingInstructionsV3}> {setupTokens.map((token, i) => <div key={token.address} className={style.TokenFarmV3InfoBox}>{token.address !== VOID_ETHEREUM_ADDRESS ? <a target="_blank" href={`${getNetworkElement({ context, chainId }, "etherscanURL")}token/${token.address}`}><LogoRenderer input={token} /></a> : <LogoRenderer input={token} />}<span> {tickData && `${formatMoneyUniV3(i === 0 ? tickData.cursorNumber : 100 - tickData.cursorNumber, 2)}%`} <span>{token.symbol}</span></span> </div>)} {!endBlockReached && <p className={style.BlockInfoV3B}> {setup.active && parseInt(setup.endBlock) > currentBlock && <span className={style.V3FarmStatusYEP}>Active</span>} {!delayedBlock && <> {(!setup.active && canActivateSetup) ? <span>{setupReady ? "new" : "Soon"}</span> : (!setup.active) ? <span>Inactive</span> : <></>} {(parseInt(setup.endBlock) <= currentBlock && parseInt(setup.endBlock) !== 0) && <span>Ended</span>}</>}{delayedBlock !== 0 && <span>Soon</span>} {!isNaN(apy) && <> <b>APR</b>: {apy === 0 ? 0 : formatMoneyUniV3(apy, 3)}%</>} </p> } {rewardTokenInfo && <p className={style.BlockInfoV3}><b>Daily Rate</b>: {formatMoneyUniV3(fromDecimals(parseInt(setup.rewardPerBlock) * 6400, rewardTokenInfo.decimals, true), 4)} {rewardTokenInfo.symbol}</p>} {mainTokenInfo && setupInfo && setupInfo.minStakeable !== '0' && <p className={style.BlockInfoV3}><b>Minimum Staking</b>: {formatMoneyUniV3(fromDecimals(setupInfo.minStakeable, mainTokenInfo.decimals, true), 6)} {mainTokenInfo.symbol}</p>} {parseInt(setup.endBlock) > 0 ? <p className={style.BlockInfoV3}><b>End</b>: <a target="_blank" href={`${getNetworkElement({ context, chainId : dualChainId || chainId }, "etherscanURL")}block/${setup.endBlock}`}>{setup.endBlock}</a></p> : <p className={style.BlockInfoV3}><b>Duration</b>: {getPeriodFromDuration(setupInfo.blockDuration)}</p>} {setupMustBeToggled && <ActionAWeb3Button onSuccess={refresh} onClick={toggleSetup}>Toggle</ActionAWeb3Button>} {!currentPosition && (!open && parseInt(setup.endBlock) > parseInt(currentBlock)) && <a className={style.RegularButtonDuo} onClick={() => void(setOpen(true), setWithdrawOpen(false), setEdit(false))}>Farm</a>} {!currentPosition && open && <RegularButtonDuo className={style.RegularButtonDuoBack} onClick={() => void(setOpen(false), setWithdrawOpen(false), setEdit(false))}>Close</RegularButtonDuo>} { !delayedBlock && canActivateSetup && <> { !open && setupReady && <> { activateLoading ? <OurCircularProgress/> : <> <RegularButtonDuo onClick={() => void(setOpen(true), setWithdrawOpen(false), setEdit(false))}>Farm</RegularButtonDuo> <p className={style.FarmDisclamerGas}>You're the first farmer on this setup, you'll spend more gas, but all of the initial currentBlock rewards are yours! </p> </> } </> } {!setupReady && <p>Not ready to be activated, come back at another time</p>} </> } {delayedBlock !== 0 && <div> <p><b>Start Block: <a href={`${getNetworkElement({ context, chainId : dualChainId || chainId }, "etherscanURL")}block/${delayedBlock}`} target="_blank">#{delayedBlock}</a></b></p> </div>} {/*<a Web3ActionBTN" onClick={async () => { var updatedSetups = [{ add: false, disable: true, index: 0, info: { blockDuration: 0, startBlock: "1000000000000000000", originalRewardPerBlock: 0, minStakeable: 0, renewTimes: 0, liquidityPoolTokenAddress: VOID_ETHEREUM_ADDRESS, mainTokenAddress: VOID_ETHEREUM_ADDRESS, involvingETH: false, setupsCount: 0, lastSetupIndex: 0, tickLower: 0, tickUpper: 320000 } }] try { var data = {from : account} var method = extensionContract.methods.setFarmingSetups(updatedSetups) data.gas = await method.estimateGas(data) var transaction = await method.send(data) } catch(e) { console.log('ALE LEGGI DA QUA') console.log(e) } }}>Terminate Setup</a> @todo remove */} </div> <div className={style.farmInfoCurve}> <p className={style.farmInfoCurveL}> <p className={style.MAinTokensel}> <a onClick={() => setsecondTokenIndex(1 - (secondTokenIndex || 0))}><img src={`${process.env.PUBLIC_URL}/img/switch.png`}/></a> {setupTokens[secondTokenIndex].symbol} per {setupTokens[1 - secondTokenIndex].symbol} </p> </p> {element.generation === 'gen1' && lpTokenInfo && <p className={style.farmInfoCurveR}> <p className={style.PriceRangeInfoFarm}> <a target="_blank" href={`${getNetworkElement({ context, chainId }, 'etherscanURL')}address/${lpTokenInfo.contract.options.address}`}><span className={style.VersionFarm}>{lpTokenInfo.amm.name}</span></a> </p> </p>} {element.generation === 'gen2' && <p className={style.farmInfoCurveR}> <p className={style.PriceRangeInfoFarm}> <a className={style.ExtLinkButton} target="_blank" href={context.uniswapV3PoolURLTemplate.split('{0}').join(dualChainId ? 'optimism/' : '').split('{1}').join(setupInfo.liquidityPoolTokenAddress)}>{formatMoneyUniV3(numberToString(parseInt(lpTokenInfo.fee) / 10000), '2')}%</a> {((currentPosition?.tokenId && currentPosition?.tokenId !== '0') || (setup.objectId && setup.objectId !== '0')) && <a className={style.ExtLinkButton} href={context.uniswapV3NFTURLTemplate.split('{0}').join(dualChainId ? 'optimism/' : '').split('{1}').join(currentPosition?.tokenId || setup.objectId)} target="_blank">NFT</a>} </p> </p>} {!tickData ? <OurCircularProgress/> : <div className={style.UniV3CurveView}> <div className={style.UniV3CurveViewCurv}> <span className={style.CircleLeftV3Curve}></span> <span className={style.CircleLeftV3CurvePrice}> {tickData.diluted ? element.generation === 'gen2' ? "Diluted" : <>&#8734;</> : tickData.tickLowerUSDPrice ? ("$" + formatMoneyUniV3(tickData.tickLowerUSDPrice)) : `${formatMoneyUniV3(tickData.minPrice)} ${setupTokens[secondTokenIndex].symbol}` } </span> <span className={style.CircleRightV3Curve}></span> <span className={style.CircleRightV3CurvePrice}> {tickData.diluted ? element.generation === 'gen2' ? "Diluted" : <>&#8734;</> : tickData.tickUpperUSDPrice ? ("$" + formatMoneyUniV3(tickData.tickUpperUSDPrice)) : `${formatMoneyUniV3(tickData.maxPrice)} ${setupTokens[secondTokenIndex].symbol}` } </span> <div className={style.CircleActualPriceV3} style={{left : `${tickData.cursor}%`}}> <span className={style.CircleRightV3Actual}> <img src={`${process.env.PUBLIC_URL}/img/arrow.png`}/> <span className={style.CircleRightV3ActualPrice}> {tickData.tickCurrentUSDPrice ? ("$" + formatMoneyUniV3(tickData.tickCurrentUSDPrice)) : `${formatMoneyUniV3(tickData.currentPrice)}` } </span> </span> </div> </div> </div>} <span className={style.UniV3TVLFIV}> <b>TVL</b>: {setupTokens.map((token, index) => <span key={token.address}>{formatMoneyUniV3(fromDecimals(token.liquidity, token.decimals, true), 4)} {token.symbol}{index !== setupTokens.length - 1 ? ' - ' : ''}</span>)} </span> </div> </div> </div> { currentPosition && <div className={style.YourFarmingPositionsFarmingFarmingFarmingChiFarmaViveComeUnPAsha}> <div className={style.FarmYou}> {manageStatus && <p><b>Your Deposit</b>:<br></br> {manageStatus.tokens.map((token, i) => <span key={token.address}> {formatMoneyUniV3(fromDecimals(manageStatus.tokenAmounts[i], token.decimals, true), 3)} {token.symbol} </span>)}</p>} {!endBlockReached && <p><b>Daily Earnings</b>:<br></br> {calculateDailyEarnings()} {rewardTokenInfo.symbol}</p>} {(!manageStatus?.withdrawOnly && !open && parseInt(setup.endBlock) > parseInt(currentBlock)) && <RegularButtonDuo onClick={() => void(setOpen(true), setWithdrawOpen(false), setEdit(false))}>Increase</RegularButtonDuo>} {open && <RegularButtonDuo onClick={() => void(setOpen(false), setWithdrawOpen(false), setEdit(false))}>Close</RegularButtonDuo>} {!manageStatus?.withdrawOnly && !withdrawOpen && <RegularButtonDuo onClick={() => void(setOpen(false), setWithdrawOpen(true), setEdit(false))}>Decrease</RegularButtonDuo>} {withdrawOpen && <RegularButtonDuo onClick={() => void(setOpen(false), setWithdrawOpen(false), setEdit(false))}>Close</RegularButtonDuo>} {manageStatus?.withdrawOnly && <> {!open && !withdrawOpen && renderSettings(true, true, undefined, <ActionAWeb3Button onSuccess={reloadData} onClick={withdrawAll}>Withdraw All</ActionAWeb3Button>)} </>} </div> <div className={style.farmed}> <p><b>Available</b>: <br></br>{formatMoneyUniV3(fromDecimals(freeAvailableRewards, rewardTokenInfo.decimals, true), 4)} {rewardTokenInfo.symbol}</p> {element.generation === 'gen2' && manageStatus && <p><b>Fees Earned</b>: <br></br>{formatMoneyUniV3(fromDecimals(manageStatus.additionalFees[0], setupTokens[0].decimals, true), 4)} {setupTokens[0].symbol} - {formatMoneyUniV3(fromDecimals(manageStatus.additionalFees[1], setupTokens[1].decimals, true), 4)} {setupTokens[1].symbol}</p>} {!manageStatus?.withdrawOnly && <> {approveFeeButton} {element.generation === 'gen2' && !open && !withdrawOpen && renderSettings(false, true)} </>} </div> </div> } {((open || withdrawOpen) && !edit) && <><hr/>{getAdvanced()}</>} {(edit && !open && !withdrawOpen) && getEdit()} </div> ) } ``` # Helper Functions const calculateLockedFixedValue = () => { const { rewardPerBlock } = setup const { maxStakeable } = setupInfo const normalizedRewardPerBlock = parseInt(rewardPerBlock) * 10 ** (18 - rewardTokenInfo.decimals) const normalizedMaxStakeable = parseInt(maxStakeable) * 10 ** (18 - mainTokenInfo.decimals) const amount = normalizedRewardPerBlock * (1 / normalizedMaxStakeable) return (canActivateSetup) ? formatMoneyUniV3(amount * parseInt(setupInfo.blockDuration), 6) : parseInt(currentBlock) >= parseInt(setup.endBlock) ? 0 : formatMoneyUniV3(amount * (parseInt(setup.endBlock) - parseInt(currentBlock)), 6) } function onSlippageChange(e) { var value = parseFloat(e.currentTarget.value) var min = parseFloat(e.currentTarget.min) var max = parseFloat(e.currentTarget.max) value = isNaN(value) ? 0 : value if(value < min) { value = min } if(value > max) { value = max } setSlippage(value) } const getAdvanced = () => { return !edit ? getManageAdvanced() : getEdit() } const getEdit = () => { return {/* @locked For upcoming release <div pb-4 px-4"> <hr /> <div row mt-2 align-items-center justify-content-start"> { setupInfo.free && <div col-12 mb-md-2"> <Input value={dfoCore.toDecimals(updatedRewardPerBlock)} min={0} onChange={(e) => setUpdatedRewardPerBlock(dfoCore.toFixed(dfoCore.fromDecimals(e.target.value), rewardTokenInfo.decimals))} label={"Reward per currentBlock"} /> </div> } <div col-12 mb-md-2"> <Input value={updatedRenewTimes} min={0} onChange={(e) => setUpdatedRenewTimes(e.target.value)} label={"Renew times"} /> </div> <div col-12"> <button onClick={() => updateSetup()} btn btn-secondary">Update</button> {setup.active && <button onClick={() => disableSetup()} btn btn-primary">Disable</button>} </div> </div> </div>*/} } function calculateDailyEarnings() { if(!manageStatus) { return 0 } var rewardPerBlock = formatNumber(fromDecimals(setup.rewardPerBlock, rewardTokenInfo.decimals, true)) var liquidityPoolAmount = formatNumber(fromDecimals(manageStatus.liquidityPoolAmount, rewardTokenInfo.decimals, true)) var totalSupply = formatNumber(fromDecimals(setup.totalSupply, rewardTokenInfo.decimals, true)) var dailyEarnings = (rewardPerBlock * 6400 * liquidityPoolAmount) / totalSupply dailyEarnings = numberToString(dailyEarnings) dailyEarnings = formatMoneyUniV3(dailyEarnings, 4) return dailyEarnings //fromDecimals((parseInt(setup.rewardPerBlock) * 6400 * parseInt(manageStatus.liquidityPoolAmount) / parseInt(setup.totalSupply)).toString().split('.')[0], rewardTokenInfo.decimals, true) } function calculateTransactedFee(percentage, amount, setupToken) { amount = numberToString(parseFloat(fromDecimals(percentage, 18, true)) * parseInt(amount)).split('.')[0] return formatMoney(fromDecimals(amount, setupToken.decimals, true), 6) } function renderSettings(renderSlippage, renderFeeType, renderAddress, content) { const postfix = "_" + numberToString(new Date() * Math.random()).split('.').join('') # UpdateEthAmount ``` const updateEthAmount = async amount => { try { setLoadingPrestoData(true) setPrestoData(null) setEthAmount(amount || "0") if (!parseFloat(amount)) { return setLoadingPrestoData(false) } var value = toDecimals(numberToString(amount), 18) var halfValue = web3Utils.toBN(value).div(web3Utils.toBN(2)).toString() var ammEthereumAddress = (await blockchainCall(ammContract.methods.data))[0] var info = setupInfo var liquidityPool = info.liquidityPoolTokenAddress var tokens = await blockchainCall(ammContract.methods.byLiquidityPool, liquidityPool) var token0 = newContract(context.ERC20ABI, tokens[2][0]) var token1 = newContract(context.ERC20ABI, tokens[2][1]) var token0decimals = tokens[2][0] === VOID_ETHEREUM_ADDRESS ? 18 : await blockchainCall(token0.methods.decimals) var token1decimals = tokens[2][1] === VOID_ETHEREUM_ADDRESS ? 18 : await blockchainCall(token1.methods.decimals) var lpDecimals = await blockchainCall(newContract(context.ERC20ABI, liquidityPool).methods.decimals) var mainTokenIndex = tokens[2].indexOf(info.mainTokenAddress) var amm = ammContract//amms[selectedAmmIndex].contract var ethereumAddress = (await blockchainCall(amm.methods.data))[0] async function calculateBestLP(firstToken, secondToken, firstDecimals, secondDecimals, hf) { var data = await blockchainCall(amm.methods.byTokens, [ethereumAddress, firstToken]) var liquidityPoolAddress = data[2] if (liquidityPoolAddress === VOID_ETHEREUM_ADDRESS) { return {} } var mainTokenIndex = data[3].indexOf(firstToken) var middleTokenIndex = data[3].indexOf(ethereumAddress) var mainAmount = formatNumber(normalizeValue(data[1][mainTokenIndex], firstDecimals)) var middleTokenAmount = formatNumber(normalizeValue(data[1][middleTokenIndex], 18)) var constant = mainAmount * middleTokenAmount var newMiddleTokenAmount = middleTokenAmount + formatNumber(normalizeValue(halfValue, 18)) var newMainAmount = constant / newMiddleTokenAmount var mainReceived = mainAmount - newMainAmount var firstTokenEthLiquidityPoolAddress = liquidityPoolAddress var token0Value = (await blockchainCall(amm.methods.getSwapOutput, ethereumAddress, hf || halfValue, [liquidityPoolAddress], [firstToken]))[1] var ratio = newMainAmount / mainAmount if (!hf) { return await calculateBestLP(firstToken, secondToken, firstDecimals, secondDecimals, halfValue = numberToString(formatNumber(halfValue) * ratio).split('.')[0]) } var token1Value = (await blockchainCall(ammContract.methods.byTokenAmount, liquidityPool, firstToken, token0Value)) var lpAmount = token1Value[0] token1Value = token1Value[1][token1Value[2].indexOf(secondToken)] lpAmount = numberToString(parseInt(lpAmount) / ratio).split('.')[0] token1Value = numberToString(parseInt(token1Value) / ratio).split('.')[0] const updatedFirstTokenAmount = formatNumber(normalizeValue(token0Value, firstDecimals)) const updatedSecondTokenAmount = formatNumber(normalizeValue(token1Value, secondDecimals)) liquidityPoolAddress = (await blockchainCall(amm.methods.byTokens, [ethereumAddress, secondToken]))[2] var secondTokenEthLiquidityPoolAddress = liquidityPoolAddress var token1ValueETH = "0" if (secondTokenEthLiquidityPoolAddress !== VOID_ETHEREUM_ADDRESS) { token1ValueETH = (await blockchainCall(amm.methods.getSwapOutput, secondToken, token1Value, [liquidityPoolAddress], [ethereumAddress]))[1] } return { lpAmount, updatedFirstTokenAmount, updatedSecondTokenAmount, token0Value, token1Value, token1ValueETH, firstTokenEthLiquidityPoolAddress, secondTokenEthLiquidityPoolAddress } } var bestLP = await calculateBestLP(token0.options.address, token1.options.address, token0decimals, token1decimals) var lpAmount = bestLP.lpAmount var firstTokenAmount = bestLP.token0Value var secondTokenAmount = bestLP.token1Value var firstTokenETH = halfValue var secondTokenETH = bestLP.token1ValueETH var token0EthLiquidityPoolAddress = bestLP.firstTokenEthLiquidityPoolAddress var token1EthLiquidityPoolAddress = bestLP.secondTokenEthLiquidityPoolAddress if (token0.options.address === ammEthereumAddress || !lpAmount || (bestLP.updatedSecondTokenAmount > bestLP.updatedFirstTokenAmount)) { bestLP = await calculateBestLP(token1.options.address, token0.options.address, token1decimals, token0decimals) lpAmount = bestLP.lpAmount firstTokenAmount = bestLP.token1Value secondTokenAmount = bestLP.token0Value firstTokenETH = bestLP.token1ValueETH secondTokenETH = halfValue token0EthLiquidityPoolAddress = bestLP.secondTokenEthLiquidityPoolAddress token1EthLiquidityPoolAddress = bestLP.firstTokenEthLiquidityPoolAddress } var operations = [] token0EthLiquidityPoolAddress !== VOID_ETHEREUM_ADDRESS && operations.push({ inputTokenAddress: ethereumAddress, inputTokenAmount: firstTokenETH, ammPlugin: amm.options.address, liquidityPoolAddresses: [token0EthLiquidityPoolAddress], swapPath: [token0.options.address], enterInETH: true, exitInETH: false, receivers: [farmingPresto.options.address], receiversPercentages: [] }) token1EthLiquidityPoolAddress !== VOID_ETHEREUM_ADDRESS && operations.push({ inputTokenAddress: ethereumAddress, inputTokenAmount: secondTokenETH, ammPlugin: amm.options.address, liquidityPoolAddresses: [token1EthLiquidityPoolAddress], swapPath: [token1.options.address], enterInETH: true, exitInETH: false, receivers: [farmingPresto.options.address], receiversPercentages: [] }) var ethValue = 0 token0EthLiquidityPoolAddress !== VOID_ETHEREUM_ADDRESS && (ethValue = web3Utils.toBN(ethValue).add(web3Utils.toBN(firstTokenETH)).toString()) token1EthLiquidityPoolAddress !== VOID_ETHEREUM_ADDRESS && (ethValue = web3Utils.toBN(ethValue).add(web3Utils.toBN(secondTokenETH)).toString()) info.involvingETH && token0.options.address === ammEthereumAddress && (ethValue = web3Utils.toBN(ethValue).add(web3Utils.toBN(firstTokenAmount)).toString()) info.involvingETH && token1.options.address === ammEthereumAddress && (ethValue = web3Utils.toBN(ethValue).add(web3Utils.toBN(secondTokenAmount)).toString()) var request = { setupIndex : setup.setupIndex, amount: mainTokenIndex === 0 ? firstTokenAmount : secondTokenAmount, amountIsLiquidityPool: false, positionOwner: isEthereumAddress(receiver) ? receiver : account } if (!setupInfo.free) { const reward = await blockchainCall(element.contract.methods.calculateLockedFarmingReward, setup.setupIndex, mainTokenIndex === 0 ? firstTokenAmount : secondTokenAmount, false, 0) setLockedEstimatedReward(fromDecimals(parseInt(reward.relativeRewardPerBlock) * (parseInt(setup.endBlock) - currentBlock), rewardTokenInfo.decimals)) } else { const val = parseInt(lpAmount) * 6400 * parseInt(setup.rewardPerBlock) / (parseInt(setup.totalSupply) + parseInt(lpAmount)) if (!isNaN(val)) { setFreeEstimatedReward(fromDecimals(val, rewardTokenInfo.decimals)) } } setPrestoData({ ethValue: value, transaction: farmingPresto.methods.openPosition( getNetworkElement({ context, chainId }, "prestoAddress"), operations, element.address, request ), firstTokenAmount, secondTokenAmount, token0decimals, token1decimals, token0Address: token0.options.address, token1Address: token1.options.address, token0Symbol: info.involvingETH && token0.options.address === ammEthereumAddress ? "ETH" : await blockchainCall(token0.methods.symbol), token1Symbol: info.involvingETH && token1.options.address === ammEthereumAddress ? "ETH" : await blockchainCall(token1.methods.symbol) }) setLpTokenAmount({ full: lpAmount, value: fromDecimals(lpAmount, lpDecimals) }) } catch (error) { console.log(error) } setLoadingPrestoData(false) } ``` # ApproveButton, onInputTypeChange ``` const ApproveButton = ({ contract, text, onApproval, spender, value }) => { const approve = useCallback(async () => { setApproveLoading(true) try { await blockchainCall(contract.methods.approve, spender, value || MAX_UINT256) } catch(e) { setApproveLoading(false) throw e } }, [contract.options.address]) return approveLoading ? <OurCircularProgress/> : <ActionAWeb3Button onClick={approve} onSuccess={() => void(setApproveLoading(), onApproval())}>{text}</ActionAWeb3Button> } const approveButton = useMemo(() => { const notApprovedIndex = tokensApprovals.findIndex(value => !value) if (notApprovedIndex !== -1) { if(!tickData || tickData.cursorNumber === 0 || tickData.cursorNumber === 100) { var index = tickData?.cursorNumber === 100 ? 0 : 1 return notApprovedIndex === index && <ApproveButton contract={setupTokens[index].contract} spender={element.address} onApproval={() => onTokenApproval(index, false)} text={`Approve ${setupTokens[index].symbol}`} /> } return <ApproveButton contract={setupTokens[notApprovedIndex].contract} spender={element.address} onApproval={() => onTokenApproval(notApprovedIndex, false)} text={`Approve ${setupTokens[notApprovedIndex].symbol}`} /> } else { return <></> } }, [tokensApprovals, lpTokenInfo, setupTokens, tickData, approveLoading]) const approveFeeButton = useMemo(() => { if(!burnFeeAllowance) { return <ActionAWeb3Button onSuccess={reloadData} onClick={withdrawReward}>Claim</ActionAWeb3Button> } return <ApproveButton contract={feeData.tokenToTransferOrBurnInApplication.contract} spender={feeData.operator} onApproval={setBurnFeeAllowance} text={`Approve ${feeData.tokenToTransferOrBurnInApplication.symbol} to transfer/burn fees`} value={feeData && feeData.transferOrBurnAmountInApplication}/> }, [feeData, burnFeeAllowance, currentPosition]) const onInputTypeChange = async (e) => { setInputType(e.target.value) const ethBalance = await web3.eth.getBalance(account) setEthBalanceOf(ethBalance) setPrestoData(null) setShowPrestoError(false) setEthAmount(0) if (e.target.value === 'add-eth') { setLpTokenAmount(0) setTokenAmounts(new Array(setupTokens.length).fill(0)) setFreeEstimatedReward("0") setLockedEstimatedReward("0") } } const onOutputTypeChange = e => { setOutputType(e.target.value) } ``` # Remove Liquidity, Claim, widthrdraw $ fee calc ``` async function percentageFeeOrBurn() { var burnData = "0x" if(feeType === "burn") { burnData = abi.encode(["bool", "bytes"], [true, "0x"]) } return burnData } const removeLiquidity = async () => { if (setupInfo.free && (!removalAmount || removalAmount === 0) && setupInfo.minStakeable === '0') return const removedLiquidity = removalAmount === 100 || setupInfo.minStakeable !== '0' ? manageStatus.liquidityPoolAmount : numberToString(parseInt(manageStatus.liquidityPoolAmount) * removalAmount / 100).split('.')[0] var amMin = await calculateSlippageAmounts(slippage, removedLiquidity, 'burn') var burnData = await percentageFeeOrBurn() if(element.generation === 'gen1') { return await blockchainCall(element.contract.methods.withdrawLiquidity, currentPosition.positionId, 0, removedLiquidity, amMin[0].full || amMin[0], amMin[1].full || amMin[1], burnData) } try { await blockchainCall(element.contract.methods.withdrawLiquidity, currentPosition.positionId, removedLiquidity, amMin[0].full || amMin[0], amMin[1].full || amMin[1], burnData) } catch(e) { console.error(e.message) const message = (e.message || e).toLowerCase() if(message.indexOf('user denied') === -1 && message.indexOf('price slippage') === -1) { await blockchainCall(element.contract.methods.withdrawLiquidity, currentPosition.positionId, removedLiquidity, burnData) } else { throw e } } } async function withdrawAll() { var amMin = await calculateSlippageAmounts(slippage, manageStatus.liquidityPoolAmount, 'burn') var burnData = await percentageFeeOrBurn() if(element.generation === 'gen1') { return await blockchainCall(element.contract.methods.withdrawLiquidity, currentPosition.positionId, 0, manageStatus.liquidityPoolAmount, amMin[0].full || amMin[0], amMin[1].full || amMin[1], burnData) } try { await element.contract.methods.withdrawLiquidity(currentPosition.positionId, manageStatus.liquidityPoolAmount, amMin[0].full || amMin[0], amMin[1].full || amMin[1], burnData).call({from : account}) } catch(e) { console.error(e.message) } try { await blockchainCall(element.contract.methods.withdrawLiquidity, currentPosition.positionId, manageStatus.liquidityPoolAmount, amMin[0].full || amMin[0], amMin[1].full || amMin[1], burnData) } catch(e) { console.error(e.message) const message = (e.message || e).toLowerCase() if(message.indexOf('user denied') === -1 && message.indexOf('price slippage') === -1) { await blockchainCall(element.contract.methods.withdrawLiquidity, currentPosition.positionId, manageStatus.liquidityPoolAmount, burnData) } else { throw e } } } async function withdrawReward() { var burnData = await percentageFeeOrBurn() try { await blockchainCall(element.contract.methods["withdrawReward(uint256,bytes)"], currentPosition.positionId, burnData) } catch(e) { var msg = (e.message || e).toLowerCase() if(msg.indexOf('user denied') === -1 && msg.indexOf("allowance") === -1) { await blockchainCall(element.contract.methods["withdrawReward(uint256)"], currentPosition.positionId) } else { throw e } } } const transferPosition = async (positionId, index) => { if (!positionId) return if (setupInfo.free) { setTransferLoading(true) try { //const gasLimit = await element.contract.methods.transferPosition(freeTransferAddress, positionId).estimateGas({ from: account }) await blockchainCall(element.contract.methods.transferPosition, account, positionId) await reloadData() } catch (error) { console.log(error) } finally { setTransferLoading(false) } } } ``` # AddLiquidity ``` async function addLiquidity(data) { if(element.generation === 'gen2') { return await addLiquidityGen2({setup, lpTokenAmount, receiver, setupTokens, inputType, setupInfo, ethereumAddress, tokenAmounts, element, currentPosition, prestoData, amountsMin, context, ...web3Data, ...data }) } const stake = { setupIndex : setup.setupIndex, amount: 0, amountIsLiquidityPool: inputType === 'add-lp' ? true : false, positionOwner: receiver || VOID_ETHEREUM_ADDRESS, amount0Min : amountsMin[0], amount1Min : amountsMin[1] } var ethTokenIndex = null var ethTokenValue = 0 var mainTokenIndex = 0 var ethereumAddress = lpTokenInfo?.amm?.ethereumAddress await Promise.all(setupTokens.map(async (token, i) => { if (setupInfo.involvingETH && token.address === VOID_ETHEREUM_ADDRESS) { ethTokenIndex = i } if (token.address === setupInfo.mainTokenAddress || setupInfo.involvingETH && token.address === VOID_ETHEREUM_ADDRESS && setupInfo.mainTokenAddress === ethereumAddress) { mainTokenIndex = i } })) var lpAmount = numberToString((lpTokenAmount && lpTokenAmount.full) || lpTokenAmount) stake.amount = numberToString(stake.amountIsLiquidityPool ? lpAmount : tokenAmounts[mainTokenIndex].full || tokenAmounts[mainTokenIndex]) ethTokenValue = ethTokenIndex === undefined || ethTokenIndex === null ? "0" : numberToString(tokenAmounts[ethTokenIndex].full || tokenAmounts[ethTokenIndex]) var value = setupInfo.involvingETH && !stake.amountIsLiquidityPool ? ethTokenValue : "0" if (!currentPosition || receiver) { await blockchainCall(element.contract.methods.openPosition, stake, { value }) } else if (currentPosition) { await blockchainCall(element.contract.methods.addLiquidity, currentPosition.positionId, stake, { value }) } } ``` # onUpdateTokenAmount function onUpdateTokenAmount(value, index, isFull) { if(value === undefined || value === null || !value) { value = '0' } var tks = tokenAmounts.map(it => it) if(value.indexOf('.') !== -1 && value.split('.')[1].length > 18) { value = value.split('.') value[1] = value[1].substring(0, 18) value = value.join('.') } const fullValue = isFull ? value : toDecimals(value, setupTokens[index].decimals) tks[index] = { value : isFull ? fromDecimals(value, setupTokens[index].decimals, true) : value, full : fullValue } //isFull && setTokenAmounts(tks.map(it => it)) if(fromDecimals(fullValue, setupTokens[index].decimals, true) === numberToString(tokenAmounts[index].value || 0)) { return } setLpTokenAmount(null) updateAmountTimeout.current && clearTimeout(updateAmountTimeout.current) if (!value) { setLockedEstimatedReward(0) setFreeEstimatedReward(0) //setTokenAmounts(tokenAmounts.map(() => 0)) return } updateAmountTimeout.current = setTimeout(async function () { var liquidityPoolAmount var surplus = 0 async function elaborateValue() { var currentIndex = parseInt(index) var val = fullValue if(arguments.length === 2) { val = tks[currentIndex = 1 - currentIndex].full } var tokenAddress = setupTokens[currentIndex].address if(element.generation === 'gen1') { tokenAddress = lpTokenInfo.originalTokenAddresses[currentIndex] const ammContract = lpTokenInfo.amm.contract var result = await blockchainCall(ammContract.methods.byTokenAmount, setupInfo.liquidityPoolTokenAddress, tokenAddress, val.ethereansosAdd(surplus)) liquidityPoolAmount = result.liquidityPoolAmount result = await blockchainCall(ammContract.methods.byLiquidityPoolAmount, setupInfo.liquidityPoolTokenAddress, liquidityPoolAmount) var ams = result.tokensAmounts if(fullValue !== ams[index] && setupTokens[index].decimals !== '18') { result = await blockchainCall(ammContract.methods.byTokenAmount, setupInfo.liquidityPoolTokenAddress, tokenAddress, ams[index]) liquidityPoolAmount = result.liquidityPoolAmount ams = result.tokensAmounts } tks[0] = { value : index === 0 && !isFull ? value : fromDecimals(ams[0], setupTokens[0].decimals, true), full : ams[0] } tks[1] = { value : index === 1 && !isFull ? value : fromDecimals(ams[1], setupTokens[1].decimals, true), full : ams[1] } } else { tokenAddress = tokenAddress === VOID_ETHEREUM_ADDRESS ? ethereumAddress : tokenAddress var pool = await createPool() var fromAmountData = {pool, tickLower : parseInt(setupInfo.tickLower), tickUpper : parseInt(setupInfo.tickUpper), useFullPrecision : false} fromAmountData[`amount${currentIndex}`] = formatNumber(val) + surplus var pos = Position[`fromAmount${currentIndex}`](fromAmountData) liquidityPoolAmount = pos.liquidity.toString() if(setup.objectId && setup.objectId !== '0') { var amount0 = pos.amount0.toSignificant(18) amount0 === '0' && tickData.cursorNumber !== 0 && tickData.cursorNumber !== 100 && (amount0 = fromDecimals('1', setupTokens[0].decimals, true)) var amount1 = pos.amount1.toSignificant(18) amount1 === '0' && tickData.cursorNumber !== 0 && tickData.cursorNumber !== 100 && (amount1 = fromDecimals('1', setupTokens[1].decimals, true)) tks[0] = { value : index === 0 && !isFull ? value : numberToString(amount0), full : toDecimals(numberToString(amount0), setupTokens[0].decimals) } tks[1] = { value : index === 1 && !isFull ? value : numberToString(amount1), full : toDecimals(numberToString(amount1), setupTokens[1].decimals) } } else { pos = pos.mintAmounts tks[0] = { value : index === 0 && !isFull ? value : fromDecimals(pos.amount0.toString(), setupTokens[0].decimals, true), full : pos.amount0.toString() } tks[1] = { value : index === 1 && !isFull ? value : fromDecimals(pos.amount1.toString(), setupTokens[1].decimals, true), full : pos.amount1.toString() } } } } await elaborateValue() while(web3Utils.toBN(tks[index].full).lt(web3Utils.toBN(fullValue))) { await elaborateValue(surplus += 999999) } const balance = setupTokens[index].address === VOID_ETHEREUM_ADDRESS ? await web3.eth.getBalance(account) : await blockchainCall(setupTokens[index].contract.methods.balanceOf, account) if(parseInt(fullValue) === parseInt(balance)) { tks[index].full = balance } const mainTokenIndex = setupTokens.indexOf(setupTokens.filter(it => web3Utils.toChecksumAddress(it.address) === web3Utils.toChecksumAddress(isWeth(setupInfo, setupInfo.mainTokenAddress) ? VOID_ETHEREUM_ADDRESS : setupInfo.mainTokenAddress))[0]) while(element.generation === 'gen2' && setupInfo.minStakeable !== '0' && index === mainTokenIndex && parseInt(tks[index].full) >= parseInt(setupInfo.minStakeable) && !await addLiquidity({test : true, tokenAmounts : tks, lpTokenAmount : liquidityPoolAmount})) { console.log("value0", tks[0].full) console.log("value1", tks[1].full) await elaborateValue(surplus += 999999, true) } console.log("Liquidity", liquidityPoolAmount) console.log("totalSupply", setup.totalSupply) console.log("value0", tks[0].full) console.log("value1", tks[1].full) tickData && tickData.cursorNumber === 0 && (tks[0] = { value : '0', full : '0' }) tickData && tickData.cursorNumber === 100 && (tks[1] = { value : '0', full : '0' }) setTokenAmounts(tks.map(it => it)) setLpTokenAmount(liquidityPoolAmount) if (parseInt(setup.totalSupply) + parseInt(liquidityPoolAmount) > 0) { var val = parseInt(liquidityPoolAmount) * 6400 * parseInt(setup.rewardPerBlock) / (parseInt(setup.totalSupply) + parseInt(liquidityPoolAmount)) val = numberToString(val).split('.')[0] if (!isNaN(val)) { setFreeEstimatedReward(fromDecimals(val, rewardTokenInfo.decimals)) } } }, 300) # CreatePool async function createPool(liquidity) { liquidity = liquidity || 0 var slot0 = await blockchainCall(lpTokenInfo.contract.methods.slot0) var tick = nearestUsableTick(parseInt(slot0.tick), TICK_SPACINGS[lpTokenInfo.fee]) var sqrtPriceX96 = TickMath.getSqrtRatioAtTick(tick).toString() var pool try { pool = new Pool(lpTokenInfo.uniswapTokens[0], lpTokenInfo.uniswapTokens[1], parseInt(lpTokenInfo.fee), parseInt(sqrtPriceX96), liquidity, tick) } catch(e) { try { pool = new Pool(lpTokenInfo.uniswapTokens[0], lpTokenInfo.uniswapTokens[1], parseInt(lpTokenInfo.fee), parseInt(slot0.sqrtPriceX96), liquidity, parseInt(slot0.tick)) } catch(e) { } } return pool } # CalculateSlippageAmmounts async function calculateSlippageAmounts(slippage, liquidity, type) { slippage = cleanSlippage(slippage) if(slippage == 0) { return ['0', '0'] } if(element.generation === 'gen1') { const amm = (await ammAggregatorPromise).amms.filter(it => web3Utils.toChecksumAddress(it.address) === web3Utils.toChecksumAddress(setupInfo.ammPlugin))[0] const result = [...(await blockchainCall(amm.contract.methods.byLiquidityPoolAmount, setupInfo.liquidityPoolTokenAddress, liquidity))[0]] result[0] = numberToString(parseInt(result[0]) * (1 - (slippage / 100))).split('.')[0] result[1] = numberToString(parseInt(result[1]) * (1 - (slippage / 100))).split('.')[0] return result } try { var toler = new Percent(slippage, 100) const partialPosition = new Position({ pool: await createPool(liquidity), liquidity, tickLower: parseInt(setupInfo.tickLower), tickUpper: parseInt(setupInfo.tickUpper) }) var { amount0: amount0Min, amount1: amount1Min } = partialPosition[`${type || 'mint'}AmountsWithSlippage`](toler) amount0Min = amount0Min.toString().split('.')[0] amount1Min = amount1Min.toString().split('.')[0] return [{ full : amount0Min, value : fromDecimals(amount0Min, setupTokens[0].decimals, true) }, { full : amount1Min, value : fromDecimals(amount1Min, setupTokens[1].decimals, true) }] } catch(e) { return ['0', '0'] } } # Calculate APY, IsWeth, Calculate SLippage const calculateApy = async (setup, setupInfo, rewardTokenAddress, rewardTokenDecimals, setupTokens) => { if (parseInt(setup.totalSupply) === 0) return -1 const yearlyBlocks = 2304000 try { const ethPrice = await getEthereumPrice({ context }) const wusdAddress = getNetworkElement({ context, chainId }, "WUSDAddress") || "" const realRewardTokenAddress = await resolveToken({ context, ...web3Data }, rewardTokenAddress) const realSetupTokens = await Promise.all(setupTokens.map(it => resolveToken({ context, ...web3Data }, {...it}))) if (setupInfo.free) { const searchTokens = [realRewardTokenAddress, ...realSetupTokens.map(it => it.address || it)].filter(it => it).map(web3Utils.toChecksumAddress).filter((it, i, arr) => arr.indexOf(it) === i) const res = await getTokenPricesInDollarsOnCoingecko({ context, web3Data }, searchTokens, { tickToPrice, Token, Pool, Position, nearestUsableTick, TICK_SPACINGS, TickMath, maxLiquidityForAmounts }) const { data } = res const rewardTokenPriceUsd = realRewardTokenAddress !== VOID_ETHEREUM_ADDRESS ? realRewardTokenAddress.toLowerCase() === wusdAddress.toLowerCase() ? 1 : data[realRewardTokenAddress.toLowerCase()].usd : ethPrice var den = 0 await Promise.all(realSetupTokens.map(async (token) => { if (token && token.address) { const tokenPrice = token.address !== VOID_ETHEREUM_ADDRESS ? token.address.toLowerCase() === wusdAddress.toLowerCase() ? 1 : data[token.address.toLowerCase()].usd : ethPrice den += (tokenPrice * token.liquidity * 10 ** (18 - token.decimals)) } })) const num = (parseInt(setup.rewardPerBlock) * 10 ** (18 - rewardTokenDecimals) * yearlyBlocks) * rewardTokenPriceUsd return (num * 100 / den) } else { const { mainTokenAddress } = setupInfo const mainTokenContract = mainTokenAddress !== VOID_ETHEREUM_ADDRESS ? newContract(context.ERC20ABI, mainTokenAddress) : null const decimals = mainTokenAddress !== VOID_ETHEREUM_ADDRESS ? await blockchainCall(mainTokenContract.methods.decimals) : 18 const searchTokens = `${rewardTokenAddress},${mainTokenAddress}` const res = await getTokenPricesInDollarsOnCoingecko({ context, web3Data }, searchTokens) const { data } = res const rewardTokenPriceUsd = rewardTokenAddress !== VOID_ETHEREUM_ADDRESS ? rewardTokenAddress.toLowerCase() === wusdAddress.toLowerCase() ? 1 : data[rewardTokenAddress.toLowerCase()].usd : ethPrice const mainTokenPriceUsd = mainTokenAddress !== VOID_ETHEREUM_ADDRESS ? mainTokenAddress.toLowerCase() === wusdAddress.toLowerCase() ? 1 : data[mainTokenAddress.toLowerCase()].usd : ethPrice const num = (parseInt(setup.rewardPerBlock) * 10 ** (18 - rewardTokenDecimals) * yearlyBlocks) * rewardTokenPriceUsd * 100 const den = (parseInt(setupInfo.maxStakeable) * 10 ** (18 - decimals) * mainTokenPriceUsd) * 2 return num / den } } catch (error) { return 0 } } const isWeth = (setupInfo, address) => { return address.toLowerCase() === ethereumAddress.toLowerCase() && setupInfo.involvingETH } const getPeriodFromDuration = (duration) => { const blockIntervals = context.blockIntervals const inv = Object.entries(blockIntervals).reduce((ret, entry) => { const [key, value] = entry ret[value] = key return ret }, {}) return inv[duration] } const activateSetup = async () => { if (!setupReady) return setActivateLoading(true) try { await blockchainCall(element.contract.methods.activateSetup, setup.infoIndex) await reloadData() } catch (error) { console.log(error) } finally { setActivateLoading(false) } } const onTokenApproval = (index, isLp) => { if (isLp) { setLpTokenInfo({ ...lpTokenInfo, approval: true }) return } setTokensApprovals(tokensApprovals.map((val, i) => i === index ? true : val)) try { if(setupInfo.minStakeable !== '0') { const index = setupTokens.indexOf(setupTokens.filter(it => web3Utils.toChecksumAddress(it.address) === web3Utils.toChecksumAddress(isWeth(setupInfo, setupInfo.mainTokenAddress) ? VOID_ETHEREUM_ADDRESS : setupInfo.mainTokenAddress))[0]) onUpdateTokenAmount(fromDecimals(setupInfo.minStakeable, setupTokens[index].decimals, true), index) } } catch(e) { } } function cleanSlippage(slippage) { slippage = numberToString(parseFloat(slippage || 0)) if(slippage === '0') { return 0 } var arr = slippage.split('.') if(arr.length > 1) { var n = parseFloat('0.' + arr[1]) slippage = numberToString(parseInt(arr[0]) + (n >= 0.5 ? 1 : 0)) } return parseInt(slippage) } ## ActivateSetup ``` function toggleSetup() { return blockchainCall(element.contract.methods.toggleSetup, setup.infoIndex) } const loadData = useCallback(async (farmSetup, farmSetupInfo, reset, loop) => { var position = null var lockPositions = [] reset && setLockedEstimatedReward(0) setUpdatedRenewTimes(farmSetupInfo.renewTimes) setUpdatedRewardPerBlock(farmSetup.rewardPerBlock) var positions = element.positions || [] var positionIds = positions.map(it => it.positionId) if(positions.length === 0) { const events = await getLogs(web3.currentProvider, 'eth_getLogs', { address: element.address, topics: [ web3.utils.sha3("Transfer(uint256,address,address)"), [], [], abi.encode(["address"], [account]) ], fromBlock: web3Utils.toHex(getNetworkElement({ context, chainId }, 'deploySearchStart')) || "0x0", toBlock: 'latest', }) positionIds = events.map(it => abi.decode(["uint256"], it.topics[1])[0].toString()) } for (const positionId of positionIds) { var pos = positions.filter(it => it.positionId === positionId)[0] || await loadFarmingPosition({ ...web3Data, context }, element.contract, positionId) if(!positions.filter(it => it.positionId === positionId)[0]) { var {'0': loadedSetup, '1': loadedSetupInfo} = await loadFarmingSetup({...web3Data, context}, element.contract, pos.setupIndex) loadedSetupInfo = {...loadedSetupInfo} loadedSetup = {...loadedSetup, setupIndex : pos.setupIndex, setupInfo : {...loadedSetupInfo}} pos = { ...pos, positionId, setup : {...loadedSetup} } } if (isValidPosition({ ...web3Data, context }, pos) && parseInt(pos.setup.setupIndex) === parseInt(setup.setupIndex)) { if (farmSetupInfo.free) { position = { ...pos, positionId } } else if (!positionIds.includes(positionId)) { lockPositions.push({ ...pos, positionId }) } } } setSetupMustBeToggled(farmSetup.active && parseInt(currentBlock) > parseInt(farmSetup.endBlock) && (parseInt(farmSetup.totalSupply) === 0 || position === undefined || position === null) && parseInt(farmSetupInfo.renewTimes) > 0) setCurrentPosition(position) setLockedPositions(lockPositions) if (!position && reset) { setOpen(false) setWithdrawOpen(false) } !extensionContract && setExtensionContract(element.extensionContract) const rewardToken = rewardTokenInfo || await loadTokenFromAddress({ context, ...web3Data, seaport }, await blockchainCall(element.contract.methods._rewardTokenAddress)) const rewardTokenApproval = await blockchainCall(rewardToken.contract.methods.allowance, account, element.address) setRewardTokenInfo(oldValue => ({ ...oldValue, ...rewardToken, approval: parseInt(rewardTokenApproval) !== 0 && parseInt(rewardTokenApproval) >= parseInt(rewardToken.balance) })) const tokenAddress = farmSetupInfo.liquidityPoolTokenAddress const lpToken = newContract(context.UniswapV3PoolABI, tokenAddress) if(!loop) { if(element.generation === 'gen1') { const lpToken = newContract(context.ERC20ABI, farmSetupInfo.liquidityPoolTokenAddress) const lpTokenSymbol = await lpToken.methods.symbol().call() const lpTokenDecimals = await lpToken.methods.decimals().call() const lpTokenBalance = await lpToken.methods.balanceOf(account).call() const lpTokenApproval = await lpToken.methods.allowance(account, element.contract.options.address).call() const info = await blockchainCall((await ammAggregatorPromise).ammAggregator.methods.findByLiquidityPool, tokenAddress) const ammAggregatorAddress = web3Utils.toChecksumAddress(info[3]) const amms = (await ammAggregatorPromise).amms const amm = amms.filter(it => it.address === ammAggregatorAddress)[0] const originalTokenAddresses = info[2].map(web3Utils.toChecksumAddress) const tokenAddresses = originalTokenAddresses.map(it => farmSetupInfo.involvingETH && it === amm.ethereumAddress ? VOID_ETHEREUM_ADDRESS : it) const tokens = await Promise.all(tokenAddresses.map(it => loadTokenFromAddress({ context, ...web3Data, seaport }, it))) const tokenValues = (await blockchainCall(amm.contract.methods.byLiquidityPoolAmount, farmSetupInfo.liquidityPoolTokenAddress, farmSetup.totalSupply))[0] setLpTokenInfo({ originalTokenAddresses, tokenAddresses, tokens, tokenValues, amm, contract: lpToken, symbol: lpTokenSymbol, decimals: lpTokenDecimals, balance: lpTokenBalance, approval: parseInt(lpTokenApproval) !== 0 && parseInt(lpTokenApproval) >= parseInt(lpTokenBalance) }) } else { const lpTokenSymbol = "UniV3" const lpTokenDecimals = "18" const lpTokenBalance = "0" const lpTokenApproval = "0" const fee = await blockchainCall(lpToken.methods.fee) const slot = await blockchainCall(lpToken.methods.slot0) var uniswapTokens = await Promise.all([ await blockchainCall(lpToken.methods.token0), await blockchainCall(lpToken.methods.token1) ].map(async tkAddress => { const currentToken = await loadTokenFromAddress({ context, ...web3Data, seaport }, tkAddress) return new Token(chainId, tkAddress, parseInt(currentToken.decimals), currentToken.symbol, currentToken.name) })) console.log("Slot", farmSetup.infoIndex, { tick: slot.tick, sqrtPriceX96: slot.sqrtPriceX96, tickLower : farmSetupInfo.tickLower, tickUpper : farmSetupInfo.tickUpper, fee, inRange : parseInt(farmSetupInfo.tickLower) >= parseInt(slot.tick) && parseInt(slot.tick) <= parseInt(farmSetupInfo.tickUpper) }) setLpTokenInfo({ uniswapTokens, fee, contract: lpToken, symbol: lpTokenSymbol, decimals: lpTokenDecimals, balance: lpTokenBalance, approval: parseInt(lpTokenApproval) !== 0 && parseInt(lpTokenApproval) >= parseInt(lpTokenBalance) }) } } const activateSetup = parseInt(farmSetupInfo.renewTimes) > 0 && !farmSetup.active && parseInt(farmSetupInfo.lastSetupIndex) === parseInt(setup.setupIndex) setCanActivateSetup(activateSetup) var startBlock = formatNumber(farmSetupInfo.startBlock || 0) setDelayedBlock(currentBlock > startBlock ? 0 : startBlock) setEndBlockReached(currentBlock > formatNumber(farmSetup.endBlock)) if(!loop) { const extensionBalance = await blockchainCall(rewardToken.contract.methods.balanceOf, element.extensionAddress) var extB = web3Utils.toBN(extensionBalance) var rwPB = web3Utils.toBN(farmSetup.rewardPerBlock) var bD = web3Utils.toBN(farmSetupInfo.blockDuration) var mul = rwPB.mul(bD) var ready = extB.gte(mul) ready = element.byMint || ready setSetupReady(ready) } var balances = ['0', '0'] var fees = ['0', '0'] if(element.generation === 'gen2') { try { ({balances, fees} = await simulateDecreaseLiquidityAndCollect(farmSetup.objectId, element.address)) } catch(e) { if(farmSetup.totalSupply !== '0') { try { const lpTokenEthers = new ethers.Contract(tokenAddress, context.UniswapV3PoolABI, ethersProvider) var data = await lpTokenEthers.callStatic.burn(farmSetupInfo.tickLower, farmSetupInfo.tickUpper, farmSetup.totalSupply, { from : getNetworkElement({ context, chainId }, "uniswapV3NonfungiblePositionManagerAddress") }) balances = [data.amount0.toString(), data.amount1.toString()] } catch(e) { console.log(e) } } } } if(element.generation === 'gen1' && lpTokenInfo) { balances = lpTokenInfo.tokenValues } const tokens = [...setupTokens] if(tokens.length === 0) { const liquidityPoolTokens = element.generation === 'gen2' ? await Promise.all([ blockchainCall(lpToken.methods.token0), blockchainCall(lpToken.methods.token1) ]) : (await blockchainCall((await ammAggregatorPromise).ammAggregator.methods.findByLiquidityPool, tokenAddress))[2] for (var i in liquidityPoolTokens) { const address = liquidityPoolTokens[i] const token = await loadTokenFromAddress({context, ...web3Data, seaport}, isWeth(farmSetupInfo, address) ? VOID_ETHEREUM_ADDRESS : address) tokens.push(token) } setSetupTokens(oldValue => (oldValue && oldValue.length > 0 && oldValue) || tokens) } const approvals = [] for(const i in tokens) { const token = tokens[i] token.balance = await blockchainCall(token.contract.methods.balanceOf, account) token.liquidity = balances[i] const approval = await blockchainCall(token.contract.methods.allowance, account, element.address) approvals.push(parseInt(approval) !== 0 && (parseInt(approval) >= parseInt(token.balance) || !token)) if (web3Utils.toChecksumAddress(token.address) === web3Utils.toChecksumAddress(farmSetupInfo.mainTokenAddress) || (web3Utils.toChecksumAddress(token.address) === VOID_ETHEREUM_ADDRESS && web3Utils.toChecksumAddress(farmSetupInfo.mainTokenAddress) === web3Utils.toChecksumAddress(farmSetupInfo.ethereumAddress))) { setMainTokenInfo(oldValue => ({...oldValue, ...token, approval: parseInt(approval) !== 0 && (parseInt(approval) >= parseInt(token.balance) || !token)})) } } setTokensApprovals(approvals) reset && setLpTokenAmount(null) reset && setTokenAmounts(new Array(tokens.length).fill(0)) // retrieve the manage data using the position if (position) { const free = position['free'] const creationBlock = position['creationBlock'] const positionSetupIndex = position['setupIndex'] const liquidityPoolTokenAmount = position['liquidityPoolTokenAmount'] const amounts = { tokenAmounts : [0, 0] } var additionalFees = ['0', '0'] try { var simulation = await simulateDecreaseLiquidityAndCollect(position.tokenId || farmSetup.objectId, element.address, position.liquidityPoolTokenAmount) amounts.tokenAmounts = simulation.liquidity additionalFees = simulation.fees } catch(e) { } if(element.generation === 'gen1') { const amm = (await ammAggregatorPromise).amms.filter(it => web3Utils.toChecksumAddress(it.address) === web3Utils.toChecksumAddress(setupInfo.ammPlugin))[0] const result = await blockchainCall(amm.contract.methods.byLiquidityPoolAmount, setupInfo.liquidityPoolTokenAddress, position.liquidityPoolTokenAmount) amounts.tokenAmounts = result[0] } console.log(position.positionId) const availableReward = await blockchainCall(element.contract.methods.calculateFreeFarmingReward, position.positionId, true) var freeReward = parseInt(availableReward) if (currentBlock < parseInt(farmSetup.endBlock)) { freeReward += (parseInt(farmSetup.rewardPerBlock) * (parseInt(position.liquidityPoolTokenAmount) / parseInt(farmSetup.totalSupply))) } freeReward = numberToString(freeReward).split('.')[0] setFreeAvailableRewards(freeReward) try { var result = await blockchainCall(element.contract.methods.calculateTradingFees, position.positionId, freeReward, fees[0], fees[1]) additionalFees = [ result[0], result[1] ] } catch(e) {} var withdrawOnly = !farmSetup.active || currentBlock > parseInt(farmSetup.endBlock) setManageStatus({ withdrawOnly, additionalFees, free, creationBlock, positionSetupIndex, liquidityPoolAmount: liquidityPoolTokenAmount, tokenAmounts: amounts['tokenAmounts'], tokens }) } // calculate APY setApy(await calculateApy(farmSetup, farmSetupInfo, rewardToken.address, rewardToken.decimals, tokens)) }, [setupTokens, account, currentBlock]) const reloadData = useCallback(async (noReset, loop) => { try { var { '0': farmSetup, '1': farmSetupInfo } = await loadFarmingSetup({ ...web3Data, context }, element.contract, setup.setupIndex) farmSetupInfo = {... farmSetupInfo, free : true, ethereumAddress : getNetworkElement({ context, chainId }, 'wethTokenAddress')} farmSetup = {... farmSetup, togglable : farmSetup.active && currentBlock > parseInt(farmSetup.endBlock)} farmSetup.setupIndex = setup.setupIndex farmSetup.setupInfo = farmSetupInfo setSetup(farmSetup) setSetupInfo(farmSetupInfo) setShowPrestoError(false) await loadData(farmSetup, farmSetupInfo, !noReset, loop) } catch (e) { console.log(e) } }, [element.address, setup && setup.setupIndex, loadData]) useEffect(() => { dequeue(intervalId) if(noInternalRefetch || !setupTokens || setupTokens.length === 0) { return } enqueue(intervalId, () => reloadData(true, true)) return () => dequeue(intervalId) }, [noInternalRefetch, reloadData, setupTokens]) async function simulateDecreaseLiquidityAndCollect(objectId, lmContractAddress, amount) { var nftPosMan = newContract(context.UniswapV3NonfungiblePositionManagerABI, getNetworkElement({ context, chainId }, "uniswapV3NonfungiblePositionManagerAddress")) var bytes = [ nftPosMan.methods.decreaseLiquidity({ tokenId : objectId, liquidity : amount || (await blockchainCall(nftPosMan.methods.positions, objectId)).liquidity, amount0Min : 0, amount1Min : 0, deadline: new Date().getTime() + 10000 }).encodeABI(), nftPosMan.methods.collect({ tokenId : objectId, recipient: lmContractAddress, amount0Max: MAX_UINT128, amount1Max: MAX_UINT128 }).encodeABI() ] var result = await nftPosMan.methods.multicall(bytes).call({ from : lmContractAddress }) var liquidity = web3.eth.abi.decodeParameters(["uint128", "uint128"], result[0]) var balances = web3.eth.abi.decodeParameters(["uint128", "uint128"], result[1]) var fees = [ web3Utils.toBN(balances[0]).sub(web3Utils.toBN(liquidity[0])).toString(), web3Utils.toBN(balances[1]).sub(web3Utils.toBN(liquidity[1])).toString(), ] return { liquidity, balances, fees } } ``` # Recalculate Fee Allowance ``` const recalculateFeeAllowance = useCallback(() => { setupTokens && setupTokens.length > 0 && feeData && (feeData.tokenToTransferOrBurnInApplication || feeData.tokenToTransferOrBurnInCreation) && setTimeout(async () => { setFeeData(oldValue => ({...oldValue, transferOrBurnAllowanceInCreation : undefined, transferOrBurnAllowanceInApplication : undefined})) async function allowed(token, operator, account, amount) { if(!token || token.address === VOID_ETHEREUM_ADDRESS || amount === '0') { return true } return parseInt(amount) <= parseInt(await blockchainCall(token.contract.methods.allowance, operator, account)) } feeData.transferOrBurnAllowanceInCreation = await allowed(feeData.tokenToTransferOrBurnInCreation, feeData.operator, account, feeData.transferOrBurnAmountInCreation) feeData.transferOrBurnAllowanceInApplication = await allowed(feeData.tokenToTransferOrBurnInCreation, feeData.operator, account, feeData.transferOrBurnAmountInApplication) var { data } = await getTokenPricesInDollarsOnCoingecko({ context, web3Data }, feeData.tokenToTransferOrBurnAddressInApplication) data = data[feeData.tokenToTransferOrBurnAddressInApplication.toLowerCase()].usd data *= parseFloat(fromDecimals(feeData.transferOrBurnAmountInApplication, feeData.tokenToTransferOrBurnInApplication.decimals, true)) const burnFeePrice = data if(feeData.feePercentageForTransacted === '0') { return setFeeType("burn") } const events = await getLogs(web3.currentProvider, 'eth_getLogs', { address: element.address, topics: [ web3.utils.sha3("Transfer(uint256,address,address)"), [], [], abi.encode(["address"], [account]) ], fromBlock: web3Utils.toHex(getNetworkElement({ context, chainId }, 'deploySearchStart')) || "0x0", toBlock: 'latest', }) var positionId = events.map(it => abi.decode(["uint256"], it.topics[1])[0].toString()) try { positionId = positionId[positionId.length - 1] if(!positionId) { return } const position = await loadFarmingPosition({ ...web3Data, context }, element.contract, positionId) const simulation = await simulateDecreaseLiquidityAndCollect(position.tokenId, element.address, position.liquidityPoolTokenAmount) console.log({simulation}) var { data } = await getTokenPricesInDollarsOnCoingecko({ context, web3Data }, setupTokens.map(it => it.address)) data = setupTokens.map(it => data[it.address.toLowerCase()].usd || data[it.address.toLowerCase()] || 0) data = data.map((it, i) => it * parseFloat(fromDecimals(simulation.fees[i], setupTokens[i].decimals, true))) data = data.reduce((acc, i) => acc + i, 0) if(data <= burnFeePrice) { return setFeeType("percentage") } } catch(e) { } }) }, [feeData && feeData.transferOrBurnTypeInApplication, setupTokens, account]) useEffect(recalculateFeeAllowance, [recalculateFeeAllowance]) ``` ## UseEffects useEffect(() => blockchainCall(element.contract.methods.initializer).then(factoryAddress => blockchainCall(newContract(context.EthereansFactoryABI, factoryAddress).methods.feeInfo)).then(result => void(setFeeData(result), reloadData())), []) useEffect(() => { updateEthAmount(ethAmount) }, [receiver, selectedAmmIndex]) useEffect(() => element.generation === 'gen2' && calculateSlippageAmounts(slippage, lpTokenAmount).then(setAmountsMin), [element.generation, slippage, lpTokenAmount]) useEffect(() => { if(element.generation !== 'gen1' || !tokenAmounts || tokenAmounts.length === 0) { return setAmountsMin(['0', '0']) } const arr = [ numberToString(parseInt(tokenAmounts[0].full || tokenAmounts[0]) * (100 - parseFloat(slippage)) / 100).split('.')[0], numberToString(parseInt(tokenAmounts[1].full || tokenAmounts[1]) * (100 - parseFloat(slippage)) / 100).split('.')[0] ] setAmountsMin(arr) }, [element.generation, tokenAmounts, slippage]) useEffect(() => setTimeout(async () => { if(element.generation === 'gen1') { try { var tickData = { diluted : true, maxPrice : 0, minPrice : 9999999, currentPrice : 0, cursorNumber : 50, outOfRangeLower : 0, outOfRangeUpper : 99999999, tickLowerUSDPrice : 0, tickUpperUSDPrice : 0, tickCurrentUSDPrice : 0 } const tokenIndex = secondTokenIndex const value = formatNumber(fromDecimals(lpTokenInfo.tokenValues[tokenIndex], lpTokenInfo.tokens[tokenIndex].decimals, true)) const price = Object.values((await getTokenPricesInDollarsOnCoingecko({context, web3Data}, lpTokenInfo.tokenAddresses[tokenIndex])).data)[0] const usdPrice = price tickData.tickCurrentUSDPrice = usdPrice setTickData(tickData) } catch(e) { } } if(element.generation === 'gen2') { try { var slot = await blockchainCall(lpTokenInfo.contract.methods.slot0) var a = formatNumber(tickToPrice(lpTokenInfo.uniswapTokens[0], lpTokenInfo.uniswapTokens[1], parseInt(setupInfo.tickLower)).toSignificant(15)) var b = formatNumber(tickToPrice(lpTokenInfo.uniswapTokens[0], lpTokenInfo.uniswapTokens[1], parseInt(setupInfo.tickUpper)).toSignificant(15)) var c = formatNumber(tickToPrice(lpTokenInfo.uniswapTokens[0], lpTokenInfo.uniswapTokens[1], parseInt(slot.tick)).toSignificant(15)) var diluted = Math.abs(parseInt(setupInfo.tickUpper) - parseInt(setupInfo.tickLower)) >= 180000 var tickData = { diluted, maxPrice : tickToPrice(lpTokenInfo.uniswapTokens[1 - secondTokenIndex], lpTokenInfo.uniswapTokens[secondTokenIndex], parseInt(setupInfo.tickLower)).toSignificant(4), minPrice : tickToPrice(lpTokenInfo.uniswapTokens[1 - secondTokenIndex], lpTokenInfo.uniswapTokens[secondTokenIndex], parseInt(setupInfo.tickUpper)).toSignificant(4), currentPrice : tickToPrice(lpTokenInfo.uniswapTokens[1 - secondTokenIndex], lpTokenInfo.uniswapTokens[secondTokenIndex], parseInt(slot.tick)).toSignificant(4), cursorNumber : !(c > a) ? 100 : !(c < b) ? 0 : null, outOfRangeLower : parseInt(slot.tick) <= parseInt(setupInfo.tickLower), outOfRangeUpper : parseInt(slot.tick) >= parseInt(setupInfo.tickUpper), tickLowerUSDPrice : 0, tickUpperUSDPrice : 0, tickCurrentUSDPrice : 0 } if(secondTokenIndex === 1) { var maxPrice = tickData.maxPrice tickData.maxPrice = tickData.minPrice tickData.minPrice = maxPrice } if(tickData.cursorNumber !== 0 && tickData.cursorNumber !== 100) { tickData.cursorNumber = (1 / ((Math.sqrt(a * b) - Math.sqrt(b * c)) / (c - Math.sqrt(b * c)) + 1)) * 100 } tickData.cursor = formatMoneyUniV3(secondTokenIndex === 1 ? 100 - tickData.cursorNumber : tickData.cursorNumber, 2) var tokensForPrice = lpTokenInfo.uniswapTokens.map(it => it.address === ethereumAddress ? VOID_ETHEREUM_ADDRESS : it.address) var ethIndex = tokensForPrice.indexOf(VOID_ETHEREUM_ADDRESS) if(ethIndex !== -1) { var ethPrice = await getEthereumPrice({ context }) tickData.tickLowerUSDPrice = formatNumber(tickToPrice(lpTokenInfo.uniswapTokens[1 - ethIndex], lpTokenInfo.uniswapTokens[ethIndex], parseInt(setupInfo.tickLower)).toSignificant(15)) * ethPrice tickData.tickUpperUSDPrice = formatNumber(tickToPrice(lpTokenInfo.uniswapTokens[1 - ethIndex], lpTokenInfo.uniswapTokens[ethIndex], parseInt(setupInfo.tickUpper)).toSignificant(15)) * ethPrice tickData.tickCurrentUSDPrice = formatNumber(tickToPrice(lpTokenInfo.uniswapTokens[1 - ethIndex], lpTokenInfo.uniswapTokens[ethIndex], parseInt(slot.tick)).toSignificant(15)) * ethPrice tickData.cursor = formatMoneyUniV3(ethIndex === 1 ? 100 - tickData.cursorNumber : tickData.cursorNumber, 2) } setTickData(tickData) } catch(e) { } } }), [lpTokenInfo, secondTokenIndex, setupInfo]) useEffect(() => { setReceiver() setMinimumStakingError() }, [open]) useEffect(() => { if(!open || !setupInfo || setupInfo.minStakeable === '0' || !setupTokens || setupTokens.length === 0 || !tokenAmounts || tokenAmounts.length === 0 || (tokenAmounts.filter(it => parseInt(it.full || it) === 0).length === 2 && minimumStakingError !== undefined && minimumStakingError !== null)) { return } const index = setupTokens.indexOf(setupTokens.filter(it => web3Utils.toChecksumAddress(it.address) === web3Utils.toChecksumAddress(isWeth(setupInfo, setupInfo.mainTokenAddress) ? VOID_ETHEREUM_ADDRESS : setupInfo.mainTokenAddress))[0]) const value = parseInt(tokenAmounts[index].full || tokenAmounts[index]) if(value < parseInt(setupInfo.minStakeable)) { if(minimumStakingError !== undefined && minimumStakingError !== null) { minimumStakingErrorTimeout.current && clearTimeout(minimumStakingErrorTimeout.current) setMinimumStakingError(`${setupTokens[index].symbol} value has been reset to the minimum amount of ${fromDecimals(setupInfo.minStakeable, setupTokens[index].decimals)}`) minimumStakingErrorTimeout.current = setTimeout(() => setMinimumStakingError(""), 2500) } else { setMinimumStakingError("") } return onUpdateTokenAmount(fromDecimals(setupInfo.minStakeable, setupTokens[index].decimals, true), index) } }, [setupTokens, setupInfo, tokenAmounts, open, minimumStakingError]) useEffect(() => { feeData && !feeData.transferOrBurnTypeInApplication && !feeData.transferOrBurnTypeInCreation && setTimeout(async () => { const tokenToTransferOrBurnInApplication = feeData.tokenToTransferOrBurnAddressInApplication !== VOID_ETHEREUM_ADDRESS && await loadTokenFromAddress({context, ...web3Data, seaport}, feeData.tokenToTransferOrBurnAddressInApplication) const tokenToTransferOrBurnInCreation = feeData.tokenToTransferOrBurnAddressInCreation !== VOID_ETHEREUM_ADDRESS && await loadTokenFromAddress({context, ...web3Data, seaport}, feeData.tokenToTransferOrBurnAddressInCreation) const transferOrBurnTypeInApplication = feeData.transferOrBurnReceiverInApplication === VOID_ETHEREUM_ADDRESS ? 'burn' : 'transfer' const transferOrBurnTypeInCreation = feeData.transferOrBurnReceiverInCreation === VOID_ETHEREUM_ADDRESS ? 'burn' : 'transfer' setFeeData(oldValue => ({...oldValue, tokenToTransferOrBurnInApplication, tokenToTransferOrBurnInCreation, transferOrBurnTypeInApplication, transferOrBurnTypeInCreation})) }) }, [feeData]) useEffect(() => { feeData && console.log("Fee data", feeData) feeType !== 'burn' && setBurnFeeAllowance() feeData && (feeData.transferOrBurnTypeInApplication || feeData.transferOrBurnTypeInCreation) && feeData.tokenToTransferOrBurnAddressInApplication !== VOID_ETHEREUM_ADDRESS && feeType === 'burn' && setTimeout(async () => { setBurnFeeAllowance(parseInt(await blockchainCall(feeData.tokenToTransferOrBurnInApplication.contract.methods.allowance, account, feeData.operator)) < parseInt(feeData.transferOrBurnAmountInApplication)) }) }, [feeData, feeType, account]) useEffect(setSettings, [open, edit, withdrawOpen]) # AMM aggregator promise & getFarmingPrestoAddress const ammAggregatorPromise = useMemo(() => new Promise(async ok => { var amms = [] const ammAggregator = newContract(context.AMMAggregatorABI, getNetworkElement({ context, chainId }, 'ammAggregatorAddress')) const ammAddresses = (await ammAggregator.methods.amms().call()).map(web3Utils.toChecksumAddress) for (var address of ammAddresses) { const ammContract = newContract(context.AMMABI, address) const amm = { address, contract: ammContract, info: await ammContract.methods.info().call(), data: await ammContract.methods.data().call() } amm.name = amm.info[0] amm.ethereumAddress = web3Utils.toChecksumAddress(amm.data[0]) amm.data[2] && amms.push(amm) } setSelectedAmmIndex(0) const uniswap = amms.filter(it => it.info[0] === 'UniswapV2')[0] const index = amms.indexOf(uniswap) amms.splice(index, 1) amms.unshift(uniswap) ok({ ammAggregator, amms }) }), [chainId]) function getFarmingPrestoAddress() { var prestoAddress = getNetworkElement({ context, chainId }, "farmingPrestoAddress") var oldPrestoAddress = getNetworkElement({ context, chainId }, "farmingPrestoAddressOld") var oldFarmingPrestoContracts = getNetworkElement({ context, chainId }, "oldFarmingPrestoContracts").map(it => web3Utils.toChecksumAddress(it)) var lmContractAddress = web3Utils.toChecksumAddress(element.address) return oldFarmingPrestoContracts.indexOf(lmContractAddress) === -1 ? prestoAddress : oldPrestoAddress } const farmingPresto = useMemo(() => newContract(context.FarmingPrestoABI, getFarmingPrestoAddress()), [chainId]) # Imports and State definitions import React, { useRef, useEffect, useState, useMemo, useCallback } from 'react' import { tickToPrice, Pool, Position, nearestUsableTick, TICK_SPACINGS, TickMath, maxLiquidityForAmounts } from '@uniswap/v3-sdk/dist/' import { Token, Percent } from "@uniswap/sdk-core/dist" import OurCircularProgress from '../../Global/OurCircularProgress' import LogoRenderer from '../../Global/LogoRenderer' import ActionAWeb3Button from '../../Global/ActionAWeb3Button' import TokenInputRegular from '../../Global/TokenInputRegular' import RegularButtonDuo from '../../Global/RegularButtonDuo' import { formatMoney, blockchainCall, getTokenPricesInDollarsOnCoingecko, ethers, sendAsync, isEthereumAddress, getEthereumPrice, normalizeValue, formatMoneyUniV3, useWeb3, useEthosContext, getNetworkElement, web3Utils, abi, VOID_ETHEREUM_ADDRESS, toDecimals, fromDecimals, numberToString, formatNumber, getTokenPriceInDollarsOnUniswap } from '@ethereansos/interfaces-core' import { loadFarmingSetup, loadFarmingPosition, isValidPosition, addLiquidityGen2 } from '../../../logic/farming' import { loadTokenFromAddress } from '../../../logic/erc20' import { getLogs } from '../../../logic/logger' import { enqueue, dequeue } from '../../../logic/interval' import style from '../../../all.module.css' import { resolveToken } from '../../../logic/dualChain' import { useOpenSea } from '../../../logic/uiUtilities' const MAX_UINT128 = '0x' + web3Utils.toBN(2).pow(web3Utils.toBN(128)).sub(web3Utils.toBN(1)).toString('hex') const MAX_UINT256 = '0x' + web3Utils.toBN(2).pow(web3Utils.toBN(256)).sub(web3Utils.toBN(1)).toString('hex') const contracts = [ "0x3889ABE350A054701e8ea55055CcD960cB4cB91a", "0x679780Ea3133C388E3c7efeb22e98a68Ccf99aFf" ].map(web3Utils.toChecksumAddress) export default props => { const { element, setupInput, refresh, noInternalRefetch } = props const context = useEthosContext() const seaport = useOpenSea() const web3Data = useWeb3() const { web3, account, chainId, newContract, block, dualChainId, dualBlock } = web3Data const currentBlock = useMemo(() => parseInt(dualBlock || block), [block, dualBlock]) const ethersProvider = useMemo(() => new ethers.providers.Web3Provider(web3.currentProvider), [web3]) // general info and setup data const [setup, setSetup] = useState(setupInput) const [setupInfo, setSetupInfo] = useState(setupInput.setupInfo) const [activateLoading, setActivateLoading] = useState(false) const [transferLoading, setTransferLoading] = useState(false) const [approveLoading, setApproveLoading] = useState() // panel status const [open, setOpen] = useState(false) const [edit, setEdit] = useState(false) const [withdrawOpen, setWithdrawOpen] = useState(false) const [showFreeTransfer, setShowFreeTransfer] = useState(false) const [canActivateSetup, setCanActivateSetup] = useState(false) const [setupReady, setSetupReady] = useState(false) const [showPrestoError, setShowPrestoError] = useState(false) // amm data const [AMM, setAMM] = useState({ name: "", version: "" }) const [ammContract, setAmmContract] = useState(null) const [freeTransferAddress, setFreeTransferAddress] = useState("") const [extensionContract, setExtensionContract] = useState(null) const [farmTokenDecimals, setFarmTokenDecimals] = useState(18) const [farmTokenERC20Address, setFarmTokenERC20Address] = useState("") const [farmTokenSymbol, setFarmTokenSymbol] = useState("") const [farmTokenBalance, setFarmTokenBalance] = useState("0") const [farmTokenRes, setFarmTokenRes] = useState([]) const [setupTokens, setSetupTokens] = useState([]) const [tokenAmounts, setTokenAmounts] = useState([]) const [tokensApprovals, setTokensApprovals] = useState([]) const [lpTokenAmount, setLpTokenAmount] = useState(null) const [lockedEstimatedReward, setLockedEstimatedReward] = useState(0) const [freeEstimatedReward, setFreeEstimatedReward] = useState(0) const [lpTokenInfo, setLpTokenInfo] = useState(null) const [mainTokenInfo, setMainTokenInfo] = useState(null) const [rewardTokenInfo, setRewardTokenInfo] = useState(null) const [removalAmount, setRemovalAmount] = useState(0) const [currentPosition, setCurrentPosition] = useState(null) const [manageStatus, setManageStatus] = useState(null) const [freeAvailableRewards, setFreeAvailableRewards] = useState(0) const [lockedPositions, setLockedPositions] = useState([]) const [lockedPositionStatuses, setLockedPositionStatuses] = useState([]) const [lockedPositionRewards, setLockedPositionRewards] = useState([]) const [updatedRewardPerBlock, setUpdatedRewardPerBlock] = useState(0) const [updatedRenewTimes, setUpdatedRenewTimes] = useState(0) const [receiver, setReceiver] = useState() const [apy, setApy] = useState(0) const [inputType, setInputType] = useState("add-pair") const [outputType, setOutputType] = useState("to-pair") const [ethAmount, setEthAmount] = useState(0) const [ethBalanceOf, setEthBalanceOf] = useState("0") const intervalId = useMemo(() => new Date().getTime() + '_' + (new Date().getTime() * Math.random()), []) const updateAmountTimeout = useRef(null) const minimumStakingErrorTimeout = useRef(null) const [prestoData, setPrestoData] = useState(null) const [selectedAmmIndex, setSelectedAmmIndex] = useState(0) const [amms, setAmms] = useState(0) const [loadingPrestoData, setLoadingPrestoData] = useState(false) const [delayedBlock, setDelayedBlock] = useState(0) const [endBlockReached, setEndBlockReached] = useState(false) const [secondTokenIndex, setsecondTokenIndex] = useState(0) const [tickData, setTickData] = useState({cursorNumber : 50}) const ethereumAddress = getNetworkElement({ context, chainId }, "wethTokenAddress") const [settings, setSettings] = useState(false) const [slippage, setSlippage] = useState(3) const [amountsMin, setAmountsMin] = useState(['0', '0']) const [minimumStakingError, setMinimumStakingError] = useState() const [feeType, setFeeType] = useState("percentage") const [feeData, setFeeData] = useState() const [burnFeeAllowance, setBurnFeeAllowance] = useState() const [setupMustBeToggled, setSetupMustBeToggled] = useState()