From d5775ceaf5611579b22e7e4a30372acfddab0508 Mon Sep 17 00:00:00 2001 From: cby3149 Date: Fri, 8 Apr 2022 16:11:01 -0700 Subject: [PATCH 01/10] Add swapBOBAForETHMetaTransaction --- .../L2/predeploys/Boba_GasPriceOracle.sol | 81 +++++++++++--- packages/contracts/package.json | 2 +- packages/contracts/src/make-genesis.ts | 3 +- .../L2/predeploys/Boba_GasPriceOracle.spec.ts | 102 +++++++++++++++++- 4 files changed, 165 insertions(+), 23 deletions(-) diff --git a/packages/contracts/contracts/L2/predeploys/Boba_GasPriceOracle.sol b/packages/contracts/contracts/L2/predeploys/Boba_GasPriceOracle.sol index 5a9285f308..afbfbd712a 100644 --- a/packages/contracts/contracts/L2/predeploys/Boba_GasPriceOracle.sol +++ b/packages/contracts/contracts/L2/predeploys/Boba_GasPriceOracle.sol @@ -3,6 +3,7 @@ pragma solidity ^0.8.9; /* Library Imports */ import { Lib_PredeployAddresses } from "../../libraries/constants/Lib_PredeployAddresses.sol"; +import { SafeMath } from "@openzeppelin/contracts/utils/math/SafeMath.sol"; /* Contract Imports */ import { L2StandardBridge } from "../messaging/L2StandardBridge.sol"; @@ -18,6 +19,7 @@ import { Address } from "@openzeppelin/contracts/utils/Address.sol"; */ contract Boba_GasPriceOracle { using SafeERC20 for IERC20; + using SafeMath for uint256; /************* * Constants * @@ -33,8 +35,8 @@ contract Boba_GasPriceOracle { // Owner address address private _owner; - // Address on L1 that will hold the fees once withdrawn. Dynamically initialized within l2geth. - address public l1FeeWallet; + // Address that will hold the fees once withdrawn. Dynamically initialized within l2geth. + address public feeWallet; // L2 Boba token address address public l2BobaAddress; @@ -57,27 +59,32 @@ contract Boba_GasPriceOracle { // Boba fee for the meta transaction uint256 public metaTransactionFee = 3e18; + // Received ETH amount for the swap - 0.005 + uint256 public receivedETHAmount = 5e15; + /************* * Events * *************/ event TransferOwnership(address, address); event UseBobaAsFeeToken(address); - event UseBobaAsFeeTokenMetaTransaction(address); + event SwapBOBAForETHMetaTransaction(address); event UseETHAsFeeToken(address); event UpdatePriceRatio(address, uint256); event UpdateMaxPriceRatio(address, uint256); event UpdateMinPriceRatio(address, uint256); event UpdateGasPriceOracleAddress(address, address); event UpdateMetaTransactionFee(address, uint256); - event Withdraw(address, address); + event UpdateReceivedETHAmount(address, uint256); + event WithdrawBOBA(address, address); + event WithdrawETH(address, address); /********************** * Function Modifiers * **********************/ modifier onlyNotInitialized() { - require(address(l1FeeWallet) == address(0), "Contract has been initialized"); + require(address(feeWallet) == address(0), "Contract has been initialized"); _; } @@ -86,6 +93,15 @@ contract Boba_GasPriceOracle { _; } + /******************** + * Fall back Functions * + ********************/ + + /** + * Receive ETH + */ + receive() external payable {} + /******************** * Public Functions * ********************/ @@ -109,11 +125,14 @@ contract Boba_GasPriceOracle { } /** - * Initialize l1FeeWallet and l2BobaAddress. + * Initialize feeWallet and l2BobaAddress. */ - function initialize(address _l1FeeWallet, address _l2BobaAddress) public onlyNotInitialized { - require(_l1FeeWallet != address(0) && _l2BobaAddress != address(0)); - l1FeeWallet = _l1FeeWallet; + function initialize(address payable _feeWallet, address _l2BobaAddress) + public + onlyNotInitialized + { + require(_feeWallet != address(0) && _l2BobaAddress != address(0)); + feeWallet = _feeWallet; l2BobaAddress = _l2BobaAddress; // Initialize the parameters @@ -130,6 +149,11 @@ contract Boba_GasPriceOracle { */ function useBobaAsFeeToken() public { require(!Address.isContract(msg.sender), "Account not EOA"); + // Users should have more than 3 BOBA + require( + L2GovernanceERC20(l2BobaAddress).balanceOf(msg.sender) >= 3e18, + "Insufficient Boba balance" + ); bobaFeeTokenUsers[msg.sender] = true; emit UseBobaAsFeeToken(msg.sender); } @@ -139,7 +163,7 @@ contract Boba_GasPriceOracle { * using the Meta Transaction * NOTE: Only works for the mainnet and local testnet */ - function useBobaAsFeeTokenMetaTransaction( + function swapBOBAForETHMetaTransaction( address tokenOwner, address spender, uint256 value, @@ -150,12 +174,14 @@ contract Boba_GasPriceOracle { ) public { require(!Address.isContract(tokenOwner), "Account not EOA"); require(spender == address(this), "Spender is not this contract"); - require(value >= metaTransactionFee, "Value is not enough"); + uint256 totalCost = receivedETHAmount.mul(priceRatio).add(metaTransactionFee); + require(value >= totalCost, "Value is not enough"); L2GovernanceERC20 bobaToken = L2GovernanceERC20(l2BobaAddress); bobaToken.permit(tokenOwner, spender, value, deadline, v, r, s); - IERC20(l2BobaAddress).safeTransferFrom(tokenOwner, address(this), metaTransactionFee); - bobaFeeTokenUsers[tokenOwner] = true; - emit UseBobaAsFeeTokenMetaTransaction(tokenOwner); + IERC20(l2BobaAddress).safeTransferFrom(tokenOwner, address(this), totalCost); + (bool sent, ) = address(msg.sender).call{ value: receivedETHAmount }(""); + require(sent, "Failed to send ETH"); + emit SwapBOBAForETHMetaTransaction(tokenOwner); } /** @@ -163,6 +189,8 @@ contract Boba_GasPriceOracle { */ function useETHAsFeeToken() public { require(!Address.isContract(msg.sender), "Account not EOA"); + // Users should have more than 0.002 ETH + require(address(msg.sender).balance >= 2e15, "Insufficient ETH balance"); bobaFeeTokenUsers[msg.sender] = false; emit UseETHAsFeeToken(msg.sender); } @@ -218,6 +246,16 @@ contract Boba_GasPriceOracle { emit UpdateMetaTransactionFee(owner(), _metaTransactionFee); } + /** + * Update the received ETH amount + * @param _receivedETHAmount the received ETH amount + */ + function updateReceivedETHAmount(uint256 _receivedETHAmount) public onlyOwner { + require(_receivedETHAmount > 1e15 && _receivedETHAmount < 10e15); + receivedETHAmount = _receivedETHAmount; + emit UpdateReceivedETHAmount(owner(), _receivedETHAmount); + } + /** * Get L1 Boba fee for fee estimation * @param _txData the data payload @@ -230,7 +268,7 @@ contract Boba_GasPriceOracle { /** * withdraw BOBA tokens to l1 fee wallet */ - function withdraw() public { + function withdrawBOBA() public { require( L2GovernanceERC20(l2BobaAddress).balanceOf(address(this)) >= MIN_WITHDRAWAL_AMOUNT, // solhint-disable-next-line max-line-length @@ -239,11 +277,20 @@ contract Boba_GasPriceOracle { L2StandardBridge(Lib_PredeployAddresses.L2_STANDARD_BRIDGE).withdrawTo( l2BobaAddress, - l1FeeWallet, + feeWallet, L2GovernanceERC20(l2BobaAddress).balanceOf(address(this)), 0, bytes("") ); - emit Withdraw(owner(), l1FeeWallet); + emit WithdrawBOBA(owner(), feeWallet); + } + + /** + * withdraw ETH tokens to l2 fee wallet + */ + function withdrawETH() public onlyOwner { + (bool sent, ) = feeWallet.call{ value: address(this).balance }(""); + require(sent, "Failed to send ETH to fee wallet"); + emit WithdrawETH(owner(), feeWallet); } } diff --git a/packages/contracts/package.json b/packages/contracts/package.json index 801950e8e7..3b1ae4e323 100644 --- a/packages/contracts/package.json +++ b/packages/contracts/package.json @@ -26,7 +26,7 @@ "autogen:artifacts": "ts-node scripts/generate-artifacts.ts && ts-node scripts/generate-deployed-artifacts.ts", "test": "yarn test:contracts", "test:contracts": "hardhat test --show-stack-traces", - "test:coverage": "NODE_OPTIONS=--max_old_space_size=8192 hardhat coverage && istanbul check-coverage --statements 79 --branches 64 --functions 71 --lines 79", + "test:coverage": "NODE_OPTIONS=--max_old_space_size=8192 hardhat coverage && istanbul check-coverage --statements 79 --branches 63 --functions 71 --lines 79", "test:slither": "slither .", "pretest:slither": "rm -f @openzeppelin && rm -f @ens && rm -f hardhat && ln -s ../../node_modules/@openzeppelin @openzeppelin && ln -s ../../node_modules/@ens @ens && ln -s ../../node_modules/hardhat hardhat", "posttest:slither": "rm -f @openzeppelin && rm -f @ens && rm -f hardhat", diff --git a/packages/contracts/src/make-genesis.ts b/packages/contracts/src/make-genesis.ts index ced32dfc8e..333ed78072 100644 --- a/packages/contracts/src/make-genesis.ts +++ b/packages/contracts/src/make-genesis.ts @@ -125,13 +125,14 @@ export const makeL2GenesisFile = async ( }, Boba_GasPriceOracle: { _owner: cfg.gasPriceOracleOwner, - l1FeeWallet: cfg.l1FeeWalletAddress, + feeWallet: cfg.l1FeeWalletAddress, l2BobaAddress: predeploys.L2GovernanceERC20, minPriceRatio: 500, maxPriceRatio: 5000, priceRatio: 2000, gasPriceOracleAddress: predeploys.OVM_GasPriceOracle, metaTransactionFee: utils.parseEther('3'), + receivedETHAmount: utils.parseEther('0.005'), } } diff --git a/packages/contracts/test/contracts/L2/predeploys/Boba_GasPriceOracle.spec.ts b/packages/contracts/test/contracts/L2/predeploys/Boba_GasPriceOracle.spec.ts index f6e7fa3d83..8b0f22af2b 100644 --- a/packages/contracts/test/contracts/L2/predeploys/Boba_GasPriceOracle.spec.ts +++ b/packages/contracts/test/contracts/L2/predeploys/Boba_GasPriceOracle.spec.ts @@ -2,9 +2,9 @@ import { expect } from '../../../setup' /* External Imports */ import { ethers } from 'hardhat' -import { ContractFactory, Contract, Signer } from 'ethers' +import { ContractFactory, Contract, Signer, utils } from 'ethers' -import { calculateL1GasUsed, calculateL1Fee } from '@eth-optimism/core-utils' +import { calculateL1Fee } from '@eth-optimism/core-utils' describe('Boba_GasPriceOracle', () => { const initialGasPrice = 0 @@ -292,7 +292,7 @@ describe('Boba_GasPriceOracle', () => { }) describe('get gasPriceOracleAddress', () => { - it('should revert if gasPriceOracleAddress is not EOA', async () => { + it('should revert if caller is not EOA', async () => { await expect( Boba_GasPriceOracle.connect(signer2).updateGasPriceOracleAddress( address1 @@ -362,7 +362,7 @@ describe('Boba_GasPriceOracle', () => { }) describe('get metaTransactionFee', () => { - it('should revert if metaTransactionFee is not EOA', async () => { + it('should revert if caller is not EOA', async () => { await expect( Boba_GasPriceOracle.connect(signer2).updateMetaTransactionFee( ethers.utils.parseEther('10') @@ -398,6 +398,100 @@ describe('Boba_GasPriceOracle', () => { }) }) + describe('receivedETHAmount', () => { + it('should revert if called by someone other than the owner', async () => { + await expect( + Boba_GasPriceOracle.connect(signer2).updateMetaTransactionFee(address1) + ).to.be.reverted + }) + + it('should revert if the new receivedETHAmount is below 0.001 ETH', async () => { + await expect( + Boba_GasPriceOracle.connect(signer1).updateReceivedETHAmount( + utils.parseEther('0.0009') + ) + ).to.be.reverted + }) + + it('should revert if the new receivedETHAmount is larger than 0.01 ETH', async () => { + await expect( + Boba_GasPriceOracle.connect(signer1).updateReceivedETHAmount( + utils.parseEther('0.011') + ) + ).to.be.reverted + }) + + it('should succeed if called by the owner', async () => { + await expect( + Boba_GasPriceOracle.connect(signer1).updateReceivedETHAmount( + ethers.utils.parseEther('0.003') + ) + ).to.not.be.reverted + }) + + it('should emit event', async () => { + const receivedETHAmount = ethers.utils.parseEther('0.006') + await expect( + Boba_GasPriceOracle.connect(signer1).updateReceivedETHAmount( + receivedETHAmount + ) + ) + .to.emit(Boba_GasPriceOracle, 'UpdateReceivedETHAmount') + .withArgs(await signer1.getAddress(), receivedETHAmount) + }) + }) + + describe('get receivedETHAmount', () => { + it('should revert if caller is not owne', async () => { + await expect( + Boba_GasPriceOracle.connect(signer2).updateReceivedETHAmount( + utils.parseEther('0.006') + ) + ).to.be.reverted + }) + it('should change when updateReceivedETHAmount is called', async () => { + await Boba_GasPriceOracle.connect(signer1).updateReceivedETHAmount( + ethers.utils.parseEther('0.005') + ) + expect(await Boba_GasPriceOracle.receivedETHAmount()).to.equal( + ethers.utils.parseEther('0.005') + ) + }) + + it('is the 9th storage slot', async () => { + const receivedETHAmount = ethers.utils.parseEther('0.003') + const slot = 9 + + // set the price + await Boba_GasPriceOracle.connect(signer1).updateReceivedETHAmount( + receivedETHAmount + ) + + // get the storage slot value + const receivedETHAmountSlot = await signer1.provider.getStorageAt( + Boba_GasPriceOracle.address, + slot + ) + expect(await Boba_GasPriceOracle.receivedETHAmount()).to.equal( + receivedETHAmountSlot + ) + }) + }) + + describe('withdrawBOBA', () => { + it('should revert if the balance is not enough', async () => { + await expect(Boba_GasPriceOracle.connect(signer2).withdrawBOBA()).to.be + .reverted + }) + }) + + describe('withdrawETH', () => { + it('should revert if called by someone other than the owner', async () => { + await expect(Boba_GasPriceOracle.connect(signer2).withdrawETH()).to.be + .reverted + }) + }) + // Test cases for gas estimation const inputs = [ '0x', From 07b34e61b405c44dab750c0b53d5f84efdabc6fe Mon Sep 17 00:00:00 2001 From: cby3149 Date: Sun, 10 Apr 2022 17:25:10 -0700 Subject: [PATCH 02/10] Add integration tests --- .../test/boba-fee-payment.spec.ts | 216 ++++++++++++++++-- packages/boba/gas-price-oracle/src/service.ts | 5 + .../L2/predeploys/Boba_GasPriceOracle.sol | 18 +- packages/contracts/src/make-genesis.ts | 1 + .../L2/predeploys/Boba_GasPriceOracle.spec.ts | 78 +++++-- 5 files changed, 279 insertions(+), 39 deletions(-) diff --git a/integration-tests/test/boba-fee-payment.spec.ts b/integration-tests/test/boba-fee-payment.spec.ts index 7d4bab822e..9086a67595 100644 --- a/integration-tests/test/boba-fee-payment.spec.ts +++ b/integration-tests/test/boba-fee-payment.spec.ts @@ -418,12 +418,12 @@ describe('Boba Fee Payment Integration Tests', async () => { }) it('{tag:boba} should not be able to withdraw fees before the minimum is met', async () => { - await expect(Boba_GasPriceOracle.withdraw()).to.be.rejected + await expect(Boba_GasPriceOracle.withdrawBOBA()).to.be.rejected }) it('{tag:boba} should be able to withdraw fees back to L1 once the minimum is met', async function () { - const l1FeeWallet = await Boba_GasPriceOracle.l1FeeWallet() - const balanceBefore = await L1Boba.balanceOf(l1FeeWallet) + const feeWallet = await Boba_GasPriceOracle.feeWallet() + const balanceBefore = await L1Boba.balanceOf(feeWallet) const withdrawalAmount = await Boba_GasPriceOracle.MIN_WITHDRAWAL_AMOUNT() const l2WalletBalance = await L2Boba.balanceOf(env.l2Wallet.address) @@ -446,7 +446,7 @@ describe('Boba Fee Payment Integration Tests', async () => { const vaultBalance = await L2Boba.balanceOf(Boba_GasPriceOracle.address) // Submit the withdrawal. - const withdrawTx = await Boba_GasPriceOracle.withdraw({ + const withdrawTx = await Boba_GasPriceOracle.withdrawBOBA({ gasPrice: 0, }) @@ -456,7 +456,7 @@ describe('Boba Fee Payment Integration Tests', async () => { await env.waitForXDomainTransaction(withdrawTx) // Balance difference should be equal to old L2 balance. - const balanceAfter = await L1Boba.balanceOf(l1FeeWallet) + const balanceAfter = await L1Boba.balanceOf(feeWallet) expect(balanceAfter.sub(balanceBefore)).to.deep.equal( BigNumber.from(vaultBalance) ) @@ -540,7 +540,7 @@ describe('Boba Fee Payment Integration Tests', async () => { while (priceRatio < 3000) { const setPriceRatio = await Boba_GasPriceOracle.connect( env.l2Wallet_4 - ).updatePriceRatio(priceRatio) + ).updatePriceRatio(priceRatio, priceRatio) await setPriceRatio.wait() const ETHBalanceBefore = await env.l2Wallet.getBalance() @@ -586,7 +586,7 @@ describe('Boba Fee Payment Integration Tests', async () => { while (priceRatio < 3000) { const setPriceRatio = await Boba_GasPriceOracle.connect( env.l2Wallet_4 - ).updatePriceRatio(priceRatio) + ).updatePriceRatio(priceRatio, priceRatio) await setPriceRatio.wait() const ETHBalanceBefore = await env.l2Wallet.getBalance() @@ -735,6 +735,12 @@ describe('Boba Fee Payment Integration Tests', async () => { }) await fundTx.wait() + const fundBobaTx = await L2Boba.transfer( + wallet.address, + ethers.utils.parseEther('10') + ) + await fundBobaTx.wait() + // Register the fee token const registerTx = await Boba_GasPriceOracle.connect( wallet @@ -779,12 +785,31 @@ describe('Boba Fee Payment Integration Tests', async () => { }) await fundTx.wait() + const fundBobaTx = await L2Boba.transfer( + wallet.address, + ethers.utils.parseEther('10') + ) + await fundBobaTx.wait() + // Register the fee token const registerTx = await Boba_GasPriceOracle.connect( wallet ).useBobaAsFeeToken() await registerTx.wait() + const BobaBalance = await L2Boba.balanceOf(wallet.address) + const estimateGas = await L2Boba.connect(wallet).estimateGas.transfer( + env.l2Wallet.address, + BobaBalance + ) + const priceRatio = await Boba_GasPriceOracle.priceRatio() + const returnBobaTx = await L2Boba.connect(wallet).transfer( + env.l2Wallet.address, + BobaBalance.sub(estimateGas.mul(priceRatio)), + { gasLimit: estimateGas } + ) + await returnBobaTx.wait() + await expect( wallet.sendTransaction({ to: env.l2Wallet.address, @@ -804,6 +829,12 @@ describe('Boba Fee Payment Integration Tests', async () => { }) await transferTx.wait() + const fundBobaTx = await L2Boba.transfer( + randomWallet.address, + ethers.utils.parseEther('10') + ) + await fundBobaTx.wait() + const registerTx = await Boba_GasPriceOracle.connect( randomWallet ).useBobaAsFeeToken() @@ -840,12 +871,24 @@ describe('Boba Fee Payment Integration Tests', async () => { name = await L2Boba.name() version = '1' chainId = (await env.l2Provider.getNetwork()).chainId + + // Add ETH first + env.l2Wallet.sendTransaction({ + to: Boba_GasPriceOracle.address, + value: ethers.utils.parseEther('10'), + }) }) it('{tag:boba} should submit the meta transaction', async () => { const owner = env.l2Wallet_2.address const spender = Boba_GasPriceOracle.address - const value = (await Boba_GasPriceOracle.metaTransactionFee()).toString() + const receivedETHAmount = await Boba_GasPriceOracle.receivedETHAmount() + const marketPriceRatio = await Boba_GasPriceOracle.marketPriceRatio() + const metaTransactionFee = await Boba_GasPriceOracle.metaTransactionFee() + const value = receivedETHAmount + .mul(marketPriceRatio) + .add(metaTransactionFee) + .toString() const nonce = (await L2Boba.nonces(env.l2Wallet_2.address)).toNumber() const deadline = Math.floor(Date.now() / 1000) + 90 const verifyingContract = L2Boba.address @@ -865,8 +908,12 @@ describe('Boba Fee Payment Integration Tests', async () => { const sig = ethers.utils.splitSignature(signature) const BobaBalanceBefore = await L2Boba.balanceOf(env.l2Wallet_2.address) + const ETHBalanceBefore = await env.l2Wallet_2.getBalance() + const GPO_ETHBalanceBefore = await env.l2Provider.getBalance( + Boba_GasPriceOracle.address + ) - await Boba_GasPriceOracle.useBobaAsFeeTokenMetaTransaction( + const tx = await Boba_GasPriceOracle.swapBOBAForETHMetaTransaction( owner, spender, value, @@ -875,22 +922,36 @@ describe('Boba Fee Payment Integration Tests', async () => { sig.r, sig.s ) + const receipt = await tx.wait() + const txETHFee = receipt.gasUsed.mul(tx.gasPrice) - const isBobaAsFeeToken = await Boba_GasPriceOracle.bobaFeeTokenUsers( - env.l2Wallet_2.address - ) const BobaBalanceAfter = await L2Boba.balanceOf(env.l2Wallet_2.address) + const ETHBalanceAfter = await env.l2Wallet_2.getBalance() + const GPO_ETHBalanceAfter = await env.l2Provider.getBalance( + Boba_GasPriceOracle.address + ) expect(BobaBalanceAfter).to.be.deep.eq( BobaBalanceBefore.sub(BigNumber.from(value)) ) - expect(isBobaAsFeeToken).to.be.eq(true) + expect(ETHBalanceAfter).to.be.deep.eq( + ETHBalanceBefore.add(receivedETHAmount) + ) + expect(GPO_ETHBalanceAfter).to.be.deep.eq( + GPO_ETHBalanceBefore.sub(receivedETHAmount) + ) }) it('{tag:boba} should revert transaction if v, r and s are incorrect', async () => { const owner = env.l2Wallet_2.address const spender = Boba_GasPriceOracle.address - const value = (await Boba_GasPriceOracle.metaTransactionFee()).toString() + const receivedETHAmount = await Boba_GasPriceOracle.receivedETHAmount() + const marketPriceRatio = await Boba_GasPriceOracle.marketPriceRatio() + const metaTransactionFee = await Boba_GasPriceOracle.metaTransactionFee() + const value = receivedETHAmount + .mul(marketPriceRatio) + .add(metaTransactionFee) + .toString() const nonce = (await L2Boba.nonces(env.l2Wallet_2.address)).toNumber() const deadline = Math.floor(Date.now() / 1000) + 90 const verifyingContract = Boba_GasPriceOracle.address @@ -910,7 +971,7 @@ describe('Boba Fee Payment Integration Tests', async () => { const sig = ethers.utils.splitSignature(signature) await expect( - Boba_GasPriceOracle.useBobaAsFeeTokenMetaTransaction( + Boba_GasPriceOracle.swapBOBAForETHMetaTransaction( owner, spender, value, @@ -925,7 +986,13 @@ describe('Boba Fee Payment Integration Tests', async () => { it("{tag:boba} should revert transaction if users don't have sufficient Boba token", async () => { const owner = env.l2Wallet_2.address const spender = Boba_GasPriceOracle.address - const value = (await Boba_GasPriceOracle.metaTransactionFee()).toString() + const receivedETHAmount = await Boba_GasPriceOracle.receivedETHAmount() + const marketPriceRatio = await Boba_GasPriceOracle.marketPriceRatio() + const metaTransactionFee = await Boba_GasPriceOracle.metaTransactionFee() + const value = receivedETHAmount + .mul(marketPriceRatio) + .add(metaTransactionFee) + .toString() const nonce = (await L2Boba.nonces(env.l2Wallet_2.address)).toNumber() const deadline = Math.floor(Date.now() / 1000) + 90 const verifyingContract = L2Boba.address @@ -959,7 +1026,9 @@ describe('Boba Fee Payment Integration Tests', async () => { await transferTx.wait() await expect( - Boba_GasPriceOracle.useBobaAsFeeTokenMetaTransaction( + Boba_GasPriceOracle.connect( + env.l2Wallet_2 + ).swapBOBAForETHMetaTransaction( owner, spender, value, @@ -982,7 +1051,13 @@ describe('Boba Fee Payment Integration Tests', async () => { it('{tag:boba} should revert transaction if spender is not correct', async () => { const owner = env.l2Wallet_2.address const spender = env.addressesBOBA.FeedRegistry - const value = (await Boba_GasPriceOracle.metaTransactionFee()).toString() + const receivedETHAmount = await Boba_GasPriceOracle.receivedETHAmount() + const marketPriceRatio = await Boba_GasPriceOracle.marketPriceRatio() + const metaTransactionFee = await Boba_GasPriceOracle.metaTransactionFee() + const value = receivedETHAmount + .mul(marketPriceRatio) + .add(metaTransactionFee) + .toString() const nonce = (await L2Boba.nonces(env.l2Wallet_2.address)).toNumber() const deadline = Math.floor(Date.now() / 1000) + 90 const verifyingContract = L2Boba.address @@ -1002,7 +1077,7 @@ describe('Boba Fee Payment Integration Tests', async () => { const sig = ethers.utils.splitSignature(signature) await expect( - Boba_GasPriceOracle.useBobaAsFeeTokenMetaTransaction( + Boba_GasPriceOracle.swapBOBAForETHMetaTransaction( owner, spender, value, @@ -1037,7 +1112,7 @@ describe('Boba Fee Payment Integration Tests', async () => { const sig = ethers.utils.splitSignature(signature) await expect( - Boba_GasPriceOracle.useBobaAsFeeTokenMetaTransaction( + Boba_GasPriceOracle.swapBOBAForETHMetaTransaction( owner, spender, value, @@ -1048,5 +1123,106 @@ describe('Boba Fee Payment Integration Tests', async () => { ) ).to.be.revertedWith('Value is not enough') }) + + it('{tag:boba} should swap BOBA for ETH using Boba as the fee token', async () => { + const newWallet = ethers.Wallet.createRandom().connect(env.l2Provider) + + // Use Boba as the fee token + await env.l2Wallet.sendTransaction({ + to: newWallet.address, + value: ethers.utils.parseEther('1'), + }) + await L2Boba.transfer(newWallet.address, ethers.utils.parseEther('100')) + await Boba_GasPriceOracle.connect(newWallet).useBobaAsFeeToken() + + // Get BOBA + await L2Boba.transfer(newWallet.address, ethers.utils.parseEther('100')) + + // Transfer ETH back + const ETHBalance = await newWallet.getBalance() + await newWallet.sendTransaction({ + to: env.l2Wallet.address, + value: ETHBalance, + }) + + const BobaBalanceBefore = await L2Boba.balanceOf(newWallet.address) + const ETHBalanceBefore = await newWallet.getBalance() + const GPO_ETHBalanceBefore = await env.l2Provider.getBalance( + Boba_GasPriceOracle.address + ) + + const owner = newWallet.address + const spender = Boba_GasPriceOracle.address + const receivedETHAmount = await Boba_GasPriceOracle.receivedETHAmount() + const marketPriceRatio = await Boba_GasPriceOracle.marketPriceRatio() + const metaTransactionFee = await Boba_GasPriceOracle.metaTransactionFee() + const value = receivedETHAmount + .mul(marketPriceRatio) + .add(metaTransactionFee) + .toString() + const nonce = (await L2Boba.nonces(newWallet.address)).toNumber() + const deadline = Math.floor(Date.now() / 1000) + 90 + const verifyingContract = L2Boba.address + + const data: any = { + primaryType: 'Permit', + types: { EIP712Domain, Permit }, + domain: { name, version, chainId, verifyingContract }, + message: { owner, spender, value, nonce, deadline }, + } + + const signature = ethSigUtil.signTypedData( + Buffer.from(newWallet.privateKey.slice(2), 'hex'), + { data } + ) + + const sig = ethers.utils.splitSignature(signature) + + await Boba_GasPriceOracle.swapBOBAForETHMetaTransaction( + owner, + spender, + value, + deadline, + sig.v, + sig.r, + sig.s + ) + + const BobaBalanceAfter = await L2Boba.balanceOf(newWallet.address) + const ETHBalanceAfter = await newWallet.getBalance() + const GPO_ETHBalanceAfter = await env.l2Provider.getBalance( + Boba_GasPriceOracle.address + ) + + expect(BobaBalanceAfter).to.be.deep.eq( + BobaBalanceBefore.sub(BigNumber.from(value)) + ) + expect(ETHBalanceAfter).to.be.deep.eq( + ETHBalanceBefore.add(receivedETHAmount) + ) + expect(GPO_ETHBalanceAfter).to.be.deep.eq( + GPO_ETHBalanceBefore.sub(receivedETHAmount) + ) + }) + + it('{tag:boba} should retrieve ETH', async () => { + const feeWallet = await Boba_GasPriceOracle.feeWallet() + const ETHBalanceBefore = await env.l2Provider.getBalance(feeWallet) + const GPO_ETHBalanceBefore = await env.l2Provider.getBalance( + Boba_GasPriceOracle.address + ) + + await Boba_GasPriceOracle.connect(env.l2Wallet_4).withdrawETH() + + const ETHBalanceAfter = await env.l2Provider.getBalance(feeWallet) + const GPO_ETHBalanceAfter = await env.l2Provider.getBalance( + Boba_GasPriceOracle.address + ) + + expect(ETHBalanceAfter).to.be.eq( + ETHBalanceBefore.add(GPO_ETHBalanceBefore) + ) + expect(GPO_ETHBalanceAfter).to.be.eq(BigNumber.from(0)) + }) }) }) diff --git a/packages/boba/gas-price-oracle/src/service.ts b/packages/boba/gas-price-oracle/src/service.ts index 11b6db3754..3d80f49fd6 100644 --- a/packages/boba/gas-price-oracle/src/service.ts +++ b/packages/boba/gas-price-oracle/src/service.ts @@ -597,6 +597,9 @@ export class GasPriceOracleService extends BaseService { this.options.bobaFeeRatio100X) / 100 ) + const targetMarketPriceRatio = Math.floor( + this.state.ETHUSDPrice / this.state.BOBAUSDPrice + ) if (targetPriceRatio !== priceRatioInt) { let targetUpdatedPriceRatio = targetPriceRatio if (targetPriceRatio > priceRatio) { @@ -618,11 +621,13 @@ export class GasPriceOracleService extends BaseService { const gasPriceTx = await this.state.Boba_GasPriceOracle.updatePriceRatio( targetUpdatedPriceRatio, + targetMarketPriceRatio, { gasPrice: 0 } ) await gasPriceTx.wait() this.logger.info('Updated price ratio', { priceRatio: targetUpdatedPriceRatio, + targetMarketPriceRatio, }) } else { this.logger.info('No need to update price ratio', { diff --git a/packages/contracts/contracts/L2/predeploys/Boba_GasPriceOracle.sol b/packages/contracts/contracts/L2/predeploys/Boba_GasPriceOracle.sol index afbfbd712a..93ff19869b 100644 --- a/packages/contracts/contracts/L2/predeploys/Boba_GasPriceOracle.sol +++ b/packages/contracts/contracts/L2/predeploys/Boba_GasPriceOracle.sol @@ -48,6 +48,7 @@ contract Boba_GasPriceOracle { uint256 public minPriceRatio = 500; // The price ratio of ETH and BOBA + // This price ratio considers the saving percentage of using BOBA as the fee token uint256 public priceRatio; // Gas price oracle address @@ -62,6 +63,9 @@ contract Boba_GasPriceOracle { // Received ETH amount for the swap - 0.005 uint256 public receivedETHAmount = 5e15; + // Price ratio without discount + uint256 public marketPriceRatio; + /************* * Events * *************/ @@ -70,7 +74,7 @@ contract Boba_GasPriceOracle { event UseBobaAsFeeToken(address); event SwapBOBAForETHMetaTransaction(address); event UseETHAsFeeToken(address); - event UpdatePriceRatio(address, uint256); + event UpdatePriceRatio(address, uint256, uint256); event UpdateMaxPriceRatio(address, uint256); event UpdateMinPriceRatio(address, uint256); event UpdateGasPriceOracleAddress(address, address); @@ -142,6 +146,7 @@ contract Boba_GasPriceOracle { maxPriceRatio = 5000; priceRatio = 2000; minPriceRatio = 500; + marketPriceRatio = 2000; } /** @@ -174,12 +179,12 @@ contract Boba_GasPriceOracle { ) public { require(!Address.isContract(tokenOwner), "Account not EOA"); require(spender == address(this), "Spender is not this contract"); - uint256 totalCost = receivedETHAmount.mul(priceRatio).add(metaTransactionFee); + uint256 totalCost = receivedETHAmount.mul(marketPriceRatio).add(metaTransactionFee); require(value >= totalCost, "Value is not enough"); L2GovernanceERC20 bobaToken = L2GovernanceERC20(l2BobaAddress); bobaToken.permit(tokenOwner, spender, value, deadline, v, r, s); IERC20(l2BobaAddress).safeTransferFrom(tokenOwner, address(this), totalCost); - (bool sent, ) = address(msg.sender).call{ value: receivedETHAmount }(""); + (bool sent, ) = address(tokenOwner).call{ value: receivedETHAmount }(""); require(sent, "Failed to send ETH"); emit SwapBOBAForETHMetaTransaction(tokenOwner); } @@ -198,11 +203,14 @@ contract Boba_GasPriceOracle { /** * Update the price ratio of ETH and BOBA * @param _priceRatio the price ratio of ETH and BOBA + * @param _marketPriceRatio tha market price ratio of ETH and BOBA */ - function updatePriceRatio(uint256 _priceRatio) public onlyOwner { + function updatePriceRatio(uint256 _priceRatio, uint256 _marketPriceRatio) public onlyOwner { require(_priceRatio <= maxPriceRatio && _priceRatio >= minPriceRatio); + require(_marketPriceRatio <= maxPriceRatio && _marketPriceRatio >= minPriceRatio); priceRatio = _priceRatio; - emit UpdatePriceRatio(owner(), _priceRatio); + marketPriceRatio = _marketPriceRatio; + emit UpdatePriceRatio(owner(), _priceRatio, _marketPriceRatio); } /** diff --git a/packages/contracts/src/make-genesis.ts b/packages/contracts/src/make-genesis.ts index 333ed78072..2695b8e48d 100644 --- a/packages/contracts/src/make-genesis.ts +++ b/packages/contracts/src/make-genesis.ts @@ -133,6 +133,7 @@ export const makeL2GenesisFile = async ( gasPriceOracleAddress: predeploys.OVM_GasPriceOracle, metaTransactionFee: utils.parseEther('3'), receivedETHAmount: utils.parseEther('0.005'), + marketPriceRatio: 2000, } } diff --git a/packages/contracts/test/contracts/L2/predeploys/Boba_GasPriceOracle.spec.ts b/packages/contracts/test/contracts/L2/predeploys/Boba_GasPriceOracle.spec.ts index 8b0f22af2b..e12d38a3a3 100644 --- a/packages/contracts/test/contracts/L2/predeploys/Boba_GasPriceOracle.spec.ts +++ b/packages/contracts/test/contracts/L2/predeploys/Boba_GasPriceOracle.spec.ts @@ -7,7 +7,6 @@ import { ContractFactory, Contract, Signer, utils } from 'ethers' import { calculateL1Fee } from '@eth-optimism/core-utils' describe('Boba_GasPriceOracle', () => { - const initialGasPrice = 0 let signer1: Signer let signer2: Signer let address1: string @@ -33,7 +32,6 @@ describe('Boba_GasPriceOracle', () => { let OVM_GasPriceOracle: Contract beforeEach(async () => { Boba_GasPriceOracle = await Factory__Boba_GasPriceOracle.deploy() - const signer1Address = await signer1.getAddress() await Boba_GasPriceOracle.initialize(address1, address2) OVM_GasPriceOracle = await Factory__OVM_GasPriceOracle.deploy( await signer1.getAddress() @@ -92,19 +90,38 @@ describe('Boba_GasPriceOracle', () => { describe('updatePriceRatio', () => { it('should revert if called by someone other than the owner', async () => { - await expect(Boba_GasPriceOracle.connect(signer2).updatePriceRatio(1234)) - .to.be.reverted + await expect( + Boba_GasPriceOracle.connect(signer2).updatePriceRatio(1234, 1234) + ).to.be.reverted + }) + + it('should revert if number is too small or too large', async () => { + await expect( + Boba_GasPriceOracle.connect(signer2).updatePriceRatio(1, 1234) + ).to.be.reverted + await expect( + Boba_GasPriceOracle.connect(signer2).updatePriceRatio(1234, 1) + ).to.be.reverted + await expect( + Boba_GasPriceOracle.connect(signer2).updatePriceRatio(12340, 1234) + ).to.be.reverted + await expect( + Boba_GasPriceOracle.connect(signer2).updatePriceRatio(1234, 12340) + ).to.be.reverted }) it('should succeed if called by the owner and is equal to `1234`', async () => { - await expect(Boba_GasPriceOracle.connect(signer1).updatePriceRatio(1234)) - .to.not.be.reverted + await expect( + Boba_GasPriceOracle.connect(signer1).updatePriceRatio(1234, 1234) + ).to.not.be.reverted }) it('should emit event', async () => { - await expect(Boba_GasPriceOracle.connect(signer1).updatePriceRatio(1234)) + await expect( + Boba_GasPriceOracle.connect(signer1).updatePriceRatio(1234, 1234) + ) .to.emit(Boba_GasPriceOracle, 'UpdatePriceRatio') - .withArgs(await signer1.getAddress(), 1234) + .withArgs(await signer1.getAddress(), 1234, 1234) }) }) @@ -112,26 +129,42 @@ describe('Boba_GasPriceOracle', () => { it('should change when priceRatio is called', async () => { const priceRatio = 1234 - await Boba_GasPriceOracle.connect(signer1).updatePriceRatio(priceRatio) + await Boba_GasPriceOracle.connect(signer1).updatePriceRatio( + priceRatio, + priceRatio + ) expect(await Boba_GasPriceOracle.priceRatio()).to.equal(priceRatio) + expect(await Boba_GasPriceOracle.marketPriceRatio()).to.equal(priceRatio) }) - it('is the 5st storage slot', async () => { + it('is the 5th and 10th storage slot', async () => { const priceRatio = 2222 - const slot = 5 + const firstSlot = 5 + const secondSlot = 10 // set the price - await Boba_GasPriceOracle.connect(signer1).updatePriceRatio(priceRatio) + await Boba_GasPriceOracle.connect(signer1).updatePriceRatio( + priceRatio, + priceRatio + ) // get the storage slot value const priceRatioAtSlot = await signer1.provider.getStorageAt( Boba_GasPriceOracle.address, - slot + firstSlot ) expect(await Boba_GasPriceOracle.priceRatio()).to.equal( ethers.BigNumber.from(priceRatioAtSlot) ) + // get the storage slot value + const marketPriceRatioAtSlot = await signer1.provider.getStorageAt( + Boba_GasPriceOracle.address, + secondSlot + ) + expect(await Boba_GasPriceOracle.marketPriceRatio()).to.equal( + ethers.BigNumber.from(marketPriceRatioAtSlot) + ) }) }) @@ -442,7 +475,7 @@ describe('Boba_GasPriceOracle', () => { }) describe('get receivedETHAmount', () => { - it('should revert if caller is not owne', async () => { + it('should revert if caller is not owner', async () => { await expect( Boba_GasPriceOracle.connect(signer2).updateReceivedETHAmount( utils.parseEther('0.006') @@ -492,6 +525,23 @@ describe('Boba_GasPriceOracle', () => { }) }) + describe('receive ETH', () => { + it('should receive ETH', async () => { + const depositAmount = utils.parseEther('1') + const ETHBalanceBefore = await signer1.provider.getBalance( + Boba_GasPriceOracle.address + ) + await signer1.sendTransaction({ + to: Boba_GasPriceOracle.address, + value: depositAmount, + }) + const ETHBalanceAfter = await signer1.provider.getBalance( + Boba_GasPriceOracle.address + ) + expect(ETHBalanceAfter.sub(ETHBalanceBefore)).to.equal(depositAmount) + }) + }) + // Test cases for gas estimation const inputs = [ '0x', From f6db3b29a756a57e0e93f8b8e0a7f665caae7a31 Mon Sep 17 00:00:00 2001 From: cby3149 Date: Mon, 11 Apr 2022 12:06:23 -0700 Subject: [PATCH 03/10] Add getBOBAForSwap method --- .../test/boba-fee-payment.spec.ts | 38 +++--------------- ...n.js => metaTransaction_swapBOBAForETH.js} | 40 ++++++++++++++++--- .../serverless-mainnet.yml | 10 ++--- .../serverless-rinkeby.yml | 10 ++--- ...96D6A5beb1F661cf052722A1424CDDA3e9418.json | 2 +- .../L2/predeploys/Boba_GasPriceOracle.sol | 7 ++++ .../L2/predeploys/Boba_GasPriceOracle.spec.ts | 12 ++++++ 7 files changed, 70 insertions(+), 49 deletions(-) rename ops_boba/api/metatransaction-api/{metaTransaction_useBobaAsFeeToken.js => metaTransaction_swapBOBAForETH.js} (78%) diff --git a/integration-tests/test/boba-fee-payment.spec.ts b/integration-tests/test/boba-fee-payment.spec.ts index 9086a67595..acef6f34ca 100644 --- a/integration-tests/test/boba-fee-payment.spec.ts +++ b/integration-tests/test/boba-fee-payment.spec.ts @@ -883,12 +883,7 @@ describe('Boba Fee Payment Integration Tests', async () => { const owner = env.l2Wallet_2.address const spender = Boba_GasPriceOracle.address const receivedETHAmount = await Boba_GasPriceOracle.receivedETHAmount() - const marketPriceRatio = await Boba_GasPriceOracle.marketPriceRatio() - const metaTransactionFee = await Boba_GasPriceOracle.metaTransactionFee() - const value = receivedETHAmount - .mul(marketPriceRatio) - .add(metaTransactionFee) - .toString() + const value = await Boba_GasPriceOracle.getBOBAForSwap() const nonce = (await L2Boba.nonces(env.l2Wallet_2.address)).toNumber() const deadline = Math.floor(Date.now() / 1000) + 90 const verifyingContract = L2Boba.address @@ -945,13 +940,7 @@ describe('Boba Fee Payment Integration Tests', async () => { it('{tag:boba} should revert transaction if v, r and s are incorrect', async () => { const owner = env.l2Wallet_2.address const spender = Boba_GasPriceOracle.address - const receivedETHAmount = await Boba_GasPriceOracle.receivedETHAmount() - const marketPriceRatio = await Boba_GasPriceOracle.marketPriceRatio() - const metaTransactionFee = await Boba_GasPriceOracle.metaTransactionFee() - const value = receivedETHAmount - .mul(marketPriceRatio) - .add(metaTransactionFee) - .toString() + const value = await Boba_GasPriceOracle.getBOBAForSwap() const nonce = (await L2Boba.nonces(env.l2Wallet_2.address)).toNumber() const deadline = Math.floor(Date.now() / 1000) + 90 const verifyingContract = Boba_GasPriceOracle.address @@ -986,13 +975,7 @@ describe('Boba Fee Payment Integration Tests', async () => { it("{tag:boba} should revert transaction if users don't have sufficient Boba token", async () => { const owner = env.l2Wallet_2.address const spender = Boba_GasPriceOracle.address - const receivedETHAmount = await Boba_GasPriceOracle.receivedETHAmount() - const marketPriceRatio = await Boba_GasPriceOracle.marketPriceRatio() - const metaTransactionFee = await Boba_GasPriceOracle.metaTransactionFee() - const value = receivedETHAmount - .mul(marketPriceRatio) - .add(metaTransactionFee) - .toString() + const value = await Boba_GasPriceOracle.getBOBAForSwap() const nonce = (await L2Boba.nonces(env.l2Wallet_2.address)).toNumber() const deadline = Math.floor(Date.now() / 1000) + 90 const verifyingContract = L2Boba.address @@ -1051,13 +1034,7 @@ describe('Boba Fee Payment Integration Tests', async () => { it('{tag:boba} should revert transaction if spender is not correct', async () => { const owner = env.l2Wallet_2.address const spender = env.addressesBOBA.FeedRegistry - const receivedETHAmount = await Boba_GasPriceOracle.receivedETHAmount() - const marketPriceRatio = await Boba_GasPriceOracle.marketPriceRatio() - const metaTransactionFee = await Boba_GasPriceOracle.metaTransactionFee() - const value = receivedETHAmount - .mul(marketPriceRatio) - .add(metaTransactionFee) - .toString() + const value = await Boba_GasPriceOracle.getBOBAForSwap() const nonce = (await L2Boba.nonces(env.l2Wallet_2.address)).toNumber() const deadline = Math.floor(Date.now() / 1000) + 90 const verifyingContract = L2Boba.address @@ -1154,12 +1131,7 @@ describe('Boba Fee Payment Integration Tests', async () => { const owner = newWallet.address const spender = Boba_GasPriceOracle.address const receivedETHAmount = await Boba_GasPriceOracle.receivedETHAmount() - const marketPriceRatio = await Boba_GasPriceOracle.marketPriceRatio() - const metaTransactionFee = await Boba_GasPriceOracle.metaTransactionFee() - const value = receivedETHAmount - .mul(marketPriceRatio) - .add(metaTransactionFee) - .toString() + const value = await Boba_GasPriceOracle.getBOBAForSwap() const nonce = (await L2Boba.nonces(newWallet.address)).toNumber() const deadline = Math.floor(Date.now() / 1000) + 90 const verifyingContract = L2Boba.address diff --git a/ops_boba/api/metatransaction-api/metaTransaction_useBobaAsFeeToken.js b/ops_boba/api/metatransaction-api/metaTransaction_swapBOBAForETH.js similarity index 78% rename from ops_boba/api/metatransaction-api/metaTransaction_useBobaAsFeeToken.js rename to ops_boba/api/metatransaction-api/metaTransaction_swapBOBAForETH.js index 31505f04fc..05b4bf4b57 100644 --- a/ops_boba/api/metatransaction-api/metaTransaction_useBobaAsFeeToken.js +++ b/ops_boba/api/metatransaction-api/metaTransaction_swapBOBAForETH.js @@ -20,8 +20,10 @@ const BobaGasPriceOracleInterface = new ethers.utils.Interface([ 'function useBobaAsFeeToken()', 'function useETHAsFeeToken()', 'function bobaFeeTokenUsers(address) view returns (bool)', - 'function useBobaAsFeeTokenMetaTransaction(address,address,uint256,uint256,uint8,bytes32,bytes32)', + 'function swapBOBAForETHMetaTransaction(address,address,uint256,uint256,uint8,bytes32,bytes32)', 'function metaTransactionFee() view returns (uint256)', + 'function marketPriceRatio() view returns (uint256)', + 'function receivedETHAmount() view returns (uint256)', ]) const L2BobaInterface = new ethers.utils.Interface([ @@ -81,9 +83,14 @@ const verifyBobay = async (body) => { } const metaTransactionFee = await Boba_GasPriceOracle.metaTransactionFee() + const marketPriceRatio = await Boba_GasPriceOracle.marketPriceRatio() + const receivedETHAmount = await Boba_GasPriceOracle.receivedETHAmount() + const totalCost = receivedETHAmount + .mul(marketPriceRatio) + .add(metaTransactionFee) const L2BobaBalance = await L2Boba.balanceOf(owner) const bigNumberValue = ethers.BigNumber.from(value) - if (bigNumberValue.lt(metaTransactionFee)) { + if (bigNumberValue.lt(totalCost)) { return { isVerified: false, errorMessage: 'Invalid value', @@ -122,7 +129,7 @@ module.exports.mainnetHandler = async (event, context, callback) => { const sig = ethers.utils.splitSignature(signature) // Send transaction to node try { - const tx = await Boba_GasPriceOracle.useBobaAsFeeTokenMetaTransaction( + const tx = await Boba_GasPriceOracle.swapBOBAForETHMetaTransaction( owner, spender, value, @@ -163,9 +170,32 @@ module.exports.rinkebyHandler = async (event, context, callback) => { }) } + const { owner, spender, value, deadline, signature } = body + // Get r s v from signature + const sig = ethers.utils.splitSignature(signature) + // Send transaction to node + try { + const tx = await Boba_GasPriceOracle.swapBOBAForETHMetaTransaction( + owner, + spender, + value, + deadline, + sig.v, + sig.r, + sig.s + ) + await tx.wait() + } catch (err) { + return callback(null, { + headers, + statusCode: 400, + body: JSON.stringify({ status: 'failure', error: err }), + }) + } + return callback(null, { headers, - statusCode: 400, - body: JSON.stringify({ status: 'failure', error: 'not support' }), + statusCode: 201, + body: JSON.stringify({ status: 'success' }), }) } diff --git a/ops_boba/api/metatransaction-api/serverless-mainnet.yml b/ops_boba/api/metatransaction-api/serverless-mainnet.yml index 72f16ca513..cccee736e8 100644 --- a/ops_boba/api/metatransaction-api/serverless-mainnet.yml +++ b/ops_boba/api/metatransaction-api/serverless-mainnet.yml @@ -1,9 +1,9 @@ -service: sls-boba-mainnet-meta-transaction # NOTE: update this with your service name +service: sls-boba-mainnet-metaTransaction # NOTE: update this with your service name provider: name: aws runtime: nodejs12.x - stackName: sls-boba-mainnet-meta-transaction + stackName: sls-boba-mainnet-metaTransaction stage: prod region: us-east-1 role: ${file(env-mainnet.yml):ROLE} @@ -15,8 +15,8 @@ package: individually: true functions: - boba_useBobaAsFeeToken: - handler: metaTransaction_useBobaAsFeeToken.mainnetHandler + boba_swapBOBAForETH: + handler: metaTransaction_swapBOBAForETH.mainnetHandler memorySize: 10240 # optional, in MB, default is 1024 timeout: 60 # optional, in seconds, default is 6 vpc: @@ -27,7 +27,7 @@ functions: - ${file(env-mainnet.yml):SUBNET_ID_2} events: - http: - path: send.useBobaAsFeeToken + path: send.swapBOBAForETH method: post cors: true layers: diff --git a/ops_boba/api/metatransaction-api/serverless-rinkeby.yml b/ops_boba/api/metatransaction-api/serverless-rinkeby.yml index ae5efb41b8..2fafdfac1a 100644 --- a/ops_boba/api/metatransaction-api/serverless-rinkeby.yml +++ b/ops_boba/api/metatransaction-api/serverless-rinkeby.yml @@ -1,9 +1,9 @@ -service: sls-boba-rinkeby-meta-transaction # NOTE: update this with your service name +service: sls-boba-rinkeby-metaTransaction # NOTE: update this with your service name provider: name: aws runtime: nodejs12.x - stackName: sls-boba-rinkeby-meta-transaction + stackName: sls-boba-rinkeby-metaTransaction stage: prod region: us-east-1 role: ${file(env-rinkeby.yml):ROLE} @@ -15,8 +15,8 @@ package: individually: true functions: - boba_useBobaAsFeeToken: - handler: metaTransaction_useBobaAsFeeToken.rinkebyHandler + boba_swapBOBAForETH: + handler: metaTransaction_swapBOBAForETH.rinkebyHandler memorySize: 10240 # optional, in MB, default is 1024 timeout: 60 # optional, in seconds, default is 6 vpc: @@ -27,7 +27,7 @@ functions: - ${file(env-rinkeby.yml):SUBNET_ID_2} events: - http: - path: send.useBobaAsFeeToken + path: send.swapBOBAForETH method: post cors: true layers: diff --git a/packages/boba/register/addresses/addressesRinkeby_0x93A96D6A5beb1F661cf052722A1424CDDA3e9418.json b/packages/boba/register/addresses/addressesRinkeby_0x93A96D6A5beb1F661cf052722A1424CDDA3e9418.json index b069fc9869..75be8406a8 100644 --- a/packages/boba/register/addresses/addressesRinkeby_0x93A96D6A5beb1F661cf052722A1424CDDA3e9418.json +++ b/packages/boba/register/addresses/addressesRinkeby_0x93A96D6A5beb1F661cf052722A1424CDDA3e9418.json @@ -78,7 +78,7 @@ "BobaStraw_BOBAUSD": "0xd05AA5531b8e8DaB3BEe675f133dF3e330d9adA8", "BobaStraw_WBTCUSD": "0xA42656199f2eA3EbEa2bf9f267CCDc3A977e553C", "BobaStraw_OMGUSD": "0xD39d22A59FAf9B18f35035b9f1604F1A948778EB", - "Boba_GasPriceOracle":"0xBa09e0FE597AD838fe0D3Ab04beDCE69a2b390fA", + "Boba_GasPriceOracle":"0x11B987f4C488D00AC5CDfE6FA9dE243be25009e1", "Proxy__Boba_GasPriceOracle":"0x7F974A09a251dEA6b75af3e0A0e29D1133DaCf4b", "BobaMonsters": "0x02C92e7420Ba673ebf0080A6F3ce76D5cd4c854e", "BobaBillingContract": "0x1f9cb265A3Ecf4b6330247D73B83B9DBe9393Bea", diff --git a/packages/contracts/contracts/L2/predeploys/Boba_GasPriceOracle.sol b/packages/contracts/contracts/L2/predeploys/Boba_GasPriceOracle.sol index 93ff19869b..c7dc8b2c6e 100644 --- a/packages/contracts/contracts/L2/predeploys/Boba_GasPriceOracle.sol +++ b/packages/contracts/contracts/L2/predeploys/Boba_GasPriceOracle.sol @@ -264,6 +264,13 @@ contract Boba_GasPriceOracle { emit UpdateReceivedETHAmount(owner(), _receivedETHAmount); } + /** + * Get the price for swapping BOBA for ETH + */ + function getBOBAForSwap() public view returns (uint256) { + return receivedETHAmount.mul(marketPriceRatio).add(metaTransactionFee); + } + /** * Get L1 Boba fee for fee estimation * @param _txData the data payload diff --git a/packages/contracts/test/contracts/L2/predeploys/Boba_GasPriceOracle.spec.ts b/packages/contracts/test/contracts/L2/predeploys/Boba_GasPriceOracle.spec.ts index e12d38a3a3..6013db9e21 100644 --- a/packages/contracts/test/contracts/L2/predeploys/Boba_GasPriceOracle.spec.ts +++ b/packages/contracts/test/contracts/L2/predeploys/Boba_GasPriceOracle.spec.ts @@ -542,6 +542,18 @@ describe('Boba_GasPriceOracle', () => { }) }) + describe('getBOBAForSwap', () => { + it('should get correct BOBA for swapping BOBA for ETH', async () => { + const BobaCost = await Boba_GasPriceOracle.getBOBAForSwap() + const receivedETHAmount = await Boba_GasPriceOracle.receivedETHAmount() + const metaTransactionFee = await Boba_GasPriceOracle.metaTransactionFee() + const marketPriceRatio = await Boba_GasPriceOracle.marketPriceRatio() + expect( + receivedETHAmount.mul(marketPriceRatio).add(metaTransactionFee) + ).to.equal(BobaCost) + }) + }) + // Test cases for gas estimation const inputs = [ '0x', From 0dee513c9dcee1f61a22016edc4a7d7fe4dbcfb9 Mon Sep 17 00:00:00 2001 From: CAPtheorem <79423264+CAPtheorem@users.noreply.github.com> Date: Mon, 11 Apr 2022 12:29:29 -0700 Subject: [PATCH 04/10] Gateway addmetaswap support (#91) * add metatransaction * test metatx --- .../gateway/src/containers/wallet/Wallet.js | 7 +- .../contracts/Boba_GasPriceOracle.json | 214 +++++++++++++----- .../gateway/src/services/networkService.js | 125 +++++----- .../boba/gateway/src/util/masterConfig.js | 4 +- 4 files changed, 224 insertions(+), 126 deletions(-) diff --git a/packages/boba/gateway/src/containers/wallet/Wallet.js b/packages/boba/gateway/src/containers/wallet/Wallet.js index 286bce6830..818593b19e 100644 --- a/packages/boba/gateway/src/containers/wallet/Wallet.js +++ b/packages/boba/gateway/src/containers/wallet/Wallet.js @@ -136,10 +136,13 @@ function Wallet() { if (res) dispatch(openAlert('Emergency Swap submitted')) } +// disable hisding the EMERGENCY SWAP for testing +// && tooSmallETH + return ( - {layer === 'L2' && tooSmallETH && + {layer === 'L2' && @@ -147,7 +150,7 @@ function Wallet() { variant="body2" component="p" > - WARNING: Low ETH balance. + NOTE: ETH balance. {' '} Using Boba requires a minimum ETH balance (of 0.002 ETH) regardless of your fee setting, otherwise MetaMask may incorrectly reject transactions. diff --git a/packages/boba/gateway/src/deployment/contracts/Boba_GasPriceOracle.json b/packages/boba/gateway/src/deployment/contracts/Boba_GasPriceOracle.json index dc7b38655c..5602be9721 100644 --- a/packages/boba/gateway/src/deployment/contracts/Boba_GasPriceOracle.json +++ b/packages/boba/gateway/src/deployment/contracts/Boba_GasPriceOracle.json @@ -4,20 +4,17 @@ "sourceName": "contracts/L2/predeploys/Boba_GasPriceOracle.sol", "abi": [ { + "anonymous": false, "inputs": [ { + "indexed": false, "internalType": "address", - "name": "_l1FeeWallet", - "type": "address" - }, - { - "internalType": "address", - "name": "_l2BobaAddress", + "name": "", "type": "address" } ], - "stateMutability": "nonpayable", - "type": "constructor" + "name": "SwapBOBAForETHMetaTransaction", + "type": "event" }, { "anonymous": false, @@ -123,6 +120,12 @@ "name": "", "type": "address" }, + { + "indexed": false, + "internalType": "uint256", + "name": "", + "type": "uint256" + }, { "indexed": false, "internalType": "uint256", @@ -141,9 +144,15 @@ "internalType": "address", "name": "", "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "", + "type": "uint256" } ], - "name": "UseBobaAsFeeToken", + "name": "UpdateReceivedETHAmount", "type": "event" }, { @@ -156,7 +165,7 @@ "type": "address" } ], - "name": "UseBobaAsFeeTokenMetaTransaction", + "name": "UseBobaAsFeeToken", "type": "event" }, { @@ -188,7 +197,26 @@ "type": "address" } ], - "name": "Withdraw", + "name": "WithdrawBOBA", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "WithdrawETH", "type": "event" }, { @@ -223,6 +251,19 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [], + "name": "feeWallet", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [], "name": "gasPriceOracleAddress", @@ -236,6 +277,19 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [], + "name": "getBOBAForSwap", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [ { @@ -258,8 +312,8 @@ { "inputs": [ { - "internalType": "address", - "name": "_l1FeeWallet", + "internalType": "address payable", + "name": "_feeWallet", "type": "address" }, { @@ -275,7 +329,7 @@ }, { "inputs": [], - "name": "l1FeeWallet", + "name": "l2BobaAddress", "outputs": [ { "internalType": "address", @@ -288,12 +342,12 @@ }, { "inputs": [], - "name": "l2BobaAddress", + "name": "marketPriceRatio", "outputs": [ { - "internalType": "address", + "internalType": "uint256", "name": "", - "type": "address" + "type": "uint256" } ], "stateMutability": "view", @@ -364,6 +418,62 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [], + "name": "receivedETHAmount", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "tokenOwner", + "type": "address" + }, + { + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + }, + { + "internalType": "uint8", + "name": "v", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "r", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "s", + "type": "bytes32" + } + ], + "name": "swapBOBAForETHMetaTransaction", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [ { @@ -435,6 +545,11 @@ "internalType": "uint256", "name": "_priceRatio", "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_marketPriceRatio", + "type": "uint256" } ], "name": "updatePriceRatio", @@ -442,52 +557,22 @@ "stateMutability": "nonpayable", "type": "function" }, - { - "inputs": [], - "name": "useBobaAsFeeToken", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, { "inputs": [ - { - "internalType": "address", - "name": "tokenOwner", - "type": "address" - }, - { - "internalType": "address", - "name": "spender", - "type": "address" - }, { "internalType": "uint256", - "name": "value", + "name": "_receivedETHAmount", "type": "uint256" - }, - { - "internalType": "uint256", - "name": "deadline", - "type": "uint256" - }, - { - "internalType": "uint8", - "name": "v", - "type": "uint8" - }, - { - "internalType": "bytes32", - "name": "r", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "s", - "type": "bytes32" } ], - "name": "useBobaAsFeeTokenMetaTransaction", + "name": "updateReceivedETHAmount", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "useBobaAsFeeToken", "outputs": [], "stateMutability": "nonpayable", "type": "function" @@ -501,14 +586,25 @@ }, { "inputs": [], - "name": "withdraw", + "name": "withdrawBOBA", "outputs": [], "stateMutability": "nonpayable", "type": "function" + }, + { + "inputs": [], + "name": "withdrawETH", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "stateMutability": "payable", + "type": "receive" } ], - "bytecode": "0x60806040526113886003556101f4600455600680546001600160a01b03191673420000000000000000000000000000000000000f1790556729a2241af62c00006008553480156200004f57600080fd5b5060405162001951380380620019518339810160408190526200007291620000fc565b6001600160a01b038216158015906200009357506001600160a01b03811615155b6200009d57600080fd5b600180546001600160a01b039384166001600160a01b031991821617909155600280549290931691811691909117909155600080549091163317905562000134565b80516001600160a01b0381168114620000f757600080fd5b919050565b600080604083850312156200011057600080fd5b6200011b83620000df565b91506200012b60208401620000df565b90509250929050565b61180d80620001446000396000f3fe608060405234801561001057600080fd5b50600436106101815760003560e01c8063872ea499116100d8578063d3e5792b1161008c578063d8bd926011610066578063d8bd9260146102ee578063e3aea9ba14610301578063f2fde38b1461031457600080fd5b8063d3e5792b146102c2578063d4ff9218146102d2578063d86732ef146102e557600080fd5b80638fcfc813116100bd5780638fcfc81314610293578063c8a05413146102a6578063d2e1fb22146102b957600080fd5b8063872ea499146102795780638da5cb5b1461028257600080fd5b80632cf12ae51161013a578063485cc95511610114578063485cc955146102205780636805491b146102335780637728195c1461026657600080fd5b80632cf12ae5146101fd57806334fe1b16146102105780633ccfd60b1461021857600080fd5b80631b6771991161016b5780631b677199146101b757806323ec6320146101bf57806324b20eda146101d257600080fd5b80625c5fb2146101865780630aa2f4201461019b575b600080fd5b61019961019436600461148a565b610327565b005b6101a460055481565b6040519081526020015b60405180910390f35b610199610412565b6101a46101cd3660046114d2565b6104cd565b6002546101e5906001600160a01b031681565b6040516001600160a01b0390911681526020016101ae565b61019961020b3660046115bd565b61057e565b6101996107ba565b610199610872565b61019961022e366004611630565b610b1b565b610256610241366004611663565b60076020526000908152604090205460ff1681565b60405190151581526020016101ae565b6006546101e5906001600160a01b031681565b6101a460085481565b6000546001600160a01b03166101e5565b6101996102a1366004611663565b610c93565b6101996102b436600461148a565b610de9565b6101a460045481565b6101a4680821ab0d441498000081565b6001546101e5906001600160a01b031681565b6101a460035481565b6101996102fc36600461148a565b610eaa565b61019961030f36600461148a565b610f6d565b610199610322366004611663565b611020565b6000546001600160a01b031633148061034957506000546001600160a01b0316155b61039a5760405162461bcd60e51b815260206004820152601760248201527f63616c6c6572206973206e6f7420746865206f776e657200000000000000000060448201526064015b60405180910390fd5b60035481111580156103ac5750600081115b6103b557600080fd5b60048190557f680f379280fc8680df45c979a924c0084a250758604482cb01dadedbaa1c09c96103ed6000546001600160a01b031690565b604080516001600160a01b03909216825260208201849052015b60405180910390a150565b333b156104615760405162461bcd60e51b815260206004820152600f60248201527f4163636f756e74206e6f7420454f4100000000000000000000000000000000006044820152606401610391565b3360008181526007602090815260409182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905590519182527f764389830e6a6b84f4ea3f2551a4c5afbb6dff806f2d8f571f6913c6c4b62a4091015b60405180910390a1565b6006546005546040517f49948e0e0000000000000000000000000000000000000000000000000000000081526000926001600160a01b0316919082906349948e0e9061051d9087906004016116f4565b60206040518083038186803b15801561053557600080fd5b505afa158015610549573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061056d9190611707565b6105779190611720565b9392505050565b863b156105cd5760405162461bcd60e51b815260206004820152600f60248201527f4163636f756e74206e6f7420454f4100000000000000000000000000000000006044820152606401610391565b6001600160a01b03861630146106255760405162461bcd60e51b815260206004820152601c60248201527f5370656e646572206973206e6f74207468697320636f6e7472616374000000006044820152606401610391565b6008548510156106775760405162461bcd60e51b815260206004820152601360248201527f56616c7565206973206e6f7420656e6f756768000000000000000000000000006044820152606401610391565b6002546040517fd505accf0000000000000000000000000000000000000000000000000000000081526001600160a01b0389811660048301528881166024830152604482018890526064820187905260ff8616608483015260a4820185905260c4820184905290911690819063d505accf9060e401600060405180830381600087803b15801561070657600080fd5b505af115801561071a573d6000803e3d6000fd5b505060085460025461073b93506001600160a01b031691508a903090611183565b6001600160a01b03881660008181526007602090815260409182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117905590519182527fa83ec7f828d05f8e5f9016e73ac39ead0d0a20d1c62324ecca568b1a0d804b23910160405180910390a15050505050505050565b333b156108095760405162461bcd60e51b815260206004820152600f60248201527f4163636f756e74206e6f7420454f4100000000000000000000000000000000006044820152606401610391565b3360008181526007602090815260409182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117905590519182527fd1787ba09c5383b33cf88983fbbf2e6ae348746a3a906e1a1bb67c729661a4ac91016104c3565b6002546040517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152680821ab0d4414980000916001600160a01b0316906370a082319060240160206040518083038186803b1580156108d757600080fd5b505afa1580156108eb573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061090f9190611707565b10156109a95760405162461bcd60e51b815260206004820152605560248201527f426f62615f47617350726963654f7261636c653a207769746864726177616c2060448201527f616d6f756e74206d7573742062652067726561746572207468616e206d696e6960648201527f6d756d207769746864726177616c20616d6f756e740000000000000000000000608482015260a401610391565b6002546001546040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201527342000000000000000000000000000000000000109263a3a79548926001600160a01b039182169291169082906370a082319060240160206040518083038186803b158015610a2957600080fd5b505afa158015610a3d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a619190611707565b6000604051806020016040528060008152506040518663ffffffff1660e01b8152600401610a93959493929190611784565b600060405180830381600087803b158015610aad57600080fd5b505af1158015610ac1573d6000803e3d6000fd5b505050507f34d58c18c6c1df2c698ccac556acea92941ca7b99d2fccf9e3ac1852d0dec36f610af86000546001600160a01b031690565b600154604080516001600160a01b039384168152929091166020830152016104c3565b6000546001600160a01b0316331480610b3d57506000546001600160a01b0316155b610b895760405162461bcd60e51b815260206004820152601760248201527f63616c6c6572206973206e6f7420746865206f776e65720000000000000000006044820152606401610391565b6001546001600160a01b031615610be25760405162461bcd60e51b815260206004820152601d60248201527f436f6e747261637420686173206265656e20696e697469616c697a65640000006044820152606401610391565b6001600160a01b03821615801590610c0257506001600160a01b03811615155b610c0b57600080fd5b600180546001600160a01b039384167fffffffffffffffffffffffff0000000000000000000000000000000000000000918216179091556002805492909316918116919091179091556006805490911673420000000000000000000000000000000000000f1790556729a2241af62c00006008556113886003556107d06005556101f4600455565b6000546001600160a01b0316331480610cb557506000546001600160a01b0316155b610d015760405162461bcd60e51b815260206004820152601760248201527f63616c6c6572206973206e6f7420746865206f776e65720000000000000000006044820152606401610391565b803b610d4f5760405162461bcd60e51b815260206004820152600e60248201527f4163636f756e7420697320454f410000000000000000000000000000000000006044820152606401610391565b6001600160a01b038116610d6257600080fd5b600680546001600160a01b0383167fffffffffffffffffffffffff00000000000000000000000000000000000000009091161790557f226bf99888a1e70d41ce744b11ce2acd4d1d1b8cf4ad17a0e72e67acff4bf5a7610dca6000546001600160a01b031690565b604080516001600160a01b039283168152918416602083015201610407565b6000546001600160a01b0316331480610e0b57506000546001600160a01b0316155b610e575760405162461bcd60e51b815260206004820152601760248201527f63616c6c6572206973206e6f7420746865206f776e65720000000000000000006044820152606401610391565b6004548110158015610e695750600081115b610e7257600080fd5b60038190557f7a28f69b71e51c4a30f620a2cfe4ce5aad2cd3fe5cc9647e400e252b65033d416103ed6000546001600160a01b031690565b6000546001600160a01b0316331480610ecc57506000546001600160a01b0316155b610f185760405162461bcd60e51b815260206004820152601760248201527f63616c6c6572206973206e6f7420746865206f776e65720000000000000000006044820152606401610391565b6003548111158015610f2c57506004548110155b610f3557600080fd5b60058190557fa718d44799032ca9af8e2ebb2e678fee2ecc0e34f391c7f54a5f2324ed71170a6103ed6000546001600160a01b031690565b6000546001600160a01b0316331480610f8f57506000546001600160a01b0316155b610fdb5760405162461bcd60e51b815260206004820152601760248201527f63616c6c6572206973206e6f7420746865206f776e65720000000000000000006044820152606401610391565b60008111610fe857600080fd5b60088190557f1071f61d642716391065a6f38aac12cdc6a436ca6a6622a18ae0530495738afc6103ed6000546001600160a01b031690565b6000546001600160a01b031633148061104257506000546001600160a01b0316155b61108e5760405162461bcd60e51b815260206004820152601760248201527f63616c6c6572206973206e6f7420746865206f776e65720000000000000000006044820152606401610391565b6001600160a01b03811661110a5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152608401610391565b600080546001600160a01b038381167fffffffffffffffffffffffff000000000000000000000000000000000000000083168117909355604080519190921680825260208201939093527f5c486528ec3e3f0ea91181cff8116f02bfa350e03b8b6f12e00765adbb5af85c910160405180910390a15050565b604080516001600160a01b0385811660248301528416604482015260648082018490528251808303909101815260849091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f23b872dd0000000000000000000000000000000000000000000000000000000017905261120b908590611211565b50505050565b6000611266826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166112fb9092919063ffffffff16565b8051909150156112f6578080602001905181019061128491906117c2565b6112f65760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610391565b505050565b606061130a8484600085611312565b949350505050565b60608247101561138a5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610391565b843b6113d85760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610391565b600080866001600160a01b031685876040516113f491906117e4565b60006040518083038185875af1925050503d8060008114611431576040519150601f19603f3d011682016040523d82523d6000602084013e611436565b606091505b5091509150611446828286611451565b979650505050505050565b60608315611460575081610577565b8251156114705782518084602001fd5b8160405162461bcd60e51b815260040161039191906116f4565b60006020828403121561149c57600080fd5b5035919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6000602082840312156114e457600080fd5b813567ffffffffffffffff808211156114fc57600080fd5b818401915084601f83011261151057600080fd5b813581811115611522576115226114a3565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f01168101908382118183101715611568576115686114a3565b8160405282815287602084870101111561158157600080fd5b826020860160208301376000928101602001929092525095945050505050565b80356001600160a01b03811681146115b857600080fd5b919050565b600080600080600080600060e0888a0312156115d857600080fd5b6115e1886115a1565b96506115ef602089016115a1565b95506040880135945060608801359350608088013560ff8116811461161357600080fd5b9699959850939692959460a0840135945060c09093013592915050565b6000806040838503121561164357600080fd5b61164c836115a1565b915061165a602084016115a1565b90509250929050565b60006020828403121561167557600080fd5b610577826115a1565b60005b83811015611699578181015183820152602001611681565b8381111561120b5750506000910152565b600081518084526116c281602086016020860161167e565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b60208152600061057760208301846116aa565b60006020828403121561171957600080fd5b5051919050565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048311821515161561177f577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b500290565b60006001600160a01b03808816835280871660208401525084604083015263ffffffff8416606083015260a0608083015261144660a08301846116aa565b6000602082840312156117d457600080fd5b8151801515811461057757600080fd5b600082516117f681846020870161167e565b919091019291505056fea164736f6c6343000809000a", - "deployedBytecode": "0x608060405234801561001057600080fd5b50600436106101815760003560e01c8063872ea499116100d8578063d3e5792b1161008c578063d8bd926011610066578063d8bd9260146102ee578063e3aea9ba14610301578063f2fde38b1461031457600080fd5b8063d3e5792b146102c2578063d4ff9218146102d2578063d86732ef146102e557600080fd5b80638fcfc813116100bd5780638fcfc81314610293578063c8a05413146102a6578063d2e1fb22146102b957600080fd5b8063872ea499146102795780638da5cb5b1461028257600080fd5b80632cf12ae51161013a578063485cc95511610114578063485cc955146102205780636805491b146102335780637728195c1461026657600080fd5b80632cf12ae5146101fd57806334fe1b16146102105780633ccfd60b1461021857600080fd5b80631b6771991161016b5780631b677199146101b757806323ec6320146101bf57806324b20eda146101d257600080fd5b80625c5fb2146101865780630aa2f4201461019b575b600080fd5b61019961019436600461148a565b610327565b005b6101a460055481565b6040519081526020015b60405180910390f35b610199610412565b6101a46101cd3660046114d2565b6104cd565b6002546101e5906001600160a01b031681565b6040516001600160a01b0390911681526020016101ae565b61019961020b3660046115bd565b61057e565b6101996107ba565b610199610872565b61019961022e366004611630565b610b1b565b610256610241366004611663565b60076020526000908152604090205460ff1681565b60405190151581526020016101ae565b6006546101e5906001600160a01b031681565b6101a460085481565b6000546001600160a01b03166101e5565b6101996102a1366004611663565b610c93565b6101996102b436600461148a565b610de9565b6101a460045481565b6101a4680821ab0d441498000081565b6001546101e5906001600160a01b031681565b6101a460035481565b6101996102fc36600461148a565b610eaa565b61019961030f36600461148a565b610f6d565b610199610322366004611663565b611020565b6000546001600160a01b031633148061034957506000546001600160a01b0316155b61039a5760405162461bcd60e51b815260206004820152601760248201527f63616c6c6572206973206e6f7420746865206f776e657200000000000000000060448201526064015b60405180910390fd5b60035481111580156103ac5750600081115b6103b557600080fd5b60048190557f680f379280fc8680df45c979a924c0084a250758604482cb01dadedbaa1c09c96103ed6000546001600160a01b031690565b604080516001600160a01b03909216825260208201849052015b60405180910390a150565b333b156104615760405162461bcd60e51b815260206004820152600f60248201527f4163636f756e74206e6f7420454f4100000000000000000000000000000000006044820152606401610391565b3360008181526007602090815260409182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905590519182527f764389830e6a6b84f4ea3f2551a4c5afbb6dff806f2d8f571f6913c6c4b62a4091015b60405180910390a1565b6006546005546040517f49948e0e0000000000000000000000000000000000000000000000000000000081526000926001600160a01b0316919082906349948e0e9061051d9087906004016116f4565b60206040518083038186803b15801561053557600080fd5b505afa158015610549573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061056d9190611707565b6105779190611720565b9392505050565b863b156105cd5760405162461bcd60e51b815260206004820152600f60248201527f4163636f756e74206e6f7420454f4100000000000000000000000000000000006044820152606401610391565b6001600160a01b03861630146106255760405162461bcd60e51b815260206004820152601c60248201527f5370656e646572206973206e6f74207468697320636f6e7472616374000000006044820152606401610391565b6008548510156106775760405162461bcd60e51b815260206004820152601360248201527f56616c7565206973206e6f7420656e6f756768000000000000000000000000006044820152606401610391565b6002546040517fd505accf0000000000000000000000000000000000000000000000000000000081526001600160a01b0389811660048301528881166024830152604482018890526064820187905260ff8616608483015260a4820185905260c4820184905290911690819063d505accf9060e401600060405180830381600087803b15801561070657600080fd5b505af115801561071a573d6000803e3d6000fd5b505060085460025461073b93506001600160a01b031691508a903090611183565b6001600160a01b03881660008181526007602090815260409182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117905590519182527fa83ec7f828d05f8e5f9016e73ac39ead0d0a20d1c62324ecca568b1a0d804b23910160405180910390a15050505050505050565b333b156108095760405162461bcd60e51b815260206004820152600f60248201527f4163636f756e74206e6f7420454f4100000000000000000000000000000000006044820152606401610391565b3360008181526007602090815260409182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117905590519182527fd1787ba09c5383b33cf88983fbbf2e6ae348746a3a906e1a1bb67c729661a4ac91016104c3565b6002546040517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152680821ab0d4414980000916001600160a01b0316906370a082319060240160206040518083038186803b1580156108d757600080fd5b505afa1580156108eb573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061090f9190611707565b10156109a95760405162461bcd60e51b815260206004820152605560248201527f426f62615f47617350726963654f7261636c653a207769746864726177616c2060448201527f616d6f756e74206d7573742062652067726561746572207468616e206d696e6960648201527f6d756d207769746864726177616c20616d6f756e740000000000000000000000608482015260a401610391565b6002546001546040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201527342000000000000000000000000000000000000109263a3a79548926001600160a01b039182169291169082906370a082319060240160206040518083038186803b158015610a2957600080fd5b505afa158015610a3d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a619190611707565b6000604051806020016040528060008152506040518663ffffffff1660e01b8152600401610a93959493929190611784565b600060405180830381600087803b158015610aad57600080fd5b505af1158015610ac1573d6000803e3d6000fd5b505050507f34d58c18c6c1df2c698ccac556acea92941ca7b99d2fccf9e3ac1852d0dec36f610af86000546001600160a01b031690565b600154604080516001600160a01b039384168152929091166020830152016104c3565b6000546001600160a01b0316331480610b3d57506000546001600160a01b0316155b610b895760405162461bcd60e51b815260206004820152601760248201527f63616c6c6572206973206e6f7420746865206f776e65720000000000000000006044820152606401610391565b6001546001600160a01b031615610be25760405162461bcd60e51b815260206004820152601d60248201527f436f6e747261637420686173206265656e20696e697469616c697a65640000006044820152606401610391565b6001600160a01b03821615801590610c0257506001600160a01b03811615155b610c0b57600080fd5b600180546001600160a01b039384167fffffffffffffffffffffffff0000000000000000000000000000000000000000918216179091556002805492909316918116919091179091556006805490911673420000000000000000000000000000000000000f1790556729a2241af62c00006008556113886003556107d06005556101f4600455565b6000546001600160a01b0316331480610cb557506000546001600160a01b0316155b610d015760405162461bcd60e51b815260206004820152601760248201527f63616c6c6572206973206e6f7420746865206f776e65720000000000000000006044820152606401610391565b803b610d4f5760405162461bcd60e51b815260206004820152600e60248201527f4163636f756e7420697320454f410000000000000000000000000000000000006044820152606401610391565b6001600160a01b038116610d6257600080fd5b600680546001600160a01b0383167fffffffffffffffffffffffff00000000000000000000000000000000000000009091161790557f226bf99888a1e70d41ce744b11ce2acd4d1d1b8cf4ad17a0e72e67acff4bf5a7610dca6000546001600160a01b031690565b604080516001600160a01b039283168152918416602083015201610407565b6000546001600160a01b0316331480610e0b57506000546001600160a01b0316155b610e575760405162461bcd60e51b815260206004820152601760248201527f63616c6c6572206973206e6f7420746865206f776e65720000000000000000006044820152606401610391565b6004548110158015610e695750600081115b610e7257600080fd5b60038190557f7a28f69b71e51c4a30f620a2cfe4ce5aad2cd3fe5cc9647e400e252b65033d416103ed6000546001600160a01b031690565b6000546001600160a01b0316331480610ecc57506000546001600160a01b0316155b610f185760405162461bcd60e51b815260206004820152601760248201527f63616c6c6572206973206e6f7420746865206f776e65720000000000000000006044820152606401610391565b6003548111158015610f2c57506004548110155b610f3557600080fd5b60058190557fa718d44799032ca9af8e2ebb2e678fee2ecc0e34f391c7f54a5f2324ed71170a6103ed6000546001600160a01b031690565b6000546001600160a01b0316331480610f8f57506000546001600160a01b0316155b610fdb5760405162461bcd60e51b815260206004820152601760248201527f63616c6c6572206973206e6f7420746865206f776e65720000000000000000006044820152606401610391565b60008111610fe857600080fd5b60088190557f1071f61d642716391065a6f38aac12cdc6a436ca6a6622a18ae0530495738afc6103ed6000546001600160a01b031690565b6000546001600160a01b031633148061104257506000546001600160a01b0316155b61108e5760405162461bcd60e51b815260206004820152601760248201527f63616c6c6572206973206e6f7420746865206f776e65720000000000000000006044820152606401610391565b6001600160a01b03811661110a5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152608401610391565b600080546001600160a01b038381167fffffffffffffffffffffffff000000000000000000000000000000000000000083168117909355604080519190921680825260208201939093527f5c486528ec3e3f0ea91181cff8116f02bfa350e03b8b6f12e00765adbb5af85c910160405180910390a15050565b604080516001600160a01b0385811660248301528416604482015260648082018490528251808303909101815260849091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f23b872dd0000000000000000000000000000000000000000000000000000000017905261120b908590611211565b50505050565b6000611266826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166112fb9092919063ffffffff16565b8051909150156112f6578080602001905181019061128491906117c2565b6112f65760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610391565b505050565b606061130a8484600085611312565b949350505050565b60608247101561138a5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610391565b843b6113d85760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610391565b600080866001600160a01b031685876040516113f491906117e4565b60006040518083038185875af1925050503d8060008114611431576040519150601f19603f3d011682016040523d82523d6000602084013e611436565b606091505b5091509150611446828286611451565b979650505050505050565b60608315611460575081610577565b8251156114705782518084602001fd5b8160405162461bcd60e51b815260040161039191906116f4565b60006020828403121561149c57600080fd5b5035919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6000602082840312156114e457600080fd5b813567ffffffffffffffff808211156114fc57600080fd5b818401915084601f83011261151057600080fd5b813581811115611522576115226114a3565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f01168101908382118183101715611568576115686114a3565b8160405282815287602084870101111561158157600080fd5b826020860160208301376000928101602001929092525095945050505050565b80356001600160a01b03811681146115b857600080fd5b919050565b600080600080600080600060e0888a0312156115d857600080fd5b6115e1886115a1565b96506115ef602089016115a1565b95506040880135945060608801359350608088013560ff8116811461161357600080fd5b9699959850939692959460a0840135945060c09093013592915050565b6000806040838503121561164357600080fd5b61164c836115a1565b915061165a602084016115a1565b90509250929050565b60006020828403121561167557600080fd5b610577826115a1565b60005b83811015611699578181015183820152602001611681565b8381111561120b5750506000910152565b600081518084526116c281602086016020860161167e565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b60208152600061057760208301846116aa565b60006020828403121561171957600080fd5b5051919050565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048311821515161561177f577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b500290565b60006001600160a01b03808816835280871660208401525084604083015263ffffffff8416606083015260a0608083015261144660a08301846116aa565b6000602082840312156117d457600080fd5b8151801515811461057757600080fd5b600082516117f681846020870161167e565b919091019291505056fea164736f6c6343000809000a", + "bytecode": "0x60806040526113886003556101f4600455600680546001600160a01b03191673420000000000000000000000000000000000000f1790556729a2241af62c00006008556611c37937e0800060095534801561005957600080fd5b50611da5806100696000396000f3fe6080604052600436106101af5760003560e01c806389df963d116100ec578063d2e1fb221161008a578063e086e5ec11610064578063e086e5ec1461047b578063e3aea9ba14610490578063f25f4b56146104b0578063f2fde38b146104d057600080fd5b8063d2e1fb2214610432578063d3e5792b14610448578063d86732ef1461046557600080fd5b8063b54016dc116100c6578063b54016dc146103bc578063bc9bd6ee146103dc578063c8a05413146103fc578063cd0514ad1461041c57600080fd5b806389df963d146103695780638da5cb5b1461037e5780638fcfc8131461039c57600080fd5b806334fe1b16116101595780635b9da5c6116101335780635b9da5c6146102d35780636805491b146102f35780637728195c14610333578063872ea4991461035357600080fd5b806334fe1b1614610289578063438ac96c1461029e578063485cc955146102b357600080fd5b80631b6771991161018a5780631b6771991461021c57806323ec63201461023157806324b20eda1461025157600080fd5b80625c5fb2146101bb5780630aa2f420146101dd57806315a0c1ac1461020657600080fd5b366101b657005b600080fd5b3480156101c757600080fd5b506101db6101d63660046119d8565b6104f0565b005b3480156101e957600080fd5b506101f360055481565b6040519081526020015b60405180910390f35b34801561021257600080fd5b506101f3600a5481565b34801561022857600080fd5b506101db6105c7565b34801561023d57600080fd5b506101f361024c366004611a20565b6106da565b34801561025d57600080fd5b50600254610271906001600160a01b031681565b6040516001600160a01b0390911681526020016101fd565b34801561029557600080fd5b506101db61078b565b3480156102aa57600080fd5b506101f361092d565b3480156102bf57600080fd5b506101db6102ce366004611b07565b610957565b3480156102df57600080fd5b506101db6102ee3660046119d8565b610a70565b3480156102ff57600080fd5b5061032361030e366004611b40565b60076020526000908152604090205460ff1681565b60405190151581526020016101fd565b34801561033f57600080fd5b50600654610271906001600160a01b031681565b34801561035f57600080fd5b506101f360085481565b34801561037557600080fd5b506101db610b27565b34801561038a57600080fd5b506000546001600160a01b0316610271565b3480156103a857600080fd5b506101db6103b7366004611b40565b610dd0565b3480156103c857600080fd5b506101db6103d7366004611b5d565b610f12565b3480156103e857600080fd5b506101db6103f7366004611bd4565b6111d4565b34801561040857600080fd5b506101db6104173660046119d8565b6112d2565b34801561042857600080fd5b506101f360095481565b34801561043e57600080fd5b506101f360045481565b34801561045457600080fd5b506101f3680821ab0d441498000081565b34801561047157600080fd5b506101f360035481565b34801561048757600080fd5b506101db61137f565b34801561049c57600080fd5b506101db6104ab3660046119d8565b6114d2565b3480156104bc57600080fd5b50600154610271906001600160a01b031681565b3480156104dc57600080fd5b506101db6104eb366004611b40565b611571565b6000546001600160a01b0316331461054f5760405162461bcd60e51b815260206004820152601760248201527f63616c6c6572206973206e6f7420746865206f776e657200000000000000000060448201526064015b60405180910390fd5b60035481111580156105615750600081115b61056a57600080fd5b60048190557f680f379280fc8680df45c979a924c0084a250758604482cb01dadedbaa1c09c96105a26000546001600160a01b031690565b604080516001600160a01b03909216825260208201849052015b60405180910390a150565b333b156106165760405162461bcd60e51b815260206004820152600f60248201527f4163636f756e74206e6f7420454f4100000000000000000000000000000000006044820152606401610546565b66071afd498d00003331101561066e5760405162461bcd60e51b815260206004820152601860248201527f496e73756666696369656e74204554482062616c616e636500000000000000006044820152606401610546565b3360008181526007602090815260409182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905590519182527f764389830e6a6b84f4ea3f2551a4c5afbb6dff806f2d8f571f6913c6c4b62a4091015b60405180910390a1565b6006546005546040517f49948e0e0000000000000000000000000000000000000000000000000000000081526000926001600160a01b0316919082906349948e0e9061072a908790600401611c6c565b60206040518083038186803b15801561074257600080fd5b505afa158015610756573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061077a9190611c7f565b6107849190611cc7565b9392505050565b333b156107da5760405162461bcd60e51b815260206004820152600f60248201527f4163636f756e74206e6f7420454f4100000000000000000000000000000000006044820152606401610546565b6002546040517f70a082310000000000000000000000000000000000000000000000000000000081523360048201526729a2241af62c0000916001600160a01b0316906370a082319060240160206040518083038186803b15801561083e57600080fd5b505afa158015610852573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108769190611c7f565b10156108c45760405162461bcd60e51b815260206004820152601960248201527f496e73756666696369656e7420426f62612062616c616e6365000000000000006044820152606401610546565b3360008181526007602090815260409182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117905590519182527fd1787ba09c5383b33cf88983fbbf2e6ae348746a3a906e1a1bb67c729661a4ac91016106d0565b600061095260085461094c600a546009546116b990919063ffffffff16565b906116c5565b905090565b6001546001600160a01b0316156109b05760405162461bcd60e51b815260206004820152601d60248201527f436f6e747261637420686173206265656e20696e697469616c697a65640000006044820152606401610546565b6001600160a01b038216158015906109d057506001600160a01b03811615155b6109d957600080fd5b600180546001600160a01b039384167fffffffffffffffffffffffff000000000000000000000000000000000000000091821617909155600280549290931691811691909117909155600080548216331790556006805490911673420000000000000000000000000000000000000f1790556729a2241af62c00006008556113886003556107d060058190556101f4600455600a55565b6000546001600160a01b03163314610aca5760405162461bcd60e51b815260206004820152601760248201527f63616c6c6572206973206e6f7420746865206f776e65720000000000000000006044820152606401610546565b66038d7ea4c6800081118015610ae65750662386f26fc1000081105b610aef57600080fd5b60098190557fdcb9e069a0d16a974c9c0f4a88e2c9b79df5c45d9721c26461043d51c44682076105a26000546001600160a01b031690565b6002546040517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152680821ab0d4414980000916001600160a01b0316906370a082319060240160206040518083038186803b158015610b8c57600080fd5b505afa158015610ba0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bc49190611c7f565b1015610c5e5760405162461bcd60e51b815260206004820152605560248201527f426f62615f47617350726963654f7261636c653a207769746864726177616c2060448201527f616d6f756e74206d7573742062652067726561746572207468616e206d696e6960648201527f6d756d207769746864726177616c20616d6f756e740000000000000000000000608482015260a401610546565b6002546001546040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201527342000000000000000000000000000000000000109263a3a79548926001600160a01b039182169291169082906370a082319060240160206040518083038186803b158015610cde57600080fd5b505afa158015610cf2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d169190611c7f565b6000604051806020016040528060008152506040518663ffffffff1660e01b8152600401610d48959493929190611d04565b600060405180830381600087803b158015610d6257600080fd5b505af1158015610d76573d6000803e3d6000fd5b505050507f2c69c3957d9ca9782726f647b7a3592dd381f4370288551f5ed43fd3cc5b7753610dad6000546001600160a01b031690565b600154604080516001600160a01b039384168152929091166020830152016106d0565b6000546001600160a01b03163314610e2a5760405162461bcd60e51b815260206004820152601760248201527f63616c6c6572206973206e6f7420746865206f776e65720000000000000000006044820152606401610546565b803b610e785760405162461bcd60e51b815260206004820152600e60248201527f4163636f756e7420697320454f410000000000000000000000000000000000006044820152606401610546565b6001600160a01b038116610e8b57600080fd5b600680546001600160a01b0383167fffffffffffffffffffffffff00000000000000000000000000000000000000009091161790557f226bf99888a1e70d41ce744b11ce2acd4d1d1b8cf4ad17a0e72e67acff4bf5a7610ef36000546001600160a01b031690565b604080516001600160a01b0392831681529184166020830152016105bc565b863b15610f615760405162461bcd60e51b815260206004820152600f60248201527f4163636f756e74206e6f7420454f4100000000000000000000000000000000006044820152606401610546565b6001600160a01b0386163014610fb95760405162461bcd60e51b815260206004820152601c60248201527f5370656e646572206973206e6f74207468697320636f6e7472616374000000006044820152606401610546565b6000610fd860085461094c600a546009546116b990919063ffffffff16565b90508086101561102a5760405162461bcd60e51b815260206004820152601360248201527f56616c7565206973206e6f7420656e6f756768000000000000000000000000006044820152606401610546565b6002546040517fd505accf0000000000000000000000000000000000000000000000000000000081526001600160a01b038a811660048301528981166024830152604482018990526064820188905260ff8716608483015260a4820186905260c4820185905290911690819063d505accf9060e401600060405180830381600087803b1580156110b957600080fd5b505af11580156110cd573d6000803e3d6000fd5b50506002546110ea92506001600160a01b031690508a30856116d1565b6009546040516000916001600160a01b038c16918381818185875af1925050503d8060008114611136576040519150601f19603f3d011682016040523d82523d6000602084013e61113b565b606091505b505090508061118c5760405162461bcd60e51b815260206004820152601260248201527f4661696c656420746f2073656e642045544800000000000000000000000000006044820152606401610546565b6040516001600160a01b038b1681527fb92b4b358dfa6e521f7f80a5d0522cf04a2082482701a0d78ff2bb615df646be9060200160405180910390a150505050505050505050565b6000546001600160a01b0316331461122e5760405162461bcd60e51b815260206004820152601760248201527f63616c6c6572206973206e6f7420746865206f776e65720000000000000000006044820152606401610546565b600354821115801561124257506004548210155b61124b57600080fd5b600354811115801561125f57506004548110155b61126857600080fd5b6005829055600a8190557f23632bbb735dece542dac9735a2ba4253234eb119ce45cdf9968cbbe12aa67906112a56000546001600160a01b031690565b604080516001600160a01b0390921682526020820185905281018390526060015b60405180910390a15050565b6000546001600160a01b0316331461132c5760405162461bcd60e51b815260206004820152601760248201527f63616c6c6572206973206e6f7420746865206f776e65720000000000000000006044820152606401610546565b600454811015801561133e5750600081115b61134757600080fd5b60038190557f7a28f69b71e51c4a30f620a2cfe4ce5aad2cd3fe5cc9647e400e252b65033d416105a26000546001600160a01b031690565b6000546001600160a01b031633146113d95760405162461bcd60e51b815260206004820152601760248201527f63616c6c6572206973206e6f7420746865206f776e65720000000000000000006044820152606401610546565b6001546040516000916001600160a01b03169047908381818185875af1925050503d8060008114611426576040519150601f19603f3d011682016040523d82523d6000602084013e61142b565b606091505b505090508061147c5760405162461bcd60e51b815260206004820181905260248201527f4661696c656420746f2073656e642045544820746f206665652077616c6c65746044820152606401610546565b7f6de63bb986f2779478e384365c03cc2e62f06b453856acca87d5a519ce0266496114af6000546001600160a01b031690565b600154604080516001600160a01b039384168152929091166020830152016105bc565b6000546001600160a01b0316331461152c5760405162461bcd60e51b815260206004820152601760248201527f63616c6c6572206973206e6f7420746865206f776e65720000000000000000006044820152606401610546565b6000811161153957600080fd5b60088190557f1071f61d642716391065a6f38aac12cdc6a436ca6a6622a18ae0530495738afc6105a26000546001600160a01b031690565b6000546001600160a01b031633146115cb5760405162461bcd60e51b815260206004820152601760248201527f63616c6c6572206973206e6f7420746865206f776e65720000000000000000006044820152606401610546565b6001600160a01b0381166116475760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152608401610546565b600080546001600160a01b038381167fffffffffffffffffffffffff000000000000000000000000000000000000000083168117909355604080519190921680825260208201939093527f5c486528ec3e3f0ea91181cff8116f02bfa350e03b8b6f12e00765adbb5af85c91016112c6565b60006107848284611cc7565b60006107848284611d42565b604080516001600160a01b0385811660248301528416604482015260648082018490528251808303909101815260849091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f23b872dd0000000000000000000000000000000000000000000000000000000017905261175990859061175f565b50505050565b60006117b4826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166118499092919063ffffffff16565b80519091501561184457808060200190518101906117d29190611d5a565b6118445760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610546565b505050565b60606118588484600085611860565b949350505050565b6060824710156118d85760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610546565b843b6119265760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610546565b600080866001600160a01b031685876040516119429190611d7c565b60006040518083038185875af1925050503d806000811461197f576040519150601f19603f3d011682016040523d82523d6000602084013e611984565b606091505b509150915061199482828661199f565b979650505050505050565b606083156119ae575081610784565b8251156119be5782518084602001fd5b8160405162461bcd60e51b81526004016105469190611c6c565b6000602082840312156119ea57600080fd5b5035919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600060208284031215611a3257600080fd5b813567ffffffffffffffff80821115611a4a57600080fd5b818401915084601f830112611a5e57600080fd5b813581811115611a7057611a706119f1565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f01168101908382118183101715611ab657611ab66119f1565b81604052828152876020848701011115611acf57600080fd5b826020860160208301376000928101602001929092525095945050505050565b6001600160a01b0381168114611b0457600080fd5b50565b60008060408385031215611b1a57600080fd5b8235611b2581611aef565b91506020830135611b3581611aef565b809150509250929050565b600060208284031215611b5257600080fd5b813561078481611aef565b600080600080600080600060e0888a031215611b7857600080fd5b8735611b8381611aef565b96506020880135611b9381611aef565b95506040880135945060608801359350608088013560ff81168114611bb757600080fd5b9699959850939692959460a0840135945060c09093013592915050565b60008060408385031215611be757600080fd5b50508035926020909101359150565b60005b83811015611c11578181015183820152602001611bf9565b838111156117595750506000910152565b60008151808452611c3a816020860160208601611bf6565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6020815260006107846020830184611c22565b600060208284031215611c9157600080fd5b5051919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615611cff57611cff611c98565b500290565b60006001600160a01b03808816835280871660208401525084604083015263ffffffff8416606083015260a0608083015261199460a0830184611c22565b60008219821115611d5557611d55611c98565b500190565b600060208284031215611d6c57600080fd5b8151801515811461078457600080fd5b60008251611d8e818460208701611bf6565b919091019291505056fea164736f6c6343000809000a", + "deployedBytecode": "0x6080604052600436106101af5760003560e01c806389df963d116100ec578063d2e1fb221161008a578063e086e5ec11610064578063e086e5ec1461047b578063e3aea9ba14610490578063f25f4b56146104b0578063f2fde38b146104d057600080fd5b8063d2e1fb2214610432578063d3e5792b14610448578063d86732ef1461046557600080fd5b8063b54016dc116100c6578063b54016dc146103bc578063bc9bd6ee146103dc578063c8a05413146103fc578063cd0514ad1461041c57600080fd5b806389df963d146103695780638da5cb5b1461037e5780638fcfc8131461039c57600080fd5b806334fe1b16116101595780635b9da5c6116101335780635b9da5c6146102d35780636805491b146102f35780637728195c14610333578063872ea4991461035357600080fd5b806334fe1b1614610289578063438ac96c1461029e578063485cc955146102b357600080fd5b80631b6771991161018a5780631b6771991461021c57806323ec63201461023157806324b20eda1461025157600080fd5b80625c5fb2146101bb5780630aa2f420146101dd57806315a0c1ac1461020657600080fd5b366101b657005b600080fd5b3480156101c757600080fd5b506101db6101d63660046119d8565b6104f0565b005b3480156101e957600080fd5b506101f360055481565b6040519081526020015b60405180910390f35b34801561021257600080fd5b506101f3600a5481565b34801561022857600080fd5b506101db6105c7565b34801561023d57600080fd5b506101f361024c366004611a20565b6106da565b34801561025d57600080fd5b50600254610271906001600160a01b031681565b6040516001600160a01b0390911681526020016101fd565b34801561029557600080fd5b506101db61078b565b3480156102aa57600080fd5b506101f361092d565b3480156102bf57600080fd5b506101db6102ce366004611b07565b610957565b3480156102df57600080fd5b506101db6102ee3660046119d8565b610a70565b3480156102ff57600080fd5b5061032361030e366004611b40565b60076020526000908152604090205460ff1681565b60405190151581526020016101fd565b34801561033f57600080fd5b50600654610271906001600160a01b031681565b34801561035f57600080fd5b506101f360085481565b34801561037557600080fd5b506101db610b27565b34801561038a57600080fd5b506000546001600160a01b0316610271565b3480156103a857600080fd5b506101db6103b7366004611b40565b610dd0565b3480156103c857600080fd5b506101db6103d7366004611b5d565b610f12565b3480156103e857600080fd5b506101db6103f7366004611bd4565b6111d4565b34801561040857600080fd5b506101db6104173660046119d8565b6112d2565b34801561042857600080fd5b506101f360095481565b34801561043e57600080fd5b506101f360045481565b34801561045457600080fd5b506101f3680821ab0d441498000081565b34801561047157600080fd5b506101f360035481565b34801561048757600080fd5b506101db61137f565b34801561049c57600080fd5b506101db6104ab3660046119d8565b6114d2565b3480156104bc57600080fd5b50600154610271906001600160a01b031681565b3480156104dc57600080fd5b506101db6104eb366004611b40565b611571565b6000546001600160a01b0316331461054f5760405162461bcd60e51b815260206004820152601760248201527f63616c6c6572206973206e6f7420746865206f776e657200000000000000000060448201526064015b60405180910390fd5b60035481111580156105615750600081115b61056a57600080fd5b60048190557f680f379280fc8680df45c979a924c0084a250758604482cb01dadedbaa1c09c96105a26000546001600160a01b031690565b604080516001600160a01b03909216825260208201849052015b60405180910390a150565b333b156106165760405162461bcd60e51b815260206004820152600f60248201527f4163636f756e74206e6f7420454f4100000000000000000000000000000000006044820152606401610546565b66071afd498d00003331101561066e5760405162461bcd60e51b815260206004820152601860248201527f496e73756666696369656e74204554482062616c616e636500000000000000006044820152606401610546565b3360008181526007602090815260409182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905590519182527f764389830e6a6b84f4ea3f2551a4c5afbb6dff806f2d8f571f6913c6c4b62a4091015b60405180910390a1565b6006546005546040517f49948e0e0000000000000000000000000000000000000000000000000000000081526000926001600160a01b0316919082906349948e0e9061072a908790600401611c6c565b60206040518083038186803b15801561074257600080fd5b505afa158015610756573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061077a9190611c7f565b6107849190611cc7565b9392505050565b333b156107da5760405162461bcd60e51b815260206004820152600f60248201527f4163636f756e74206e6f7420454f4100000000000000000000000000000000006044820152606401610546565b6002546040517f70a082310000000000000000000000000000000000000000000000000000000081523360048201526729a2241af62c0000916001600160a01b0316906370a082319060240160206040518083038186803b15801561083e57600080fd5b505afa158015610852573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108769190611c7f565b10156108c45760405162461bcd60e51b815260206004820152601960248201527f496e73756666696369656e7420426f62612062616c616e6365000000000000006044820152606401610546565b3360008181526007602090815260409182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117905590519182527fd1787ba09c5383b33cf88983fbbf2e6ae348746a3a906e1a1bb67c729661a4ac91016106d0565b600061095260085461094c600a546009546116b990919063ffffffff16565b906116c5565b905090565b6001546001600160a01b0316156109b05760405162461bcd60e51b815260206004820152601d60248201527f436f6e747261637420686173206265656e20696e697469616c697a65640000006044820152606401610546565b6001600160a01b038216158015906109d057506001600160a01b03811615155b6109d957600080fd5b600180546001600160a01b039384167fffffffffffffffffffffffff000000000000000000000000000000000000000091821617909155600280549290931691811691909117909155600080548216331790556006805490911673420000000000000000000000000000000000000f1790556729a2241af62c00006008556113886003556107d060058190556101f4600455600a55565b6000546001600160a01b03163314610aca5760405162461bcd60e51b815260206004820152601760248201527f63616c6c6572206973206e6f7420746865206f776e65720000000000000000006044820152606401610546565b66038d7ea4c6800081118015610ae65750662386f26fc1000081105b610aef57600080fd5b60098190557fdcb9e069a0d16a974c9c0f4a88e2c9b79df5c45d9721c26461043d51c44682076105a26000546001600160a01b031690565b6002546040517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152680821ab0d4414980000916001600160a01b0316906370a082319060240160206040518083038186803b158015610b8c57600080fd5b505afa158015610ba0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bc49190611c7f565b1015610c5e5760405162461bcd60e51b815260206004820152605560248201527f426f62615f47617350726963654f7261636c653a207769746864726177616c2060448201527f616d6f756e74206d7573742062652067726561746572207468616e206d696e6960648201527f6d756d207769746864726177616c20616d6f756e740000000000000000000000608482015260a401610546565b6002546001546040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201527342000000000000000000000000000000000000109263a3a79548926001600160a01b039182169291169082906370a082319060240160206040518083038186803b158015610cde57600080fd5b505afa158015610cf2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d169190611c7f565b6000604051806020016040528060008152506040518663ffffffff1660e01b8152600401610d48959493929190611d04565b600060405180830381600087803b158015610d6257600080fd5b505af1158015610d76573d6000803e3d6000fd5b505050507f2c69c3957d9ca9782726f647b7a3592dd381f4370288551f5ed43fd3cc5b7753610dad6000546001600160a01b031690565b600154604080516001600160a01b039384168152929091166020830152016106d0565b6000546001600160a01b03163314610e2a5760405162461bcd60e51b815260206004820152601760248201527f63616c6c6572206973206e6f7420746865206f776e65720000000000000000006044820152606401610546565b803b610e785760405162461bcd60e51b815260206004820152600e60248201527f4163636f756e7420697320454f410000000000000000000000000000000000006044820152606401610546565b6001600160a01b038116610e8b57600080fd5b600680546001600160a01b0383167fffffffffffffffffffffffff00000000000000000000000000000000000000009091161790557f226bf99888a1e70d41ce744b11ce2acd4d1d1b8cf4ad17a0e72e67acff4bf5a7610ef36000546001600160a01b031690565b604080516001600160a01b0392831681529184166020830152016105bc565b863b15610f615760405162461bcd60e51b815260206004820152600f60248201527f4163636f756e74206e6f7420454f4100000000000000000000000000000000006044820152606401610546565b6001600160a01b0386163014610fb95760405162461bcd60e51b815260206004820152601c60248201527f5370656e646572206973206e6f74207468697320636f6e7472616374000000006044820152606401610546565b6000610fd860085461094c600a546009546116b990919063ffffffff16565b90508086101561102a5760405162461bcd60e51b815260206004820152601360248201527f56616c7565206973206e6f7420656e6f756768000000000000000000000000006044820152606401610546565b6002546040517fd505accf0000000000000000000000000000000000000000000000000000000081526001600160a01b038a811660048301528981166024830152604482018990526064820188905260ff8716608483015260a4820186905260c4820185905290911690819063d505accf9060e401600060405180830381600087803b1580156110b957600080fd5b505af11580156110cd573d6000803e3d6000fd5b50506002546110ea92506001600160a01b031690508a30856116d1565b6009546040516000916001600160a01b038c16918381818185875af1925050503d8060008114611136576040519150601f19603f3d011682016040523d82523d6000602084013e61113b565b606091505b505090508061118c5760405162461bcd60e51b815260206004820152601260248201527f4661696c656420746f2073656e642045544800000000000000000000000000006044820152606401610546565b6040516001600160a01b038b1681527fb92b4b358dfa6e521f7f80a5d0522cf04a2082482701a0d78ff2bb615df646be9060200160405180910390a150505050505050505050565b6000546001600160a01b0316331461122e5760405162461bcd60e51b815260206004820152601760248201527f63616c6c6572206973206e6f7420746865206f776e65720000000000000000006044820152606401610546565b600354821115801561124257506004548210155b61124b57600080fd5b600354811115801561125f57506004548110155b61126857600080fd5b6005829055600a8190557f23632bbb735dece542dac9735a2ba4253234eb119ce45cdf9968cbbe12aa67906112a56000546001600160a01b031690565b604080516001600160a01b0390921682526020820185905281018390526060015b60405180910390a15050565b6000546001600160a01b0316331461132c5760405162461bcd60e51b815260206004820152601760248201527f63616c6c6572206973206e6f7420746865206f776e65720000000000000000006044820152606401610546565b600454811015801561133e5750600081115b61134757600080fd5b60038190557f7a28f69b71e51c4a30f620a2cfe4ce5aad2cd3fe5cc9647e400e252b65033d416105a26000546001600160a01b031690565b6000546001600160a01b031633146113d95760405162461bcd60e51b815260206004820152601760248201527f63616c6c6572206973206e6f7420746865206f776e65720000000000000000006044820152606401610546565b6001546040516000916001600160a01b03169047908381818185875af1925050503d8060008114611426576040519150601f19603f3d011682016040523d82523d6000602084013e61142b565b606091505b505090508061147c5760405162461bcd60e51b815260206004820181905260248201527f4661696c656420746f2073656e642045544820746f206665652077616c6c65746044820152606401610546565b7f6de63bb986f2779478e384365c03cc2e62f06b453856acca87d5a519ce0266496114af6000546001600160a01b031690565b600154604080516001600160a01b039384168152929091166020830152016105bc565b6000546001600160a01b0316331461152c5760405162461bcd60e51b815260206004820152601760248201527f63616c6c6572206973206e6f7420746865206f776e65720000000000000000006044820152606401610546565b6000811161153957600080fd5b60088190557f1071f61d642716391065a6f38aac12cdc6a436ca6a6622a18ae0530495738afc6105a26000546001600160a01b031690565b6000546001600160a01b031633146115cb5760405162461bcd60e51b815260206004820152601760248201527f63616c6c6572206973206e6f7420746865206f776e65720000000000000000006044820152606401610546565b6001600160a01b0381166116475760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152608401610546565b600080546001600160a01b038381167fffffffffffffffffffffffff000000000000000000000000000000000000000083168117909355604080519190921680825260208201939093527f5c486528ec3e3f0ea91181cff8116f02bfa350e03b8b6f12e00765adbb5af85c91016112c6565b60006107848284611cc7565b60006107848284611d42565b604080516001600160a01b0385811660248301528416604482015260648082018490528251808303909101815260849091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f23b872dd0000000000000000000000000000000000000000000000000000000017905261175990859061175f565b50505050565b60006117b4826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166118499092919063ffffffff16565b80519091501561184457808060200190518101906117d29190611d5a565b6118445760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610546565b505050565b60606118588484600085611860565b949350505050565b6060824710156118d85760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610546565b843b6119265760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610546565b600080866001600160a01b031685876040516119429190611d7c565b60006040518083038185875af1925050503d806000811461197f576040519150601f19603f3d011682016040523d82523d6000602084013e611984565b606091505b509150915061199482828661199f565b979650505050505050565b606083156119ae575081610784565b8251156119be5782518084602001fd5b8160405162461bcd60e51b81526004016105469190611c6c565b6000602082840312156119ea57600080fd5b5035919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600060208284031215611a3257600080fd5b813567ffffffffffffffff80821115611a4a57600080fd5b818401915084601f830112611a5e57600080fd5b813581811115611a7057611a706119f1565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f01168101908382118183101715611ab657611ab66119f1565b81604052828152876020848701011115611acf57600080fd5b826020860160208301376000928101602001929092525095945050505050565b6001600160a01b0381168114611b0457600080fd5b50565b60008060408385031215611b1a57600080fd5b8235611b2581611aef565b91506020830135611b3581611aef565b809150509250929050565b600060208284031215611b5257600080fd5b813561078481611aef565b600080600080600080600060e0888a031215611b7857600080fd5b8735611b8381611aef565b96506020880135611b9381611aef565b95506040880135945060608801359350608088013560ff81168114611bb757600080fd5b9699959850939692959460a0840135945060c09093013592915050565b60008060408385031215611be757600080fd5b50508035926020909101359150565b60005b83811015611c11578181015183820152602001611bf9565b838111156117595750506000910152565b60008151808452611c3a816020860160208601611bf6565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6020815260006107846020830184611c22565b600060208284031215611c9157600080fd5b5051919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615611cff57611cff611c98565b500290565b60006001600160a01b03808816835280871660208401525084604083015263ffffffff8416606083015260a0608083015261199460a0830184611c22565b60008219821115611d5557611d55611c98565b500190565b600060208284031215611d6c57600080fd5b8151801515811461078457600080fd5b60008251611d8e818460208701611bf6565b919091019291505056fea164736f6c6343000809000a", "linkReferences": {}, "deployedLinkReferences": {} } diff --git a/packages/boba/gateway/src/services/networkService.js b/packages/boba/gateway/src/services/networkService.js index 73f6ac4653..3bcd2a4f19 100644 --- a/packages/boba/gateway/src/services/networkService.js +++ b/packages/boba/gateway/src/services/networkService.js @@ -487,69 +487,68 @@ class NetworkService { console.log("triggering getETHMetaTransaction") - // const EIP712Domain = [ - // { name: 'name', type: 'string' }, - // { name: 'version', type: 'string' }, - // { name: 'chainId', type: 'uint256' }, - // { name: 'verifyingContract', type: 'address' }, - // ] - // const Permit = [ - // { name: 'owner', type: 'address' }, - // { name: 'spender', type: 'address' }, - // { name: 'value', type: 'uint256' }, - // { name: 'nonce', type: 'uint256' }, - // { name: 'deadline', type: 'uint256' }, - // ] - - // const bobaFeeContract = new ethers.Contract( - // allAddresses.Boba_GasPriceOracle, - // Boba_GasPriceOracleJson.abi, - // this.provider.getSigner() - // ) - - // const name = await this.BobaContract.name() - // const version = '1' - // const chainId = (await this.L2Provider.getNetwork()).chainId - - // const owner = this.account - // const spender = bobaFeeContract.address - // const value = (await bobaFeeContract.metaTransactionFee()).toNumber() - // const nonce = (await this.BobaContract.nonces(this.account)).toNumber() - - // // 5 minutes - // const deadline = Math.floor(Date.now() / 1000) + 300 - // const verifyingContract = this.BobaContract.address - - // const data = { - // primaryType: 'Permit', - // types: { EIP712Domain, Permit }, - // domain: { name, version, chainId, verifyingContract }, - // message: { owner, spender, value, nonce, deadline }, - // } - - // let signature - // try { - // signature = await this.provider.send('eth_signTypedData_v4', [this.account, JSON.stringify(data)]) - // } catch (error) { - // console.log(error) - // return error - // } - // // Send request - // try { - // const response = await metaTransactionAxiosInstance( - // this.networkGateway - // ).post('/send.useBobaAsFeeToken', { owner, spender, value, deadline, signature, data }) - // console.log("response",response) - // await this.getBobaFeeChoice() - // } catch (error) { - // console.log(error) - // // sigh - // let errorData = error.response.data.error - // if(errorData.hasOwnProperty('error')) { - // errorData = errorData.error.error.body - // } - // return errorData - // } + const EIP712Domain = [ + { name: 'name', type: 'string' }, + { name: 'version', type: 'string' }, + { name: 'chainId', type: 'uint256' }, + { name: 'verifyingContract', type: 'address' }, + ] + const Permit = [ + { name: 'owner', type: 'address' }, + { name: 'spender', type: 'address' }, + { name: 'value', type: 'uint256' }, + { name: 'nonce', type: 'uint256' }, + { name: 'deadline', type: 'uint256' }, + ] + + const owner = this.account + const spender = allAddresses.Boba_GasPriceOracle + + const Boba_GasPriceOracle = new ethers.Contract( + allAddresses.Boba_GasPriceOracle, + Boba_GasPriceOracleJson.abi, + this.provider.getSigner() + ) + + let value = (await Boba_GasPriceOracle.getBOBAForSwap()).toString() + const nonce = (await this.BobaContract.nonces(this.account)).toNumber() + const deadline = Math.floor(Date.now() / 1000) + 300 + const verifyingContract = this.BobaContract.address + + const name = await this.BobaContract.name() + const version = '1' + const chainId = (await this.L2Provider.getNetwork()).chainId + + const data = { + primaryType: 'Permit', + types: { EIP712Domain, Permit }, + domain: { name, version, chainId, verifyingContract }, + message: { owner, spender, value, nonce, deadline }, + } + + let signature + try { + signature = await this.provider.send('eth_signTypedData_v4', [this.account, JSON.stringify(data)]) + } catch (error) { + console.log(error) + return error + } + + try { + const response = await metaTransactionAxiosInstance( + this.networkGateway + ).post('/send.swapBOBAForETH', { owner, spender, value, deadline, signature, data }) + console.log("response",response) + await this.getBobaFeeChoice() + } catch (error) { + console.log(error) + // sigh + let errorData = error.response.data.error + if(errorData.hasOwnProperty('error')) { + errorData = errorData.error.error.body + } + return errorData + } } async getAddress(contractName, varToSet) { diff --git a/packages/boba/gateway/src/util/masterConfig.js b/packages/boba/gateway/src/util/masterConfig.js index 5d1a51fc74..6ad5d12bf8 100644 --- a/packages/boba/gateway/src/util/masterConfig.js +++ b/packages/boba/gateway/src/util/masterConfig.js @@ -130,9 +130,9 @@ const BaseServices = { //ETH gas station ETH_GAS_STATION_URL: `https://ethgasstation.info/`, // Mainnet meta transaction - MAINNET_META_TRANSACTION: `https://api-metatx.mainnet.boba.network/`, + MAINNET_META_TRANSACTION: `https://api-meta-transaction.mainnet.boba.network/`, // Rinkeby meta transaction - RINKEBY_META_TRANSACTION: `https://api-metatx.rinkeby.boba.network/`, + RINKEBY_META_TRANSACTION: `https://api-meta-transaction.rinkeby.boba.network/`, } export function getNetwork () { From 6e3da25e4bd3b5f31cf9ff810ad6be8a0b337f9f Mon Sep 17 00:00:00 2001 From: cby3149 Date: Mon, 11 Apr 2022 13:36:50 -0700 Subject: [PATCH 05/10] Update Boba_GasPriceOracle address --- ...essesMainnet_0x8376ac6C3f73a25Dd994E0b0669ca7ee0C02F089.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/boba/register/addresses/addressesMainnet_0x8376ac6C3f73a25Dd994E0b0669ca7ee0C02F089.json b/packages/boba/register/addresses/addressesMainnet_0x8376ac6C3f73a25Dd994E0b0669ca7ee0C02F089.json index 024aeca6ba..c7f6b8b1fa 100644 --- a/packages/boba/register/addresses/addressesMainnet_0x8376ac6C3f73a25Dd994E0b0669ca7ee0C02F089.json +++ b/packages/boba/register/addresses/addressesMainnet_0x8376ac6C3f73a25Dd994E0b0669ca7ee0C02F089.json @@ -81,7 +81,7 @@ "BobaTuringCredit": "0xd8E006702bdCbE2582dF13f900bCF750129bB449", "Proxy__BobaTuringCredit": "0xF8D2f1b0292C0Eeef80D8F47661A9DaCDB4b23bf", "BobaMonsters": "0xce458FC7cfC322cDd65eC77Cf7B6410002E2D793", - "Boba_GasPriceOracle":"0x9853D79f0ae1297Ba697D078D4Fd187a1E3a05b0", + "Boba_GasPriceOracle":"0x5d0763cf905DA3689B072FD19baD8dF823b2c349", "Proxy__Boba_GasPriceOracle":"0xeE06ee2F239d2ab11792D77f3C347d919ddA0d51", "BobaBillingContract": "0x4a792F51CCc616b82EF74d2478C732e161c5E6b1", "Proxy__BobaBillingContract": "0x29F373e4869e69faaeCD3bF747dd1d965328b69f" From bedefb6007fbc7eb8f6360a9b5ac1617eb221441 Mon Sep 17 00:00:00 2001 From: CAPtheorem <79423264+CAPtheorem@users.noreply.github.com> Date: Mon, 11 Apr 2022 13:38:27 -0700 Subject: [PATCH 06/10] Update Wallet.js --- packages/boba/gateway/src/containers/wallet/Wallet.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/boba/gateway/src/containers/wallet/Wallet.js b/packages/boba/gateway/src/containers/wallet/Wallet.js index 818593b19e..8d5a21a79f 100644 --- a/packages/boba/gateway/src/containers/wallet/Wallet.js +++ b/packages/boba/gateway/src/containers/wallet/Wallet.js @@ -99,10 +99,10 @@ function Wallet() { console.log("l2Balances",l2Balances) const l2BalanceETH = l2Balances.find((i) => i.symbol === 'ETH') const l2BalanceBOBA = l2Balances.find((i) => i.symbol === 'BOBA') - if (l2BalanceETH[0]) { + if (l2BalanceETH && l2BalanceETH[0]) { setTooSmallETH(new BN(logAmount(l2BalanceETH[0].balance, 18)).lt(new BN(0.003))) } - if (l2BalanceBOBA[0]) { + if (l2BalanceBOBA && l2BalanceBOBA[0]) { setTooSmallBOBA(new BN(logAmount(l2BalanceBOBA[0].balance, 18)).lt(new BN(4.0))) } } From ad891a16215404343fa6ec4909f8e089a4a72ff8 Mon Sep 17 00:00:00 2001 From: CAPtheorem <79423264+CAPtheorem@users.noreply.github.com> Date: Mon, 11 Apr 2022 13:51:03 -0700 Subject: [PATCH 07/10] improved help text for emergency swaps --- .../boba/gateway/src/containers/wallet/Wallet.js | 13 ++++++++----- packages/boba/gateway/src/layout/index.js | 1 + 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/packages/boba/gateway/src/containers/wallet/Wallet.js b/packages/boba/gateway/src/containers/wallet/Wallet.js index 8d5a21a79f..a9a49a6cc9 100644 --- a/packages/boba/gateway/src/containers/wallet/Wallet.js +++ b/packages/boba/gateway/src/containers/wallet/Wallet.js @@ -137,25 +137,28 @@ function Wallet() { } // disable hisding the EMERGENCY SWAP for testing -// && tooSmallETH +// return ( - {layer === 'L2' && + {layer === 'L2' && tooSmallETH && NOTE: ETH balance. {' '} Using Boba requires a minimum ETH balance (of 0.002 ETH) regardless of your fee setting, otherwise MetaMask may incorrectly reject transactions. - If you are stuck because you ran out of ETH, use EMERGENCY SWAP to swap BOBA for - 0.05 ETH at market rates. +

If you are stuck because you ran out of ETH, use EMERGENCY SWAP to swap BOBA for + 0.05 ETH at market rates. +

EMERGENCY SWAPs are metatransactions and are not shown in + the history tab, but can be looked up in the blockexplorer token transfers for BOBA. +