From 358876b4099d649479bcdc88cbf26a045dbb9bad Mon Sep 17 00:00:00 2001 From: CAPtheorem <79423264+CAPtheorem@users.noreply.github.com> Date: Tue, 12 Apr 2022 16:49:26 -0700 Subject: [PATCH 1/3] add GasEsimationApproval logic --- .../src/containers/wallet/token/Token.js | 19 ++++++ .../gateway/src/services/networkService.js | 60 +++++++++++++++++++ 2 files changed, 79 insertions(+) diff --git a/packages/boba/gateway/src/containers/wallet/token/Token.js b/packages/boba/gateway/src/containers/wallet/token/Token.js index b465e6f031..0356dafe3d 100644 --- a/packages/boba/gateway/src/containers/wallet/token/Token.js +++ b/packages/boba/gateway/src/containers/wallet/token/Token.js @@ -10,11 +10,14 @@ import { selectTokens } from 'selectors/tokenSelector' import * as S from './Token.styles' import { tokenTableHeads } from './token.tableHeads' import ListToken from 'components/listToken/listToken' +import Button from 'components/button/Button' import lightLoader from 'images/boba2/loading_light.gif' import darkLoader from 'images/boba2/loading_dark.gif' import Link from 'components/icons/LinkIcon' +import networkService from 'services/networkService' + function TokenPage() { const dispatch = useDispatch() @@ -61,6 +64,13 @@ function TokenPage() { getLookupPrice() }, [ getLookupPrice, accountEnabled ]) + const GasEstimateApprove = () => { + let approval = networkService.estimateApprove() + console.log("GasEstimateApprove:",approval) + } + + const debug = false + if (!accountEnabled) { return ( @@ -101,6 +111,15 @@ function TokenPage() { >Oolongswap + {debug && + + } } diff --git a/packages/boba/gateway/src/services/networkService.js b/packages/boba/gateway/src/services/networkService.js index 334cbf1868..e9e9de3b07 100644 --- a/packages/boba/gateway/src/services/networkService.js +++ b/packages/boba/gateway/src/services/networkService.js @@ -650,6 +650,7 @@ class NetworkService { if (!(await this.getAddressCached(addresses, 'DiscretionaryExitBurn', 'DiscretionaryExitBurn'))) return if (!(await this.getAddressCached(addresses, 'Proxy__BobaFixedSavings', 'BobaFixedSavings'))) return if (!(await this.getAddressCached(addresses, 'Proxy__Boba_GasPriceOracle', 'Boba_GasPriceOracle'))) return + if (!(await this.getAddressCached(addresses, 'DiscretionaryExitFee', 'DiscretionaryExitFee'))) return // not critical this.getAddressCached(addresses, 'BobaAirdropL1', 'BobaAirdropL1') @@ -4049,6 +4050,65 @@ class NetworkService { } } + async estimateApprove() { + + const approvalAmount = utils.parseEther('10.0') + + let allowance_BN = await this.BobaContract + .connect(this.provider.getSigner()) + .allowance( + this.account, + allAddresses.BobaFixedSavings + ) + console.log("Fixed Savings Allowance", allowance_BN.toString()) + + let approveStatus = await this.BobaContract + .connect(this.provider.getSigner()) + .approve( + allAddresses.BobaFixedSavings, + approvalAmount + ) + await approveStatus.wait() + console.log("Fixed Savings Approval", approveStatus) + + // DiscretionaryExitFee: 0x583963636aa1344B9A609b34E1C9e7b5603df0A5 + allowance_BN = await this.BobaContract + .connect(this.provider.getSigner()) + .allowance( + this.account, + allAddresses.DiscretionaryExitFee + ) + console.log("DiscretionaryExitFee Allowance", allowance_BN.toString()) + + approveStatus = await this.BobaContract + .connect(this.provider.getSigner()) + .approve( + allAddresses.DiscretionaryExitFee, + approvalAmount + ) + await approveStatus.wait() + console.log("DiscretionaryExitFee Approval", approveStatus) + + // L2LP + allowance_BN = await this.BobaContract + .connect(this.provider.getSigner()) + .allowance( + this.account, + allAddresses.L2LPAddress + ) + console.log("L2LP", allowance_BN.toString()) + + approveStatus = await this.BobaContract + .connect(this.provider.getSigner()) + .approve( + allAddresses.L2LPAddress, + approvalAmount + ) + await approveStatus.wait() + console.log("L2LP", approveStatus) + + } + async getFS_Info() { if(this.account === null) { From b0d9a428976ce376b074076aff31426644799422 Mon Sep 17 00:00:00 2001 From: cby3149 Date: Tue, 12 Apr 2022 20:07:55 -0700 Subject: [PATCH 2/3] Add Boba exit fee --- .../boba/gateway/src/actions/balanceAction.js | 4 + .../modals/exit/steps/DoExitStep.js | 58 ++++--- .../modals/exit/steps/DoExitStepFast.js | 55 ++++--- .../gateway/src/reducers/balanceReducer.js | 12 +- .../gateway/src/selectors/balanceSelector.js | 4 + .../gateway/src/services/networkService.js | 144 ++++++++++++++---- 6 files changed, 201 insertions(+), 76 deletions(-) diff --git a/packages/boba/gateway/src/actions/balanceAction.js b/packages/boba/gateway/src/actions/balanceAction.js index de70c0bec5..76a76d8522 100644 --- a/packages/boba/gateway/src/actions/balanceAction.js +++ b/packages/boba/gateway/src/actions/balanceAction.js @@ -81,3 +81,7 @@ export function fetchL2BalanceBOBA() { export function fetchUserAndL2LPBalanceBatch(tokenList) { return createAction('FETCH/USER/L2LP/BALANCE/BATCH', () => networkService.getL2UserAndLPBalanceBatch(tokenList)) } + +export function fetchExitFee() { + return createAction('FETCH/EXITFEE', () => networkService.getExitFeeFromBillingContract()) +} diff --git a/packages/boba/gateway/src/containers/modals/exit/steps/DoExitStep.js b/packages/boba/gateway/src/containers/modals/exit/steps/DoExitStep.js index fa593f6b94..5a0949b7e3 100644 --- a/packages/boba/gateway/src/containers/modals/exit/steps/DoExitStep.js +++ b/packages/boba/gateway/src/containers/modals/exit/steps/DoExitStep.js @@ -43,16 +43,18 @@ import parse from 'html-react-parser' import BN from 'bignumber.js' -import { +import { fetchClassicExitCost, - fetchL2BalanceETH, - fetchL2BalanceBOBA, + fetchL2BalanceETH, + fetchL2BalanceBOBA, + fetchExitFee, } from 'actions/balanceAction' -import { +import { selectClassicExitCost, //estimated total cost of this exit selectL2BalanceETH, selectL2BalanceBOBA, + selectExitFee, } from 'selectors/balanceSelector' function DoExitStep({ handleClose, token }) { @@ -82,13 +84,15 @@ function DoExitStep({ handleClose, token }) { const feeUseBoba = useSelector(selectBobaFeeChoice()) const feePriceRatio = useSelector(selectBobaPriceRatio()) + const exitFee = useSelector(selectExitFee) + function setAmount(value) { const balance = Number(logAmount(token.balance, token.decimals)) const tooSmall = new BN(value).lte(new BN(0.0)) const tooBig = new BN(value).gt(new BN(max_Float)) - + setErrorString('') if (tooSmall || tooBig) { @@ -96,11 +100,11 @@ function DoExitStep({ handleClose, token }) { setValidValue(false) setValue(value) return false - } + } else if ( !feeUseBoba && // check is needed regardless of fee token choice - token.symbol === 'ETH' && - (Number(value) + feeETH) > balance) + token.symbol === 'ETH' && + (Number(value) + feeETH) > balance) { // insufficient ETH to cover the ETH amount plus gas // due to MetaMask issue, this is needed even if you are paying in ETH @@ -111,8 +115,8 @@ function DoExitStep({ handleClose, token }) { } else if ( feeUseBoba && // check is needed regardless of fee token choice - token.symbol === 'ETH' && - (Number(value) + feeETH) > balance) + token.symbol === 'ETH' && + (Number(value) + feeETH) > balance) { // insufficient ETH to cover the ETH amount plus gas // due to MetaMask issue, this is needed even if you are paying in ETH @@ -123,8 +127,8 @@ function DoExitStep({ handleClose, token }) { } else if ( feeUseBoba && - token.symbol === 'BOBA' && - (Number(value) + feeBOBA) > balance) + token.symbol === 'BOBA' && + (Number(value) + feeBOBA) > balance) { // insufficient BOBA to cover the BOBA amount plus gas setErrorString('Warning: BOBA amount + fees > balance') @@ -134,7 +138,7 @@ function DoExitStep({ handleClose, token }) { } else if ( !feeUseBoba && - feeETH > Number(feeBalanceETH)) + feeETH > Number(feeBalanceETH)) { // insufficient ETH to cover exit fees setErrorString('Warning: ETH balance too low.') @@ -144,7 +148,7 @@ function DoExitStep({ handleClose, token }) { } else if ( feeUseBoba && - feeETH > Number(feeBalanceETH)) + feeETH > Number(feeBalanceETH)) { // insufficient ETH to cover exit fees setErrorString('Warning: ETH balance too low. Even if you pay in BOBA, you still need to maintain a minimum ETH balance in your wallet.') @@ -154,7 +158,7 @@ function DoExitStep({ handleClose, token }) { } else if ( feeUseBoba && - feeBOBA > Number(feeBalanceBOBA)) + feeBOBA > Number(feeBalanceBOBA)) { // insufficient BOBA to cover exit fees setErrorString('Warning: BOBA balance too low') @@ -208,13 +212,14 @@ function DoExitStep({ handleClose, token }) { dispatch(fetchClassicExitCost(token.address)) dispatch(fetchL2BalanceETH()) dispatch(fetchL2BalanceBOBA()) + dispatch(fetchExitFee()) } }, [ token, dispatch ]) useEffect(() => { function estimateMax() { - + const safeCost = Number(cost) * 1.04 // 1.04 = safety margin on the cost console.log("ETH fees:", safeCost) console.log("BOBA fees:", safeCost * feePriceRatio) @@ -230,13 +235,13 @@ function DoExitStep({ handleClose, token }) { setMax_Float(balance - safeCost) else setMax_Float(0.0) - } + } else if (token.symbol === 'BOBA' && feeUseBoba) { if(balance - safeCost > 0.0) setMax_Float(balance - safeCost) else setMax_Float(0.0) - } + } else { setMax_Float(balance) } @@ -248,17 +253,17 @@ function DoExitStep({ handleClose, token }) { if(feeETH && Number(feeETH) > 0) { if(feeUseBoba) { - ETHstring = `Estimated gas (approval + exit): ${Number(feeBOBA).toFixed(4)} BOBA` + ETHstring = `Estimated gas (approval + exit): ${Number(feeBOBA).toFixed(4)} BOBA` } else { - ETHstring = `Estimated gas (approval + exit): ${Number(feeETH).toFixed(4)} ETH` + ETHstring = `Estimated gas (approval + exit): ${Number(feeETH).toFixed(4)} ETH` } } - // prohibit ExitAll when paying with the token that is to be exited + // prohibit ExitAll when paying with the token that is to be exited let allowExitall = true if(token.symbol === 'ETH') { allowExitall = false - } + } else if (token.symbol === 'BOBA' && feeUseBoba) { allowExitall = false } @@ -281,6 +286,7 @@ function DoExitStep({ handleClose, token }) { setValue_Wei_String(toWei_String(i.target.value, token.decimals)) }} onUseMax={(i)=>{//they want to use the maximum + console.log(i) setAmount(max_Float) //so the display value updates for the user setValue_Wei_String(token.balance.toString()) }} @@ -304,11 +310,15 @@ function DoExitStep({ handleClose, token }) { on L1. Your funds will be available on L1 in 7 days.`} )} - + {parse(ETHstring)} - + + + {parse(`Exit Fee: ${exitFee} BOBA`)} + + {errorString !== '' && {errorString} diff --git a/packages/boba/gateway/src/containers/modals/exit/steps/DoExitStepFast.js b/packages/boba/gateway/src/containers/modals/exit/steps/DoExitStepFast.js index de4a578122..8d5b861241 100644 --- a/packages/boba/gateway/src/containers/modals/exit/steps/DoExitStepFast.js +++ b/packages/boba/gateway/src/containers/modals/exit/steps/DoExitStepFast.js @@ -45,7 +45,8 @@ import { fetchL1FeeRateN, fetchL2BalanceBOBA, fetchL2BalanceETH, - fetchL1LPLiquidity + fetchL1LPLiquidity, + fetchExitFee, } from 'actions/balanceAction' import { @@ -56,7 +57,8 @@ import { selectL1LPPendingString, selectL2BalanceBOBA, selectL2BalanceETH, - selectL1LPLiquidity + selectL1LPLiquidity, + selectExitFee, } from 'selectors/balanceSelector' import { @@ -104,9 +106,11 @@ function DoExitStepFast({ handleClose, token }) { const lpUnits = logAmount(LPBalance, token.decimals) const balanceSubPending = lpUnits - logAmount(LPPending, token.decimals) //subtract the in flight exits + const exitFee = useSelector(selectExitFee) + function setAmount(value) { - const balance = Number(logAmount(token.balance, token.decimals)) + const balance = Number(logAmount(token.balance, token.decimals)) const tooSmall = new BN(value).lte(new BN(0.0)) const tooBig = new BN(value).gt(new BN(max_Float)) @@ -118,9 +122,9 @@ function DoExitStepFast({ handleClose, token }) { setValidValue(false) setValue(value) return false - } + } else if ( - token.symbol === 'ETH' && + token.symbol === 'ETH' && (Number(value) + feeETH) > balance) { if(feeUseBoba) setErrorString('Warning: ETH amount + fees > balance. Even if you pay in BOBA, you still need to maintain a minimum ETH balance in your wallet') @@ -133,8 +137,8 @@ function DoExitStepFast({ handleClose, token }) { else if ( //pay BOBA, exit BOBA - check BOBA amount feeUseBoba && - token.symbol === 'BOBA' && - (Number(value) + feeBOBA) > balance) + token.symbol === 'BOBA' && + (Number(value) + feeBOBA) > balance) { // insufficient BOBA to cover the BOBA amount plus gas setErrorString('Warning: BOBA amount + fees > balance') @@ -145,7 +149,7 @@ function DoExitStepFast({ handleClose, token }) { else if ( // insufficient ETH to cover exit fees // it does not matter if you are paying in ETH or BOBA - feeETH > Number(feeBalanceETH)) + feeETH > Number(feeBalanceETH)) { // insufficient ETH to cover exit fees if(feeUseBoba) @@ -159,13 +163,13 @@ function DoExitStepFast({ handleClose, token }) { else if ( // insufficient BOBA to cover exit fees feeUseBoba && - feeBOBA > Number(feeBalanceBOBA)) + feeBOBA > Number(feeBalanceBOBA)) { setErrorString('Warning: BOBA balance too low to cover gas') setValidValue(false) setValue(value) return false - } + } else if (Number(LPRatio) < 0.1) { // not enough balance/liquidity ratio // we always want some balance for unstaking @@ -173,7 +177,7 @@ function DoExitStepFast({ handleClose, token }) { setValidValue(false) setValue(value) return false - } + } else if (Number(value) > Number(balanceSubPending) * 0.9) { //not enough absolute balance //we don't want one large bridge to wipe out all the balance @@ -200,7 +204,7 @@ function DoExitStepFast({ handleClose, token }) { async function doExit() { console.log("Amount to exit:", value_Wei_String) - + let res = await dispatch( depositL2LP( token.address, @@ -231,6 +235,7 @@ function DoExitStepFast({ handleClose, token }) { dispatch(fetchFastExitCost(token.address)) dispatch(fetchL2BalanceETH()) dispatch(fetchL2BalanceBOBA()) + dispatch(fetchExitFee()) } // to clean up state and fix the // error in console for max state update. @@ -258,9 +263,9 @@ function DoExitStepFast({ handleClose, token }) { useEffect(() => { function estimateMax() { - + const safeCost = Number(cost) * 1.04 // 1.04 = safety margin on the cost - + //console.log("ETH fees:", safeCost) //console.log("BOBA fees:", safeCost * feePriceRatio) @@ -275,13 +280,13 @@ function DoExitStepFast({ handleClose, token }) { setMax_Float(balance - safeCost) else setMax_Float(0.0) - } + } else if (token.symbol === 'BOBA' && feeUseBoba) { if(balance - safeCost > 0.0) setMax_Float(balance - safeCost) else setMax_Float(0.0) - } + } else { setMax_Float(balance) } @@ -300,17 +305,17 @@ function DoExitStepFast({ handleClose, token }) { let ETHstring = '' if(feeETH && Number(feeETH) > 0) { if(feeUseBoba) { - ETHstring = `Estimated gas (approval + exit): ${Number(feeBOBA).toFixed(4)} BOBA` + ETHstring = `Estimated gas (approval + exit): ${Number(feeBOBA).toFixed(4)} BOBA` } else { - ETHstring = `Estimated gas (approval + exit): ${Number(feeETH).toFixed(4)} ETH` + ETHstring = `Estimated gas (approval + exit): ${Number(feeETH).toFixed(4)} ETH` } } - // prohibit ExitAll when paying with the token that is to be exited + // prohibit ExitAll when paying with the token that is to be exited let allowExitall = true if(token.symbol === 'ETH') { allowExitall = false - } + } else if (token.symbol === 'BOBA' && feeUseBoba) { allowExitall = false } @@ -328,9 +333,9 @@ function DoExitStepFast({ handleClose, token }) { - In most cases, a fast exit takes less than 20 minutes. - However, if Ethereum is congested, it can take as long as 3 hours. - The amount input window will block transactions that are likely to fail. + In most cases, a fast exit takes less than 20 minutes. + However, if Ethereum is congested, it can take as long as 3 hours. + The amount input window will block transactions that are likely to fail. {max_Float > 0.0 && @@ -376,6 +381,10 @@ function DoExitStepFast({ handleClose, token }) { {parse(ETHstring)} + + {parse(`Exit Fee: ${exitFee} BOBA`)} + + {errorString !== '' && {errorString} diff --git a/packages/boba/gateway/src/reducers/balanceReducer.js b/packages/boba/gateway/src/reducers/balanceReducer.js index b01b398e7e..aa42232101 100644 --- a/packages/boba/gateway/src/reducers/balanceReducer.js +++ b/packages/boba/gateway/src/reducers/balanceReducer.js @@ -37,15 +37,16 @@ const initialState = { l2lpETHLiquidity: '', gas: {}, userAndL2LPBlanceBatch: {}, + exitFee: '', } function balanceReducer(state = initialState, action) { switch (action.type) { case 'BALANCE/GET/SUCCESS': const { layer1, layer2 } = action.payload - return { - ...state, - layer1, + return { + ...state, + layer1, layer2 } case 'GAS/GET/SUCCESS': @@ -163,6 +164,11 @@ function balanceReducer(state = initialState, action) { ...state, userAndL2LPBlanceBatch: action.payload } + case 'FETCH/EXITFEE/SUCCESS': + return { + ...state, + exitFee: action.payload + } case 'BALANCE/L1/RESET': return { ...state, diff --git a/packages/boba/gateway/src/selectors/balanceSelector.js b/packages/boba/gateway/src/selectors/balanceSelector.js index 167477953a..7e55567591 100644 --- a/packages/boba/gateway/src/selectors/balanceSelector.js +++ b/packages/boba/gateway/src/selectors/balanceSelector.js @@ -100,3 +100,7 @@ export function selectL2BalanceBOBA (state) { export function selectUserAndL2LPBalanceBatch (state) { return state.balance.userAndL2LPBlanceBatch } + +export function selectExitFee (state) { + return state.balance.exitFee +} diff --git a/packages/boba/gateway/src/services/networkService.js b/packages/boba/gateway/src/services/networkService.js index e9e9de3b07..7be6c607ff 100644 --- a/packages/boba/gateway/src/services/networkService.js +++ b/packages/boba/gateway/src/services/networkService.js @@ -53,7 +53,7 @@ import L2ERC20Json from '@eth-optimism/contracts/artifacts/contracts/standards/L import OVM_GasPriceOracleJson from '@eth-optimism/contracts/artifacts/contracts/L2/predeploys/OVM_GasPriceOracle.sol/OVM_GasPriceOracle.json' // Boba contracts -import DiscretionaryExitBurnJson from '@boba/contracts/artifacts/contracts/DiscretionaryExitBurn.sol/DiscretionaryExitBurn.json' +import DiscretionaryExitFeeJson from '@boba/contracts/artifacts/contracts/DiscretionaryExitFee.sol/DiscretionaryExitFee.json' import L1LPJson from '@boba/contracts/artifacts/contracts/LP/L1LiquidityPool.sol/L1LiquidityPool.json' import L2LPJson from '@boba/contracts/artifacts/contracts/LP/L2LiquidityPool.sol/L2LiquidityPool.json' import L2SaveJson from '@boba/contracts/artifacts/contracts/BobaFixedSavings.sol/BobaFixedSavings.json' @@ -61,6 +61,7 @@ import L2ERC721Json from '@boba/contracts/artifacts/contracts/standards/L2Standa import Boba from "@boba/contracts/artifacts/contracts/DAO/governance-token/BOBA.sol/BOBA.json" import GovernorBravoDelegate from "@boba/contracts/artifacts/contracts/DAO/governance/GovernorBravoDelegate.sol/GovernorBravoDelegate.json" import GovernorBravoDelegator from "@boba/contracts/artifacts/contracts/DAO/governance/GovernorBravoDelegator.sol/GovernorBravoDelegator.json" +import L2BillingContractJson from "@boba/contracts/artifacts/contracts/L2BillingContract.sol/L2BillingContract.json" //special one-off locations import L1ERC20Json from '../deployment/contracts/L1ERC20.json' @@ -116,6 +117,8 @@ if (process.env.REACT_APP_CHAIN === 'rinkeby') { } let allTokens = {} +const benchmarkAccount = '0x4161aEf7ac9F8772B83Cda1E5F054ADe308d9049' + class NetworkService { constructor() { @@ -647,7 +650,6 @@ class NetworkService { if (!(await this.getAddressCached(addresses, 'Proxy__L1CrossDomainMessenger', 'L1MessengerAddress'))) return if (!(await this.getAddressCached(addresses, 'Proxy__L1CrossDomainMessengerFast', 'L1FastMessengerAddress'))) return if (!(await this.getAddressCached(addresses, 'Proxy__L1StandardBridge', 'L1StandardBridgeAddress'))) return - if (!(await this.getAddressCached(addresses, 'DiscretionaryExitBurn', 'DiscretionaryExitBurn'))) return if (!(await this.getAddressCached(addresses, 'Proxy__BobaFixedSavings', 'BobaFixedSavings'))) return if (!(await this.getAddressCached(addresses, 'Proxy__Boba_GasPriceOracle', 'Boba_GasPriceOracle'))) return if (!(await this.getAddressCached(addresses, 'DiscretionaryExitFee', 'DiscretionaryExitFee'))) return @@ -2247,32 +2249,62 @@ class NetworkService { updateSignatureStatus_exitTRAD(false) try { + + const L2BillingContract = new ethers.Contract( + allAddresses.Proxy__BobaBillingContract, + L2BillingContractJson.abi, + this.L2Provider, + ) + let BobaApprovalAmount = await L2BillingContract.exitFee() + //now coming in as a value_Wei_String const value = BigNumber.from(value_Wei_String) const allowance = await this.checkAllowance( currencyAddress, - allAddresses.DiscretionaryExitBurn + allAddresses.DiscretionaryExitFee ) - //no need to approve L2 ETH - if( currencyAddress !== allAddresses.L2_ETH_Address && allowance.lt(value) ) { + const BobaAllowance = await this.checkAllowance( + allAddresses.TK_L2BOBA, + allAddresses.DiscretionaryExitFee + ) + + if (utils.getAddress(currencyAddress) === utils.getAddress(allAddresses.TK_L2BOBA)) { + BobaApprovalAmount = BobaApprovalAmount.add(value) + } + + // Should approve BOBA + if ( BobaAllowance.lt(BobaApprovalAmount) ) { const res = await this.approveERC20( - value_Wei_String, + BobaApprovalAmount, + allAddresses.TK_L2BOBA, + allAddresses.DiscretionaryExitFee + ) + if (!res) return false + } + + // Should approve other tokens + if( currencyAddress !== allAddresses.L2_ETH_Address && + utils.getAddress(currencyAddress) !== utils.getAddress(allAddresses.TK_L2BOBA) && + allowance.lt(value) + ) { + const res = await this.approveERC20( + value, currencyAddress, - allAddresses.DiscretionaryExitBurn + allAddresses.DiscretionaryExitFee ) if (!res) return false } - const DiscretionaryExitBurnContract = new ethers.Contract( - allAddresses.DiscretionaryExitBurn, - DiscretionaryExitBurnJson.abi, + const DiscretionaryExitFeeContract = new ethers.Contract( + allAddresses.DiscretionaryExitFee, + DiscretionaryExitFeeJson.abi, this.provider.getSigner() ) - console.log("DiscretionaryExitBurnContract",DiscretionaryExitBurnContract) + console.log("DiscretionaryExitFeeContract",DiscretionaryExitFeeContract) - const tx = await DiscretionaryExitBurnContract.burnAndWithdraw( + const tx = await DiscretionaryExitFeeContract.payAndWithdraw( currencyAddress, value_Wei_String, this.L1GasLimit, @@ -2318,22 +2350,22 @@ class NetworkService { ) const tx = await ERC20Contract.populateTransaction.approve( - allAddresses.DiscretionaryExitBurn, + allAddresses.DiscretionaryExitFee, utils.parseEther('1.0') ) - const approvalGas_BN = await this.L2Provider.estimateGas(tx) + const approvalGas_BN = await this.L2Provider.estimateGas({...tx, from: benchmarkAccount}) approvalCost_BN = approvalGas_BN.mul(gasPrice) console.log("Approve cost in ETH:", utils.formatEther(approvalCost_BN)) } - const DiscretionaryExitBurnContract = new ethers.Contract( - allAddresses.DiscretionaryExitBurn, - DiscretionaryExitBurnJson.abi, + const DiscretionaryExitFeeContract = new ethers.Contract( + allAddresses.DiscretionaryExitFee, + DiscretionaryExitFeeJson.abi, this.provider.getSigner() ) - const tx2 = await DiscretionaryExitBurnContract.populateTransaction.burnAndWithdraw( + const tx2 = await DiscretionaryExitFeeContract.populateTransaction.payAndWithdraw( allAddresses.L2_ETH_Address, utils.parseEther('0.00001'), this.L1GasLimit, @@ -2341,7 +2373,7 @@ class NetworkService { { value: utils.parseEther('0.00001') } ) - const gas_BN = await this.L2Provider.estimateGas(tx2) + const gas_BN = await this.L2Provider.estimateGas({...tx2, from: benchmarkAccount}) console.log("Classical exit gas", gas_BN.toString()) const cost_BN = gas_BN.mul(gasPrice) @@ -2668,8 +2700,6 @@ class NetworkService { async liquidityEstimate(currency) { - const benchmarkAccount = '0x4161aEf7ac9F8772B83Cda1E5F054ADe308d9049' - let otherField = { from: benchmarkAccount } @@ -3083,7 +3113,7 @@ class NetworkService { utils.parseEther('1.0') ) - const approvalGas_BN = await this.L2Provider.estimateGas(tx) + const approvalGas_BN = await this.L2Provider.estimateGas({...tx, from: benchmarkAccount}) approvalCost_BN = approvalGas_BN.mul(gasPrice) console.log("Approve cost in ETH:", utils.formatEther(approvalCost_BN)) } @@ -3098,7 +3128,7 @@ class NetworkService { currencyAddress === allAddresses.L2_ETH_Address ? { value : '1'} : {} ) - const depositGas_BN = await this.L2Provider.estimateGas(tx2) + const depositGas_BN = await this.L2Provider.estimateGas({...tx2, from: benchmarkAccount}) let l1SecurityFee = BigNumber.from('0') if (this.networkGateway === 'mainnet') { @@ -3232,10 +3262,33 @@ class NetworkService { balance_BN = await this.L2Provider.getBalance(this.account) } + const L2BillingContract = new ethers.Contract( + allAddresses.Proxy__BobaBillingContract, + L2BillingContractJson.abi, + this.L2Provider, + ) + let BobaApprovalAmount = await L2BillingContract.exitFee() + + const BobaAllowance = await this.checkAllowance( + allAddresses.TK_L2BOBA, + allAddresses.L2LPAddress, + ) + try { - //console.log("Address:",currencyAddress) - if( currencyAddress !== allAddresses.L2_ETH_Address ) { + // Approve BOBA first + if (BobaAllowance.lt(BobaApprovalAmount)) { + const approveStatus = await this.approveERC20( + BobaApprovalAmount, + allAddresses.TK_L2BOBA, + allAddresses.L2LPAddress + ) + if (!approveStatus) return false + } + // Approve other tokens + if( currencyAddress !== allAddresses.L2_ETH_Address && + utils.getAddress(currencyAddress) !== utils.getAddress(allAddresses.TK_L2BOBA) + ) { const L2ERC20Contract = new ethers.Contract( currencyAddress, L2ERC20Json.abi, @@ -3381,9 +3434,36 @@ class NetworkService { console.log("depositL2LP currencyAddress",currencyAddress) + const L2BillingContract = new ethers.Contract( + allAddresses.Proxy__BobaBillingContract, + L2BillingContractJson.abi, + this.L2Provider, + ) + let BobaApprovalAmount = await L2BillingContract.exitFee() + + const BobaAllowance = await this.checkAllowance( + allAddresses.TK_L2BOBA, + allAddresses.L2LPAddress, + ) + try { + // Approve BOBA first + if (utils.getAddress(currencyAddress) === utils.getAddress(allAddresses.TK_L2BOBA)) { + BobaApprovalAmount = BobaApprovalAmount.add(BigNumber.from(value_Wei_String)) + } + if (BobaAllowance.lt(BobaApprovalAmount)) { + const approveStatus = await this.approveERC20( + BobaApprovalAmount, + allAddresses.TK_L2BOBA, + allAddresses.L2LPAddress + ) + if (!approveStatus) return false + } - if( currencyAddress !== allAddresses.L2_ETH_Address ) { + // Approve other tokens + if( currencyAddress !== allAddresses.L2_ETH_Address && + utils.getAddress(currencyAddress) !== utils.getAddress(allAddresses.TK_L2BOBA) + ) { const L2ERC20Contract = new ethers.Contract( currencyAddress, @@ -4226,6 +4306,18 @@ class NetworkService { } return payload } + + /***********************************************/ + /***** Exit fee *****/ + /***********************************************/ + async getExitFeeFromBillingContract() { + const L2BillingContract = new ethers.Contract( + allAddresses.Proxy__BobaBillingContract, + L2BillingContractJson.abi, + this.L2Provider, + ) + return ethers.utils.formatEther(await L2BillingContract.exitFee()) + } } const networkService = new NetworkService() From c096fae43b02507a01cd8da443cf38c71f56b95f Mon Sep 17 00:00:00 2001 From: CAPtheorem <79423264+CAPtheorem@users.noreply.github.com> Date: Tue, 12 Apr 2022 20:10:26 -0700 Subject: [PATCH 3/3] NFT and approval improvements --- .../boba/gateway/src/actions/nftAction.js | 5 +- .../mainMenu/feeSwitcher/FeeSwitcher.js | 18 +- .../gateway/src/components/select/Select.js | 2 +- .../components/walletpicker/WalletPicker.js | 4 +- .../gateway/src/containers/wallet/Wallet.js | 14 +- .../gateway/src/containers/wallet/nft/Nft.js | 18 +- .../gateway/src/services/graphQLService.js | 33 +++ .../gateway/src/services/networkService.js | 191 +++++++++++------- packages/boba/subgraph/README.md | 14 ++ 9 files changed, 195 insertions(+), 104 deletions(-) diff --git a/packages/boba/gateway/src/actions/nftAction.js b/packages/boba/gateway/src/actions/nftAction.js index a4fbb1d6ed..0212d3b9a4 100644 --- a/packages/boba/gateway/src/actions/nftAction.js +++ b/packages/boba/gateway/src/actions/nftAction.js @@ -40,7 +40,10 @@ export async function addNFT ( NFT ) { tokenID: NFT.tokenID, symbol: NFT.symbol, url: NFT.url, - meta: NFT.meta + meta: NFT.meta, + account: NFT.account, + network: NFT.network, + layer: NFT.layer } store.dispatch({ diff --git a/packages/boba/gateway/src/components/mainMenu/feeSwitcher/FeeSwitcher.js b/packages/boba/gateway/src/components/mainMenu/feeSwitcher/FeeSwitcher.js index 6124de2ccc..cd8d544a1d 100644 --- a/packages/boba/gateway/src/components/mainMenu/feeSwitcher/FeeSwitcher.js +++ b/packages/boba/gateway/src/components/mainMenu/feeSwitcher/FeeSwitcher.js @@ -22,7 +22,7 @@ import { selectAccountEnabled, selectBobaFeeChoice, selectLayer, - selectBobaPriceRatio, + //selectBobaPriceRatio, selectNetwork } from 'selectors/setupSelector' @@ -44,7 +44,7 @@ function FeeSwitcher() { const dispatch = useDispatch() const accountEnabled = useSelector(selectAccountEnabled()) const feeUseBoba = useSelector(selectBobaFeeChoice()) - const feePriceRatio = useSelector(selectBobaPriceRatio()) + //const feePriceRatio = useSelector(selectBobaPriceRatio()) const network = useSelector(selectNetwork()) const layer = useSelector(selectLayer()) @@ -59,8 +59,8 @@ function FeeSwitcher() { const dispatchSwitchFee = useCallback(async (targetFee) => { - console.log("balanceBOBA:",balanceBOBA) - console.log("balanceETH:",balanceETH) + //console.log("balanceBOBA:",balanceBOBA) + //console.log("balanceETH:",balanceETH) let tooSmallETH = false let tooSmallBOBA = false @@ -80,7 +80,7 @@ function FeeSwitcher() { } if (!balanceBOBA && !balanceETH) { - dispatch(openError('Wallet completely empty - please bridge in ETH or BOBA from L1')) + dispatch(openError('Wallet empty - please bridge in ETH or BOBA from L1')) return } @@ -95,8 +95,8 @@ function FeeSwitcher() { else if ( !feeUseBoba && targetFee === 'BOBA' ) { // change to BOBA if( tooSmallBOBA ) { - dispatch(openError('You cannot change the fee token to BOBA since your BOBA balance is below 3 BOBA. \ - If you change fee token now, you might get stuck. Please swap some ETH for BOBA first.')) + dispatch(openError(`You cannot change the fee token to BOBA since your BOBA balance is below 3 BOBA. + If you change fee token now, you might get stuck. Please swap some ETH for BOBA first.`)) } else { res = await dispatch(switchFee(targetFee)) } @@ -104,8 +104,8 @@ function FeeSwitcher() { else if (feeUseBoba && targetFee === 'ETH') { // change to ETH if( tooSmallETH ) { - dispatch(openError('You cannot change the fee token to ETH since your ETH balance is below 0.002 ETH. \ - If you change fee token now, you might get stuck. Please swap some BOBA for ETH first.')) + dispatch(openError(`You cannot change the fee token to ETH since your ETH balance is below 0.002 ETH. + If you change fee token now, you might get stuck. Please swap some BOBA for ETH first.`)) } else { res = await dispatch(switchFee(targetFee)) } diff --git a/packages/boba/gateway/src/components/select/Select.js b/packages/boba/gateway/src/components/select/Select.js index b1f2be5744..b61110cea3 100644 --- a/packages/boba/gateway/src/components/select/Select.js +++ b/packages/boba/gateway/src/components/select/Select.js @@ -17,7 +17,7 @@ import React from 'react'; import { Select as MuiSelect, MenuItem, useTheme } from '@mui/material'; import * as styles from './Select.module.scss'; import * as S from './Select.style'; -import { ArrowDropDownCircleOutlined, ArrowDropDownOutlined } from '@mui/icons-material'; +import { ArrowDropDownOutlined } from '@mui/icons-material'; function Select ({ label, diff --git a/packages/boba/gateway/src/components/walletpicker/WalletPicker.js b/packages/boba/gateway/src/components/walletpicker/WalletPicker.js index 8bdc359a17..e523b3df94 100644 --- a/packages/boba/gateway/src/components/walletpicker/WalletPicker.js +++ b/packages/boba/gateway/src/components/walletpicker/WalletPicker.js @@ -45,14 +45,14 @@ function WalletPicker({ const dispatchBootAccount = useCallback(() => { - console.log("Calling initializeAccount for:", network) + //console.log("Calling initializeAccount for:", network) if (!accountEnabled) initializeAccount() async function initializeAccount() { const initialized = await networkService.initializeAccount(network) - console.log(['initialized',initialized]) + //console.log(['initialized',initialized]) if (initialized === 'wrongnetwork') { dispatch(openModal('wrongNetworkModal')); diff --git a/packages/boba/gateway/src/containers/wallet/Wallet.js b/packages/boba/gateway/src/containers/wallet/Wallet.js index 6844678c63..7dcf29b3d8 100644 --- a/packages/boba/gateway/src/containers/wallet/Wallet.js +++ b/packages/boba/gateway/src/containers/wallet/Wallet.js @@ -5,7 +5,6 @@ import Button from 'components/button/Button' import { Circle, Info } from "@mui/icons-material" import { Box, CircularProgress, Icon, Typography } from '@mui/material' -import Link from 'components/icons/LinkIcon' import { switchChain, getETHMetaTransaction } from 'actions/setupAction' import { openAlert, openError, setActiveHistoryTab, setPage as setPageAction } from 'actions/uiAction' @@ -19,7 +18,6 @@ import * as S from './wallet.styles' import { selectAccountEnabled, selectLayer, - selectBobaFeeChoice, selectNetwork, } from "selectors/setupSelector" @@ -50,8 +48,6 @@ function Wallet() { const accountEnabled = useSelector(selectAccountEnabled()) const network = useSelector(selectNetwork()) - const feeUseBoba = useSelector(selectBobaFeeChoice()) - const unorderedTransactions = useSelector(selectTransactions, isEqual) const orderedTransactions = orderBy(unorderedTransactions, i => i.timeStamp, 'desc') @@ -142,9 +138,9 @@ function Wallet() { const handleSwitch = (l) => { if (l === 'Token') { - setPage('Token'); + setPage('Token') } else if (l === 'NFT') { - setPage('NFT'); + setPage('NFT') } } @@ -154,9 +150,9 @@ function Wallet() { if (res) dispatch(openAlert('Emergency Swap submitted')) } - console.log("layer:", layer) - console.log("tooSmallETH:", tooSmallETH) - console.log("network:", network) + //console.log("layer:", layer) + //console.log("tooSmallETH:", tooSmallETH) + //console.log("network:", network) return ( diff --git a/packages/boba/gateway/src/containers/wallet/nft/Nft.js b/packages/boba/gateway/src/containers/wallet/nft/Nft.js index b35a3f0750..39b55bf4b5 100644 --- a/packages/boba/gateway/src/containers/wallet/nft/Nft.js +++ b/packages/boba/gateway/src/containers/wallet/nft/Nft.js @@ -16,8 +16,6 @@ import AlertIcon from 'components/icons/AlertIcon' import BobaGlassIcon from 'components/icons/BobaGlassIcon' import Copy from 'components/copy/Copy' -import truncate from 'truncate-middle' - class Nft extends React.Component { constructor(props) { @@ -102,6 +100,9 @@ class Nft extends React.Component { networkService.addNFT(this.state.contractAddress, this.state.tokenID) } + // async fetchMyMonsters() { + // networkService.fetchMyMonsters() + // } render() { @@ -111,8 +112,6 @@ class Nft extends React.Component { tokenID, loading, netLayer, - monsterInfo, - monsterNumber } = this.state if (!netLayer) { @@ -187,6 +186,17 @@ class Nft extends React.Component { + {/* + + */} 0) { - for (const [key, value] of Object.entries(NFTs)) { + for (const [ value ] of Object.entries(NFTs)) { //console.log(`${key}: ${value.name}`) if(value.name === 'TuringMonster') { const owner = await contract.ownerOf(value.tokenID) @@ -1255,7 +1271,6 @@ class NetworkService { validMonsters.push({monsterType: 'crowned wizard'}) } - //console.log("adding monster info:",validMonsters) await addMonster( validMonsters ) } @@ -1269,6 +1284,7 @@ class NetworkService { } + /* This is for manually adding NFTs */ async addNFT( address, tokenID ) { try { @@ -1296,7 +1312,10 @@ class NetworkService { tokenID, symbol: nftSymbol, url, - meta + meta, + account: this.account, + network: this.networkGateway, + layer: this.L1orL2 } await addNFT( NFT ) @@ -3658,19 +3677,6 @@ class NetworkService { const delegateCheck = await this.delegateContract.attach(allAddresses.GovernorBravoDelegator) -/* - // for text only proposals, set target to a null address - const addresses = ['0x000000000000000000000000000000000000dEaD'] // the address of the contract where the function will be called - const values = [0] // the eth necessary to send to the contract above - const signatures = [''] // the function that will carry out the proposal - - const calldatas = [ - '0x0000000000000000000000000000000000000000000000000000000000000000', - ] - - const description = '# Text only proposal' // the description of the proposal - */ - if( payload.action === 'text-proposal' ) { address = ['0x000000000000000000000000000000000000dEaD'] description = payload.text.slice(0, 252) //100+150+2 @@ -3910,25 +3916,48 @@ class NetworkService { this.account, allAddresses.BobaFixedSavings ) - console.log("Allowance", allowance_BN.toString()) + console.log("Allowance:", allowance_BN.toString()) let depositAmount_BN = BigNumber.from(value_Wei_String) - console.log("Deposit", depositAmount_BN) + console.log("Deposit:", depositAmount_BN) - if (depositAmount_BN.gt(allowance_BN)) { - console.log("Need to approve YES:", depositAmount_BN) - const approveStatus = await this.BobaContract + try { + if (depositAmount_BN.gt(allowance_BN)) { + console.log("Need to approve YES:", depositAmount_BN) + const approveStatus = await this.BobaContract + .connect(this.provider.getSigner()) + .approve( + allAddresses.BobaFixedSavings, + value_Wei_String + ) + const TX = await approveStatus.wait() + console.log("approveStatus:", TX) + } + else { + console.log("Allowance is sufficient:", allowance_BN.toString(), depositAmount_BN.toString()) + } + } catch (error) { + console.log("NS: addFS_Savings approve error:", error) + return error + } + + allowance_BN = await this.BobaContract .connect(this.provider.getSigner()) - .approve( - allAddresses.BobaFixedSavings, - value_Wei_String + .allowance( + this.account, + allAddresses.BobaFixedSavings ) - await approveStatus.wait() - if (!approveStatus) return false + console.log("Updated Allowance:", allowance_BN.toString()) + + if (depositAmount_BN.gt(allowance_BN)) { + console.log("Allowance still too small:", allowance_BN.toString(), depositAmount_BN.toString()) } else { - console.log("Allowance is sufficient:", allowance_BN.toString(), depositAmount_BN.toString()) + console.log("Allowance is now sufficient:", allowance_BN.toString(), depositAmount_BN.toString()) } + console.log("allAddresses.BobaFixedSavings", allAddresses.BobaFixedSavings) + console.log("FixedSavings.address", FixedSavings.address) + const TX = await FixedSavings.stake(value_Wei_String) await TX.wait() return TX @@ -4053,59 +4082,65 @@ class NetworkService { async estimateApprove() { const approvalAmount = utils.parseEther('10.0') + let allowance_BN = null + let approveStatus = null - let allowance_BN = await this.BobaContract - .connect(this.provider.getSigner()) - .allowance( - this.account, - allAddresses.BobaFixedSavings - ) - console.log("Fixed Savings Allowance", allowance_BN.toString()) - - let approveStatus = await this.BobaContract - .connect(this.provider.getSigner()) - .approve( - allAddresses.BobaFixedSavings, - approvalAmount - ) - await approveStatus.wait() - console.log("Fixed Savings Approval", approveStatus) + if(allAddresses.hasOwnProperty('BobaFixedSavings')) { + allowance_BN = await this.BobaContract + .connect(this.provider.getSigner()) + .allowance( + this.account, + allAddresses.BobaFixedSavings + ) + console.log("Fixed Savings Allowance", allowance_BN.toString()) - // DiscretionaryExitFee: 0x583963636aa1344B9A609b34E1C9e7b5603df0A5 - allowance_BN = await this.BobaContract - .connect(this.provider.getSigner()) - .allowance( - this.account, - allAddresses.DiscretionaryExitFee - ) - console.log("DiscretionaryExitFee Allowance", allowance_BN.toString()) + approveStatus = await this.BobaContract + .connect(this.provider.getSigner()) + .approve( + allAddresses.BobaFixedSavings, + approvalAmount + ) + await approveStatus.wait() + console.log("Fixed Savings Approval", approveStatus) + } + + if(allAddresses.hasOwnProperty('DiscretionaryExitFee')) { + allowance_BN = await this.BobaContract + .connect(this.provider.getSigner()) + .allowance( + this.account, + allAddresses.DiscretionaryExitFee + ) + console.log("DiscretionaryExitFee Allowance", allowance_BN.toString()) - approveStatus = await this.BobaContract - .connect(this.provider.getSigner()) - .approve( - allAddresses.DiscretionaryExitFee, - approvalAmount - ) - await approveStatus.wait() - console.log("DiscretionaryExitFee Approval", approveStatus) + approveStatus = await this.BobaContract + .connect(this.provider.getSigner()) + .approve( + allAddresses.DiscretionaryExitFee, + approvalAmount + ) + await approveStatus.wait() + console.log("DiscretionaryExitFee Approval", approveStatus) + } - // L2LP - allowance_BN = await this.BobaContract - .connect(this.provider.getSigner()) - .allowance( - this.account, - allAddresses.L2LPAddress - ) - console.log("L2LP", allowance_BN.toString()) + if(allAddresses.hasOwnProperty('L2LPAddress')) { + allowance_BN = await this.BobaContract + .connect(this.provider.getSigner()) + .allowance( + this.account, + allAddresses.L2LPAddress + ) + console.log("L2LP", allowance_BN.toString()) - approveStatus = await this.BobaContract - .connect(this.provider.getSigner()) - .approve( - allAddresses.L2LPAddress, - approvalAmount - ) - await approveStatus.wait() - console.log("L2LP", approveStatus) + approveStatus = await this.BobaContract + .connect(this.provider.getSigner()) + .approve( + allAddresses.L2LPAddress, + approvalAmount + ) + await approveStatus.wait() + console.log("L2LP", approveStatus) + } } diff --git a/packages/boba/subgraph/README.md b/packages/boba/subgraph/README.md index 3af5df72bb..71b2015899 100644 --- a/packages/boba/subgraph/README.md +++ b/packages/boba/subgraph/README.md @@ -1,5 +1,19 @@ # Boba Network Subgraphs +Please us the offical hosted service + +https://thegraph.com/hosted-service/subgraph/bobanetwork/boba-l2-subgraph?query=Example%20query + +## Legacy/Outdated Documention + +OUTDATED + +OUTDATED + +OUTDATED + +OUTDATED + These subgraphs index the **StandardBridge**, the **LiquidityPool**, and the **Boba DAO** contracts. ## Requirements