Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for rollup mode when using fee token #252

Draft
wants to merge 59 commits into
base: develop
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 57 commits
Commits
Show all changes
59 commits
Select commit Hold shift + click to select a range
36e3996
Start of custom fee tokens for rollups
yahgwai Sep 18, 2024
84ef567
Do not exclude batch reports when using fee token
gvladika Sep 19, 2024
8125656
Add condition for submitting the batch report, and do the scaling
gvladika Sep 19, 2024
74f9939
Add IFeeTokenPricer
gvladika Sep 19, 2024
504dbc0
Add getter and setter for pricer to the interface
gvladika Sep 19, 2024
44f3986
Add setter for feeTokenPricer
gvladika Sep 19, 2024
ef4f1fb
Add missing param
gvladika Sep 19, 2024
a6a3f55
Use new SeqInbox init param
gvladika Sep 19, 2024
f3eb844
Make existing tests work with feeTokenPricer
gvladika Sep 20, 2024
2897ce6
Format
gvladika Sep 20, 2024
70f6ad4
Add setFeeTokenPricer tests
gvladika Sep 20, 2024
213039f
Fee token pricing deployment
yahgwai Sep 20, 2024
4c643e1
Merge branch 'custom-fee-rollup' of https://github.com/OffchainLabs/n…
yahgwai Sep 20, 2024
57f46ed
Revert if trying to set fee token pricer when fee token is not used
gvladika Sep 20, 2024
33420d4
Add fuzz test for different exchange rates
gvladika Sep 23, 2024
8a1dfdd
Handle overflow case due to too high exchange rate
gvladika Sep 23, 2024
252f599
Updated erc20rollupeventinbox to do gas price scaling
yahgwai Sep 25, 2024
e852b6a
Merge branch 'custom-fee-rollup' of https://github.com/OffchainLabs/n…
yahgwai Sep 25, 2024
a702a08
Added integration test for batch poster reimbursement
yahgwai Sep 26, 2024
86c5a94
Update rollupInitialized test
gvladika Sep 26, 2024
1bcf1aa
Refactor tests and check initial cost is properly reported
gvladika Sep 26, 2024
e752cb7
Merge branch 'custom-fee-rollup' of https://github.com/OffchainLabs/n…
yahgwai Sep 26, 2024
14297dc
Added fee token pricer arg
yahgwai Sep 26, 2024
e3217ed
Use token fee pricer testnode ref
yahgwai Sep 26, 2024
cf42d00
Updated int fee token tests
yahgwai Sep 26, 2024
f64df33
Formatting
yahgwai Sep 26, 2024
70c19e8
Updated comments
yahgwai Sep 26, 2024
e3a7f9b
Formatting
yahgwai Sep 26, 2024
fcb4950
Try tests with init
yahgwai Sep 26, 2024
483171b
Added separate job for e2e tests
yahgwai Sep 26, 2024
913bf45
Missed test name change
yahgwai Sep 26, 2024
2956969
Disable while true condition linting
yahgwai Sep 26, 2024
1f33876
Fixed 4844 tests
yahgwai Sep 26, 2024
f22ec8c
Added fee token pricer address zero to arb rollup spec
yahgwai Sep 26, 2024
2b57aac
Formatting
yahgwai Sep 26, 2024
e6b0beb
Updated orbit ame
yahgwai Sep 26, 2024
2f876cf
Updated sigs and storage
yahgwai Sep 26, 2024
fde0833
Added estimate gas
yahgwai Sep 26, 2024
14a10ef
L1 wal balance console
yahgwai Sep 26, 2024
20ebdbe
Console logging
yahgwai Sep 26, 2024
782c792
Added gas price estimation
yahgwai Sep 26, 2024
9f17bcb
Update Slither db, no new findings
gvladika Sep 27, 2024
7f4161f
Add fuzz test for rollupInitialized
gvladika Sep 27, 2024
96d2592
Merge branch 'develop' into custom-fee-rollup
gzeoneth Oct 1, 2024
bf402da
Merge branch 'develop' into custom-fee-rollup
gvladika Oct 9, 2024
e071dde
Clean up
gvladika Oct 9, 2024
f050fdb
Update slither db
gvladika Oct 9, 2024
c015aaf
Update audit-ci.jsonc
gvladika Oct 9, 2024
5711d1e
Updated format command
yahgwai Nov 28, 2024
d34fb05
Comment updates
yahgwai Nov 28, 2024
2cd9b03
Merge from develop
yahgwai Nov 28, 2024
931670e
Updated slither
yahgwai Nov 28, 2024
988b807
Updated slither
yahgwai Nov 28, 2024
51da15a
Merge from bold-merge
yahgwai Nov 29, 2024
5d4d1f9
Formatting
yahgwai Nov 29, 2024
af2754f
Updated signatures and storage
yahgwai Nov 29, 2024
36a4e3b
Slither
yahgwai Nov 29, 2024
d6ed473
Merge from develop
yahgwai Dec 20, 2024
b805e8c
Formatting
yahgwai Dec 20, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 71 additions & 0 deletions .github/workflows/contract-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -278,3 +278,74 @@ jobs:

- name: Test upgrade
run: L1_RPC=${{ secrets.L1_RPC || 'https://rpc.ankr.com/eth' }} yarn test:upgrade

test-e2e-custom-fee-token:
name: Test e2e custom fee token
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
submodules: recursive

- uses: OffchainLabs/actions/run-nitro-test-node@main
with:
l3-node: true
args: --l3-fee-token --l3-fee-token-pricer
no-token-bridge: true
no-l3-token-bridge: true
nitro-testnode-ref: fee-token-pricer
nitro-contracts-branch: '${{ github.event.pull_request.head.sha || github.sha }}'

- name: Setup node/yarn
uses: actions/setup-node@v3
with:
node-version: 18
cache: 'yarn'
cache-dependency-path: '**/yarn.lock'

- name: Install packages
run: yarn

- name: Compile contracts
run: yarn build

- name: Run e2e orbit tests
run: yarn test:e2e:orbit

- name: Run e2e orbit custom fee token rollup tests
run: yarn test:e2e:orbit-fee-token-rollup
test-e2e-fee-token-6-decimals:
name: Test e2e fee token with 6 decimals
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
submodules: recursive

- uses: OffchainLabs/actions/run-nitro-test-node@main
with:
l3-node: true
args: --l3-fee-token --l3-fee-token-pricer --l3-fee-token-decimals 6
no-token-bridge: true
no-l3-token-bridge: true
nitro-testnode-ref: fee-token-pricer
nitro-contracts-branch: '${{ github.event.pull_request.head.sha || github.sha }}'

- name: Setup node/yarn
uses: actions/setup-node@v3
with:
node-version: 18
cache: 'yarn'
cache-dependency-path: '**/yarn.lock'

- name: Install packages
run: yarn

- name: Compile contracts
run: yarn build

- name: Run e2e tests
run: yarn test:e2e:orbit

- name: Run e2e orbit custom fee token rollup tests
run: yarn test:e2e:orbit-fee-token-rollup
5 changes: 4 additions & 1 deletion foundry.toml
Original file line number Diff line number Diff line change
Expand Up @@ -38,4 +38,7 @@ ignore = []
contract_new_lines = false
sort_imports = false

# See more config options https://github.com/foundry-rs/foundry/tree/master/config
[fuzz]
runs = 1000

# See more config options https://github.com/foundry-rs/foundry/tree/master/config
3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@
"test:compatibility": "yarn run build:0.6 && yarn run build:0.7",
"test:storage": "./test/storage/test.bash",
"test:signatures": "./test/signatures/test-sigs.bash",
"test:e2e:orbit": "hardhat test test/e2e/orbitChain.ts",
"test:e2e:orbit-fee-token-rollup": "hardhat test test/e2e/customFeeRollup.ts",
"test:e2e": "hardhat test test/e2e/*.ts",
"test:upgrade": "./scripts/testUpgrade.bash",
"test:foundry": "forge test --gas-limit 10000000000",
Expand All @@ -50,6 +52,7 @@
"deploy-eth-rollup": "hardhat run scripts/createEthRollup.ts",
"deploy-erc20-rollup": "hardhat run scripts/createERC20Rollup.ts",
"create-rollup-testnode": "hardhat run scripts/local-deployment/deployCreatorAndCreateRollup.ts",
"slither-triage": "slither . --skip-assembly --triage-mode",
"script:bold-prepare": "hardhat run ./scripts/prepareBoldUpgrade.ts",
"script:bold-populate-lookup": "hardhat run ./scripts/populateLookup.ts",
"script:bold-local-execute": "hardhat run ./scripts/executeBoldUpgrade.ts",
Expand Down
14 changes: 13 additions & 1 deletion scripts/createERC20Rollup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,24 @@ async function main() {
throw new Error('STAKE_TOKEN_ADDRESS not set')
}

console.log('Creating new rollup with', customFeeTokenAddress, 'as fee token')
let feeTokenPricer = process.env.FEE_TOKEN_PRICER_ADDRESS
if (!feeTokenPricer) {
feeTokenPricer = ethers.constants.AddressZero
}

console.log(
'Creating new rollup with',
customFeeTokenAddress,
'as fee token and',
feeTokenPricer,
'as fee token pricer'
)
await createRollup(
deployer,
false,
rollupCreatorAddress,
customFeeTokenAddress,
feeTokenPricer,
stakeTokenAddress
)
}
Expand Down
2 changes: 2 additions & 0 deletions scripts/createEthRollup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { createRollup } from './rollupCreation'

async function main() {
const feeToken = ethers.constants.AddressZero
const feeTokenPricer = ethers.constants.AddressZero
const rollupCreatorAddress = process.env.ROLLUP_CREATOR_ADDRESS
if (!rollupCreatorAddress) {
throw new Error('ROLLUP_CREATOR_ADDRESS not set')
Expand All @@ -21,6 +22,7 @@ async function main() {
false,
rollupCreatorAddress,
feeToken,
feeTokenPricer,
stakeTokenAddress
)
}
Expand Down
5 changes: 5 additions & 0 deletions scripts/local-deployment/deployCreatorAndCreateRollup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,10 @@ async function main() {
if (!feeToken) {
feeToken = ethers.constants.AddressZero
}
let feeTokenPricer = process.env.FEE_TOKEN_PRICER_ADDRESS as string
if (!feeTokenPricer) {
feeTokenPricer = ethers.constants.AddressZero
}

/// get stake token address, if undefined deploy WETH and set it as stake token
let stakeToken = process.env.STAKE_TOKEN_ADDRESS as string
Expand Down Expand Up @@ -84,6 +88,7 @@ async function main() {
true,
contracts.rollupCreator.address,
feeToken,
feeTokenPricer,
stakeToken
)

Expand Down
24 changes: 19 additions & 5 deletions scripts/rollupCreation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,13 @@ import '@nomiclabs/hardhat-ethers'
import { run } from 'hardhat'
import { abi as rollupCreatorAbi } from '../build/contracts/src/rollup/RollupCreator.sol/RollupCreator.json'
import { config, maxDataSize } from './config'
import { BigNumber, Signer } from 'ethers'
import { ERC20, ERC20__factory, IERC20__factory } from '../build/types'
import { BigNumber, Event, Signer } from 'ethers'
import {
ERC20,
ERC20__factory,
IERC20__factory,
RollupCreator,
} from '../build/types'
import { sleep } from './testSetup'
import { promises as fs } from 'fs'
import { _isRunningOnArbitrum, verifyContract } from './deploymentUtils'
Expand Down Expand Up @@ -60,6 +65,7 @@ export async function createRollup(
isDevDeployment: boolean,
rollupCreatorAddress: string,
feeToken: string,
feeTokenPricer: string,
stakeToken: string
): Promise<{
rollupCreationResult: RollupCreationResult
Expand All @@ -75,7 +81,7 @@ export async function createRollup(
rollupCreatorAddress,
rollupCreatorAbi,
signer
)
) as RollupCreator
const validatorWalletCreator = await rollupCreator.validatorWalletCreator()

try {
Expand All @@ -100,7 +106,12 @@ export async function createRollup(
// Call the createRollup function
console.log('Calling createRollup to generate a new rollup ...')
const deployParams = isDevDeployment
? await _getDevRollupConfig(feeToken, validatorWalletCreator, stakeToken)
? await _getDevRollupConfig(
feeToken,
feeTokenPricer,
validatorWalletCreator,
stakeToken
)
: {
config: config.rollupConfig,
validators: config.validators,
Expand All @@ -110,6 +121,7 @@ export async function createRollup(
maxFeePerGasForRetryables: MAX_FER_PER_GAS,
batchPosters: config.batchPosters,
batchPosterManager: config.batchPosterManager,
feeTokenPricer: feeTokenPricer,
}

const createRollupTx = await rollupCreator.createRollup(deployParams, {
Expand All @@ -118,7 +130,7 @@ export async function createRollup(
const createRollupReceipt = await createRollupTx.wait()

const rollupCreatedEvent = createRollupReceipt.events?.find(
(event: RollupCreatedEvent) =>
(event: Event): event is Event =>
event.event === 'RollupCreated' &&
event.address.toLowerCase() === rollupCreatorAddress.toLowerCase()
)
Expand Down Expand Up @@ -218,6 +230,7 @@ export async function createRollup(

async function _getDevRollupConfig(
feeToken: string,
feeTokenPricer: string,
validatorWalletCreator: string,
stakeToken: string
) {
Expand Down Expand Up @@ -330,6 +343,7 @@ async function _getDevRollupConfig(
maxFeePerGasForRetryables: MAX_FER_PER_GAS,
batchPosters: batchPosters,
batchPosterManager: batchPosterManager,
feeTokenPricer: feeTokenPricer,
}

function _createValidatorAddress(
Expand Down
2 changes: 1 addition & 1 deletion slither.db.json

Large diffs are not rendered by default.

31 changes: 30 additions & 1 deletion src/bridge/ISequencerInbox.sol
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,15 @@ interface ISequencerInbox is IDelayedMessageProvider {
/// This enables the batch poster to do key rotation
function batchPosterManager() external view returns (address);

/// @notice The fee token pricer is used to get the exchange rate between the child chain's fee token
/// and parent chain's fee token. This is needed when the child chain uses a custom fee
/// token which is different from the parent chain's fee token. The exchange rate is
/// used to correctly report converted gas price in the batch spending reports, so
/// the batch poster can get properly reimbursed on the child chain. If the chain uses
/// a custom fee token, but the pricer is not set, then the batch poster reports won't be reported
/// and the batch poster won't get reimbursed.
function feeTokenPricer() external view returns (IFeeTokenPricer);

struct DasKeySetInfo {
bool isValidKeyset;
uint64 creationBlock;
Expand Down Expand Up @@ -321,6 +330,15 @@ interface ISequencerInbox is IDelayedMessageProvider {
address newBatchPosterManager
) external;

/**
* @notice Updates the fee token pricer, the contract which is used to get the exchange rate between child
* chain's fee token and parent chain's fee token in rollups that use a custom fee token.
* @param newFeeTokenPricer The new fee token pricer to be set
*/
function setFeeTokenPricer(
IFeeTokenPricer newFeeTokenPricer
) external;

/// @notice Allows the rollup owner to sync the rollup address
function updateRollupAddress() external;

Expand All @@ -329,6 +347,17 @@ interface ISequencerInbox is IDelayedMessageProvider {
function initialize(
IBridge bridge_,
MaxTimeVariation calldata maxTimeVariation_,
BufferConfig calldata bufferConfig_
BufferConfig calldata bufferConfig_,
IFeeTokenPricer feeTokenPricer_
) external;
}

interface IFeeTokenPricer {
/**
* @notice Get the number of child chain fee tokens per 1 parent chain fee token. Exchange rate must be
* denominated in 18 decimals. Function is mutable so it allows the pricer to keep internal state.
* @dev For example, parent chain's native token is ETH, fee token is DAI. If price of 1ETH = 2000DAI, then function should return 2000*1e18.
* If fee token is USDC instead and price of 1ETH = 2000USDC, function should still return 2000*1e18, despite USDC using 6 decimals.
*/
function getExchangeRate() external returns (uint256);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

instead of a getter that return spot rate, I think it make more sense to have a mutable method spendingInEth(uint256 wei, address spender) that take the number of eth spent as input and return the number of token spent. This allow the pricer to do more complex internal accounting if needed.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As we discussed, we can probably satisfy all use-cases with getExchangeRate(). It's mutable so it enables internal accounting. Gas reporting hooks can be used to update state and account for which state is updated can be tx.origin or 'spender' as reported by the hook.

}
Loading
Loading