Try   HackMD

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()