Commit e29fab10 authored by Maurelian's avatar Maurelian Committed by GitHub

Pass additional information across domains via token gateways (#824)

* feat(contracts): add from and data args to L1ERC20Gateway

fix(integration): add gasLimit to fundUser

refactor(contracts): add data to gateway events
add changeset

fix(integration): provide data in outboundTransfer

refactor(contracts): reset Abs_L2TokenGateway to Abs_L2DepositedToken

refactor(contracts): fix mismatched names

* feat[contracts]: add custom gas arg to gateway

fix(contracts): take max of user vs. default gas

* fix(integrations): update ovm-eth function call

* fix(integration): remove unecessary explicit gasLimit

* test(contracts): 32kb transfer, 9MM gas

* fix(contracts): fixup comment, bytes arg last

* fix(integration): args order in integrations

* fix(contracts): remove unused L2 gas arg

* fix(contracts): limit data that can be passed to L2

* fix(integration): better tests for data length

* test: check for error on too large data

* Experimental: specify gaslimit in before hook

* fix(integration): add l2 gas argument

* fix: increase gas on fundUser

* fix(contracts): remove duplicate max size limit

* fix(integration): fine tune gas amounts

* lint

* fix: large data test

* fix(integration): set gas closer to real cost

* fix(contracts): remove unused bridge variables
These variables were the default gas amounts for cross domain messages

* fix(contracts): Reorder args

Place dynamic length args last

* fix(integration): update estimateGas values

* fix(integration): reset eth withdraw estimate to 21000

* fix(integration): update expected gas amount

* fix(integration): reduce gas amount for ETH withdraw
parent a41311c9
---
'@eth-optimism/contracts': patch
---
Token gateways pass additional information: sender and arbitrary data.
...@@ -5,6 +5,11 @@ import { Direction } from './shared/watcher-utils' ...@@ -5,6 +5,11 @@ import { Direction } from './shared/watcher-utils'
import { PROXY_SEQUENCER_ENTRYPOINT_ADDRESS } from './shared/utils' import { PROXY_SEQUENCER_ENTRYPOINT_ADDRESS } from './shared/utils'
import { OptimismEnv } from './shared/env' import { OptimismEnv } from './shared/env'
const DEFAULT_TEST_GAS_L1 = 230_000
const DEFAULT_TEST_GAS_L2 = 825_000
// TX size enforced by CTC:
const MAX_ROLLUP_TX_SIZE = 50_000
describe('Native ETH Integration Tests', async () => { describe('Native ETH Integration Tests', async () => {
let env: OptimismEnv let env: OptimismEnv
let l1Bob: Wallet let l1Bob: Wallet
...@@ -50,8 +55,8 @@ describe('Native ETH Integration Tests', async () => { ...@@ -50,8 +55,8 @@ describe('Native ETH Integration Tests', async () => {
it('Should estimate gas for ETH withdraw', async () => { it('Should estimate gas for ETH withdraw', async () => {
const amount = utils.parseEther('0.5') const amount = utils.parseEther('0.5')
const gas = await env.ovmEth.estimateGas.withdraw(amount) const gas = await env.ovmEth.estimateGas.withdraw(amount, 0, '0xFFFF')
expect(gas).to.be.deep.eq(BigNumber.from(61400489396)) expect(gas).to.be.deep.eq(BigNumber.from(0x0f5203e9bf))
}) })
}) })
...@@ -59,7 +64,10 @@ describe('Native ETH Integration Tests', async () => { ...@@ -59,7 +64,10 @@ describe('Native ETH Integration Tests', async () => {
const depositAmount = 10 const depositAmount = 10
const preBalances = await getBalances(env) const preBalances = await getBalances(env)
const { tx, receipt } = await env.waitForXDomainTransaction( const { tx, receipt } = await env.waitForXDomainTransaction(
env.gateway.deposit({ value: depositAmount }), env.gateway.deposit(DEFAULT_TEST_GAS_L2, '0xFFFF', {
value: depositAmount,
gasLimit: DEFAULT_TEST_GAS_L1,
}),
Direction.L1ToL2 Direction.L1ToL2
) )
...@@ -81,8 +89,9 @@ describe('Native ETH Integration Tests', async () => { ...@@ -81,8 +89,9 @@ describe('Native ETH Integration Tests', async () => {
const depositAmount = 10 const depositAmount = 10
const preBalances = await getBalances(env) const preBalances = await getBalances(env)
const depositReceipts = await env.waitForXDomainTransaction( const depositReceipts = await env.waitForXDomainTransaction(
env.gateway.depositTo(l2Bob.address, { env.gateway.depositTo(l2Bob.address, DEFAULT_TEST_GAS_L2, '0xFFFF', {
value: depositAmount, value: depositAmount,
gasLimit: DEFAULT_TEST_GAS_L1,
}), }),
Direction.L1ToL2 Direction.L1ToL2
) )
...@@ -102,6 +111,50 @@ describe('Native ETH Integration Tests', async () => { ...@@ -102,6 +111,50 @@ describe('Native ETH Integration Tests', async () => {
) )
}) })
it('deposit passes with a large data argument', async () => {
const ASSUMED_L2_GAS_LIMIT = 8_000_000
const depositAmount = 10
const preBalances = await getBalances(env)
// Set data length slightly less than MAX_ROLLUP_TX_SIZE
// to allow for encoding and other arguments
const data = `0x` + 'ab'.repeat(MAX_ROLLUP_TX_SIZE - 500)
const { tx, receipt } = await env.waitForXDomainTransaction(
env.gateway.deposit(ASSUMED_L2_GAS_LIMIT, data, {
value: depositAmount,
gasLimit: 4_000_000,
}),
Direction.L1ToL2
)
const l1FeePaid = receipt.gasUsed.mul(tx.gasPrice)
const postBalances = await getBalances(env)
expect(postBalances.l1GatewayBalance).to.deep.eq(
preBalances.l1GatewayBalance.add(depositAmount)
)
expect(postBalances.l2UserBalance).to.deep.eq(
preBalances.l2UserBalance.add(depositAmount)
)
expect(postBalances.l1UserBalance).to.deep.eq(
preBalances.l1UserBalance.sub(l1FeePaid.add(depositAmount))
)
})
it('deposit fails with a TOO large data argument', async () => {
const depositAmount = 10
const data = `0x` + 'ab'.repeat(MAX_ROLLUP_TX_SIZE + 1)
await expect(
env.gateway.deposit(DEFAULT_TEST_GAS_L2, data, {
value: depositAmount,
gasLimit: 4_000_000,
})
).to.be.revertedWith(
'Transaction data size exceeds maximum for rollup transaction.'
)
})
it('withdraw', async () => { it('withdraw', async () => {
const withdrawAmount = BigNumber.from(3) const withdrawAmount = BigNumber.from(3)
const preBalances = await getBalances(env) const preBalances = await getBalances(env)
...@@ -111,7 +164,7 @@ describe('Native ETH Integration Tests', async () => { ...@@ -111,7 +164,7 @@ describe('Native ETH Integration Tests', async () => {
) )
const receipts = await env.waitForXDomainTransaction( const receipts = await env.waitForXDomainTransaction(
env.ovmEth.withdraw(withdrawAmount), env.ovmEth.withdraw(withdrawAmount, DEFAULT_TEST_GAS_L1, '0xFFFF'),
Direction.L2ToL1 Direction.L2ToL1
) )
const fee = receipts.tx.gasLimit.mul(receipts.tx.gasPrice) const fee = receipts.tx.gasLimit.mul(receipts.tx.gasPrice)
...@@ -140,7 +193,12 @@ describe('Native ETH Integration Tests', async () => { ...@@ -140,7 +193,12 @@ describe('Native ETH Integration Tests', async () => {
) )
const receipts = await env.waitForXDomainTransaction( const receipts = await env.waitForXDomainTransaction(
env.ovmEth.withdrawTo(l1Bob.address, withdrawAmount), env.ovmEth.withdrawTo(
l1Bob.address,
withdrawAmount,
DEFAULT_TEST_GAS_L1,
'0xFFFF'
),
Direction.L2ToL1 Direction.L2ToL1
) )
const fee = receipts.tx.gasLimit.mul(receipts.tx.gasPrice) const fee = receipts.tx.gasLimit.mul(receipts.tx.gasPrice)
...@@ -162,8 +220,9 @@ describe('Native ETH Integration Tests', async () => { ...@@ -162,8 +220,9 @@ describe('Native ETH Integration Tests', async () => {
// 1. deposit // 1. deposit
const amount = utils.parseEther('1') const amount = utils.parseEther('1')
await env.waitForXDomainTransaction( await env.waitForXDomainTransaction(
env.gateway.deposit({ env.gateway.deposit(DEFAULT_TEST_GAS_L2, '0xFFFF', {
value: amount, value: amount,
gasLimit: DEFAULT_TEST_GAS_L1,
}), }),
Direction.L1ToL2 Direction.L1ToL2
) )
...@@ -180,7 +239,9 @@ describe('Native ETH Integration Tests', async () => { ...@@ -180,7 +239,9 @@ describe('Native ETH Integration Tests', async () => {
// 3. do withdrawal // 3. do withdrawal
const withdrawnAmount = utils.parseEther('0.95') const withdrawnAmount = utils.parseEther('0.95')
const receipts = await env.waitForXDomainTransaction( const receipts = await env.waitForXDomainTransaction(
env.ovmEth.connect(other).withdraw(withdrawnAmount), env.ovmEth
.connect(other)
.withdraw(withdrawnAmount, DEFAULT_TEST_GAS_L1, '0xFFFF'),
Direction.L2ToL1 Direction.L2ToL1
) )
......
...@@ -101,8 +101,9 @@ export const fundUser = async ( ...@@ -101,8 +101,9 @@ export const fundUser = async (
) => { ) => {
const value = BigNumber.from(amount) const value = BigNumber.from(amount)
const tx = recipient const tx = recipient
? gateway.depositTo(recipient, { value }) ? gateway.depositTo(recipient, 1_000_000, '0xFFFF', { value })
: gateway.deposit({ value }) : gateway.deposit(1_000_000, '0xFFFF', { value })
await waitForXDomainTransaction(watcher, tx, Direction.L1ToL2) await waitForXDomainTransaction(watcher, tx, Direction.L1ToL2)
} }
......
...@@ -52,13 +52,9 @@ abstract contract Abs_L1TokenGateway is iOVM_L1TokenGateway, OVM_CrossDomainEnab ...@@ -52,13 +52,9 @@ abstract contract Abs_L1TokenGateway is iOVM_L1TokenGateway, OVM_CrossDomainEnab
* Overridable Accounting logic * * Overridable Accounting logic *
********************************/ ********************************/
// Default gas value which can be overridden if more complex logic runs on L2.
uint32 internal constant DEFAULT_FINALIZE_DEPOSIT_L2_GAS = 1200000;
/** /**
* @dev Core logic to be performed when a withdrawal is finalized on L1. * @dev Core logic to be performed when a withdrawal is finalized on L1.
* In most cases, this will simply send locked funds to the withdrawer. * In most cases, this will simply send locked funds to the withdrawer.
*
* param _to Address being withdrawn to. * param _to Address being withdrawn to.
* param _amount Amount being withdrawn. * param _amount Amount being withdrawn.
*/ */
...@@ -75,7 +71,6 @@ abstract contract Abs_L1TokenGateway is iOVM_L1TokenGateway, OVM_CrossDomainEnab ...@@ -75,7 +71,6 @@ abstract contract Abs_L1TokenGateway is iOVM_L1TokenGateway, OVM_CrossDomainEnab
/** /**
* @dev Core logic to be performed when a deposit is initiated on L1. * @dev Core logic to be performed when a deposit is initiated on L1.
* In most cases, this will simply send locked funds to the withdrawer. * In most cases, this will simply send locked funds to the withdrawer.
*
* param _from Address being deposited from on L1. * param _from Address being deposited from on L1.
* param _to Address being deposited into on L2. * param _to Address being deposited into on L2.
* param _amount Amount being deposited. * param _amount Amount being deposited.
...@@ -91,54 +86,50 @@ abstract contract Abs_L1TokenGateway is iOVM_L1TokenGateway, OVM_CrossDomainEnab ...@@ -91,54 +86,50 @@ abstract contract Abs_L1TokenGateway is iOVM_L1TokenGateway, OVM_CrossDomainEnab
revert("Implement me in child contracts"); revert("Implement me in child contracts");
} }
/**
* @dev Overridable getter for the L2 gas limit, in the case it may be
* dynamic, and the above public constant does not suffice.
*
*/
function getFinalizeDepositL2Gas()
public
view
virtual
returns(
uint32
)
{
return DEFAULT_FINALIZE_DEPOSIT_L2_GAS;
}
/************** /**************
* Depositing * * Depositing *
**************/ **************/
/** /**
* @dev deposit an amount of the ERC20 to the caller's balance on L2 * @dev deposit an amount of the ERC20 to the caller's balance on L2.
* @param _amount Amount of the ERC20 to deposit * @param _amount Amount of the ERC20 to deposit
* @param _l2Gas Gas limit required to complete the deposit on L2.
* @param _data Optional data to forward to L2. This data is provided
* solely as a convenience for external contracts. Aside from enforcing a maximum
* length, these contracts provide no guarantees about its content.
*/ */
function deposit( function deposit(
uint _amount uint256 _amount,
uint32 _l2Gas,
bytes calldata _data
) )
external external
override override
virtual virtual
{ {
_initiateDeposit(msg.sender, msg.sender, _amount); _initiateDeposit(msg.sender, msg.sender, _amount, _l2Gas, _data);
} }
/** /**
* @dev deposit an amount of ERC20 to a recipients's balance on L2 * @dev deposit an amount of ERC20 to a recipient's balance on L2.
* @param _to L2 address to credit the withdrawal to * @param _to L2 address to credit the withdrawal to.
* @param _amount Amount of the ERC20 to deposit * @param _amount Amount of the ERC20 to deposit.
* @param _l2Gas Gas limit required to complete the deposit on L2.
* @param _data Optional data to forward to L2. This data is provided
* solely as a convenience for external contracts. Aside from enforcing a maximum
* length, these contracts provide no guarantees about its content.
*/ */
function depositTo( function depositTo(
address _to, address _to,
uint _amount uint256 _amount,
uint32 _l2Gas,
bytes calldata _data
) )
external external
override override
virtual virtual
{ {
_initiateDeposit(msg.sender, _to, _amount); _initiateDeposit(msg.sender, _to, _amount, _l2Gas, _data);
} }
/** /**
...@@ -148,11 +139,17 @@ abstract contract Abs_L1TokenGateway is iOVM_L1TokenGateway, OVM_CrossDomainEnab ...@@ -148,11 +139,17 @@ abstract contract Abs_L1TokenGateway is iOVM_L1TokenGateway, OVM_CrossDomainEnab
* @param _from Account to pull the deposit from on L1 * @param _from Account to pull the deposit from on L1
* @param _to Account to give the deposit to on L2 * @param _to Account to give the deposit to on L2
* @param _amount Amount of the ERC20 to deposit. * @param _amount Amount of the ERC20 to deposit.
* @param _l2Gas Gas limit required to complete the deposit on L2.
* @param _data Optional data to forward to L2. This data is provided
* solely as a convenience for external contracts. Aside from enforcing a maximum
* length, these contracts provide no guarantees about its content.
*/ */
function _initiateDeposit( function _initiateDeposit(
address _from, address _from,
address _to, address _to,
uint _amount uint256 _amount,
uint32 _l2Gas,
bytes calldata _data
) )
internal internal
{ {
...@@ -164,20 +161,23 @@ abstract contract Abs_L1TokenGateway is iOVM_L1TokenGateway, OVM_CrossDomainEnab ...@@ -164,20 +161,23 @@ abstract contract Abs_L1TokenGateway is iOVM_L1TokenGateway, OVM_CrossDomainEnab
); );
// Construct calldata for l2DepositedToken.finalizeDeposit(_to, _amount) // Construct calldata for l2DepositedToken.finalizeDeposit(_to, _amount)
bytes memory data = abi.encodeWithSelector( bytes memory message = abi.encodeWithSelector(
iOVM_L2DepositedToken.finalizeDeposit.selector, iOVM_L2DepositedToken.finalizeDeposit.selector,
_from,
_to, _to,
_amount _amount,
_data
); );
// Send calldata into L2 // Send calldata into L2
sendCrossDomainMessage( sendCrossDomainMessage(
l2DepositedToken, l2DepositedToken,
data, _l2Gas,
getFinalizeDepositL2Gas() message
); );
emit DepositInitiated(_from, _to, _amount); // We omit _data here because events only support bytes32 types.
emit DepositInitiated(_from, _to, _amount, _data);
} }
/************************* /*************************
...@@ -189,12 +189,18 @@ abstract contract Abs_L1TokenGateway is iOVM_L1TokenGateway, OVM_CrossDomainEnab ...@@ -189,12 +189,18 @@ abstract contract Abs_L1TokenGateway is iOVM_L1TokenGateway, OVM_CrossDomainEnab
* L1 ERC20 token. * L1 ERC20 token.
* This call will fail if the initialized withdrawal from L2 has not been finalized. * This call will fail if the initialized withdrawal from L2 has not been finalized.
* *
* @param _to L1 address to credit the withdrawal to * @param _from L2 address initiating the transfer.
* @param _amount Amount of the ERC20 to withdraw * @param _to L1 address to credit the withdrawal to.
* @param _amount Amount of the ERC20 to deposit.
* @param _data Data provided by the sender on L2. This data is provided
* solely as a convenience for external contracts. Aside from enforcing a maximum
* length, these contracts provide no guarantees about its content.
*/ */
function finalizeWithdrawal( function finalizeWithdrawal(
address _from,
address _to, address _to,
uint _amount uint256 _amount,
bytes calldata _data
) )
external external
override override
...@@ -206,7 +212,6 @@ abstract contract Abs_L1TokenGateway is iOVM_L1TokenGateway, OVM_CrossDomainEnab ...@@ -206,7 +212,6 @@ abstract contract Abs_L1TokenGateway is iOVM_L1TokenGateway, OVM_CrossDomainEnab
_to, _to,
_amount _amount
); );
emit WithdrawalFinalized(_from, _to, _amount, _data);
emit WithdrawalFinalized(_to, _amount);
} }
} }
...@@ -40,7 +40,7 @@ abstract contract Abs_L2DepositedToken is iOVM_L2DepositedToken, OVM_CrossDomain ...@@ -40,7 +40,7 @@ abstract contract Abs_L2DepositedToken is iOVM_L2DepositedToken, OVM_CrossDomain
********************************/ ********************************/
/** /**
* @param _l2CrossDomainMessenger L1 Messenger address being used for cross-chain communications. * @param _l2CrossDomainMessenger L2 Messenger address being used for cross-chain communications.
*/ */
constructor( constructor(
address _l2CrossDomainMessenger address _l2CrossDomainMessenger
...@@ -50,9 +50,10 @@ abstract contract Abs_L2DepositedToken is iOVM_L2DepositedToken, OVM_CrossDomain ...@@ -50,9 +50,10 @@ abstract contract Abs_L2DepositedToken is iOVM_L2DepositedToken, OVM_CrossDomain
/** /**
* @dev Initialize this contract with the L1 token gateway address. * @dev Initialize this contract with the L1 token gateway address.
* The flow: 1) this contract gets deployed on L2, 2) the L1 * The flow:
* gateway is deployed with addr from (1), 3) L1 gateway address passed here. * 1) this contract is deployed on L2,
* * 2) the L1 gateway is deployed with addr from (1),
* 3) L1 gateway address passed here.
* @param _l1TokenGateway Address of the corresponding L1 gateway deployed to the main chain * @param _l1TokenGateway Address of the corresponding L1 gateway deployed to the main chain
*/ */
function init( function init(
...@@ -80,19 +81,15 @@ abstract contract Abs_L2DepositedToken is iOVM_L2DepositedToken, OVM_CrossDomain ...@@ -80,19 +81,15 @@ abstract contract Abs_L2DepositedToken is iOVM_L2DepositedToken, OVM_CrossDomain
* Overridable Accounting logic * * Overridable Accounting logic *
********************************/ ********************************/
// Default gas value which can be overridden if more complex logic runs on L1.
uint32 internal constant DEFAULT_FINALIZE_WITHDRAWAL_L1_GAS = 100000;
/** /**
* @dev Core logic to be performed when a withdrawal from L2 is initialized. * @dev Core logic to be performed when a withdrawal from L2 is initialized.
* In most cases, this will simply burn the withdrawn L2 funds. * In most cases, this will simply burn the withdrawn L2 funds.
* * param _to Address being withdrawn to.
* param _to Address being withdrawn to * param _amount Amount being withdrawn.
* param _amount Amount being withdrawn
*/ */
function _handleInitiateWithdrawal( function _handleInitiateWithdrawal(
address, // _to, address, // _to,
uint // _amount uint256 // _amount
) )
internal internal
virtual virtual
...@@ -103,13 +100,12 @@ abstract contract Abs_L2DepositedToken is iOVM_L2DepositedToken, OVM_CrossDomain ...@@ -103,13 +100,12 @@ abstract contract Abs_L2DepositedToken is iOVM_L2DepositedToken, OVM_CrossDomain
/** /**
* @dev Core logic to be performed when a deposit from L2 is finalized on L2. * @dev Core logic to be performed when a deposit from L2 is finalized on L2.
* In most cases, this will simply _mint() to credit L2 funds to the recipient. * In most cases, this will simply _mint() to credit L2 funds to the recipient.
* * param _to Address being deposited to on L2.
* param _to Address being deposited to on L2 * param _amount Amount which was deposited on L1.
* param _amount Amount which was deposited on L1
*/ */
function _handleFinalizeDeposit( function _handleFinalizeDeposit(
address, // _to address, // _to
uint // _amount uint256 // _amount
) )
internal internal
virtual virtual
...@@ -117,67 +113,82 @@ abstract contract Abs_L2DepositedToken is iOVM_L2DepositedToken, OVM_CrossDomain ...@@ -117,67 +113,82 @@ abstract contract Abs_L2DepositedToken is iOVM_L2DepositedToken, OVM_CrossDomain
revert("Accounting must be implemented by child contract."); revert("Accounting must be implemented by child contract.");
} }
/**
* @dev Overridable getter for the *L1* gas limit of settling the withdrawal, in the case it may be
* dynamic, and the above public constant does not suffice.
*/
function getFinalizeWithdrawalL1Gas()
public
view
virtual
returns(
uint32
)
{
return DEFAULT_FINALIZE_WITHDRAWAL_L1_GAS;
}
/*************** /***************
* Withdrawing * * Withdrawing *
***************/ ***************/
/** /**
* @dev initiate a withdraw of some tokens to the caller's account on L1 * @dev initiate a withdraw of some tokens to the caller's account on L1
* @param _amount Amount of the token to withdraw * @param _amount Amount of the token to withdraw.
* param _l1Gas Unused, but included for potential forward compatibility considerations.
* @param _data Optional data to forward to L1. This data is provided
* solely as a convenience for external contracts. Aside from enforcing a maximum
* length, these contracts provide no guarantees about its content.
*/ */
function withdraw( function withdraw(
uint _amount uint256 _amount,
uint32, // _l1Gas,
bytes calldata _data
) )
external external
override override
virtual virtual
onlyInitialized() onlyInitialized()
{ {
_initiateWithdrawal(msg.sender, _amount); _initiateWithdrawal(
msg.sender,
msg.sender,
_amount,
0,
_data
);
} }
/** /**
* @dev initiate a withdraw of some token to a recipient's account on L1 * @dev initiate a withdraw of some token to a recipient's account on L1.
* @param _to L1 adress to credit the withdrawal to * @param _to L1 adress to credit the withdrawal to.
* @param _amount Amount of the token to withdraw * @param _amount Amount of the token to withdraw.
* param _l1Gas Unused, but included for potential forward compatibility considerations.
* @param _data Optional data to forward to L1. This data is provided
* solely as a convenience for external contracts. Aside from enforcing a maximum
* length, these contracts provide no guarantees about its content.
*/ */
function withdrawTo( function withdrawTo(
address _to, address _to,
uint _amount uint256 _amount,
uint32, // _l1Gas,
bytes calldata _data
) )
external external
override override
virtual virtual
onlyInitialized() onlyInitialized()
{ {
_initiateWithdrawal(_to, _amount); _initiateWithdrawal(
msg.sender,
_to,
_amount,
0,
_data
);
} }
/** /**
* @dev Performs the logic for deposits by storing the token and informing the L2 token Gateway of the deposit. * @dev Performs the logic for deposits by storing the token and informing the L2 token Gateway of the deposit.
* * @param _from Account to pull the deposit from on L2.
* @param _to Account to give the withdrawal to on L1 * @param _to Account to give the withdrawal to on L1.
* @param _amount Amount of the token to withdraw * @param _amount Amount of the token to withdraw.
* param _l1Gas Unused, but included for potential forward compatibility considerations.
* @param _data Optional data to forward to L1. This data is provided
* solely as a convenience for external contracts. Aside from enforcing a maximum
* length, these contracts provide no guarantees about its content.
*/ */
function _initiateWithdrawal( function _initiateWithdrawal(
address _from,
address _to, address _to,
uint _amount uint256 _amount,
uint32, // _l1Gas,
bytes calldata _data
) )
internal internal
{ {
...@@ -185,20 +196,22 @@ abstract contract Abs_L2DepositedToken is iOVM_L2DepositedToken, OVM_CrossDomain ...@@ -185,20 +196,22 @@ abstract contract Abs_L2DepositedToken is iOVM_L2DepositedToken, OVM_CrossDomain
_handleInitiateWithdrawal(_to, _amount); _handleInitiateWithdrawal(_to, _amount);
// Construct calldata for l1TokenGateway.finalizeWithdrawal(_to, _amount) // Construct calldata for l1TokenGateway.finalizeWithdrawal(_to, _amount)
bytes memory data = abi.encodeWithSelector( bytes memory message = abi.encodeWithSelector(
iOVM_L1TokenGateway.finalizeWithdrawal.selector, iOVM_L1TokenGateway.finalizeWithdrawal.selector,
_from,
_to, _to,
_amount _amount,
_data
); );
// Send message up to L1 gateway // Send message up to L1 gateway
sendCrossDomainMessage( sendCrossDomainMessage(
address(l1TokenGateway), address(l1TokenGateway),
data, 0,
getFinalizeWithdrawalL1Gas() message
); );
emit WithdrawalInitiated(msg.sender, _to, _amount); emit WithdrawalInitiated(msg.sender, _to, _amount, _data);
} }
/************************************ /************************************
...@@ -209,13 +222,18 @@ abstract contract Abs_L2DepositedToken is iOVM_L2DepositedToken, OVM_CrossDomain ...@@ -209,13 +222,18 @@ abstract contract Abs_L2DepositedToken is iOVM_L2DepositedToken, OVM_CrossDomain
* @dev Complete a deposit from L1 to L2, and credits funds to the recipient's balance of this * @dev Complete a deposit from L1 to L2, and credits funds to the recipient's balance of this
* L2 token. * L2 token.
* This call will fail if it did not originate from a corresponding deposit in OVM_l1TokenGateway. * This call will fail if it did not originate from a corresponding deposit in OVM_l1TokenGateway.
* * @param _from Account to pull the deposit from on L2.
* @param _to Address to receive the withdrawal at * @param _to Address to receive the withdrawal at
* @param _amount Amount of the token to withdraw * @param _amount Amount of the token to withdraw
* @param _data Data provider by the sender on L1. This data is provided
* solely as a convenience for external contracts. Aside from enforcing a maximum
* length, these contracts provide no guarantees about its content.
*/ */
function finalizeDeposit( function finalizeDeposit(
address _from,
address _to, address _to,
uint _amount uint256 _amount,
bytes calldata _data
) )
external external
override override
...@@ -224,6 +242,6 @@ abstract contract Abs_L2DepositedToken is iOVM_L2DepositedToken, OVM_CrossDomain ...@@ -224,6 +242,6 @@ abstract contract Abs_L2DepositedToken is iOVM_L2DepositedToken, OVM_CrossDomain
onlyFromCrossDomainAccount(address(l1TokenGateway)) onlyFromCrossDomainAccount(address(l1TokenGateway))
{ {
_handleFinalizeDeposit(_to, _amount); _handleFinalizeDeposit(_to, _amount);
emit DepositFinalized(_to, _amount); emit DepositFinalized(_from, _to, _amount, _data);
} }
} }
...@@ -35,8 +35,8 @@ contract OVM_L1ERC20Gateway is Abs_L1TokenGateway { ...@@ -35,8 +35,8 @@ contract OVM_L1ERC20Gateway is Abs_L1TokenGateway {
***************/ ***************/
/** /**
* @param _l1ERC20 L1 ERC20 address this contract stores deposits for * @param _l1ERC20 L1 ERC20 address this contract stores deposits for.
* @param _l2DepositedERC20 L2 Gateway address on the chain being deposited into * @param _l2DepositedERC20 L2 Gateway address on the chain being deposited into.
*/ */
constructor( constructor(
iOVM_ERC20 _l1ERC20, iOVM_ERC20 _l1ERC20,
...@@ -58,11 +58,11 @@ contract OVM_L1ERC20Gateway is Abs_L1TokenGateway { ...@@ -58,11 +58,11 @@ contract OVM_L1ERC20Gateway is Abs_L1TokenGateway {
/** /**
* @dev When a deposit is initiated on L1, the L1 Gateway * @dev When a deposit is initiated on L1, the L1 Gateway
* transfers the funds to itself for future withdrawals * transfers the funds to itself for future withdrawals.
* *
* @param _from L1 address ETH is being deposited from * @param _from L1 address ETH is being deposited from.
* param _to L2 address that the ETH is being deposited to * param _to L2 address that the ETH is being deposited to.
* @param _amount Amount of ERC20 to send * @param _amount Amount of ERC20 to send.
*/ */
function _handleInitiateDeposit( function _handleInitiateDeposit(
address _from, address _from,
...@@ -82,14 +82,14 @@ contract OVM_L1ERC20Gateway is Abs_L1TokenGateway { ...@@ -82,14 +82,14 @@ contract OVM_L1ERC20Gateway is Abs_L1TokenGateway {
/** /**
* @dev When a withdrawal is finalized on L1, the L1 Gateway * @dev When a withdrawal is finalized on L1, the L1 Gateway
* transfers the funds to the withdrawer * transfers the funds to the withdrawer.
* *
* @param _to L1 address that the ERC20 is being withdrawn to * @param _to L1 address that the ERC20 is being withdrawn to.
* @param _amount Amount of ERC20 to send * @param _amount Amount of ERC20 to send.
*/ */
function _handleFinalizeWithdrawal( function _handleFinalizeWithdrawal(
address _to, address _to,
uint _amount uint256 _amount
) )
internal internal
override override
......
...@@ -21,12 +21,6 @@ import { Lib_AddressManager } from "../../../libraries/resolver/Lib_AddressManag ...@@ -21,12 +21,6 @@ import { Lib_AddressManager } from "../../../libraries/resolver/Lib_AddressManag
*/ */
contract OVM_L1ETHGateway is iOVM_L1ETHGateway, OVM_CrossDomainEnabled, Lib_AddressResolver { contract OVM_L1ETHGateway is iOVM_L1ETHGateway, OVM_CrossDomainEnabled, Lib_AddressResolver {
/********************
* Public Constants *
********************/
uint32 public constant override getFinalizeDepositL2Gas = 1200000;
/******************************** /********************************
* External Contract References * * External Contract References *
********************************/ ********************************/
...@@ -41,7 +35,6 @@ contract OVM_L1ETHGateway is iOVM_L1ETHGateway, OVM_CrossDomainEnabled, Lib_Addr ...@@ -41,7 +35,6 @@ contract OVM_L1ETHGateway is iOVM_L1ETHGateway, OVM_CrossDomainEnabled, Lib_Addr
constructor() constructor()
OVM_CrossDomainEnabled(address(0)) OVM_CrossDomainEnabled(address(0))
Lib_AddressResolver(address(0)) Lib_AddressResolver(address(0))
public
{} {}
/****************** /******************
...@@ -68,66 +61,102 @@ contract OVM_L1ETHGateway is iOVM_L1ETHGateway, OVM_CrossDomainEnabled, Lib_Addr ...@@ -68,66 +61,102 @@ contract OVM_L1ETHGateway is iOVM_L1ETHGateway, OVM_CrossDomainEnabled, Lib_Addr
* Depositing * * Depositing *
**************/ **************/
/**
* @dev This function can be called with no data
* to deposit an amount of ETH to the caller's balance on L2.
* Since the receive function doesn't take data, a conservative
* default of 1.2 Million gas is forwarded to L2.
*/
receive() receive()
external external
payable payable
{ {
_initiateDeposit(msg.sender, msg.sender); _initiateDeposit(msg.sender, msg.sender, 1_200_000, bytes(""));
} }
/** /**
* @dev deposit an amount of the ETH to the caller's balance on L2 * @dev Deposit an amount of the ETH to the caller's balance on L2.
* @param _l2Gas Gas limit required to complete the deposit on L2.
* @param _data Optional data to forward to L2. This data is provided
* solely as a convenience for external contracts. Aside from enforcing a maximum
* length, these contracts provide no guarantees about its content.
*/ */
function deposit() function deposit(
uint32 _l2Gas,
bytes calldata _data
)
external external
override override
payable payable
{ {
_initiateDeposit(msg.sender, msg.sender); _initiateDeposit(
msg.sender,
msg.sender,
_l2Gas,
_data
);
} }
/** /**
* @dev deposit an amount of ETH to a recipients's balance on L2 * @dev Deposit an amount of ETH to a recipient's balance on L2.
* @param _to L2 address to credit the withdrawal to * @param _to L2 address to credit the withdrawal to.
* @param _l2Gas Gas limit required to complete the deposit on L2.
* @param _data Optional data to forward to L2. This data is provided
* solely as a convenience for external contracts. Aside from enforcing a maximum
* length, these contracts provide no guarantees about its content.
*/ */
function depositTo( function depositTo(
address _to address _to,
uint32 _l2Gas,
bytes calldata _data
) )
external external
override override
payable payable
{ {
_initiateDeposit(msg.sender, _to); _initiateDeposit(
msg.sender,
_to,
_l2Gas,
_data
);
} }
/** /**
* @dev Performs the logic for deposits by storing the ETH and informing the L2 ETH Gateway of the deposit. * @dev Performs the logic for deposits by storing the ETH and informing the L2 ETH Gateway of the deposit.
* * @param _from Account to pull the deposit from on L1.
* @param _from Account to pull the deposit from on L1 * @param _to Account to give the deposit to on L2.
* @param _to Account to give the deposit to on L2 * @param _l2Gas Gas limit required to complete the deposit on L2.
* @param _data Optional data to forward to L2. This data is provided
* solely as a convenience for external contracts. Aside from enforcing a maximum
* length, these contracts provide no guarantees about its content.
*/ */
function _initiateDeposit( function _initiateDeposit(
address _from, address _from,
address _to address _to,
uint32 _l2Gas,
bytes memory _data
) )
internal internal
{ {
// Construct calldata for l2ETHGateway.finalizeDeposit(_to, _amount) // Construct calldata for l2ETHGateway.finalizeDeposit(_to, _amount)
bytes memory data = bytes memory message =
abi.encodeWithSelector( abi.encodeWithSelector(
iOVM_L2DepositedToken.finalizeDeposit.selector, iOVM_L2DepositedToken.finalizeDeposit.selector,
_from,
_to, _to,
msg.value msg.value,
_data
); );
// Send calldata into L2 // Send calldata into L2
sendCrossDomainMessage( sendCrossDomainMessage(
ovmEth, ovmEth,
data, _l2Gas,
getFinalizeDepositL2Gas message
); );
emit DepositInitiated(_from, _to, msg.value); emit DepositInitiated(_from, _to, msg.value, _data);
} }
/************************* /*************************
...@@ -138,13 +167,18 @@ contract OVM_L1ETHGateway is iOVM_L1ETHGateway, OVM_CrossDomainEnabled, Lib_Addr ...@@ -138,13 +167,18 @@ contract OVM_L1ETHGateway is iOVM_L1ETHGateway, OVM_CrossDomainEnabled, Lib_Addr
* @dev Complete a withdrawal from L2 to L1, and credit funds to the recipient's balance of the * @dev Complete a withdrawal from L2 to L1, and credit funds to the recipient's balance of the
* L1 ETH token. * L1 ETH token.
* Since only the xDomainMessenger can call this function, it will never be called before the withdrawal is finalized. * Since only the xDomainMessenger can call this function, it will never be called before the withdrawal is finalized.
* * @param _from L2 address initiating the transfer.
* @param _to L1 address to credit the withdrawal to * @param _to L1 address to credit the withdrawal to.
* @param _amount Amount of the ETH to withdraw * @param _amount Amount of the ERC20 to deposit.
* @param _data Optional data to forward to L2. This data is provided
* solely as a convenience for external contracts. Aside from enforcing a maximum
* length, these contracts provide no guarantees about its content.
*/ */
function finalizeWithdrawal( function finalizeWithdrawal(
address _from,
address _to, address _to,
uint256 _amount uint256 _amount,
bytes calldata _data
) )
external external
override override
...@@ -152,7 +186,7 @@ contract OVM_L1ETHGateway is iOVM_L1ETHGateway, OVM_CrossDomainEnabled, Lib_Addr ...@@ -152,7 +186,7 @@ contract OVM_L1ETHGateway is iOVM_L1ETHGateway, OVM_CrossDomainEnabled, Lib_Addr
{ {
_safeTransferETH(_to, _amount); _safeTransferETH(_to, _amount);
emit WithdrawalFinalized(_to, _amount); emit WithdrawalFinalized(_from, _to, _amount, _data);
} }
/********************************** /**********************************
...@@ -162,8 +196,8 @@ contract OVM_L1ETHGateway is iOVM_L1ETHGateway, OVM_CrossDomainEnabled, Lib_Addr ...@@ -162,8 +196,8 @@ contract OVM_L1ETHGateway is iOVM_L1ETHGateway, OVM_CrossDomainEnabled, Lib_Addr
/** /**
* @dev Internal accounting function for moving around L1 ETH. * @dev Internal accounting function for moving around L1 ETH.
* *
* @param _to L1 address to transfer ETH to * @param _to L1 address to transfer ETH to.
* @param _value Amount of ETH to send to * @param _value Amount of ETH to transfer.
*/ */
function _safeTransferETH( function _safeTransferETH(
address _to, address _to,
...@@ -180,8 +214,8 @@ contract OVM_L1ETHGateway is iOVM_L1ETHGateway, OVM_CrossDomainEnabled, Lib_Addr ...@@ -180,8 +214,8 @@ contract OVM_L1ETHGateway is iOVM_L1ETHGateway, OVM_CrossDomainEnabled, Lib_Addr
*****************************/ *****************************/
/** /**
* @dev Migrates entire ETH balance to another gateway * @dev Migrates entire ETH balance to another gateway.
* @param _to Gateway Proxy address to migrate ETH to * @param _to Gateway Proxy address to migrate ETH to.
*/ */
function migrateEth(address payable _to) external { function migrateEth(address payable _to) external {
address owner = Lib_AddressManager(libAddressManager).owner(); address owner = Lib_AddressManager(libAddressManager).owner();
...@@ -192,7 +226,7 @@ contract OVM_L1ETHGateway is iOVM_L1ETHGateway, OVM_CrossDomainEnabled, Lib_Addr ...@@ -192,7 +226,7 @@ contract OVM_L1ETHGateway is iOVM_L1ETHGateway, OVM_CrossDomainEnabled, Lib_Addr
/** /**
* @dev Adds ETH balance to the account. This is meant to allow for ETH * @dev Adds ETH balance to the account. This is meant to allow for ETH
* to be migrated from an old gateway to a new gateway * to be migrated from an old gateway to a new gateway.
*/ */
function donateETH() external payable {} function donateETH() external payable {}
} }
...@@ -31,8 +31,8 @@ contract OVM_L2DepositedERC20 is Abs_L2DepositedToken, UniswapV2ERC20 { ...@@ -31,8 +31,8 @@ contract OVM_L2DepositedERC20 is Abs_L2DepositedToken, UniswapV2ERC20 {
/** /**
* @param _l2CrossDomainMessenger Cross-domain messenger used by this contract. * @param _l2CrossDomainMessenger Cross-domain messenger used by this contract.
* @param _name ERC20 name * @param _name ERC20 name.
* @param _symbol ERC20 symbol * @param _symbol ERC20 symbol.
*/ */
constructor( constructor(
address _l2CrossDomainMessenger, address _l2CrossDomainMessenger,
...@@ -46,7 +46,7 @@ contract OVM_L2DepositedERC20 is Abs_L2DepositedToken, UniswapV2ERC20 { ...@@ -46,7 +46,7 @@ contract OVM_L2DepositedERC20 is Abs_L2DepositedToken, UniswapV2ERC20 {
// When a withdrawal is initiated, we burn the withdrawer's funds to prevent subsequent L2 usage. // When a withdrawal is initiated, we burn the withdrawer's funds to prevent subsequent L2 usage.
function _handleInitiateWithdrawal( function _handleInitiateWithdrawal(
address, // _to, address, // _to,
uint _amount uint256 _amount
) )
internal internal
override override
...@@ -57,7 +57,7 @@ contract OVM_L2DepositedERC20 is Abs_L2DepositedToken, UniswapV2ERC20 { ...@@ -57,7 +57,7 @@ contract OVM_L2DepositedERC20 is Abs_L2DepositedToken, UniswapV2ERC20 {
// When a deposit is finalized, we credit the account on L2 with the same amount of tokens. // When a deposit is finalized, we credit the account on L2 with the same amount of tokens.
function _handleFinalizeDeposit( function _handleFinalizeDeposit(
address _to, address _to,
uint _amount uint256 _amount
) )
internal internal
override override
......
...@@ -13,25 +13,33 @@ interface iOVM_L1ETHGateway { ...@@ -13,25 +13,33 @@ interface iOVM_L1ETHGateway {
event DepositInitiated( event DepositInitiated(
address indexed _from, address indexed _from,
address _to, address indexed _to,
uint256 _amount uint256 _amount,
bytes _data
); );
event WithdrawalFinalized( event WithdrawalFinalized(
address indexed _from,
address indexed _to, address indexed _to,
uint256 _amount uint256 _amount,
bytes _data
); );
/******************** /********************
* Public Functions * * Public Functions *
********************/ ********************/
function deposit() function deposit(
uint32 _l2Gas,
bytes calldata _data
)
external external
payable; payable;
function depositTo( function depositTo(
address _to address _to,
uint32 _l2Gas,
bytes calldata _data
) )
external external
payable; payable;
...@@ -41,15 +49,11 @@ interface iOVM_L1ETHGateway { ...@@ -41,15 +49,11 @@ interface iOVM_L1ETHGateway {
*************************/ *************************/
function finalizeWithdrawal( function finalizeWithdrawal(
address _from,
address _to, address _to,
uint _amount uint _amount,
bytes calldata _data
) )
external; external;
function getFinalizeDepositL2Gas()
external
view
returns(
uint32
);
} }
...@@ -13,13 +13,16 @@ interface iOVM_L1TokenGateway { ...@@ -13,13 +13,16 @@ interface iOVM_L1TokenGateway {
event DepositInitiated( event DepositInitiated(
address indexed _from, address indexed _from,
address _to, address indexed _to,
uint256 _amount uint256 _amount,
bytes _data
); );
event WithdrawalFinalized( event WithdrawalFinalized(
address indexed _from,
address indexed _to, address indexed _to,
uint256 _amount uint256 _amount,
bytes _data
); );
...@@ -28,13 +31,17 @@ interface iOVM_L1TokenGateway { ...@@ -28,13 +31,17 @@ interface iOVM_L1TokenGateway {
********************/ ********************/
function deposit( function deposit(
uint _amount uint _amount,
uint32 _l2Gas,
bytes calldata _data
) )
external; external;
function depositTo( function depositTo(
address _to, address _to,
uint _amount uint _amount,
uint32 _l2Gas,
bytes calldata _data
) )
external; external;
...@@ -44,8 +51,11 @@ interface iOVM_L1TokenGateway { ...@@ -44,8 +51,11 @@ interface iOVM_L1TokenGateway {
*************************/ *************************/
function finalizeWithdrawal( function finalizeWithdrawal(
address _from,
address _to, address _to,
uint _amount uint _amount,
bytes calldata _data
) )
external; external;
} }
...@@ -13,13 +13,16 @@ interface iOVM_L2DepositedToken { ...@@ -13,13 +13,16 @@ interface iOVM_L2DepositedToken {
event WithdrawalInitiated( event WithdrawalInitiated(
address indexed _from, address indexed _from,
address _to, address indexed _to,
uint256 _amount uint256 _amount,
bytes _data
); );
event DepositFinalized( event DepositFinalized(
address indexed _from,
address indexed _to, address indexed _to,
uint256 _amount uint256 _amount,
bytes _data
); );
...@@ -28,13 +31,17 @@ interface iOVM_L2DepositedToken { ...@@ -28,13 +31,17 @@ interface iOVM_L2DepositedToken {
********************/ ********************/
function withdraw( function withdraw(
uint _amount uint _amount,
uint32 _l1Gas,
bytes calldata _data
) )
external; external;
function withdrawTo( function withdrawTo(
address _to, address _to,
uint _amount uint _amount,
uint32 _l1Gas,
bytes calldata _data
) )
external; external;
...@@ -44,8 +51,11 @@ interface iOVM_L2DepositedToken { ...@@ -44,8 +51,11 @@ interface iOVM_L2DepositedToken {
*************************/ *************************/
function finalizeDeposit( function finalizeDeposit(
address _from,
address _to, address _to,
uint _amount uint _amount,
bytes calldata _data
) )
external; external;
} }
...@@ -23,7 +23,7 @@ contract OVM_CrossDomainEnabled { ...@@ -23,7 +23,7 @@ contract OVM_CrossDomainEnabled {
/*************** /***************
* Constructor * * Constructor *
***************/ ***************/
/** /**
* @param _messenger Address of the CrossDomainMessenger on the current layer. * @param _messenger Address of the CrossDomainMessenger on the current layer.
...@@ -68,7 +68,7 @@ contract OVM_CrossDomainEnabled { ...@@ -68,7 +68,7 @@ contract OVM_CrossDomainEnabled {
/** /**
* Gets the messenger, usually from storage. This function is exposed in case a child contract * Gets the messenger, usually from storage. This function is exposed in case a child contract
* needs to override. * needs to override.
* @return The address of the cross-domain messenger contract which should be used. * @return The address of the cross-domain messenger contract which should be used.
*/ */
function getCrossDomainMessenger() function getCrossDomainMessenger()
internal internal
...@@ -83,17 +83,17 @@ contract OVM_CrossDomainEnabled { ...@@ -83,17 +83,17 @@ contract OVM_CrossDomainEnabled {
/** /**
* Sends a message to an account on another domain * Sends a message to an account on another domain
* @param _crossDomainTarget The intended recipient on the destination domain * @param _crossDomainTarget The intended recipient on the destination domain
* @param _data The data to send to the target (usually calldata to a function with * @param _message The data to send to the target (usually calldata to a function with
* `onlyFromCrossDomainAccount()`) * `onlyFromCrossDomainAccount()`)
* @param _gasLimit The gasLimit for the receipt of the message on the target domain. * @param _gasLimit The gasLimit for the receipt of the message on the target domain.
*/ */
function sendCrossDomainMessage( function sendCrossDomainMessage(
address _crossDomainTarget, address _crossDomainTarget,
bytes memory _data, uint32 _gasLimit,
uint32 _gasLimit bytes memory _message
) )
internal internal
{ {
getCrossDomainMessenger().sendMessage(_crossDomainTarget, _data, _gasLimit); getCrossDomainMessenger().sendMessage(_crossDomainTarget, _message, _gasLimit);
} }
} }
...@@ -6,9 +6,10 @@ import { Signer, ContractFactory, Contract, constants } from 'ethers' ...@@ -6,9 +6,10 @@ import { Signer, ContractFactory, Contract, constants } from 'ethers'
import { smockit, MockContract, smoddit } from '@eth-optimism/smock' import { smockit, MockContract, smoddit } from '@eth-optimism/smock'
/* Internal Imports */ /* Internal Imports */
import { NON_ZERO_ADDRESS } from '../../../../helpers' import { NON_NULL_BYTES32, NON_ZERO_ADDRESS } from '../../../../helpers'
const INITIAL_TOTAL_L1_SUPPLY = 3000 const INITIAL_TOTAL_L1_SUPPLY = 3000
const FINALIZATION_GAS = 1_200_000
const ERR_INVALID_MESSENGER = 'OVM_XCHAIN: messenger contract unauthenticated' const ERR_INVALID_MESSENGER = 'OVM_XCHAIN: messenger contract unauthenticated'
const ERR_INVALID_X_DOMAIN_MSG_SENDER = const ERR_INVALID_X_DOMAIN_MSG_SENDER =
...@@ -46,7 +47,6 @@ describe('OVM_L1ERC20Gateway', () => { ...@@ -46,7 +47,6 @@ describe('OVM_L1ERC20Gateway', () => {
let OVM_L1ERC20Gateway: Contract let OVM_L1ERC20Gateway: Contract
let Mock__OVM_L1CrossDomainMessenger: MockContract let Mock__OVM_L1CrossDomainMessenger: MockContract
let finalizeDepositGasLimit: number
beforeEach(async () => { beforeEach(async () => {
// Create a special signer which will enable us to send messages from the L1Messenger contract // Create a special signer which will enable us to send messages from the L1Messenger contract
let l1MessengerImpersonator: Signer let l1MessengerImpersonator: Signer
...@@ -65,8 +65,6 @@ describe('OVM_L1ERC20Gateway', () => { ...@@ -65,8 +65,6 @@ describe('OVM_L1ERC20Gateway', () => {
Mock__OVM_L2DepositedERC20.address, Mock__OVM_L2DepositedERC20.address,
Mock__OVM_L1CrossDomainMessenger.address Mock__OVM_L1CrossDomainMessenger.address
) )
finalizeDepositGasLimit = await OVM_L1ERC20Gateway.getFinalizeDepositL2Gas()
}) })
describe('finalizeWithdrawal', () => { describe('finalizeWithdrawal', () => {
...@@ -81,7 +79,12 @@ describe('OVM_L1ERC20Gateway', () => { ...@@ -81,7 +79,12 @@ describe('OVM_L1ERC20Gateway', () => {
) )
await expect( await expect(
OVM_L1ERC20Gateway.finalizeWithdrawal(constants.AddressZero, 1) OVM_L1ERC20Gateway.finalizeWithdrawal(
constants.AddressZero,
constants.AddressZero,
1,
NON_NULL_BYTES32
)
).to.be.revertedWith(ERR_INVALID_MESSENGER) ).to.be.revertedWith(ERR_INVALID_MESSENGER)
}) })
...@@ -91,9 +94,15 @@ describe('OVM_L1ERC20Gateway', () => { ...@@ -91,9 +94,15 @@ describe('OVM_L1ERC20Gateway', () => {
) )
await expect( await expect(
OVM_L1ERC20Gateway.finalizeWithdrawal(constants.AddressZero, 1, { OVM_L1ERC20Gateway.finalizeWithdrawal(
from: Mock__OVM_L1CrossDomainMessenger.address, constants.AddressZero,
}) constants.AddressZero,
1,
NON_NULL_BYTES32,
{
from: Mock__OVM_L1CrossDomainMessenger.address,
}
)
).to.be.revertedWith(ERR_INVALID_X_DOMAIN_MSG_SENDER) ).to.be.revertedWith(ERR_INVALID_X_DOMAIN_MSG_SENDER)
}) })
...@@ -109,8 +118,10 @@ describe('OVM_L1ERC20Gateway', () => { ...@@ -109,8 +118,10 @@ describe('OVM_L1ERC20Gateway', () => {
await L1ERC20.transfer(OVM_L1ERC20Gateway.address, withdrawalAmount) await L1ERC20.transfer(OVM_L1ERC20Gateway.address, withdrawalAmount)
const res = await OVM_L1ERC20Gateway.finalizeWithdrawal( const res = await OVM_L1ERC20Gateway.finalizeWithdrawal(
NON_ZERO_ADDRESS,
NON_ZERO_ADDRESS, NON_ZERO_ADDRESS,
withdrawalAmount, withdrawalAmount,
NON_NULL_BYTES32,
{ from: Mock__OVM_L1CrossDomainMessenger.address } { from: Mock__OVM_L1CrossDomainMessenger.address }
) )
...@@ -125,8 +136,6 @@ describe('OVM_L1ERC20Gateway', () => { ...@@ -125,8 +136,6 @@ describe('OVM_L1ERC20Gateway', () => {
const OVM_L2DepositedERC20 = await ( const OVM_L2DepositedERC20 = await (
await ethers.getContractFactory('OVM_L2DepositedERC20') await ethers.getContractFactory('OVM_L2DepositedERC20')
).deploy(constants.AddressZero, '', '') ).deploy(constants.AddressZero, '', '')
const defaultFinalizeWithdrawalGas = await OVM_L2DepositedERC20.getFinalizeWithdrawalL1Gas()
await expect(gasUsed.gt((defaultFinalizeWithdrawalGas * 11) / 10))
}) })
it.skip('finalizeWithdrawalAndCall(): should should credit funds to the withdrawer, and forward from and data', async () => { it.skip('finalizeWithdrawalAndCall(): should should credit funds to the withdrawer, and forward from and data', async () => {
...@@ -171,7 +180,11 @@ describe('OVM_L1ERC20Gateway', () => { ...@@ -171,7 +180,11 @@ describe('OVM_L1ERC20Gateway', () => {
it('deposit() escrows the deposit amount and sends the correct deposit message', async () => { it('deposit() escrows the deposit amount and sends the correct deposit message', async () => {
// alice calls deposit on the gateway and the L1 gateway calls transferFrom on the token // alice calls deposit on the gateway and the L1 gateway calls transferFrom on the token
await OVM_L1ERC20Gateway.deposit(depositAmount) await OVM_L1ERC20Gateway.deposit(
depositAmount,
FINALIZATION_GAS,
NON_NULL_BYTES32
)
const depositCallToMessenger = const depositCallToMessenger =
Mock__OVM_L1CrossDomainMessenger.smocked.sendMessage.calls[0] Mock__OVM_L1CrossDomainMessenger.smocked.sendMessage.calls[0]
...@@ -195,16 +208,21 @@ describe('OVM_L1ERC20Gateway', () => { ...@@ -195,16 +208,21 @@ describe('OVM_L1ERC20Gateway', () => {
expect(depositCallToMessenger._message).to.equal( expect(depositCallToMessenger._message).to.equal(
await Mock__OVM_L2DepositedERC20.interface.encodeFunctionData( await Mock__OVM_L2DepositedERC20.interface.encodeFunctionData(
'finalizeDeposit', 'finalizeDeposit',
[depositer, depositAmount] [depositer, depositer, depositAmount, NON_NULL_BYTES32]
) )
) )
expect(depositCallToMessenger._gasLimit).to.equal(finalizeDepositGasLimit) expect(depositCallToMessenger._gasLimit).to.equal(FINALIZATION_GAS)
}) })
it('depositTo() escrows the deposit amount and sends the correct deposit message', async () => { it('depositTo() escrows the deposit amount and sends the correct deposit message', async () => {
// depositor calls deposit on the gateway and the L1 gateway calls transferFrom on the token // depositor calls deposit on the gateway and the L1 gateway calls transferFrom on the token
const bobsAddress = await bob.getAddress() const bobsAddress = await bob.getAddress()
await OVM_L1ERC20Gateway.depositTo(bobsAddress, depositAmount) await OVM_L1ERC20Gateway.depositTo(
bobsAddress,
depositAmount,
FINALIZATION_GAS,
NON_NULL_BYTES32
)
const depositCallToMessenger = const depositCallToMessenger =
Mock__OVM_L1CrossDomainMessenger.smocked.sendMessage.calls[0] Mock__OVM_L1CrossDomainMessenger.smocked.sendMessage.calls[0]
...@@ -228,10 +246,10 @@ describe('OVM_L1ERC20Gateway', () => { ...@@ -228,10 +246,10 @@ describe('OVM_L1ERC20Gateway', () => {
expect(depositCallToMessenger._message).to.equal( expect(depositCallToMessenger._message).to.equal(
await Mock__OVM_L2DepositedERC20.interface.encodeFunctionData( await Mock__OVM_L2DepositedERC20.interface.encodeFunctionData(
'finalizeDeposit', 'finalizeDeposit',
[bobsAddress, depositAmount] [depositer, bobsAddress, depositAmount, NON_NULL_BYTES32]
) )
) )
expect(depositCallToMessenger._gasLimit).to.equal(finalizeDepositGasLimit) expect(depositCallToMessenger._gasLimit).to.equal(FINALIZATION_GAS)
}) })
}) })
}) })
...@@ -6,7 +6,11 @@ import { Signer, Contract, constants } from 'ethers' ...@@ -6,7 +6,11 @@ import { Signer, Contract, constants } from 'ethers'
import { smockit, MockContract } from '@eth-optimism/smock' import { smockit, MockContract } from '@eth-optimism/smock'
/* Internal Imports */ /* Internal Imports */
import { NON_ZERO_ADDRESS, makeAddressManager } from '../../../../helpers' import {
NON_ZERO_ADDRESS,
makeAddressManager,
NON_NULL_BYTES32,
} from '../../../../helpers'
const L1_MESSENGER_NAME = 'Proxy__OVM_L1CrossDomainMessenger' const L1_MESSENGER_NAME = 'Proxy__OVM_L1CrossDomainMessenger'
...@@ -14,6 +18,7 @@ const ERR_INVALID_MESSENGER = 'OVM_XCHAIN: messenger contract unauthenticated' ...@@ -14,6 +18,7 @@ const ERR_INVALID_MESSENGER = 'OVM_XCHAIN: messenger contract unauthenticated'
const ERR_INVALID_X_DOMAIN_MSG_SENDER = const ERR_INVALID_X_DOMAIN_MSG_SENDER =
'OVM_XCHAIN: wrong sender of cross-domain message' 'OVM_XCHAIN: wrong sender of cross-domain message'
const ERR_ALREADY_INITIALIZED = 'Contract has already been initialized.' const ERR_ALREADY_INITIALIZED = 'Contract has already been initialized.'
const FINALIZATION_GAS = 1_200_000
describe('OVM_L1ETHGateway', () => { describe('OVM_L1ETHGateway', () => {
// init signers // init signers
...@@ -38,7 +43,6 @@ describe('OVM_L1ETHGateway', () => { ...@@ -38,7 +43,6 @@ describe('OVM_L1ETHGateway', () => {
let OVM_L1ETHGateway: Contract let OVM_L1ETHGateway: Contract
let Mock__OVM_L1CrossDomainMessenger: MockContract let Mock__OVM_L1CrossDomainMessenger: MockContract
let finalizeDepositGasLimit: number
beforeEach(async () => { beforeEach(async () => {
// Get a new mock L1 messenger // Get a new mock L1 messenger
Mock__OVM_L1CrossDomainMessenger = await smockit( Mock__OVM_L1CrossDomainMessenger = await smockit(
...@@ -54,8 +58,6 @@ describe('OVM_L1ETHGateway', () => { ...@@ -54,8 +58,6 @@ describe('OVM_L1ETHGateway', () => {
AddressManager.address, AddressManager.address,
Mock__OVM_L2DepositedERC20.address Mock__OVM_L2DepositedERC20.address
) )
finalizeDepositGasLimit = await OVM_L1ETHGateway.getFinalizeDepositL2Gas()
}) })
describe('initialize', () => { describe('initialize', () => {
...@@ -75,7 +77,9 @@ describe('OVM_L1ETHGateway', () => { ...@@ -75,7 +77,9 @@ describe('OVM_L1ETHGateway', () => {
await expect( await expect(
OVM_L1ETHGateway.connect(alice).finalizeWithdrawal( OVM_L1ETHGateway.connect(alice).finalizeWithdrawal(
constants.AddressZero, constants.AddressZero,
1 constants.AddressZero,
1,
NON_NULL_BYTES32
) )
).to.be.revertedWith(ERR_INVALID_MESSENGER) ).to.be.revertedWith(ERR_INVALID_MESSENGER)
}) })
...@@ -99,7 +103,12 @@ describe('OVM_L1ETHGateway', () => { ...@@ -99,7 +103,12 @@ describe('OVM_L1ETHGateway', () => {
) )
await expect( await expect(
OVM_L1ETHGateway.finalizeWithdrawal(constants.AddressZero, 1) OVM_L1ETHGateway.finalizeWithdrawal(
constants.AddressZero,
constants.AddressZero,
1,
NON_NULL_BYTES32
)
).to.be.revertedWith(ERR_INVALID_X_DOMAIN_MSG_SENDER) ).to.be.revertedWith(ERR_INVALID_X_DOMAIN_MSG_SENDER)
}) })
...@@ -115,14 +124,20 @@ describe('OVM_L1ETHGateway', () => { ...@@ -115,14 +124,20 @@ describe('OVM_L1ETHGateway', () => {
) )
// thanks Alice // thanks Alice
await OVM_L1ETHGateway.connect(alice).deposit({ await OVM_L1ETHGateway.connect(alice).deposit(
value: ethers.utils.parseEther('1.0'), FINALIZATION_GAS,
gasPrice: 0, NON_NULL_BYTES32,
}) {
value: ethers.utils.parseEther('1.0'),
gasPrice: 0,
}
)
const res = await OVM_L1ETHGateway.finalizeWithdrawal( const res = await OVM_L1ETHGateway.finalizeWithdrawal(
NON_ZERO_ADDRESS,
NON_ZERO_ADDRESS, NON_ZERO_ADDRESS,
withdrawalAmount, withdrawalAmount,
NON_NULL_BYTES32,
{ from: Mock__OVM_L1CrossDomainMessenger.address } { from: Mock__OVM_L1CrossDomainMessenger.address }
) )
...@@ -138,12 +153,6 @@ describe('OVM_L1ETHGateway', () => { ...@@ -138,12 +153,6 @@ describe('OVM_L1ETHGateway', () => {
const OVM_L2DepositedERC20 = await ( const OVM_L2DepositedERC20 = await (
await ethers.getContractFactory('OVM_L2DepositedERC20') await ethers.getContractFactory('OVM_L2DepositedERC20')
).deploy(constants.AddressZero, '', '') ).deploy(constants.AddressZero, '', '')
await expect(
gasUsed.gt(
((await OVM_L2DepositedERC20.getFinalizeWithdrawalL1Gas()) * 11) / 10
)
)
}) })
it.skip('finalizeWithdrawalAndCall(): should should credit funds to the withdrawer, and forward from and data', async () => { it.skip('finalizeWithdrawalAndCall(): should should credit funds to the withdrawer, and forward from and data', async () => {
...@@ -182,10 +191,14 @@ describe('OVM_L1ETHGateway', () => { ...@@ -182,10 +191,14 @@ describe('OVM_L1ETHGateway', () => {
const initialBalance = await ethers.provider.getBalance(depositer) const initialBalance = await ethers.provider.getBalance(depositer)
// alice calls deposit on the gateway and the L1 gateway calls transferFrom on the token // alice calls deposit on the gateway and the L1 gateway calls transferFrom on the token
await OVM_L1ETHGateway.connect(alice).deposit({ await OVM_L1ETHGateway.connect(alice).deposit(
value: depositAmount, FINALIZATION_GAS,
gasPrice: 0, NON_NULL_BYTES32,
}) {
value: depositAmount,
gasPrice: 0,
}
)
const depositCallToMessenger = const depositCallToMessenger =
Mock__OVM_L1CrossDomainMessenger.smocked.sendMessage.calls[0] Mock__OVM_L1CrossDomainMessenger.smocked.sendMessage.calls[0]
...@@ -211,10 +224,10 @@ describe('OVM_L1ETHGateway', () => { ...@@ -211,10 +224,10 @@ describe('OVM_L1ETHGateway', () => {
expect(depositCallToMessenger._message).to.equal( expect(depositCallToMessenger._message).to.equal(
await Mock__OVM_L2DepositedERC20.interface.encodeFunctionData( await Mock__OVM_L2DepositedERC20.interface.encodeFunctionData(
'finalizeDeposit', 'finalizeDeposit',
[depositer, depositAmount] [depositer, depositer, depositAmount, NON_NULL_BYTES32]
) )
) )
expect(depositCallToMessenger._gasLimit).to.equal(finalizeDepositGasLimit) expect(depositCallToMessenger._gasLimit).to.equal(FINALIZATION_GAS)
}) })
it('depositTo() escrows the deposit amount and sends the correct deposit message', async () => { it('depositTo() escrows the deposit amount and sends the correct deposit message', async () => {
...@@ -223,10 +236,15 @@ describe('OVM_L1ETHGateway', () => { ...@@ -223,10 +236,15 @@ describe('OVM_L1ETHGateway', () => {
const aliceAddress = await alice.getAddress() const aliceAddress = await alice.getAddress()
const initialBalance = await ethers.provider.getBalance(aliceAddress) const initialBalance = await ethers.provider.getBalance(aliceAddress)
await OVM_L1ETHGateway.connect(alice).depositTo(bobsAddress, { await OVM_L1ETHGateway.connect(alice).depositTo(
value: depositAmount, bobsAddress,
gasPrice: 0, FINALIZATION_GAS,
}) NON_NULL_BYTES32,
{
value: depositAmount,
gasPrice: 0,
}
)
const depositCallToMessenger = const depositCallToMessenger =
Mock__OVM_L1CrossDomainMessenger.smocked.sendMessage.calls[0] Mock__OVM_L1CrossDomainMessenger.smocked.sendMessage.calls[0]
...@@ -250,12 +268,13 @@ describe('OVM_L1ETHGateway', () => { ...@@ -250,12 +268,13 @@ describe('OVM_L1ETHGateway', () => {
expect(depositCallToMessenger._message).to.equal( expect(depositCallToMessenger._message).to.equal(
await Mock__OVM_L2DepositedERC20.interface.encodeFunctionData( await Mock__OVM_L2DepositedERC20.interface.encodeFunctionData(
'finalizeDeposit', 'finalizeDeposit',
[bobsAddress, depositAmount] [aliceAddress, bobsAddress, depositAmount, NON_NULL_BYTES32]
) )
) )
expect(depositCallToMessenger._gasLimit).to.equal(finalizeDepositGasLimit) expect(depositCallToMessenger._gasLimit).to.equal(FINALIZATION_GAS)
}) })
}) })
describe('migrating ETH', () => { describe('migrating ETH', () => {
const migrateAmount = 1_000 const migrateAmount = 1_000
......
...@@ -11,7 +11,9 @@ import { ...@@ -11,7 +11,9 @@ import {
} from '@eth-optimism/smock' } from '@eth-optimism/smock'
/* Internal Imports */ /* Internal Imports */
import { NON_ZERO_ADDRESS } from '../../../../helpers' import { NON_NULL_BYTES32, NON_ZERO_ADDRESS } from '../../../../helpers'
const FINALIZATION_GAS = 1_200_000
const ERR_INVALID_MESSENGER = 'OVM_XCHAIN: messenger contract unauthenticated' const ERR_INVALID_MESSENGER = 'OVM_XCHAIN: messenger contract unauthenticated'
const ERR_INVALID_X_DOMAIN_MSG_SENDER = const ERR_INVALID_X_DOMAIN_MSG_SENDER =
...@@ -32,7 +34,6 @@ describe('OVM_L2DepositedERC20', () => { ...@@ -32,7 +34,6 @@ describe('OVM_L2DepositedERC20', () => {
let OVM_L2DepositedERC20: Contract let OVM_L2DepositedERC20: Contract
let Mock__OVM_L2CrossDomainMessenger: MockContract let Mock__OVM_L2CrossDomainMessenger: MockContract
let finalizeWithdrawalGasLimit: number
beforeEach(async () => { beforeEach(async () => {
// Create a special signer which will enable us to send messages from the L2Messenger contract // Create a special signer which will enable us to send messages from the L2Messenger contract
let l2MessengerImpersonator: Signer let l2MessengerImpersonator: Signer
...@@ -52,8 +53,6 @@ describe('OVM_L2DepositedERC20', () => { ...@@ -52,8 +53,6 @@ describe('OVM_L2DepositedERC20', () => {
// initialize the L2 Gateway with the L1G ateway addrss // initialize the L2 Gateway with the L1G ateway addrss
await OVM_L2DepositedERC20.init(MOCK_L1GATEWAY_ADDRESS) await OVM_L2DepositedERC20.init(MOCK_L1GATEWAY_ADDRESS)
finalizeWithdrawalGasLimit = await OVM_L2DepositedERC20.getFinalizeWithdrawalL1Gas()
}) })
// test the transfer flow of moving a token from L2 to L1 // test the transfer flow of moving a token from L2 to L1
...@@ -66,7 +65,12 @@ describe('OVM_L2DepositedERC20', () => { ...@@ -66,7 +65,12 @@ describe('OVM_L2DepositedERC20', () => {
await OVM_L2DepositedERC20.init(NON_ZERO_ADDRESS) await OVM_L2DepositedERC20.init(NON_ZERO_ADDRESS)
await expect( await expect(
OVM_L2DepositedERC20.finalizeDeposit(constants.AddressZero, 0) OVM_L2DepositedERC20.finalizeDeposit(
constants.AddressZero,
constants.AddressZero,
0,
NON_NULL_BYTES32
)
).to.be.revertedWith(ERR_INVALID_MESSENGER) ).to.be.revertedWith(ERR_INVALID_MESSENGER)
}) })
...@@ -76,9 +80,15 @@ describe('OVM_L2DepositedERC20', () => { ...@@ -76,9 +80,15 @@ describe('OVM_L2DepositedERC20', () => {
) )
await expect( await expect(
OVM_L2DepositedERC20.finalizeDeposit(constants.AddressZero, 0, { OVM_L2DepositedERC20.finalizeDeposit(
from: Mock__OVM_L2CrossDomainMessenger.address, constants.AddressZero,
}) constants.AddressZero,
0,
NON_NULL_BYTES32,
{
from: Mock__OVM_L2CrossDomainMessenger.address,
}
)
).to.be.revertedWith(ERR_INVALID_X_DOMAIN_MSG_SENDER) ).to.be.revertedWith(ERR_INVALID_X_DOMAIN_MSG_SENDER)
}) })
...@@ -89,8 +99,10 @@ describe('OVM_L2DepositedERC20', () => { ...@@ -89,8 +99,10 @@ describe('OVM_L2DepositedERC20', () => {
) )
await OVM_L2DepositedERC20.finalizeDeposit( await OVM_L2DepositedERC20.finalizeDeposit(
NON_ZERO_ADDRESS,
await alice.getAddress(), await alice.getAddress(),
depositAmount, depositAmount,
NON_NULL_BYTES32,
{ from: Mock__OVM_L2CrossDomainMessenger.address } { from: Mock__OVM_L2CrossDomainMessenger.address }
) )
...@@ -124,7 +136,11 @@ describe('OVM_L2DepositedERC20', () => { ...@@ -124,7 +136,11 @@ describe('OVM_L2DepositedERC20', () => {
}) })
it('withdraw() burns and sends the correct withdrawal message', async () => { it('withdraw() burns and sends the correct withdrawal message', async () => {
await SmoddedL2Gateway.withdraw(withdrawAmount) await SmoddedL2Gateway.withdraw(
withdrawAmount,
FINALIZATION_GAS,
NON_NULL_BYTES32
)
const withdrawalCallToMessenger = const withdrawalCallToMessenger =
Mock__OVM_L2CrossDomainMessenger.smocked.sendMessage.calls[0] Mock__OVM_L2CrossDomainMessenger.smocked.sendMessage.calls[0]
...@@ -149,17 +165,37 @@ describe('OVM_L2DepositedERC20', () => { ...@@ -149,17 +165,37 @@ describe('OVM_L2DepositedERC20', () => {
expect(withdrawalCallToMessenger._message).to.equal( expect(withdrawalCallToMessenger._message).to.equal(
await Factory__OVM_L1ERC20Gateway.interface.encodeFunctionData( await Factory__OVM_L1ERC20Gateway.interface.encodeFunctionData(
'finalizeWithdrawal', 'finalizeWithdrawal',
[await alice.getAddress(), withdrawAmount] [
await alice.getAddress(),
await alice.getAddress(),
withdrawAmount,
NON_NULL_BYTES32,
]
) )
) )
// Hardcoded gaslimit should be correct // gaslimit should be correct
expect(withdrawalCallToMessenger._gasLimit).to.equal( expect(withdrawalCallToMessenger._gasLimit).to.equal(0)
finalizeWithdrawalGasLimit })
it('withdraw() uses the user provided gas limit if it is larger than the default value ', async () => {
await SmoddedL2Gateway.withdraw(
withdrawAmount,
FINALIZATION_GAS,
NON_NULL_BYTES32
) )
const withdrawalCallToMessenger =
Mock__OVM_L2CrossDomainMessenger.smocked.sendMessage.calls[0]
// gas value is ignored and set to 0.
expect(withdrawalCallToMessenger._gasLimit).to.equal(0)
}) })
it('withdrawTo() burns and sends the correct withdrawal message', async () => { it('withdrawTo() burns and sends the correct withdrawal message', async () => {
await SmoddedL2Gateway.withdrawTo(await bob.getAddress(), withdrawAmount) await SmoddedL2Gateway.withdrawTo(
await bob.getAddress(),
withdrawAmount,
FINALIZATION_GAS,
NON_NULL_BYTES32
)
const withdrawalCallToMessenger = const withdrawalCallToMessenger =
Mock__OVM_L2CrossDomainMessenger.smocked.sendMessage.calls[0] Mock__OVM_L2CrossDomainMessenger.smocked.sendMessage.calls[0]
...@@ -184,13 +220,30 @@ describe('OVM_L2DepositedERC20', () => { ...@@ -184,13 +220,30 @@ describe('OVM_L2DepositedERC20', () => {
expect(withdrawalCallToMessenger._message).to.equal( expect(withdrawalCallToMessenger._message).to.equal(
await Factory__OVM_L1ERC20Gateway.interface.encodeFunctionData( await Factory__OVM_L1ERC20Gateway.interface.encodeFunctionData(
'finalizeWithdrawal', 'finalizeWithdrawal',
[await bob.getAddress(), withdrawAmount] [
await alice.getAddress(),
await bob.getAddress(),
withdrawAmount,
NON_NULL_BYTES32,
]
) )
) )
// Hardcoded gaslimit should be correct // gas value is ignored and set to 0.
expect(withdrawalCallToMessenger._gasLimit).to.equal( expect(withdrawalCallToMessenger._gasLimit).to.equal(0)
finalizeWithdrawalGasLimit })
it('withdrawTo() uses the user provided gas limit if it is larger than the default value ', async () => {
await SmoddedL2Gateway.withdrawTo(
await bob.getAddress(),
withdrawAmount,
FINALIZATION_GAS,
NON_NULL_BYTES32
) )
const withdrawalCallToMessenger =
Mock__OVM_L2CrossDomainMessenger.smocked.sendMessage.calls[0]
// gas value is ignored and set to 0.
expect(withdrawalCallToMessenger._gasLimit).to.equal(0)
}) })
}) })
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment