mirror of
https://github.com/scroll-tech/scroll.git
synced 2026-01-12 07:28:08 -05:00
Compare commits
5 Commits
fix/devnet
...
sepolia
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
af3913d607 | ||
|
|
c586d2f223 | ||
|
|
0039ef7d5a | ||
|
|
14730d46a3 | ||
|
|
1cfecad426 |
138
.github/workflows/contracts.yml
vendored
Normal file
138
.github/workflows/contracts.yml
vendored
Normal file
@@ -0,0 +1,138 @@
|
||||
name: Contracts
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- staging
|
||||
- develop
|
||||
- alpha
|
||||
paths:
|
||||
- 'contracts/**'
|
||||
- '.github/workflows/contracts.yaml'
|
||||
pull_request:
|
||||
types:
|
||||
- opened
|
||||
- reopened
|
||||
- synchronize
|
||||
- ready_for_review
|
||||
paths:
|
||||
- 'contracts/**'
|
||||
- '.github/workflows/contracts.yaml'
|
||||
|
||||
defaults:
|
||||
run:
|
||||
working-directory: 'contracts'
|
||||
|
||||
jobs:
|
||||
foundry:
|
||||
if: github.event.pull_request.draft == false
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout sources
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
- name: Install Foundry
|
||||
uses: foundry-rs/foundry-toolchain@v1
|
||||
with:
|
||||
version: nightly
|
||||
|
||||
- name: Setup LCOV
|
||||
uses: hrishikesh-kadam/setup-lcov@v1
|
||||
|
||||
- name: Install Node.js 18
|
||||
uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: '18'
|
||||
|
||||
- name: Get yarn cache directory path
|
||||
id: yarn-cache-dir-path
|
||||
run: echo "::set-output name=dir::$(yarn cache dir)"
|
||||
|
||||
- name: Cache yarn dependencies
|
||||
uses: actions/cache@v2
|
||||
id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`)
|
||||
with:
|
||||
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
|
||||
key: ${{ runner.os }}-yarn-${{ hashFiles('contracts/yarn.lock') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-yarn-
|
||||
|
||||
- name: Cache node_modules
|
||||
id: npm_cache
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: node_modules
|
||||
key: node_modules-${{ hashFiles('contracts/yarn.lock') }}
|
||||
|
||||
- name: yarn install
|
||||
# if: steps.npm_cache.outputs.cache-hit != 'true'
|
||||
run: yarn install
|
||||
|
||||
- name: Compile with foundry
|
||||
run: forge build --evm-version cancun
|
||||
|
||||
- name: Run foundry tests
|
||||
run: forge test --evm-version cancun -vvv
|
||||
|
||||
- name: Run foundry coverage
|
||||
run : forge coverage --evm-version cancun --report lcov
|
||||
|
||||
- name : Prune coverage
|
||||
run : lcov --rc branch_coverage=1 --remove ./lcov.info -o ./lcov.info.pruned 'src/mocks/*' 'src/test/*' 'scripts/*' 'node_modules/*' 'lib/*'
|
||||
|
||||
- name: Upload coverage reports to Codecov
|
||||
uses: codecov/codecov-action@v3
|
||||
env:
|
||||
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
|
||||
with:
|
||||
files: contracts/lcov.info.pruned
|
||||
flags: contracts
|
||||
|
||||
hardhat:
|
||||
if: github.event.pull_request.draft == false
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout sources
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
- name: Install Node.js 18
|
||||
uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: '18'
|
||||
|
||||
- name: Get yarn cache directory path
|
||||
id: yarn-cache-dir-path
|
||||
run: echo "::set-output name=dir::$(yarn cache dir)"
|
||||
|
||||
- name: Cache yarn dependencies
|
||||
uses: actions/cache@v2
|
||||
id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`)
|
||||
with:
|
||||
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
|
||||
key: ${{ runner.os }}-yarn-${{ hashFiles('contracts/yarn.lock') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-yarn-
|
||||
|
||||
- name: Cache node_modules
|
||||
id: npm_cache
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: node_modules
|
||||
key: node_modules-${{ hashFiles('contracts/yarn.lock') }}
|
||||
|
||||
- name: yarn install
|
||||
# if: steps.npm_cache.outputs.cache-hit != 'true'
|
||||
run: yarn install
|
||||
|
||||
- name: Compile with hardhat
|
||||
run: npx hardhat compile
|
||||
|
||||
- name: Run hardhat tests
|
||||
run: npx hardhat test
|
||||
@@ -1,41 +0,0 @@
|
||||
name: Docker-coordinator-api-arm64
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
tag:
|
||||
description: "tag of this image (suffix -arm64 is added automatically)"
|
||||
required: true
|
||||
type: string
|
||||
|
||||
jobs:
|
||||
build-and-push-arm64-image:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
arch:
|
||||
- aarch64
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v2
|
||||
- name: Set up QEMU
|
||||
run: |
|
||||
docker run --rm --privileged multiarch/qemu-user-static --reset -p yes
|
||||
docker buildx create --name multiarch --driver docker-container --use
|
||||
- name: Set up Docker Buildx
|
||||
id: buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
- name: Build docker image
|
||||
uses: docker/build-push-action@v2
|
||||
with:
|
||||
platforms: linux/arm64
|
||||
context: .
|
||||
file: ./build/dockerfiles/coordinator-api.Dockerfile
|
||||
push: true
|
||||
tags: scrolltech/coordinator-api:${{inputs.tag}}-arm64
|
||||
46
.github/workflows/docker.yml
vendored
46
.github/workflows/docker.yml
vendored
@@ -9,6 +9,51 @@ env:
|
||||
AWS_REGION: us-west-2
|
||||
|
||||
jobs:
|
||||
event_watcher:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v2
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
- name: Configure AWS credentials
|
||||
uses: aws-actions/configure-aws-credentials@v4
|
||||
with:
|
||||
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
||||
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
||||
aws-region: ${{ env.AWS_REGION }}
|
||||
- name: Login to Amazon ECR
|
||||
id: login-ecr
|
||||
uses: aws-actions/amazon-ecr-login@v2
|
||||
- name: check repo and create it if not exist
|
||||
env:
|
||||
REPOSITORY: event-watcher
|
||||
run: |
|
||||
aws --region ${{ env.AWS_REGION }} ecr describe-repositories --repository-names ${{ env.REPOSITORY }} && : || aws --region ${{ env.AWS_REGION }} ecr create-repository --repository-name ${{ env.REPOSITORY }}
|
||||
- name: Build and push
|
||||
uses: docker/build-push-action@v3
|
||||
env:
|
||||
ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }}
|
||||
REPOSITORY: event-watcher
|
||||
IMAGE_TAG: ${{ github.ref_name }}
|
||||
with:
|
||||
context: .
|
||||
file: ./build/dockerfiles/event_watcher.Dockerfile
|
||||
platforms: linux/amd64,linux/arm64
|
||||
push: true
|
||||
tags: |
|
||||
${{ secrets.DOCKERHUB_USERNAME }}/${{ env.REPOSITORY }}:${{ env.IMAGE_TAG }}
|
||||
${{ secrets.DOCKERHUB_USERNAME }}/${{ env.REPOSITORY }}:latest
|
||||
${{ env.ECR_REGISTRY }}/${{ env.REPOSITORY }}:${{ env.IMAGE_TAG }}
|
||||
${{ env.ECR_REGISTRY }}/${{ env.REPOSITORY }}:latest
|
||||
|
||||
gas_oracle:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
@@ -316,6 +361,7 @@ jobs:
|
||||
with:
|
||||
context: .
|
||||
file: ./build/dockerfiles/coordinator-api.Dockerfile
|
||||
platforms: linux/amd64
|
||||
push: true
|
||||
tags: |
|
||||
${{ secrets.DOCKERHUB_USERNAME }}/${{ env.REPOSITORY }}:${{ env.IMAGE_TAG }}
|
||||
|
||||
15
.gitmodules
vendored
15
.gitmodules
vendored
@@ -1,3 +1,12 @@
|
||||
[submodule "scroll-contracts"]
|
||||
path = scroll-contracts
|
||||
url = https://github.com/scroll-tech/scroll-contracts.git
|
||||
[submodule "l2geth"]
|
||||
path = l2geth
|
||||
url = git@github.com:scroll-tech/go-ethereum.git
|
||||
[submodule "contracts/lib/ds-test"]
|
||||
path = contracts/lib/ds-test
|
||||
url = https://github.com/dapphub/ds-test
|
||||
[submodule "contracts/lib/forge-std"]
|
||||
path = contracts/lib/forge-std
|
||||
url = https://github.com/foundry-rs/forge-std
|
||||
[submodule "contracts/lib/solmate"]
|
||||
path = contracts/lib/solmate
|
||||
url = https://github.com/rari-capital/solmate
|
||||
|
||||
4
Makefile
4
Makefile
@@ -12,6 +12,7 @@ update:
|
||||
cd $(PWD)/common/ && go get -u github.com/scroll-tech/go-ethereum@${L2GETH_TAG}&& go mod tidy
|
||||
cd $(PWD)/coordinator/ && go get -u github.com/scroll-tech/go-ethereum@${L2GETH_TAG} && go mod tidy
|
||||
cd $(PWD)/database/ && go get -u github.com/scroll-tech/go-ethereum@${L2GETH_TAG} && go mod tidy
|
||||
cd $(PWD)/prover/ && go get -u github.com/scroll-tech/go-ethereum@${L2GETH_TAG}&& go mod tidy
|
||||
cd $(PWD)/rollup/ && go get -u github.com/scroll-tech/go-ethereum@${L2GETH_TAG} && go mod tidy
|
||||
cd $(PWD)/tests/integration-test/ && go get -u github.com/scroll-tech/go-ethereum@${L2GETH_TAG} && go mod tidy
|
||||
|
||||
@@ -20,6 +21,7 @@ lint: ## The code's format and security checks.
|
||||
make -C common lint
|
||||
make -C coordinator lint
|
||||
make -C database lint
|
||||
make -C prover lint
|
||||
make -C bridge-history-api lint
|
||||
|
||||
fmt: ## format the code
|
||||
@@ -28,6 +30,7 @@ fmt: ## format the code
|
||||
cd $(PWD)/common/ && go mod tidy
|
||||
cd $(PWD)/coordinator/ && go mod tidy
|
||||
cd $(PWD)/database/ && go mod tidy
|
||||
cd $(PWD)/prover/ && go mod tidy
|
||||
cd $(PWD)/rollup/ && go mod tidy
|
||||
cd $(PWD)/tests/integration-test/ && go mod tidy
|
||||
|
||||
@@ -35,6 +38,7 @@ fmt: ## format the code
|
||||
goimports -local $(PWD)/common/ -w .
|
||||
goimports -local $(PWD)/coordinator/ -w .
|
||||
goimports -local $(PWD)/database/ -w .
|
||||
goimports -local $(PWD)/prover/ -w .
|
||||
goimports -local $(PWD)/rollup/ -w .
|
||||
goimports -local $(PWD)/tests/integration-test/ -w .
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
# Scroll Monorepo
|
||||
|
||||
[](https://github.com/scroll-tech/scroll/actions/workflows/rollup.yml)
|
||||
[](https://github.com/scroll-tech/scroll/actions/workflows/contracts.yml)
|
||||
[](https://github.com/scroll-tech/scroll/actions/workflows/bridge_history_api.yml)
|
||||
[](https://github.com/scroll-tech/scroll/actions/workflows/coordinator.yml)
|
||||
[](https://github.com/scroll-tech/scroll/actions/workflows/prover.yml)
|
||||
@@ -51,6 +52,12 @@ go test -v -race -covermode=atomic scroll-tech/database/...
|
||||
go test -v -race -covermode=atomic scroll-tech/common/...
|
||||
```
|
||||
|
||||
## Testing Contracts
|
||||
|
||||
You can find the unit tests in [`contracts/src/test/`](/contracts/src/test/), and integration tests in [`contracts/integration-test/`](/contracts/integration-test/).
|
||||
|
||||
See [`contracts`](/contracts) for more details on the contracts.
|
||||
|
||||
## License
|
||||
|
||||
Scroll Monorepo is licensed under the [MIT](./LICENSE) license.
|
||||
|
||||
@@ -96,7 +96,7 @@ func action(ctx *cli.Context) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Run bridge-history-backend api cmd instance.
|
||||
// Run event watcher cmd instance.
|
||||
func Run() {
|
||||
if err := app.Run(os.Args); err != nil {
|
||||
_, _ = fmt.Fprintln(os.Stderr, err)
|
||||
|
||||
@@ -84,7 +84,7 @@ func action(ctx *cli.Context) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Run bridge-history-backend fetcher cmd instance.
|
||||
// Run event watcher cmd instance.
|
||||
func Run() {
|
||||
if err := app.Run(os.Args); err != nil {
|
||||
_, _ = fmt.Fprintln(os.Stderr, err)
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
"ScrollChainAddr": "0xa13BAF47339d63B743e7Da8741db5456DAc1E556",
|
||||
"GatewayRouterAddr": "0xF8B1378579659D8F7EE5f3C929c2f3E332E41Fd6",
|
||||
"MessageQueueAddr": "0x0d7E906BD9cAFa154b048cFa766Cc1E54E39AF9B",
|
||||
"BatchBridgeGatewayAddr": "0x5Bcfd99c34cf7E06fc756f6f5aE7400504852bc4"
|
||||
"BatchBridgeGatewayAddr": "0x0000000000000000000000000000000000000000"
|
||||
},
|
||||
"L2": {
|
||||
"confirmation": 0,
|
||||
@@ -39,7 +39,7 @@
|
||||
"PufferGatewayAddr": "0x9eBf2f33526CD571f8b2ad312492cb650870CFd6",
|
||||
"GatewayRouterAddr": "0x4C0926FF5252A435FD19e10ED15e5a249Ba19d79",
|
||||
"MessageQueueAddr": "0x5300000000000000000000000000000000000000",
|
||||
"BatchBridgeGatewayAddr": "0xa1a12158bE6269D7580C63eC5E609Cdc0ddD82bC"
|
||||
"BatchBridgeGatewayAddr": "0x0000000000000000000000000000000000000000"
|
||||
},
|
||||
"db": {
|
||||
"dsn": "postgres://postgres:123456@localhost:5444/test?sslmode=disable",
|
||||
|
||||
@@ -141,7 +141,7 @@ func (c *L2MessageFetcher) fetchAndSaveEvents(confirmation uint64) {
|
||||
return
|
||||
}
|
||||
|
||||
if updateErr := c.eventUpdateLogic.UpdateL2WithdrawMessageProofs(c.ctx, c.l2SyncHeight); updateErr != nil {
|
||||
if updateErr := c.eventUpdateLogic.UpdateL1BatchIndexAndStatus(c.ctx, c.l2SyncHeight); updateErr != nil {
|
||||
log.Error("failed to update L1 batch index and status", "from", from, "to", to, "err", updateErr)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -125,11 +125,6 @@ func (b *EventUpdateLogic) L1InsertOrUpdate(ctx context.Context, l1FetcherResult
|
||||
}
|
||||
|
||||
func (b *EventUpdateLogic) updateL2WithdrawMessageInfos(ctx context.Context, batchIndex, startBlock, endBlock uint64) error {
|
||||
if startBlock > endBlock {
|
||||
log.Warn("start block is greater than end block", "start", startBlock, "end", endBlock)
|
||||
return nil
|
||||
}
|
||||
|
||||
l2WithdrawMessages, err := b.crossMessageOrm.GetL2WithdrawalsByBlockRange(ctx, startBlock, endBlock)
|
||||
if err != nil {
|
||||
log.Error("failed to get L2 withdrawals by batch index", "batch index", batchIndex, "err", err)
|
||||
@@ -152,7 +147,7 @@ func (b *EventUpdateLogic) updateL2WithdrawMessageInfos(ctx context.Context, bat
|
||||
}
|
||||
|
||||
if withdrawTrie.NextMessageNonce != l2WithdrawMessages[0].MessageNonce {
|
||||
log.Error("nonce mismatch", "expected next message nonce", withdrawTrie.NextMessageNonce, "actual next message nonce", l2WithdrawMessages[0].MessageNonce)
|
||||
log.Error("nonce mismatch", "expected next message nonce", withdrawTrie.NextMessageNonce, "actuall next message nonce", l2WithdrawMessages[0].MessageNonce)
|
||||
return fmt.Errorf("nonce mismatch")
|
||||
}
|
||||
|
||||
@@ -178,42 +173,24 @@ func (b *EventUpdateLogic) updateL2WithdrawMessageInfos(ctx context.Context, bat
|
||||
return nil
|
||||
}
|
||||
|
||||
// UpdateL2WithdrawMessageProofs updates L2 withdrawal message proofs.
|
||||
func (b *EventUpdateLogic) UpdateL2WithdrawMessageProofs(ctx context.Context, height uint64) error {
|
||||
lastUpdatedFinalizedBlockHeight, err := b.batchEventOrm.GetLastUpdatedFinalizedBlockHeight(ctx)
|
||||
// UpdateL1BatchIndexAndStatus updates L1 finalized batch index and status
|
||||
func (b *EventUpdateLogic) UpdateL1BatchIndexAndStatus(ctx context.Context, height uint64) error {
|
||||
finalizedBatches, err := b.batchEventOrm.GetFinalizedBatchesLEBlockHeight(ctx, height)
|
||||
if err != nil {
|
||||
log.Error("failed to get last updated finalized block height", "error", err)
|
||||
return err
|
||||
}
|
||||
|
||||
finalizedBatches, err := b.batchEventOrm.GetUnupdatedFinalizedBatchesLEBlockHeight(ctx, height)
|
||||
if err != nil {
|
||||
log.Error("failed to get unupdated finalized batches >= block height", "error", err)
|
||||
log.Error("failed to get batches >= block height", "error", err)
|
||||
return err
|
||||
}
|
||||
|
||||
for _, finalizedBatch := range finalizedBatches {
|
||||
log.Info("update finalized batch or bundle info of L2 withdrawals", "index", finalizedBatch.BatchIndex, "lastUpdatedFinalizedBlockHeight", lastUpdatedFinalizedBlockHeight, "start", finalizedBatch.StartBlockNumber, "end", finalizedBatch.EndBlockNumber)
|
||||
// This method is compatible with both "finalize by batch" and "finalize by bundle" modes:
|
||||
// - In "finalize by batch" mode, each batch emits a FinalizedBatch event.
|
||||
// - In "finalize by bundle" mode, all batches in the bundle emit only one FinalizedBatch event, using the last batch's index and hash.
|
||||
//
|
||||
// The method updates two types of information in L2 withdrawal messages:
|
||||
// 1. Withdraw proof generation:
|
||||
// - finalize by batch: Generates proofs for each batch.
|
||||
// - finalize by bundle: Generates proofs for the entire bundle at once.
|
||||
// 2. Batch index updating:
|
||||
// - finalize by batch: Updates the batch index for withdrawal messages in each processed batch.
|
||||
// - finalize by bundle: Updates the batch index for all withdrawal messages in the bundle, using the index of the last batch in the bundle.
|
||||
if updateErr := b.updateL2WithdrawMessageInfos(ctx, finalizedBatch.BatchIndex, lastUpdatedFinalizedBlockHeight+1, finalizedBatch.EndBlockNumber); updateErr != nil {
|
||||
log.Error("failed to update L2 withdraw message infos", "index", finalizedBatch.BatchIndex, "lastUpdatedFinalizedBlockHeight", lastUpdatedFinalizedBlockHeight, "start", finalizedBatch.StartBlockNumber, "end", finalizedBatch.EndBlockNumber, "error", updateErr)
|
||||
log.Info("update finalized batch info of L2 withdrawals", "index", finalizedBatch.BatchIndex, "start", finalizedBatch.StartBlockNumber, "end", finalizedBatch.EndBlockNumber)
|
||||
if updateErr := b.updateL2WithdrawMessageInfos(ctx, finalizedBatch.BatchIndex, finalizedBatch.StartBlockNumber, finalizedBatch.EndBlockNumber); updateErr != nil {
|
||||
log.Error("failed to update L2 withdraw message infos", "index", finalizedBatch.BatchIndex, "start", finalizedBatch.StartBlockNumber, "end", finalizedBatch.EndBlockNumber, "error", updateErr)
|
||||
return updateErr
|
||||
}
|
||||
if dbErr := b.batchEventOrm.UpdateBatchEventStatus(ctx, finalizedBatch.BatchIndex); dbErr != nil {
|
||||
log.Error("failed to update batch event status as updated", "index", finalizedBatch.BatchIndex, "lastUpdatedFinalizedBlockHeight", lastUpdatedFinalizedBlockHeight, "start", finalizedBatch.StartBlockNumber, "end", finalizedBatch.EndBlockNumber, "error", dbErr)
|
||||
log.Error("failed to update batch event status as updated", "index", finalizedBatch.BatchIndex, "start", finalizedBatch.StartBlockNumber, "end", finalizedBatch.EndBlockNumber, "error", dbErr)
|
||||
return dbErr
|
||||
}
|
||||
lastUpdatedFinalizedBlockHeight = finalizedBatch.EndBlockNumber
|
||||
b.eventUpdateLogicL1FinalizeBatchEventL2BlockUpdateHeight.Set(float64(finalizedBatch.EndBlockNumber))
|
||||
}
|
||||
return nil
|
||||
|
||||
@@ -53,26 +53,8 @@ func (c *BatchEvent) GetBatchEventSyncedHeightInDB(ctx context.Context) (uint64,
|
||||
return batch.L1BlockNumber, nil
|
||||
}
|
||||
|
||||
// GetLastUpdatedFinalizedBlockHeight returns the last updated finalized block height in db.
|
||||
func (c *BatchEvent) GetLastUpdatedFinalizedBlockHeight(ctx context.Context) (uint64, error) {
|
||||
var batch BatchEvent
|
||||
db := c.db.WithContext(ctx)
|
||||
db = db.Model(&BatchEvent{})
|
||||
db = db.Where("batch_status = ?", btypes.BatchStatusTypeFinalized)
|
||||
db = db.Where("update_status = ?", btypes.UpdateStatusTypeUpdated)
|
||||
db = db.Order("batch_index desc")
|
||||
if err := db.First(&batch).Error; err != nil {
|
||||
if err == gorm.ErrRecordNotFound {
|
||||
// No finalized batch found, return genesis batch's end block number.
|
||||
return 0, nil
|
||||
}
|
||||
return 0, fmt.Errorf("failed to get last updated finalized block height, error: %w", err)
|
||||
}
|
||||
return batch.EndBlockNumber, nil
|
||||
}
|
||||
|
||||
// GetUnupdatedFinalizedBatchesLEBlockHeight returns the finalized batches with end block <= given block height in db.
|
||||
func (c *BatchEvent) GetUnupdatedFinalizedBatchesLEBlockHeight(ctx context.Context, blockHeight uint64) ([]*BatchEvent, error) {
|
||||
// GetFinalizedBatchesLEBlockHeight returns the finalized batches with end block <= given block height in db.
|
||||
func (c *BatchEvent) GetFinalizedBatchesLEBlockHeight(ctx context.Context, blockHeight uint64) ([]*BatchEvent, error) {
|
||||
var batches []*BatchEvent
|
||||
db := c.db.WithContext(ctx)
|
||||
db = db.Model(&BatchEvent{})
|
||||
@@ -84,7 +66,7 @@ func (c *BatchEvent) GetUnupdatedFinalizedBatchesLEBlockHeight(ctx context.Conte
|
||||
if err == gorm.ErrRecordNotFound {
|
||||
return nil, nil
|
||||
}
|
||||
return nil, fmt.Errorf("failed to get unupdated finalized batches >= block height, error: %w", err)
|
||||
return nil, fmt.Errorf("failed to get batches >= block height, error: %w", err)
|
||||
}
|
||||
return batches, nil
|
||||
}
|
||||
@@ -110,7 +92,6 @@ func (c *BatchEvent) InsertOrUpdateBatchEvents(ctx context.Context, l1BatchEvent
|
||||
db = db.Where("batch_index = ?", l1BatchEvent.BatchIndex)
|
||||
db = db.Where("batch_hash = ?", l1BatchEvent.BatchHash)
|
||||
updateFields["batch_status"] = btypes.BatchStatusTypeFinalized
|
||||
updateFields["l1_block_number"] = l1BatchEvent.L1BlockNumber
|
||||
if err := db.Updates(updateFields).Error; err != nil {
|
||||
return fmt.Errorf("failed to update batch event, error: %w", err)
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# Download Go dependencies
|
||||
FROM scrolltech/go-rust-builder:go-1.21-rust-nightly-2023-12-03 as base
|
||||
FROM golang:1.21-alpine3.19 as base
|
||||
|
||||
WORKDIR /src
|
||||
COPY go.mod* ./
|
||||
@@ -11,13 +11,11 @@ FROM base as builder
|
||||
|
||||
RUN --mount=target=. \
|
||||
--mount=type=cache,target=/root/.cache/go-build \
|
||||
cd /src/bridge-history-api/cmd/api && CGO_LDFLAGS="-Wl,--no-as-needed -ldl" go build -v -p 4 -o /bin/bridgehistoryapi-api
|
||||
cd /src/bridge-history-api/cmd/api && go build -v -p 4 -o /bin/bridgehistoryapi-api
|
||||
|
||||
# Pull bridgehistoryapi-api into a second stage deploy ubuntu container
|
||||
FROM ubuntu:20.04
|
||||
|
||||
ENV CGO_LDFLAGS="-Wl,--no-as-needed -ldl"
|
||||
# Pull bridgehistoryapi-api into a second stage deploy alpine container
|
||||
FROM alpine:latest
|
||||
|
||||
COPY --from=builder /bin/bridgehistoryapi-api /bin/
|
||||
WORKDIR /app
|
||||
ENTRYPOINT ["bridgehistoryapi-api"]
|
||||
ENTRYPOINT ["bridgehistoryapi-api"]
|
||||
@@ -1,5 +1,5 @@
|
||||
# Download Go dependencies
|
||||
FROM scrolltech/go-rust-builder:go-1.21-rust-nightly-2023-12-03 as base
|
||||
FROM golang:1.21-alpine3.19 as base
|
||||
|
||||
WORKDIR /src
|
||||
COPY go.mod* ./
|
||||
@@ -11,13 +11,11 @@ FROM base as builder
|
||||
|
||||
RUN --mount=target=. \
|
||||
--mount=type=cache,target=/root/.cache/go-build \
|
||||
cd /src/bridge-history-api/cmd/fetcher && CGO_LDFLAGS="-Wl,--no-as-needed -ldl" go build -v -p 4 -o /bin/bridgehistoryapi-fetcher
|
||||
cd /src/bridge-history-api/cmd/fetcher && go build -v -p 4 -o /bin/bridgehistoryapi-fetcher
|
||||
|
||||
# Pull bridgehistoryapi-fetcher into a second stage deploy ubuntu container
|
||||
FROM ubuntu:20.04
|
||||
|
||||
ENV CGO_LDFLAGS="-Wl,--no-as-needed -ldl"
|
||||
# Pull bridgehistoryapi-fetcher into a second stage deploy alpine container
|
||||
FROM alpine:latest
|
||||
|
||||
COPY --from=builder /bin/bridgehistoryapi-fetcher /bin/
|
||||
WORKDIR /app
|
||||
ENTRYPOINT ["bridgehistoryapi-fetcher"]
|
||||
ENTRYPOINT ["bridgehistoryapi-fetcher"]
|
||||
@@ -23,6 +23,7 @@ COPY ./rollup/go.* ./rollup/
|
||||
COPY ./common/go.* ./common/
|
||||
COPY ./coordinator/go.* ./coordinator/
|
||||
COPY ./database/go.* ./database/
|
||||
COPY ./prover/go.* ./prover/
|
||||
COPY ./tests/integration-test/go.* ./tests/integration-test/
|
||||
COPY ./bridge-history-api/go.* ./bridge-history-api/
|
||||
RUN go mod download -x
|
||||
@@ -33,12 +34,11 @@ FROM base as builder
|
||||
COPY . .
|
||||
RUN cp -r ./common/libzkp/interface ./coordinator/internal/logic/verifier/lib
|
||||
COPY --from=zkp-builder /app/target/release/libzkp.so ./coordinator/internal/logic/verifier/lib/
|
||||
RUN cd ./coordinator && CGO_LDFLAGS="-Wl,--no-as-needed -ldl" make coordinator_api_skip_libzkp && mv ./build/bin/coordinator_api /bin/coordinator_api && mv internal/logic/verifier/lib /bin/
|
||||
RUN cd ./coordinator && make coordinator_api_skip_libzkp && mv ./build/bin/coordinator_api /bin/coordinator_api && mv internal/logic/verifier/lib /bin/
|
||||
|
||||
# Pull coordinator into a second stage deploy ubuntu container
|
||||
# Pull coordinator into a second stage deploy alpine container
|
||||
FROM ubuntu:20.04
|
||||
ENV LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/src/coordinator/internal/logic/verifier/lib
|
||||
ENV CGO_LDFLAGS="-Wl,--no-as-needed -ldl"
|
||||
# ENV CHAIN_ID=534353
|
||||
RUN mkdir -p /src/coordinator/internal/logic/verifier/lib
|
||||
COPY --from=builder /bin/lib /src/coordinator/internal/logic/verifier/lib
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# Download Go dependencies
|
||||
FROM scrolltech/go-rust-builder:go-1.21-rust-nightly-2023-12-03 as base
|
||||
FROM scrolltech/go-alpine-builder:1.21 as base
|
||||
|
||||
WORKDIR /src
|
||||
COPY go.work* ./
|
||||
@@ -7,6 +7,7 @@ COPY ./rollup/go.* ./rollup/
|
||||
COPY ./common/go.* ./common/
|
||||
COPY ./coordinator/go.* ./coordinator/
|
||||
COPY ./database/go.* ./database/
|
||||
COPY ./prover/go.* ./prover/
|
||||
COPY ./tests/integration-test/go.* ./tests/integration-test/
|
||||
COPY ./bridge-history-api/go.* ./bridge-history-api/
|
||||
RUN go mod download -x
|
||||
@@ -15,13 +16,10 @@ RUN go mod download -x
|
||||
FROM base as builder
|
||||
RUN --mount=target=. \
|
||||
--mount=type=cache,target=/root/.cache/go-build \
|
||||
cd /src/coordinator/cmd/cron/ && CGO_LDFLAGS="-Wl,--no-as-needed -ldl" go build -v -p 4 -o /bin/coordinator_cron
|
||||
|
||||
# Pull coordinator into a second stage deploy ubuntu container
|
||||
FROM ubuntu:20.04
|
||||
|
||||
ENV CGO_LDFLAGS="-Wl,--no-as-needed -ldl"
|
||||
cd /src/coordinator/cmd/cron/ && go build -v -p 4 -o /bin/coordinator_cron
|
||||
|
||||
# Pull coordinator into a second stage deploy alpine container
|
||||
FROM alpine:latest
|
||||
COPY --from=builder /bin/coordinator_cron /bin/
|
||||
WORKDIR /app
|
||||
ENTRYPOINT ["coordinator_cron"]
|
||||
ENTRYPOINT ["coordinator_cron"]
|
||||
@@ -7,6 +7,7 @@ COPY ./rollup/go.* ./rollup/
|
||||
COPY ./common/go.* ./common/
|
||||
COPY ./coordinator/go.* ./coordinator/
|
||||
COPY ./database/go.* ./database/
|
||||
COPY ./prover/go.* ./prover/
|
||||
COPY ./tests/integration-test/go.* ./tests/integration-test/
|
||||
COPY ./bridge-history-api/go.* ./bridge-history-api/
|
||||
RUN go mod download -x
|
||||
|
||||
29
build/dockerfiles/event_watcher.Dockerfile
Normal file
29
build/dockerfiles/event_watcher.Dockerfile
Normal file
@@ -0,0 +1,29 @@
|
||||
# Download Go dependencies
|
||||
FROM scrolltech/go-rust-builder:go-1.21-rust-nightly-2023-12-03 as base
|
||||
|
||||
WORKDIR /src
|
||||
COPY go.work* ./
|
||||
COPY ./rollup/go.* ./rollup/
|
||||
COPY ./common/go.* ./common/
|
||||
COPY ./coordinator/go.* ./coordinator/
|
||||
COPY ./database/go.* ./database/
|
||||
COPY ./prover/go.* ./prover/
|
||||
COPY ./tests/integration-test/go.* ./tests/integration-test/
|
||||
COPY ./bridge-history-api/go.* ./bridge-history-api/
|
||||
RUN go mod download -x
|
||||
|
||||
# Build event_watcher
|
||||
FROM base as builder
|
||||
|
||||
RUN --mount=target=. \
|
||||
--mount=type=cache,target=/root/.cache/go-build \
|
||||
cd /src/rollup/cmd/event_watcher/ && CGO_LDFLAGS="-ldl" go build -v -p 4 -o /bin/event_watcher
|
||||
|
||||
# Pull event_watcher into a second stage deploy alpine container
|
||||
FROM ubuntu:20.04
|
||||
|
||||
ENV CGO_LDFLAGS="-ldl"
|
||||
|
||||
COPY --from=builder /bin/event_watcher /bin/
|
||||
WORKDIR /app
|
||||
ENTRYPOINT ["event_watcher"]
|
||||
5
build/dockerfiles/event_watcher.Dockerfile.dockerignore
Normal file
5
build/dockerfiles/event_watcher.Dockerfile.dockerignore
Normal file
@@ -0,0 +1,5 @@
|
||||
assets/
|
||||
docs/
|
||||
l2geth/
|
||||
rpc-gateway/
|
||||
*target/*
|
||||
@@ -7,6 +7,7 @@ COPY ./rollup/go.* ./rollup/
|
||||
COPY ./common/go.* ./common/
|
||||
COPY ./coordinator/go.* ./coordinator/
|
||||
COPY ./database/go.* ./database/
|
||||
COPY ./prover/go.* ./prover/
|
||||
COPY ./tests/integration-test/go.* ./tests/integration-test/
|
||||
COPY ./bridge-history-api/go.* ./bridge-history-api/
|
||||
RUN go mod download -x
|
||||
@@ -18,11 +19,11 @@ RUN --mount=target=. \
|
||||
--mount=type=cache,target=/root/.cache/go-build \
|
||||
cd /src/rollup/cmd/gas_oracle/ && CGO_LDFLAGS="-ldl" go build -v -p 4 -o /bin/gas_oracle
|
||||
|
||||
# Pull gas_oracle into a second stage deploy ubuntu container
|
||||
# Pull gas_oracle into a second stage deploy alpine container
|
||||
FROM ubuntu:20.04
|
||||
|
||||
ENV CGO_LDFLAGS="-ldl"
|
||||
|
||||
COPY --from=builder /bin/gas_oracle /bin/
|
||||
WORKDIR /app
|
||||
ENTRYPOINT ["gas_oracle"]
|
||||
ENTRYPOINT ["gas_oracle"]
|
||||
@@ -7,6 +7,7 @@ COPY ./rollup/go.* ./rollup/
|
||||
COPY ./common/go.* ./common/
|
||||
COPY ./coordinator/go.* ./coordinator/
|
||||
COPY ./database/go.* ./database/
|
||||
COPY ./prover/go.* ./prover/
|
||||
COPY ./tests/integration-test/go.* ./tests/integration-test/
|
||||
COPY ./bridge-history-api/go.* ./bridge-history-api/
|
||||
RUN go mod download -x
|
||||
@@ -18,7 +19,7 @@ RUN --mount=target=. \
|
||||
--mount=type=cache,target=/root/.cache/go-build \
|
||||
cd /src/rollup/cmd/rollup_relayer/ && CGO_LDFLAGS="-ldl" go build -v -p 4 -o /bin/rollup_relayer
|
||||
|
||||
# Pull rollup_relayer into a second stage deploy ubuntu container
|
||||
# Pull rollup_relayer into a second stage deploy alpine container
|
||||
FROM ubuntu:20.04
|
||||
|
||||
ENV CGO_LDFLAGS="-ldl"
|
||||
|
||||
20
common/libzkp/impl/Cargo.lock
generated
20
common/libzkp/impl/Cargo.lock
generated
@@ -31,7 +31,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "aggregator"
|
||||
version = "0.11.0"
|
||||
source = "git+https://github.com/scroll-tech/zkevm-circuits.git?tag=v0.11.4#38a68e22d3d8449bd39a50c22da55b9e741de453"
|
||||
source = "git+https://github.com/scroll-tech/zkevm-circuits.git?tag=v0.11.1#512996f1bac1218c93d9d3de49d7b86f52726c27"
|
||||
dependencies = [
|
||||
"ark-std 0.3.0",
|
||||
"bitstream-io",
|
||||
@@ -537,7 +537,7 @@ checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1"
|
||||
[[package]]
|
||||
name = "bus-mapping"
|
||||
version = "0.11.0"
|
||||
source = "git+https://github.com/scroll-tech/zkevm-circuits.git?tag=v0.11.4#38a68e22d3d8449bd39a50c22da55b9e741de453"
|
||||
source = "git+https://github.com/scroll-tech/zkevm-circuits.git?tag=v0.11.1#512996f1bac1218c93d9d3de49d7b86f52726c27"
|
||||
dependencies = [
|
||||
"eth-types",
|
||||
"ethers-core",
|
||||
@@ -1126,7 +1126,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "eth-types"
|
||||
version = "0.11.0"
|
||||
source = "git+https://github.com/scroll-tech/zkevm-circuits.git?tag=v0.11.4#38a68e22d3d8449bd39a50c22da55b9e741de453"
|
||||
source = "git+https://github.com/scroll-tech/zkevm-circuits.git?tag=v0.11.1#512996f1bac1218c93d9d3de49d7b86f52726c27"
|
||||
dependencies = [
|
||||
"base64 0.13.1",
|
||||
"ethers-core",
|
||||
@@ -1283,7 +1283,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "external-tracer"
|
||||
version = "0.11.0"
|
||||
source = "git+https://github.com/scroll-tech/zkevm-circuits.git?tag=v0.11.4#38a68e22d3d8449bd39a50c22da55b9e741de453"
|
||||
source = "git+https://github.com/scroll-tech/zkevm-circuits.git?tag=v0.11.1#512996f1bac1218c93d9d3de49d7b86f52726c27"
|
||||
dependencies = [
|
||||
"eth-types",
|
||||
"geth-utils",
|
||||
@@ -1465,7 +1465,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "gadgets"
|
||||
version = "0.11.0"
|
||||
source = "git+https://github.com/scroll-tech/zkevm-circuits.git?tag=v0.11.4#38a68e22d3d8449bd39a50c22da55b9e741de453"
|
||||
source = "git+https://github.com/scroll-tech/zkevm-circuits.git?tag=v0.11.1#512996f1bac1218c93d9d3de49d7b86f52726c27"
|
||||
dependencies = [
|
||||
"eth-types",
|
||||
"halo2_proofs",
|
||||
@@ -1488,7 +1488,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "geth-utils"
|
||||
version = "0.11.0"
|
||||
source = "git+https://github.com/scroll-tech/zkevm-circuits.git?tag=v0.11.4#38a68e22d3d8449bd39a50c22da55b9e741de453"
|
||||
source = "git+https://github.com/scroll-tech/zkevm-circuits.git?tag=v0.11.1#512996f1bac1218c93d9d3de49d7b86f52726c27"
|
||||
dependencies = [
|
||||
"env_logger 0.10.0",
|
||||
"gobuild",
|
||||
@@ -2237,7 +2237,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "mock"
|
||||
version = "0.11.0"
|
||||
source = "git+https://github.com/scroll-tech/zkevm-circuits.git?tag=v0.11.4#38a68e22d3d8449bd39a50c22da55b9e741de453"
|
||||
source = "git+https://github.com/scroll-tech/zkevm-circuits.git?tag=v0.11.1#512996f1bac1218c93d9d3de49d7b86f52726c27"
|
||||
dependencies = [
|
||||
"eth-types",
|
||||
"ethers-core",
|
||||
@@ -2252,7 +2252,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "mpt-zktrie"
|
||||
version = "0.11.0"
|
||||
source = "git+https://github.com/scroll-tech/zkevm-circuits.git?tag=v0.11.4#38a68e22d3d8449bd39a50c22da55b9e741de453"
|
||||
source = "git+https://github.com/scroll-tech/zkevm-circuits.git?tag=v0.11.1#512996f1bac1218c93d9d3de49d7b86f52726c27"
|
||||
dependencies = [
|
||||
"eth-types",
|
||||
"halo2curves",
|
||||
@@ -2724,7 +2724,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "prover"
|
||||
version = "0.11.0"
|
||||
source = "git+https://github.com/scroll-tech/zkevm-circuits.git?tag=v0.11.4#38a68e22d3d8449bd39a50c22da55b9e741de453"
|
||||
source = "git+https://github.com/scroll-tech/zkevm-circuits.git?tag=v0.11.1#512996f1bac1218c93d9d3de49d7b86f52726c27"
|
||||
dependencies = [
|
||||
"aggregator",
|
||||
"anyhow",
|
||||
@@ -4361,7 +4361,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "zkevm-circuits"
|
||||
version = "0.11.0"
|
||||
source = "git+https://github.com/scroll-tech/zkevm-circuits.git?tag=v0.11.4#38a68e22d3d8449bd39a50c22da55b9e741de453"
|
||||
source = "git+https://github.com/scroll-tech/zkevm-circuits.git?tag=v0.11.1#512996f1bac1218c93d9d3de49d7b86f52726c27"
|
||||
dependencies = [
|
||||
"array-init",
|
||||
"bus-mapping",
|
||||
|
||||
@@ -25,7 +25,7 @@ bls12_381 = { git = "https://github.com/scroll-tech/bls12_381", branch = "feat/i
|
||||
[dependencies]
|
||||
halo2_proofs = { git = "https://github.com/scroll-tech/halo2.git", branch = "v1.1" }
|
||||
snark-verifier-sdk = { git = "https://github.com/scroll-tech/snark-verifier", branch = "develop", default-features = false, features = ["loader_halo2", "loader_evm", "halo2-pse"] }
|
||||
prover = { git = "https://github.com/scroll-tech/zkevm-circuits.git", tag = "v0.11.4", default-features = false, features = ["parallel_syn", "scroll"] }
|
||||
prover = { git = "https://github.com/scroll-tech/zkevm-circuits.git", tag = "v0.11.1", default-features = false, features = ["parallel_syn", "scroll"] }
|
||||
|
||||
base64 = "0.13.0"
|
||||
env_logger = "0.9.0"
|
||||
|
||||
@@ -12,8 +12,12 @@ import (
|
||||
type MockAppName string
|
||||
|
||||
var (
|
||||
// EventWatcherApp the name of mock event-watcher app.
|
||||
EventWatcherApp MockAppName = "event-watcher-test"
|
||||
// GasOracleApp the name of mock gas-oracle app.
|
||||
GasOracleApp MockAppName = "gas-oracle-test"
|
||||
// MessageRelayerApp the name of mock message-relayer app.
|
||||
MessageRelayerApp MockAppName = "message-relayer-test"
|
||||
// RollupRelayerApp the name of mock rollup-relayer app.
|
||||
RollupRelayerApp MockAppName = "rollup-relayer-test"
|
||||
|
||||
@@ -24,6 +28,11 @@ var (
|
||||
CoordinatorAPIApp MockAppName = "coordinator-api-test"
|
||||
// CoordinatorCronApp the name of mock coordinator cron app.
|
||||
CoordinatorCronApp MockAppName = "coordinator-cron-test"
|
||||
|
||||
// ChunkProverApp the name of mock chunk prover app.
|
||||
ChunkProverApp MockAppName = "chunkProver-test"
|
||||
// BatchProverApp the name of mock batch prover app.
|
||||
BatchProverApp MockAppName = "batchProver-test"
|
||||
)
|
||||
|
||||
// RegisterSimulation register initializer function for integration-test.
|
||||
|
||||
@@ -5,7 +5,7 @@ import (
|
||||
"runtime/debug"
|
||||
)
|
||||
|
||||
var tag = "v4.4.26"
|
||||
var tag = "v4.4.17"
|
||||
|
||||
var commit = func() string {
|
||||
if info, ok := debug.ReadBuildInfo(); ok {
|
||||
|
||||
12
contracts/.env.example
Normal file
12
contracts/.env.example
Normal file
@@ -0,0 +1,12 @@
|
||||
### NOTE: DO NOT USE THIS FILE IF USING TESTNET'S .ENV
|
||||
ETHERSCAN_API_KEY=ABC123ABC123ABC123ABC123ABC123ABC1
|
||||
|
||||
RINKEBY_RPC=https://eth-rinkeby.alchemyapi.io/v2/<YOUR ALCHEMY KEY>
|
||||
SCROLL_L1_RPC=https://prealpha.scroll.io/l1
|
||||
SCROLL_L2_RPC=https://prealpha.scroll.io/l2
|
||||
|
||||
RINKEBY_PRIVATE_KEY=0xabc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc1
|
||||
L1_DEPLOYER_PRIVATE_KEY=0xabc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc1
|
||||
L2_DEPLOYER_PRIVATE_KEY=0xabc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc1
|
||||
|
||||
CHAIN_ID_L2="5343541"
|
||||
4
contracts/.eslintignore
Normal file
4
contracts/.eslintignore
Normal file
@@ -0,0 +1,4 @@
|
||||
node_modules
|
||||
artifacts
|
||||
cache
|
||||
coverage
|
||||
24
contracts/.eslintrc.js
Normal file
24
contracts/.eslintrc.js
Normal file
@@ -0,0 +1,24 @@
|
||||
module.exports = {
|
||||
env: {
|
||||
browser: false,
|
||||
es2021: true,
|
||||
mocha: true,
|
||||
node: true,
|
||||
},
|
||||
plugins: ["@typescript-eslint"],
|
||||
extends: [
|
||||
"standard",
|
||||
"plugin:prettier/recommended",
|
||||
"plugin:node/recommended",
|
||||
],
|
||||
parser: "@typescript-eslint/parser",
|
||||
parserOptions: {
|
||||
ecmaVersion: 12,
|
||||
},
|
||||
rules: {
|
||||
"node/no-unsupported-features/es-syntax": [
|
||||
"error",
|
||||
{ ignores: ["modules"] },
|
||||
],
|
||||
},
|
||||
};
|
||||
17
contracts/.gitignore
vendored
Normal file
17
contracts/.gitignore
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
node_modules
|
||||
.env
|
||||
coverage
|
||||
coverage.json
|
||||
typechain
|
||||
|
||||
# Hardhat/Foundry files
|
||||
cache
|
||||
cache-hardhat
|
||||
artifacts
|
||||
broadcast
|
||||
|
||||
# logs
|
||||
*.log
|
||||
|
||||
# eslint
|
||||
.eslintcache
|
||||
5
contracts/.husky/pre-commit
Executable file
5
contracts/.husky/pre-commit
Executable file
@@ -0,0 +1,5 @@
|
||||
#!/usr/bin/env sh
|
||||
. "$(dirname -- "$0")/_/husky.sh"
|
||||
|
||||
cd contracts
|
||||
yarn lint-staged
|
||||
3
contracts/.npmignore
Normal file
3
contracts/.npmignore
Normal file
@@ -0,0 +1,3 @@
|
||||
hardhat.config.ts
|
||||
scripts
|
||||
test
|
||||
1
contracts/.nvmrc
Normal file
1
contracts/.nvmrc
Normal file
@@ -0,0 +1 @@
|
||||
v18.15.0
|
||||
8
contracts/.prettierignore
Normal file
8
contracts/.prettierignore
Normal file
@@ -0,0 +1,8 @@
|
||||
node_modules
|
||||
artifacts
|
||||
cache
|
||||
coverage*
|
||||
gasReporterOutput.json
|
||||
src/libraries/verifier/ZkTrieVerifier.sol
|
||||
src/libraries/verifier/PatriciaMerkleTrieVerifier.sol
|
||||
src/L2/predeploys/L1BlockContainer.sol
|
||||
28
contracts/.prettierrc
Normal file
28
contracts/.prettierrc
Normal file
@@ -0,0 +1,28 @@
|
||||
{
|
||||
"printWidth": 120,
|
||||
"singleQuote": false,
|
||||
"tabWidth": 2,
|
||||
"bracketSpacing": true,
|
||||
"overrides": [
|
||||
{
|
||||
"files": "src/**/*.sol",
|
||||
"options": {
|
||||
"printWidth": 120,
|
||||
"tabWidth": 4,
|
||||
"useTabs": false,
|
||||
"singleQuote": false,
|
||||
"bracketSpacing": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"files": "scripts/**/*.sol",
|
||||
"options": {
|
||||
"printWidth": 120,
|
||||
"tabWidth": 4,
|
||||
"useTabs": false,
|
||||
"singleQuote": false,
|
||||
"bracketSpacing": false
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
10
contracts/.solcover.js
Normal file
10
contracts/.solcover.js
Normal file
@@ -0,0 +1,10 @@
|
||||
module.exports = {
|
||||
skipFiles: [
|
||||
'mocks',
|
||||
'test',
|
||||
'L2/predeploys/L1BlockContainer.sol',
|
||||
'libraries/verifier/ZkTrieVerifier.sol',
|
||||
'libraries/verifier/PatriciaMerkleTrieVerifier.sol'
|
||||
],
|
||||
istanbulReporter: ["lcov", "json"]
|
||||
};
|
||||
7
contracts/.solhint.json
Normal file
7
contracts/.solhint.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"extends": "solhint:recommended",
|
||||
"rules": {
|
||||
"compiler-version": ["error", "^0.8.0"],
|
||||
"func-visibility": ["warn", { "ignoreConstructors": true }]
|
||||
}
|
||||
}
|
||||
1
contracts/.solhintignore
Normal file
1
contracts/.solhintignore
Normal file
@@ -0,0 +1 @@
|
||||
node_modules
|
||||
78
contracts/README.md
Normal file
78
contracts/README.md
Normal file
@@ -0,0 +1,78 @@
|
||||
# Scroll Contracts
|
||||
|
||||
This directory contains the solidity code for Scroll L1 bridge and rollup contracts and L2 bridge and pre-deployed contracts. You can also find contract APIs and more details in the [`docs`](./docs) folder.
|
||||
|
||||
## Directory Structure
|
||||
|
||||
<pre>
|
||||
├── <a href="./docs/">docs</a>: Documentation for the contracts
|
||||
├── <a href="./integration-test/">integration-test</a>: Hardhat integration tests
|
||||
├── <a href="./lib/">lib</a>: External libraries and testing tools
|
||||
├── <a href="./scripts">scripts</a>: Deployment scripts
|
||||
├── <a href="./src">src</a>
|
||||
│ ├── <a href="./src/gas-swap/">gas-swap</a>: Utility contract that allows gas payment in other tokens
|
||||
│ ├── <a href="./src/interfaces/">interfaces</a>: Common contract interfaces
|
||||
│ ├── <a href="./src/L1/">L1</a>: Contracts deployed on the L1 (Ethereum)
|
||||
│ │ ├── <a href="./src/L1/gateways/">gateways</a>: Gateway router and token gateway contracts
|
||||
│ │ ├── <a href="./src/L1/rollup/">rollup</a>: Rollup contracts for data availability and finalization
|
||||
│ │ ├── <a href="./src/L1/IL1ScrollMessenger.sol">IL1ScrollMessenger.sol</a>: L1 Scroll messenger interface
|
||||
│ │ └── <a href="./src/L1/L1ScrollMessenger.sol">L1ScrollMessenger.sol</a>: L1 Scroll messenger contract
|
||||
│ ├── <a href="./src/L2/">L2</a>: Contracts deployed on the L2 (Scroll)
|
||||
│ │ ├── <a href="./src/L2/gateways/">gateways</a>: Gateway router and token gateway contracts
|
||||
│ │ ├── <a href="./src/L2/predeploys/">predeploys</a>: Pre-deployed contracts on L2
|
||||
│ │ ├── <a href="./src/L2/IL2ScrollMessenger.sol">IL2ScrollMessenger.sol</a>: L2 Scroll messenger interface
|
||||
│ │ └── <a href="./src/L2/L2ScrollMessenger.sol">L2ScrollMessenger.sol</a>: L2 Scroll messenger contract
|
||||
│ ├── <a href="./src/libraries/">libraries</a>: Shared contract libraries
|
||||
│ ├── <a href="./src/misc/">misc</a>: Miscellaneous contracts
|
||||
│ ├── <a href="./src/mocks/">mocks</a>: Mock contracts used in the testing
|
||||
│ ├── <a href="./src/rate-limiter/">rate-limiter</a>: Rater limiter contract
|
||||
│ └── <a href="./src/test/">test</a>: Unit tests in solidity
|
||||
├── <a href="./foundry.toml">foundry.toml</a>: Foundry configuration
|
||||
├── <a href="./hardhat.config.ts">hardhat.config.ts</a>: Hardhat configuration
|
||||
├── <a href="./remappings.txt">remappings.txt</a>: Foundry dependency mappings
|
||||
...
|
||||
</pre>
|
||||
|
||||
## Dependencies
|
||||
|
||||
### Node.js
|
||||
|
||||
First install [`Node.js`](https://nodejs.org/en) and [`npm`](https://www.npmjs.com/).
|
||||
Run the following command to install [`yarn`](https://classic.yarnpkg.com/en/):
|
||||
|
||||
```bash
|
||||
npm install --global yarn
|
||||
```
|
||||
|
||||
### Foundry
|
||||
|
||||
Install `foundryup`, the Foundry toolchain installer:
|
||||
|
||||
```bash
|
||||
curl -L https://foundry.paradigm.xyz | bash
|
||||
```
|
||||
|
||||
If you do not want to use the redirect, feel free to manually download the `foundryup` installation script from [here](https://raw.githubusercontent.com/foundry-rs/foundry/master/foundryup/foundryup).
|
||||
|
||||
Then, run `foundryup` in a new terminal session or after reloading `PATH`.
|
||||
|
||||
Other ways to install Foundry can be found [here](https://github.com/foundry-rs/foundry#installation).
|
||||
|
||||
### Hardhat
|
||||
|
||||
Run the following command to install [Hardhat](https://hardhat.org/) and other dependencies.
|
||||
|
||||
```
|
||||
yarn install
|
||||
```
|
||||
|
||||
## Build
|
||||
|
||||
- Run `git submodule update --init --recursive` to initialize git submodules.
|
||||
- Run `yarn prettier:solidity` to run linting in fix mode, will auto-format all solidity codes.
|
||||
- Run `yarn prettier` to run linting in fix mode, will auto-format all typescript codes.
|
||||
- Run `yarn prepare` to install the precommit linting hook.
|
||||
- Run `forge build` to compile contracts with foundry.
|
||||
- Run `npx hardhat compile` to compile with hardhat.
|
||||
- Run `forge test -vvv` to run foundry units tests. It will compile all contracts before running the unit tests.
|
||||
- Run `npx hardhat test` to run integration tests. It may not compile all contracts before running, it's better to run `npx hardhat compile` first.
|
||||
3
contracts/circomlib.d.ts
vendored
Normal file
3
contracts/circomlib.d.ts
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
declare module "circomlib/src/evmasm";
|
||||
declare module "circomlib/src/poseidon_gencontract";
|
||||
declare module "circomlib/src/poseidon_constants";
|
||||
16
contracts/deployments/README.md
Normal file
16
contracts/deployments/README.md
Normal file
@@ -0,0 +1,16 @@
|
||||
# Deployments
|
||||
|
||||
## local testnet
|
||||
|
||||
```bash
|
||||
# start local hardhat node
|
||||
npx hardhat node
|
||||
```
|
||||
|
||||
### layer 1
|
||||
|
||||
Contract addresses can be found in [deployments](./l1geth.json).
|
||||
|
||||
### layer 2
|
||||
|
||||
Contract addresses can be found in [deployments](./l2geth.json).
|
||||
23
contracts/deployments/l1geth.json
Normal file
23
contracts/deployments/l1geth.json
Normal file
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"ProxyAdmin": null,
|
||||
"ZKRollup": {
|
||||
"implementation": null,
|
||||
"proxy": null
|
||||
},
|
||||
"L1ScrollMessenger": {
|
||||
"implementation": null,
|
||||
"proxy": null
|
||||
},
|
||||
"L1GatewayRouter": {
|
||||
"implementation": null,
|
||||
"proxy": null
|
||||
},
|
||||
"L1StandardERC20Gateway": {
|
||||
"implementation": null,
|
||||
"proxy": null
|
||||
},
|
||||
"L1WETHGateway": {
|
||||
"implementation": null,
|
||||
"proxy": null
|
||||
}
|
||||
}
|
||||
20
contracts/deployments/l2geth.json
Normal file
20
contracts/deployments/l2geth.json
Normal file
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"ProxyAdmin": null,
|
||||
"WETH": null,
|
||||
"Whitelist": null,
|
||||
"ScrollStandardERC20": null,
|
||||
"ScrollStandardERC20Factory": null,
|
||||
"L2ScrollMessenger": null,
|
||||
"L2GatewayRouter": {
|
||||
"implementation": null,
|
||||
"proxy": null
|
||||
},
|
||||
"L2StandardERC20Gateway": {
|
||||
"implementation": null,
|
||||
"proxy": null
|
||||
},
|
||||
"L2WETHGateway": {
|
||||
"implementation": null,
|
||||
"proxy": null
|
||||
}
|
||||
}
|
||||
599
contracts/docs/apis/L1ERC1155Gateway.md
Normal file
599
contracts/docs/apis/L1ERC1155Gateway.md
Normal file
@@ -0,0 +1,599 @@
|
||||
# L1ERC1155Gateway
|
||||
|
||||
|
||||
|
||||
> L1ERC1155Gateway
|
||||
|
||||
The `L1ERC1155Gateway` is used to deposit ERC1155 compatible NFT on layer 1 and finalize withdraw the NFTs from layer 2.
|
||||
|
||||
*The deposited NFTs are held in this gateway. On finalizing withdraw, the corresponding NFT will be transfer to the recipient directly. This will be changed if we have more specific scenarios.*
|
||||
|
||||
## Methods
|
||||
|
||||
### batchDepositERC1155
|
||||
|
||||
```solidity
|
||||
function batchDepositERC1155(address _token, uint256[] _tokenIds, uint256[] _amounts, uint256 _gasLimit) external payable
|
||||
```
|
||||
|
||||
Deposit a list of some ERC1155 NFT to caller's account on layer 2.
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _token | address | The address of ERC1155 NFT on layer 1. |
|
||||
| _tokenIds | uint256[] | The list of token ids to deposit. |
|
||||
| _amounts | uint256[] | The list of corresponding number of token to deposit. |
|
||||
| _gasLimit | uint256 | Estimated gas limit required to complete the deposit on layer 2. |
|
||||
|
||||
### batchDepositERC1155
|
||||
|
||||
```solidity
|
||||
function batchDepositERC1155(address _token, address _to, uint256[] _tokenIds, uint256[] _amounts, uint256 _gasLimit) external payable
|
||||
```
|
||||
|
||||
Deposit a list of some ERC1155 NFT to a recipient's account on layer 2.
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _token | address | The address of ERC1155 NFT on layer 1. |
|
||||
| _to | address | The address of recipient on layer 2. |
|
||||
| _tokenIds | uint256[] | The list of token ids to deposit. |
|
||||
| _amounts | uint256[] | The list of corresponding number of token to deposit. |
|
||||
| _gasLimit | uint256 | Estimated gas limit required to complete the deposit on layer 2. |
|
||||
|
||||
### counterpart
|
||||
|
||||
```solidity
|
||||
function counterpart() external view returns (address)
|
||||
```
|
||||
|
||||
The address of corresponding L1/L2 Gateway contract.
|
||||
|
||||
|
||||
|
||||
|
||||
#### Returns
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _0 | address | undefined |
|
||||
|
||||
### depositERC1155
|
||||
|
||||
```solidity
|
||||
function depositERC1155(address _token, address _to, uint256 _tokenId, uint256 _amount, uint256 _gasLimit) external payable
|
||||
```
|
||||
|
||||
Deposit some ERC1155 NFT to a recipient's account on layer 2.
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _token | address | The address of ERC1155 NFT on layer 1. |
|
||||
| _to | address | The address of recipient on layer 2. |
|
||||
| _tokenId | uint256 | The token id to deposit. |
|
||||
| _amount | uint256 | The amount of token to deposit. |
|
||||
| _gasLimit | uint256 | Estimated gas limit required to complete the deposit on layer 2. |
|
||||
|
||||
### depositERC1155
|
||||
|
||||
```solidity
|
||||
function depositERC1155(address _token, uint256 _tokenId, uint256 _amount, uint256 _gasLimit) external payable
|
||||
```
|
||||
|
||||
Deposit some ERC1155 NFT to caller's account on layer 2.
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _token | address | The address of ERC1155 NFT on layer 1. |
|
||||
| _tokenId | uint256 | The token id to deposit. |
|
||||
| _amount | uint256 | The amount of token to deposit. |
|
||||
| _gasLimit | uint256 | Estimated gas limit required to complete the deposit on layer 2. |
|
||||
|
||||
### finalizeBatchWithdrawERC1155
|
||||
|
||||
```solidity
|
||||
function finalizeBatchWithdrawERC1155(address _l1Token, address _l2Token, address _from, address _to, uint256[] _tokenIds, uint256[] _amounts) external nonpayable
|
||||
```
|
||||
|
||||
Complete ERC1155 batch withdraw from layer 2 to layer 1 and send fund to recipient's account on layer 1. The function should only be called by L1ScrollMessenger. The function should also only be called by L2ERC1155Gateway on layer 2.
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _l1Token | address | The address of corresponding layer 1 token. |
|
||||
| _l2Token | address | The address of corresponding layer 2 token. |
|
||||
| _from | address | The address of account who withdraw the token on layer 2. |
|
||||
| _to | address | The address of recipient on layer 1 to receive the token. |
|
||||
| _tokenIds | uint256[] | The list of token ids to withdraw. |
|
||||
| _amounts | uint256[] | The list of corresponding number of token to withdraw. |
|
||||
|
||||
### finalizeWithdrawERC1155
|
||||
|
||||
```solidity
|
||||
function finalizeWithdrawERC1155(address _l1Token, address _l2Token, address _from, address _to, uint256 _tokenId, uint256 _amount) external nonpayable
|
||||
```
|
||||
|
||||
Complete ERC1155 withdraw from layer 2 to layer 1 and send fund to recipient's account on layer 1. The function should only be called by L1ScrollMessenger. The function should also only be called by L2ERC1155Gateway on layer 2.
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _l1Token | address | The address of corresponding layer 1 token. |
|
||||
| _l2Token | address | The address of corresponding layer 2 token. |
|
||||
| _from | address | The address of account who withdraw the token on layer 2. |
|
||||
| _to | address | The address of recipient on layer 1 to receive the token. |
|
||||
| _tokenId | uint256 | The token id to withdraw. |
|
||||
| _amount | uint256 | The amount of token to withdraw. |
|
||||
|
||||
### initialize
|
||||
|
||||
```solidity
|
||||
function initialize(address _counterpart, address _messenger) external nonpayable
|
||||
```
|
||||
|
||||
Initialize the storage of L1ERC1155Gateway.
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _counterpart | address | The address of L2ERC1155Gateway in L2. |
|
||||
| _messenger | address | The address of L1ScrollMessenger in L1. |
|
||||
|
||||
### messenger
|
||||
|
||||
```solidity
|
||||
function messenger() external view returns (address)
|
||||
```
|
||||
|
||||
The address of corresponding L1ScrollMessenger/L2ScrollMessenger contract.
|
||||
|
||||
|
||||
|
||||
|
||||
#### Returns
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _0 | address | undefined |
|
||||
|
||||
### onDropMessage
|
||||
|
||||
```solidity
|
||||
function onDropMessage(bytes _message) external payable
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _message | bytes | undefined |
|
||||
|
||||
### onERC1155BatchReceived
|
||||
|
||||
```solidity
|
||||
function onERC1155BatchReceived(address, address, uint256[], uint256[], bytes) external nonpayable returns (bytes4)
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _0 | address | undefined |
|
||||
| _1 | address | undefined |
|
||||
| _2 | uint256[] | undefined |
|
||||
| _3 | uint256[] | undefined |
|
||||
| _4 | bytes | undefined |
|
||||
|
||||
#### Returns
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _0 | bytes4 | undefined |
|
||||
|
||||
### onERC1155Received
|
||||
|
||||
```solidity
|
||||
function onERC1155Received(address, address, uint256, uint256, bytes) external nonpayable returns (bytes4)
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _0 | address | undefined |
|
||||
| _1 | address | undefined |
|
||||
| _2 | uint256 | undefined |
|
||||
| _3 | uint256 | undefined |
|
||||
| _4 | bytes | undefined |
|
||||
|
||||
#### Returns
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _0 | bytes4 | undefined |
|
||||
|
||||
### owner
|
||||
|
||||
```solidity
|
||||
function owner() external view returns (address)
|
||||
```
|
||||
|
||||
|
||||
|
||||
*Returns the address of the current owner.*
|
||||
|
||||
|
||||
#### Returns
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _0 | address | undefined |
|
||||
|
||||
### renounceOwnership
|
||||
|
||||
```solidity
|
||||
function renounceOwnership() external nonpayable
|
||||
```
|
||||
|
||||
|
||||
|
||||
*Leaves the contract without owner. It will not be possible to call `onlyOwner` functions. Can only be called by the current owner. NOTE: Renouncing ownership will leave the contract without an owner, thereby disabling any functionality that is only available to the owner.*
|
||||
|
||||
|
||||
### router
|
||||
|
||||
```solidity
|
||||
function router() external view returns (address)
|
||||
```
|
||||
|
||||
The address of L1GatewayRouter/L2GatewayRouter contract.
|
||||
|
||||
|
||||
|
||||
|
||||
#### Returns
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _0 | address | undefined |
|
||||
|
||||
### supportsInterface
|
||||
|
||||
```solidity
|
||||
function supportsInterface(bytes4 interfaceId) external view returns (bool)
|
||||
```
|
||||
|
||||
|
||||
|
||||
*See {IERC165-supportsInterface}.*
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| interfaceId | bytes4 | undefined |
|
||||
|
||||
#### Returns
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _0 | bool | undefined |
|
||||
|
||||
### tokenMapping
|
||||
|
||||
```solidity
|
||||
function tokenMapping(address) external view returns (address)
|
||||
```
|
||||
|
||||
Mapping from l1 token address to l2 token address for ERC1155 NFT.
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _0 | address | undefined |
|
||||
|
||||
#### Returns
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _0 | address | undefined |
|
||||
|
||||
### transferOwnership
|
||||
|
||||
```solidity
|
||||
function transferOwnership(address newOwner) external nonpayable
|
||||
```
|
||||
|
||||
|
||||
|
||||
*Transfers ownership of the contract to a new account (`newOwner`). Can only be called by the current owner.*
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| newOwner | address | undefined |
|
||||
|
||||
### updateTokenMapping
|
||||
|
||||
```solidity
|
||||
function updateTokenMapping(address _l1Token, address _l2Token) external nonpayable
|
||||
```
|
||||
|
||||
Update layer 2 to layer 2 token mapping.
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _l1Token | address | The address of ERC1155 token on layer 1. |
|
||||
| _l2Token | address | The address of corresponding ERC1155 token on layer 2. |
|
||||
|
||||
|
||||
|
||||
## Events
|
||||
|
||||
### BatchDepositERC1155
|
||||
|
||||
```solidity
|
||||
event BatchDepositERC1155(address indexed _l1Token, address indexed _l2Token, address indexed _from, address _to, uint256[] _tokenIds, uint256[] _amounts)
|
||||
```
|
||||
|
||||
Emitted when the ERC1155 NFT is batch deposited to gateway on layer 1.
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _l1Token `indexed` | address | The address of ERC1155 NFT on layer 1. |
|
||||
| _l2Token `indexed` | address | The address of ERC1155 NFT on layer 2. |
|
||||
| _from `indexed` | address | The address of sender on layer 1. |
|
||||
| _to | address | The address of recipient on layer 2. |
|
||||
| _tokenIds | uint256[] | The list of token ids of the ERC1155 NFT to deposit on layer 1. |
|
||||
| _amounts | uint256[] | The list of corresponding number of token to deposit on layer 1. |
|
||||
|
||||
### BatchRefundERC1155
|
||||
|
||||
```solidity
|
||||
event BatchRefundERC1155(address indexed token, address indexed recipient, uint256[] tokenIds, uint256[] amounts)
|
||||
```
|
||||
|
||||
Emitted when some ERC1155 token is refunded.
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| token `indexed` | address | The address of the token in L1. |
|
||||
| recipient `indexed` | address | The address of receiver in L1. |
|
||||
| tokenIds | uint256[] | The list of ids of token refunded. |
|
||||
| amounts | uint256[] | The list of amount of token refunded. |
|
||||
|
||||
### DepositERC1155
|
||||
|
||||
```solidity
|
||||
event DepositERC1155(address indexed _l1Token, address indexed _l2Token, address indexed _from, address _to, uint256 _tokenId, uint256 _amount)
|
||||
```
|
||||
|
||||
Emitted when the ERC1155 NFT is deposited to gateway on layer 1.
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _l1Token `indexed` | address | The address of ERC1155 NFT on layer 1. |
|
||||
| _l2Token `indexed` | address | The address of ERC1155 NFT on layer 2. |
|
||||
| _from `indexed` | address | The address of sender on layer 1. |
|
||||
| _to | address | The address of recipient on layer 2. |
|
||||
| _tokenId | uint256 | The token id of the ERC1155 NFT to deposit on layer 1. |
|
||||
| _amount | uint256 | The number of token to deposit on layer 1. |
|
||||
|
||||
### FinalizeBatchWithdrawERC1155
|
||||
|
||||
```solidity
|
||||
event FinalizeBatchWithdrawERC1155(address indexed _l1Token, address indexed _l2Token, address indexed _from, address _to, uint256[] _tokenIds, uint256[] _amounts)
|
||||
```
|
||||
|
||||
Emitted when the ERC1155 NFT is batch transferred to recipient on layer 1.
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _l1Token `indexed` | address | The address of ERC1155 NFT on layer 1. |
|
||||
| _l2Token `indexed` | address | The address of ERC1155 NFT on layer 2. |
|
||||
| _from `indexed` | address | The address of sender on layer 2. |
|
||||
| _to | address | The address of recipient on layer 1. |
|
||||
| _tokenIds | uint256[] | The list of token ids of the ERC1155 NFT to withdraw from layer 2. |
|
||||
| _amounts | uint256[] | The list of corresponding number of token to withdraw from layer 2. |
|
||||
|
||||
### FinalizeWithdrawERC1155
|
||||
|
||||
```solidity
|
||||
event FinalizeWithdrawERC1155(address indexed _l1Token, address indexed _l2Token, address indexed _from, address _to, uint256 _tokenId, uint256 _amount)
|
||||
```
|
||||
|
||||
Emitted when the ERC1155 NFT is transferred to recipient on layer 1.
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _l1Token `indexed` | address | The address of ERC1155 NFT on layer 1. |
|
||||
| _l2Token `indexed` | address | The address of ERC1155 NFT on layer 2. |
|
||||
| _from `indexed` | address | The address of sender on layer 2. |
|
||||
| _to | address | The address of recipient on layer 1. |
|
||||
| _tokenId | uint256 | The token id of the ERC1155 NFT to withdraw from layer 2. |
|
||||
| _amount | uint256 | The number of token to withdraw from layer 2. |
|
||||
|
||||
### Initialized
|
||||
|
||||
```solidity
|
||||
event Initialized(uint8 version)
|
||||
```
|
||||
|
||||
|
||||
|
||||
*Triggered when the contract has been initialized or reinitialized.*
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| version | uint8 | undefined |
|
||||
|
||||
### OwnershipTransferred
|
||||
|
||||
```solidity
|
||||
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner)
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| previousOwner `indexed` | address | undefined |
|
||||
| newOwner `indexed` | address | undefined |
|
||||
|
||||
### RefundERC1155
|
||||
|
||||
```solidity
|
||||
event RefundERC1155(address indexed token, address indexed recipient, uint256 tokenId, uint256 amount)
|
||||
```
|
||||
|
||||
Emitted when some ERC1155 token is refunded.
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| token `indexed` | address | The address of the token in L1. |
|
||||
| recipient `indexed` | address | The address of receiver in L1. |
|
||||
| tokenId | uint256 | The id of token refunded. |
|
||||
| amount | uint256 | The amount of token refunded. |
|
||||
|
||||
### UpdateTokenMapping
|
||||
|
||||
```solidity
|
||||
event UpdateTokenMapping(address indexed l1Token, address indexed oldL2Token, address indexed newL2Token)
|
||||
```
|
||||
|
||||
Emitted when token mapping for ERC1155 token is updated.
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| l1Token `indexed` | address | The address of ERC1155 token in layer 1. |
|
||||
| oldL2Token `indexed` | address | The address of the old corresponding ERC1155 token in layer 2. |
|
||||
| newL2Token `indexed` | address | The address of the new corresponding ERC1155 token in layer 2. |
|
||||
|
||||
|
||||
|
||||
## Errors
|
||||
|
||||
### ErrorCallerIsNotCounterpartGateway
|
||||
|
||||
```solidity
|
||||
error ErrorCallerIsNotCounterpartGateway()
|
||||
```
|
||||
|
||||
|
||||
|
||||
*Thrown when the cross chain sender is not the counterpart gateway contract.*
|
||||
|
||||
|
||||
### ErrorCallerIsNotMessenger
|
||||
|
||||
```solidity
|
||||
error ErrorCallerIsNotMessenger()
|
||||
```
|
||||
|
||||
|
||||
|
||||
*Thrown when the caller is not corresponding `L1ScrollMessenger` or `L2ScrollMessenger`.*
|
||||
|
||||
|
||||
### ErrorNotInDropMessageContext
|
||||
|
||||
```solidity
|
||||
error ErrorNotInDropMessageContext()
|
||||
```
|
||||
|
||||
|
||||
|
||||
*Thrown when ScrollMessenger is not dropping message.*
|
||||
|
||||
|
||||
### ErrorZeroAddress
|
||||
|
||||
```solidity
|
||||
error ErrorZeroAddress()
|
||||
```
|
||||
|
||||
|
||||
|
||||
*Thrown when the given address is `address(0)`.*
|
||||
|
||||
|
||||
|
||||
538
contracts/docs/apis/L1ERC721Gateway.md
Normal file
538
contracts/docs/apis/L1ERC721Gateway.md
Normal file
@@ -0,0 +1,538 @@
|
||||
# L1ERC721Gateway
|
||||
|
||||
|
||||
|
||||
> L1ERC721Gateway
|
||||
|
||||
The `L1ERC721Gateway` is used to deposit ERC721 compatible NFT on layer 1 and finalize withdraw the NFTs from layer 2.
|
||||
|
||||
*The deposited NFTs are held in this gateway. On finalizing withdraw, the corresponding NFT will be transfer to the recipient directly. This will be changed if we have more specific scenarios.*
|
||||
|
||||
## Methods
|
||||
|
||||
### batchDepositERC721
|
||||
|
||||
```solidity
|
||||
function batchDepositERC721(address _token, address _to, uint256[] _tokenIds, uint256 _gasLimit) external payable
|
||||
```
|
||||
|
||||
Deposit a list of some ERC721 NFT to a recipient's account on layer 2.
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _token | address | The address of ERC721 NFT on layer 1. |
|
||||
| _to | address | The address of recipient on layer 2. |
|
||||
| _tokenIds | uint256[] | The list of token ids to deposit. |
|
||||
| _gasLimit | uint256 | Estimated gas limit required to complete the deposit on layer 2. |
|
||||
|
||||
### batchDepositERC721
|
||||
|
||||
```solidity
|
||||
function batchDepositERC721(address _token, uint256[] _tokenIds, uint256 _gasLimit) external payable
|
||||
```
|
||||
|
||||
Deposit a list of some ERC721 NFT to caller's account on layer 2.
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _token | address | The address of ERC721 NFT on layer 1. |
|
||||
| _tokenIds | uint256[] | The list of token ids to deposit. |
|
||||
| _gasLimit | uint256 | Estimated gas limit required to complete the deposit on layer 2. |
|
||||
|
||||
### counterpart
|
||||
|
||||
```solidity
|
||||
function counterpart() external view returns (address)
|
||||
```
|
||||
|
||||
The address of corresponding L1/L2 Gateway contract.
|
||||
|
||||
|
||||
|
||||
|
||||
#### Returns
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _0 | address | undefined |
|
||||
|
||||
### depositERC721
|
||||
|
||||
```solidity
|
||||
function depositERC721(address _token, address _to, uint256 _tokenId, uint256 _gasLimit) external payable
|
||||
```
|
||||
|
||||
Deposit some ERC721 NFT to a recipient's account on layer 2.
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _token | address | The address of ERC721 NFT on layer 1. |
|
||||
| _to | address | The address of recipient on layer 2. |
|
||||
| _tokenId | uint256 | The token id to deposit. |
|
||||
| _gasLimit | uint256 | Estimated gas limit required to complete the deposit on layer 2. |
|
||||
|
||||
### depositERC721
|
||||
|
||||
```solidity
|
||||
function depositERC721(address _token, uint256 _tokenId, uint256 _gasLimit) external payable
|
||||
```
|
||||
|
||||
Deposit some ERC721 NFT to caller's account on layer 2.
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _token | address | The address of ERC721 NFT on layer 1. |
|
||||
| _tokenId | uint256 | The token id to deposit. |
|
||||
| _gasLimit | uint256 | Estimated gas limit required to complete the deposit on layer 2. |
|
||||
|
||||
### finalizeBatchWithdrawERC721
|
||||
|
||||
```solidity
|
||||
function finalizeBatchWithdrawERC721(address _l1Token, address _l2Token, address _from, address _to, uint256[] _tokenIds) external nonpayable
|
||||
```
|
||||
|
||||
Complete ERC721 batch withdraw from layer 2 to layer 1 and send NFT to recipient's account on layer 1.
|
||||
|
||||
*Requirements: - The function should only be called by L1ScrollMessenger. - The function should also only be called by L2ERC721Gateway on layer 2.*
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _l1Token | address | The address of corresponding layer 1 token. |
|
||||
| _l2Token | address | The address of corresponding layer 2 token. |
|
||||
| _from | address | The address of account who withdraw the token on layer 2. |
|
||||
| _to | address | The address of recipient on layer 1 to receive the token. |
|
||||
| _tokenIds | uint256[] | The list of token ids to withdraw. |
|
||||
|
||||
### finalizeWithdrawERC721
|
||||
|
||||
```solidity
|
||||
function finalizeWithdrawERC721(address _l1Token, address _l2Token, address _from, address _to, uint256 _tokenId) external nonpayable
|
||||
```
|
||||
|
||||
Complete ERC721 withdraw from layer 2 to layer 1 and send NFT to recipient's account on layer 1.
|
||||
|
||||
*Requirements: - The function should only be called by L1ScrollMessenger. - The function should also only be called by L2ERC721Gateway on layer 2.*
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _l1Token | address | The address of corresponding layer 1 token. |
|
||||
| _l2Token | address | The address of corresponding layer 2 token. |
|
||||
| _from | address | The address of account who withdraw the token on layer 2. |
|
||||
| _to | address | The address of recipient on layer 1 to receive the token. |
|
||||
| _tokenId | uint256 | The token id to withdraw. |
|
||||
|
||||
### initialize
|
||||
|
||||
```solidity
|
||||
function initialize(address _counterpart, address _messenger) external nonpayable
|
||||
```
|
||||
|
||||
Initialize the storage of L1ERC721Gateway.
|
||||
|
||||
*The parameters `_counterpart` and `_messenger` are no longer used.*
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _counterpart | address | The address of L2ERC721Gateway in L2. |
|
||||
| _messenger | address | The address of L1ScrollMessenger in L1. |
|
||||
|
||||
### messenger
|
||||
|
||||
```solidity
|
||||
function messenger() external view returns (address)
|
||||
```
|
||||
|
||||
The address of corresponding L1ScrollMessenger/L2ScrollMessenger contract.
|
||||
|
||||
|
||||
|
||||
|
||||
#### Returns
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _0 | address | undefined |
|
||||
|
||||
### onDropMessage
|
||||
|
||||
```solidity
|
||||
function onDropMessage(bytes _message) external payable
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _message | bytes | undefined |
|
||||
|
||||
### onERC721Received
|
||||
|
||||
```solidity
|
||||
function onERC721Received(address, address, uint256, bytes) external nonpayable returns (bytes4)
|
||||
```
|
||||
|
||||
|
||||
|
||||
*See {IERC721Receiver-onERC721Received}. Always returns `IERC721Receiver.onERC721Received.selector`.*
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _0 | address | undefined |
|
||||
| _1 | address | undefined |
|
||||
| _2 | uint256 | undefined |
|
||||
| _3 | bytes | undefined |
|
||||
|
||||
#### Returns
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _0 | bytes4 | undefined |
|
||||
|
||||
### owner
|
||||
|
||||
```solidity
|
||||
function owner() external view returns (address)
|
||||
```
|
||||
|
||||
|
||||
|
||||
*Returns the address of the current owner.*
|
||||
|
||||
|
||||
#### Returns
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _0 | address | undefined |
|
||||
|
||||
### renounceOwnership
|
||||
|
||||
```solidity
|
||||
function renounceOwnership() external nonpayable
|
||||
```
|
||||
|
||||
|
||||
|
||||
*Leaves the contract without owner. It will not be possible to call `onlyOwner` functions. Can only be called by the current owner. NOTE: Renouncing ownership will leave the contract without an owner, thereby disabling any functionality that is only available to the owner.*
|
||||
|
||||
|
||||
### router
|
||||
|
||||
```solidity
|
||||
function router() external view returns (address)
|
||||
```
|
||||
|
||||
The address of L1GatewayRouter/L2GatewayRouter contract.
|
||||
|
||||
|
||||
|
||||
|
||||
#### Returns
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _0 | address | undefined |
|
||||
|
||||
### tokenMapping
|
||||
|
||||
```solidity
|
||||
function tokenMapping(address) external view returns (address)
|
||||
```
|
||||
|
||||
Mapping from l1 token address to l2 token address for ERC721 NFT.
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _0 | address | undefined |
|
||||
|
||||
#### Returns
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _0 | address | undefined |
|
||||
|
||||
### transferOwnership
|
||||
|
||||
```solidity
|
||||
function transferOwnership(address newOwner) external nonpayable
|
||||
```
|
||||
|
||||
|
||||
|
||||
*Transfers ownership of the contract to a new account (`newOwner`). Can only be called by the current owner.*
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| newOwner | address | undefined |
|
||||
|
||||
### updateTokenMapping
|
||||
|
||||
```solidity
|
||||
function updateTokenMapping(address _l1Token, address _l2Token) external nonpayable
|
||||
```
|
||||
|
||||
Update layer 2 to layer 2 token mapping.
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _l1Token | address | The address of ERC721 token on layer 1. |
|
||||
| _l2Token | address | The address of corresponding ERC721 token on layer 2. |
|
||||
|
||||
|
||||
|
||||
## Events
|
||||
|
||||
### BatchDepositERC721
|
||||
|
||||
```solidity
|
||||
event BatchDepositERC721(address indexed _l1Token, address indexed _l2Token, address indexed _from, address _to, uint256[] _tokenIds)
|
||||
```
|
||||
|
||||
Emitted when the ERC721 NFT is batch deposited to gateway on layer 1.
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _l1Token `indexed` | address | The address of ERC721 NFT on layer 1. |
|
||||
| _l2Token `indexed` | address | The address of ERC721 NFT on layer 2. |
|
||||
| _from `indexed` | address | The address of sender on layer 1. |
|
||||
| _to | address | The address of recipient on layer 2. |
|
||||
| _tokenIds | uint256[] | The list of token ids of the ERC721 NFT to deposit on layer 1. |
|
||||
|
||||
### BatchRefundERC721
|
||||
|
||||
```solidity
|
||||
event BatchRefundERC721(address indexed token, address indexed recipient, uint256[] tokenIds)
|
||||
```
|
||||
|
||||
Emitted when a batch of ERC721 tokens are refunded.
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| token `indexed` | address | The address of the token in L1. |
|
||||
| recipient `indexed` | address | The address of receiver in L1. |
|
||||
| tokenIds | uint256[] | The list of token ids of the ERC721 NFT refunded. |
|
||||
|
||||
### DepositERC721
|
||||
|
||||
```solidity
|
||||
event DepositERC721(address indexed _l1Token, address indexed _l2Token, address indexed _from, address _to, uint256 _tokenId)
|
||||
```
|
||||
|
||||
Emitted when the ERC721 NFT is deposited to gateway on layer 1.
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _l1Token `indexed` | address | The address of ERC721 NFT on layer 1. |
|
||||
| _l2Token `indexed` | address | The address of ERC721 NFT on layer 2. |
|
||||
| _from `indexed` | address | The address of sender on layer 1. |
|
||||
| _to | address | The address of recipient on layer 2. |
|
||||
| _tokenId | uint256 | The token id of the ERC721 NFT to deposit on layer 1. |
|
||||
|
||||
### FinalizeBatchWithdrawERC721
|
||||
|
||||
```solidity
|
||||
event FinalizeBatchWithdrawERC721(address indexed _l1Token, address indexed _l2Token, address indexed _from, address _to, uint256[] _tokenIds)
|
||||
```
|
||||
|
||||
Emitted when the ERC721 NFT is batch transferred to recipient on layer 1.
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _l1Token `indexed` | address | The address of ERC721 NFT on layer 1. |
|
||||
| _l2Token `indexed` | address | The address of ERC721 NFT on layer 2. |
|
||||
| _from `indexed` | address | The address of sender on layer 2. |
|
||||
| _to | address | The address of recipient on layer 1. |
|
||||
| _tokenIds | uint256[] | The list of token ids of the ERC721 NFT to withdraw from layer 2. |
|
||||
|
||||
### FinalizeWithdrawERC721
|
||||
|
||||
```solidity
|
||||
event FinalizeWithdrawERC721(address indexed _l1Token, address indexed _l2Token, address indexed _from, address _to, uint256 _tokenId)
|
||||
```
|
||||
|
||||
Emitted when the ERC721 NFT is transferred to recipient on layer 1.
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _l1Token `indexed` | address | The address of ERC721 NFT on layer 1. |
|
||||
| _l2Token `indexed` | address | The address of ERC721 NFT on layer 2. |
|
||||
| _from `indexed` | address | The address of sender on layer 2. |
|
||||
| _to | address | The address of recipient on layer 1. |
|
||||
| _tokenId | uint256 | The token id of the ERC721 NFT to withdraw from layer 2. |
|
||||
|
||||
### Initialized
|
||||
|
||||
```solidity
|
||||
event Initialized(uint8 version)
|
||||
```
|
||||
|
||||
|
||||
|
||||
*Triggered when the contract has been initialized or reinitialized.*
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| version | uint8 | undefined |
|
||||
|
||||
### OwnershipTransferred
|
||||
|
||||
```solidity
|
||||
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner)
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| previousOwner `indexed` | address | undefined |
|
||||
| newOwner `indexed` | address | undefined |
|
||||
|
||||
### RefundERC721
|
||||
|
||||
```solidity
|
||||
event RefundERC721(address indexed token, address indexed recipient, uint256 tokenId)
|
||||
```
|
||||
|
||||
Emitted when some ERC721 token is refunded.
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| token `indexed` | address | The address of the token in L1. |
|
||||
| recipient `indexed` | address | The address of receiver in L1. |
|
||||
| tokenId | uint256 | The id of token refunded. |
|
||||
|
||||
### UpdateTokenMapping
|
||||
|
||||
```solidity
|
||||
event UpdateTokenMapping(address indexed l1Token, address indexed oldL2Token, address indexed newL2Token)
|
||||
```
|
||||
|
||||
Emitted when token mapping for ERC721 token is updated.
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| l1Token `indexed` | address | The address of ERC721 token in layer 1. |
|
||||
| oldL2Token `indexed` | address | The address of the old corresponding ERC721 token in layer 2. |
|
||||
| newL2Token `indexed` | address | The address of the new corresponding ERC721 token in layer 2. |
|
||||
|
||||
|
||||
|
||||
## Errors
|
||||
|
||||
### ErrorCallerIsNotCounterpartGateway
|
||||
|
||||
```solidity
|
||||
error ErrorCallerIsNotCounterpartGateway()
|
||||
```
|
||||
|
||||
|
||||
|
||||
*Thrown when the cross chain sender is not the counterpart gateway contract.*
|
||||
|
||||
|
||||
### ErrorCallerIsNotMessenger
|
||||
|
||||
```solidity
|
||||
error ErrorCallerIsNotMessenger()
|
||||
```
|
||||
|
||||
|
||||
|
||||
*Thrown when the caller is not corresponding `L1ScrollMessenger` or `L2ScrollMessenger`.*
|
||||
|
||||
|
||||
### ErrorNotInDropMessageContext
|
||||
|
||||
```solidity
|
||||
error ErrorNotInDropMessageContext()
|
||||
```
|
||||
|
||||
|
||||
|
||||
*Thrown when ScrollMessenger is not dropping message.*
|
||||
|
||||
|
||||
### ErrorZeroAddress
|
||||
|
||||
```solidity
|
||||
error ErrorZeroAddress()
|
||||
```
|
||||
|
||||
|
||||
|
||||
*Thrown when the given address is `address(0)`.*
|
||||
|
||||
|
||||
|
||||
620
contracts/docs/apis/L1GatewayRouter.md
Normal file
620
contracts/docs/apis/L1GatewayRouter.md
Normal file
@@ -0,0 +1,620 @@
|
||||
# L1GatewayRouter
|
||||
|
||||
|
||||
|
||||
> L1GatewayRouter
|
||||
|
||||
The `L1GatewayRouter` is the main entry for depositing Ether and ERC20 tokens. All deposited tokens are routed to corresponding gateways.
|
||||
|
||||
*One can also use this contract to query L1/L2 token address mapping. In the future, ERC-721 and ERC-1155 tokens will be added to the router too.*
|
||||
|
||||
## Methods
|
||||
|
||||
### ERC20Gateway
|
||||
|
||||
```solidity
|
||||
function ERC20Gateway(address) external view returns (address)
|
||||
```
|
||||
|
||||
Mapping from ERC20 token address to corresponding L1ERC20Gateway.
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _0 | address | undefined |
|
||||
|
||||
#### Returns
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _0 | address | undefined |
|
||||
|
||||
### defaultERC20Gateway
|
||||
|
||||
```solidity
|
||||
function defaultERC20Gateway() external view returns (address)
|
||||
```
|
||||
|
||||
The addess of default ERC20 gateway, normally the L1StandardERC20Gateway contract.
|
||||
|
||||
|
||||
|
||||
|
||||
#### Returns
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _0 | address | undefined |
|
||||
|
||||
### depositERC20
|
||||
|
||||
```solidity
|
||||
function depositERC20(address _token, uint256 _amount, uint256 _gasLimit) external payable
|
||||
```
|
||||
|
||||
Deposit some token to a caller's account on L2.
|
||||
|
||||
*Make this function payable to send relayer fee in Ether.*
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _token | address | The address of token in L1. |
|
||||
| _amount | uint256 | The amount of token to transfer. |
|
||||
| _gasLimit | uint256 | Gas limit required to complete the deposit on L2. |
|
||||
|
||||
### depositERC20
|
||||
|
||||
```solidity
|
||||
function depositERC20(address _token, address _to, uint256 _amount, uint256 _gasLimit) external payable
|
||||
```
|
||||
|
||||
Deposit some token to a recipient's account on L2.
|
||||
|
||||
*Make this function payable to send relayer fee in Ether.*
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _token | address | The address of token in L1. |
|
||||
| _to | address | The address of recipient's account on L2. |
|
||||
| _amount | uint256 | The amount of token to transfer. |
|
||||
| _gasLimit | uint256 | Gas limit required to complete the deposit on L2. |
|
||||
|
||||
### depositERC20AndCall
|
||||
|
||||
```solidity
|
||||
function depositERC20AndCall(address _token, address _to, uint256 _amount, bytes _data, uint256 _gasLimit) external payable
|
||||
```
|
||||
|
||||
Deposit some token to a recipient's account on L2 and call.
|
||||
|
||||
*Make this function payable to send relayer fee in Ether.*
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _token | address | The address of token in L1. |
|
||||
| _to | address | The address of recipient's account on L2. |
|
||||
| _amount | uint256 | The amount of token to transfer. |
|
||||
| _data | bytes | Optional data to forward to recipient's account. |
|
||||
| _gasLimit | uint256 | Gas limit required to complete the deposit on L2. |
|
||||
|
||||
### depositETH
|
||||
|
||||
```solidity
|
||||
function depositETH(uint256 _amount, uint256 _gasLimit) external payable
|
||||
```
|
||||
|
||||
Deposit ETH to caller's account in L2.
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _amount | uint256 | undefined |
|
||||
| _gasLimit | uint256 | undefined |
|
||||
|
||||
### depositETH
|
||||
|
||||
```solidity
|
||||
function depositETH(address _to, uint256 _amount, uint256 _gasLimit) external payable
|
||||
```
|
||||
|
||||
Deposit ETH to some recipient's account in L2.
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _to | address | undefined |
|
||||
| _amount | uint256 | undefined |
|
||||
| _gasLimit | uint256 | undefined |
|
||||
|
||||
### depositETHAndCall
|
||||
|
||||
```solidity
|
||||
function depositETHAndCall(address _to, uint256 _amount, bytes _data, uint256 _gasLimit) external payable
|
||||
```
|
||||
|
||||
Deposit ETH to some recipient's account in L2 and call the target contract.
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _to | address | undefined |
|
||||
| _amount | uint256 | undefined |
|
||||
| _data | bytes | undefined |
|
||||
| _gasLimit | uint256 | undefined |
|
||||
|
||||
### ethGateway
|
||||
|
||||
```solidity
|
||||
function ethGateway() external view returns (address)
|
||||
```
|
||||
|
||||
The address of L1ETHGateway.
|
||||
|
||||
|
||||
|
||||
|
||||
#### Returns
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _0 | address | undefined |
|
||||
|
||||
### finalizeWithdrawERC20
|
||||
|
||||
```solidity
|
||||
function finalizeWithdrawERC20(address, address, address, address, uint256, bytes) external payable
|
||||
```
|
||||
|
||||
Complete ERC20 withdraw from L2 to L1 and send fund to recipient's account in L1.
|
||||
|
||||
*Make this function payable to handle WETH deposit/withdraw. The function should only be called by L1ScrollMessenger. The function should also only be called by L2ERC20Gateway in L2.*
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _0 | address | undefined |
|
||||
| _1 | address | undefined |
|
||||
| _2 | address | undefined |
|
||||
| _3 | address | undefined |
|
||||
| _4 | uint256 | undefined |
|
||||
| _5 | bytes | undefined |
|
||||
|
||||
### finalizeWithdrawETH
|
||||
|
||||
```solidity
|
||||
function finalizeWithdrawETH(address, address, uint256, bytes) external payable
|
||||
```
|
||||
|
||||
Complete ETH withdraw from L2 to L1 and send fund to recipient's account in L1.
|
||||
|
||||
*This function should only be called by L1ScrollMessenger. This function should also only be called by L1ETHGateway in L2.*
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _0 | address | undefined |
|
||||
| _1 | address | undefined |
|
||||
| _2 | uint256 | undefined |
|
||||
| _3 | bytes | undefined |
|
||||
|
||||
### gatewayInContext
|
||||
|
||||
```solidity
|
||||
function gatewayInContext() external view returns (address)
|
||||
```
|
||||
|
||||
The address of gateway in current execution context.
|
||||
|
||||
|
||||
|
||||
|
||||
#### Returns
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _0 | address | undefined |
|
||||
|
||||
### getERC20Gateway
|
||||
|
||||
```solidity
|
||||
function getERC20Gateway(address _token) external view returns (address)
|
||||
```
|
||||
|
||||
Return the corresponding gateway address for given token address.
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _token | address | The address of token to query. |
|
||||
|
||||
#### Returns
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _0 | address | undefined |
|
||||
|
||||
### getL2ERC20Address
|
||||
|
||||
```solidity
|
||||
function getL2ERC20Address(address _l1Address) external view returns (address)
|
||||
```
|
||||
|
||||
Return the corresponding l2 token address given l1 token address.
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _l1Address | address | undefined |
|
||||
|
||||
#### Returns
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _0 | address | undefined |
|
||||
|
||||
### initialize
|
||||
|
||||
```solidity
|
||||
function initialize(address _ethGateway, address _defaultERC20Gateway) external nonpayable
|
||||
```
|
||||
|
||||
Initialize the storage of L1GatewayRouter.
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _ethGateway | address | The address of L1ETHGateway contract. |
|
||||
| _defaultERC20Gateway | address | The address of default ERC20 Gateway contract. |
|
||||
|
||||
### owner
|
||||
|
||||
```solidity
|
||||
function owner() external view returns (address)
|
||||
```
|
||||
|
||||
|
||||
|
||||
*Returns the address of the current owner.*
|
||||
|
||||
|
||||
#### Returns
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _0 | address | undefined |
|
||||
|
||||
### renounceOwnership
|
||||
|
||||
```solidity
|
||||
function renounceOwnership() external nonpayable
|
||||
```
|
||||
|
||||
|
||||
|
||||
*Leaves the contract without owner. It will not be possible to call `onlyOwner` functions. Can only be called by the current owner. NOTE: Renouncing ownership will leave the contract without an owner, thereby disabling any functionality that is only available to the owner.*
|
||||
|
||||
|
||||
### requestERC20
|
||||
|
||||
```solidity
|
||||
function requestERC20(address _sender, address _token, uint256 _amount) external nonpayable returns (uint256)
|
||||
```
|
||||
|
||||
Request ERC20 token transfer from users to gateways.
|
||||
|
||||
*All the gateways should have reentrancy guard to prevent potential attack though this function.*
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _sender | address | undefined |
|
||||
| _token | address | undefined |
|
||||
| _amount | uint256 | undefined |
|
||||
|
||||
#### Returns
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _0 | uint256 | undefined |
|
||||
|
||||
### setDefaultERC20Gateway
|
||||
|
||||
```solidity
|
||||
function setDefaultERC20Gateway(address _newDefaultERC20Gateway) external nonpayable
|
||||
```
|
||||
|
||||
Update the address of default ERC20 gateway contract.
|
||||
|
||||
*This function should only be called by contract owner.*
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _newDefaultERC20Gateway | address | undefined |
|
||||
|
||||
### setERC20Gateway
|
||||
|
||||
```solidity
|
||||
function setERC20Gateway(address[] _tokens, address[] _gateways) external nonpayable
|
||||
```
|
||||
|
||||
Update the mapping from token address to gateway address.
|
||||
|
||||
*This function should only be called by contract owner.*
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _tokens | address[] | The list of addresses of tokens to update. |
|
||||
| _gateways | address[] | The list of addresses of gateways to update. |
|
||||
|
||||
### setETHGateway
|
||||
|
||||
```solidity
|
||||
function setETHGateway(address _newEthGateway) external nonpayable
|
||||
```
|
||||
|
||||
Update the address of ETH gateway contract.
|
||||
|
||||
*This function should only be called by contract owner.*
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _newEthGateway | address | undefined |
|
||||
|
||||
### transferOwnership
|
||||
|
||||
```solidity
|
||||
function transferOwnership(address newOwner) external nonpayable
|
||||
```
|
||||
|
||||
|
||||
|
||||
*Transfers ownership of the contract to a new account (`newOwner`). Can only be called by the current owner.*
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| newOwner | address | undefined |
|
||||
|
||||
|
||||
|
||||
## Events
|
||||
|
||||
### DepositERC20
|
||||
|
||||
```solidity
|
||||
event DepositERC20(address indexed l1Token, address indexed l2Token, address indexed from, address to, uint256 amount, bytes data)
|
||||
```
|
||||
|
||||
Emitted when someone deposit ERC20 token from L1 to L2.
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| l1Token `indexed` | address | The address of the token in L1. |
|
||||
| l2Token `indexed` | address | The address of the token in L2. |
|
||||
| from `indexed` | address | The address of sender in L1. |
|
||||
| to | address | The address of recipient in L2. |
|
||||
| amount | uint256 | The amount of token will be deposited from L1 to L2. |
|
||||
| data | bytes | The optional calldata passed to recipient in L2. |
|
||||
|
||||
### DepositETH
|
||||
|
||||
```solidity
|
||||
event DepositETH(address indexed from, address indexed to, uint256 amount, bytes data)
|
||||
```
|
||||
|
||||
Emitted when someone deposit ETH from L1 to L2.
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| from `indexed` | address | The address of sender in L1. |
|
||||
| to `indexed` | address | The address of recipient in L2. |
|
||||
| amount | uint256 | The amount of ETH will be deposited from L1 to L2. |
|
||||
| data | bytes | The optional calldata passed to recipient in L2. |
|
||||
|
||||
### FinalizeWithdrawERC20
|
||||
|
||||
```solidity
|
||||
event FinalizeWithdrawERC20(address indexed l1Token, address indexed l2Token, address indexed from, address to, uint256 amount, bytes data)
|
||||
```
|
||||
|
||||
Emitted when ERC20 token is withdrawn from L2 to L1 and transfer to recipient.
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| l1Token `indexed` | address | The address of the token in L1. |
|
||||
| l2Token `indexed` | address | The address of the token in L2. |
|
||||
| from `indexed` | address | The address of sender in L2. |
|
||||
| to | address | The address of recipient in L1. |
|
||||
| amount | uint256 | The amount of token withdrawn from L2 to L1. |
|
||||
| data | bytes | The optional calldata passed to recipient in L1. |
|
||||
|
||||
### FinalizeWithdrawETH
|
||||
|
||||
```solidity
|
||||
event FinalizeWithdrawETH(address indexed from, address indexed to, uint256 amount, bytes data)
|
||||
```
|
||||
|
||||
Emitted when ETH is withdrawn from L2 to L1 and transfer to recipient.
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| from `indexed` | address | The address of sender in L2. |
|
||||
| to `indexed` | address | The address of recipient in L1. |
|
||||
| amount | uint256 | The amount of ETH withdrawn from L2 to L1. |
|
||||
| data | bytes | The optional calldata passed to recipient in L1. |
|
||||
|
||||
### Initialized
|
||||
|
||||
```solidity
|
||||
event Initialized(uint8 version)
|
||||
```
|
||||
|
||||
|
||||
|
||||
*Triggered when the contract has been initialized or reinitialized.*
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| version | uint8 | undefined |
|
||||
|
||||
### OwnershipTransferred
|
||||
|
||||
```solidity
|
||||
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner)
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| previousOwner `indexed` | address | undefined |
|
||||
| newOwner `indexed` | address | undefined |
|
||||
|
||||
### RefundERC20
|
||||
|
||||
```solidity
|
||||
event RefundERC20(address indexed token, address indexed recipient, uint256 amount)
|
||||
```
|
||||
|
||||
Emitted when some ERC20 token is refunded.
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| token `indexed` | address | The address of the token in L1. |
|
||||
| recipient `indexed` | address | The address of receiver in L1. |
|
||||
| amount | uint256 | The amount of token refunded to receiver. |
|
||||
|
||||
### RefundETH
|
||||
|
||||
```solidity
|
||||
event RefundETH(address indexed recipient, uint256 amount)
|
||||
```
|
||||
|
||||
Emitted when some ETH is refunded.
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| recipient `indexed` | address | The address of receiver in L1. |
|
||||
| amount | uint256 | The amount of ETH refunded to receiver. |
|
||||
|
||||
### SetDefaultERC20Gateway
|
||||
|
||||
```solidity
|
||||
event SetDefaultERC20Gateway(address indexed oldDefaultERC20Gateway, address indexed newDefaultERC20Gateway)
|
||||
```
|
||||
|
||||
Emitted when the address of default ERC20 Gateway is updated.
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| oldDefaultERC20Gateway `indexed` | address | The address of the old default ERC20 Gateway. |
|
||||
| newDefaultERC20Gateway `indexed` | address | The address of the new default ERC20 Gateway. |
|
||||
|
||||
### SetERC20Gateway
|
||||
|
||||
```solidity
|
||||
event SetERC20Gateway(address indexed token, address indexed oldGateway, address indexed newGateway)
|
||||
```
|
||||
|
||||
Emitted when the `gateway` for `token` is updated.
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| token `indexed` | address | The address of token updated. |
|
||||
| oldGateway `indexed` | address | The corresponding address of the old gateway. |
|
||||
| newGateway `indexed` | address | The corresponding address of the new gateway. |
|
||||
|
||||
### SetETHGateway
|
||||
|
||||
```solidity
|
||||
event SetETHGateway(address indexed oldETHGateway, address indexed newEthGateway)
|
||||
```
|
||||
|
||||
Emitted when the address of ETH Gateway is updated.
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| oldETHGateway `indexed` | address | The address of the old ETH Gateway. |
|
||||
| newEthGateway `indexed` | address | The address of the new ETH Gateway. |
|
||||
|
||||
|
||||
|
||||
627
contracts/docs/apis/L1ScrollMessenger.md
Normal file
627
contracts/docs/apis/L1ScrollMessenger.md
Normal file
@@ -0,0 +1,627 @@
|
||||
# L1ScrollMessenger
|
||||
|
||||
|
||||
|
||||
> L1ScrollMessenger
|
||||
|
||||
The `L1ScrollMessenger` contract can: 1. send messages from layer 1 to layer 2; 2. relay messages from layer 2 layer 1; 3. replay failed message by replacing the gas limit; 4. drop expired message due to sequencer problems.
|
||||
|
||||
*All deposited Ether (including `WETH` deposited throng `L1WETHGateway`) will locked in this contract.*
|
||||
|
||||
## Methods
|
||||
|
||||
### counterpart
|
||||
|
||||
```solidity
|
||||
function counterpart() external view returns (address)
|
||||
```
|
||||
|
||||
The address of counterpart ScrollMessenger contract in L1/L2.
|
||||
|
||||
|
||||
|
||||
|
||||
#### Returns
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _0 | address | undefined |
|
||||
|
||||
### dropMessage
|
||||
|
||||
```solidity
|
||||
function dropMessage(address _from, address _to, uint256 _value, uint256 _messageNonce, bytes _message) external nonpayable
|
||||
```
|
||||
|
||||
Drop a skipped message.
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _from | address | undefined |
|
||||
| _to | address | undefined |
|
||||
| _value | uint256 | undefined |
|
||||
| _messageNonce | uint256 | undefined |
|
||||
| _message | bytes | undefined |
|
||||
|
||||
### feeVault
|
||||
|
||||
```solidity
|
||||
function feeVault() external view returns (address)
|
||||
```
|
||||
|
||||
The address of fee vault, collecting cross domain messaging fee.
|
||||
|
||||
|
||||
|
||||
|
||||
#### Returns
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _0 | address | undefined |
|
||||
|
||||
### initialize
|
||||
|
||||
```solidity
|
||||
function initialize(address _counterpart, address _feeVault, address _rollup, address _messageQueue) external nonpayable
|
||||
```
|
||||
|
||||
Initialize the storage of L1ScrollMessenger.
|
||||
|
||||
*The parameters `_counterpart`, `_rollup` and `_messageQueue` are no longer used.*
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _counterpart | address | The address of L2ScrollMessenger contract in L2. |
|
||||
| _feeVault | address | The address of fee vault, which will be used to collect relayer fee. |
|
||||
| _rollup | address | The address of ScrollChain contract. |
|
||||
| _messageQueue | address | The address of L1MessageQueue contract. |
|
||||
|
||||
### isL1MessageDropped
|
||||
|
||||
```solidity
|
||||
function isL1MessageDropped(bytes32) external view returns (bool)
|
||||
```
|
||||
|
||||
Mapping from L1 message hash to drop status.
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _0 | bytes32 | undefined |
|
||||
|
||||
#### Returns
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _0 | bool | undefined |
|
||||
|
||||
### isL2MessageExecuted
|
||||
|
||||
```solidity
|
||||
function isL2MessageExecuted(bytes32) external view returns (bool)
|
||||
```
|
||||
|
||||
Mapping from L2 message hash to a boolean value indicating if the message has been successfully executed.
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _0 | bytes32 | undefined |
|
||||
|
||||
#### Returns
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _0 | bool | undefined |
|
||||
|
||||
### maxReplayTimes
|
||||
|
||||
```solidity
|
||||
function maxReplayTimes() external view returns (uint256)
|
||||
```
|
||||
|
||||
The maximum number of times each L1 message can be replayed.
|
||||
|
||||
|
||||
|
||||
|
||||
#### Returns
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _0 | uint256 | undefined |
|
||||
|
||||
### messageQueue
|
||||
|
||||
```solidity
|
||||
function messageQueue() external view returns (address)
|
||||
```
|
||||
|
||||
The address of L1MessageQueue contract.
|
||||
|
||||
|
||||
|
||||
|
||||
#### Returns
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _0 | address | undefined |
|
||||
|
||||
### messageSendTimestamp
|
||||
|
||||
```solidity
|
||||
function messageSendTimestamp(bytes32) external view returns (uint256)
|
||||
```
|
||||
|
||||
Mapping from L1 message hash to the timestamp when the message is sent.
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _0 | bytes32 | undefined |
|
||||
|
||||
#### Returns
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _0 | uint256 | undefined |
|
||||
|
||||
### owner
|
||||
|
||||
```solidity
|
||||
function owner() external view returns (address)
|
||||
```
|
||||
|
||||
|
||||
|
||||
*Returns the address of the current owner.*
|
||||
|
||||
|
||||
#### Returns
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _0 | address | undefined |
|
||||
|
||||
### paused
|
||||
|
||||
```solidity
|
||||
function paused() external view returns (bool)
|
||||
```
|
||||
|
||||
|
||||
|
||||
*Returns true if the contract is paused, and false otherwise.*
|
||||
|
||||
|
||||
#### Returns
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _0 | bool | undefined |
|
||||
|
||||
### prevReplayIndex
|
||||
|
||||
```solidity
|
||||
function prevReplayIndex(uint256) external view returns (uint256)
|
||||
```
|
||||
|
||||
Mapping from queue index to previous replay queue index.
|
||||
|
||||
*If a message `x` was replayed 3 times with index `q1`, `q2` and `q3`, the value of `prevReplayIndex` and `replayStates` will be `replayStates[hash(x)].lastIndex = q3`, `replayStates[hash(x)].times = 3`, `prevReplayIndex[q3] = q2`, `prevReplayIndex[q2] = q1`, `prevReplayIndex[q1] = x` and `prevReplayIndex[x]=nil`.The index `x` that `prevReplayIndex[x]=nil` is used as the termination of the list. Usually we use `0` to represent `nil`, but we cannot distinguish it with the first message with index zero. So a nonzero offset `1` is added to the value of `prevReplayIndex[x]` to avoid such situation.*
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _0 | uint256 | undefined |
|
||||
|
||||
#### Returns
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _0 | uint256 | undefined |
|
||||
|
||||
### relayMessageWithProof
|
||||
|
||||
```solidity
|
||||
function relayMessageWithProof(address _from, address _to, uint256 _value, uint256 _nonce, bytes _message, IL1ScrollMessenger.L2MessageProof _proof) external nonpayable
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _from | address | undefined |
|
||||
| _to | address | undefined |
|
||||
| _value | uint256 | undefined |
|
||||
| _nonce | uint256 | undefined |
|
||||
| _message | bytes | undefined |
|
||||
| _proof | IL1ScrollMessenger.L2MessageProof | undefined |
|
||||
|
||||
### renounceOwnership
|
||||
|
||||
```solidity
|
||||
function renounceOwnership() external nonpayable
|
||||
```
|
||||
|
||||
|
||||
|
||||
*Leaves the contract without owner. It will not be possible to call `onlyOwner` functions. Can only be called by the current owner. NOTE: Renouncing ownership will leave the contract without an owner, thereby disabling any functionality that is only available to the owner.*
|
||||
|
||||
|
||||
### replayMessage
|
||||
|
||||
```solidity
|
||||
function replayMessage(address _from, address _to, uint256 _value, uint256 _messageNonce, bytes _message, uint32 _newGasLimit, address _refundAddress) external payable
|
||||
```
|
||||
|
||||
Replay an existing message.
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _from | address | undefined |
|
||||
| _to | address | undefined |
|
||||
| _value | uint256 | undefined |
|
||||
| _messageNonce | uint256 | undefined |
|
||||
| _message | bytes | undefined |
|
||||
| _newGasLimit | uint32 | undefined |
|
||||
| _refundAddress | address | undefined |
|
||||
|
||||
### replayStates
|
||||
|
||||
```solidity
|
||||
function replayStates(bytes32) external view returns (uint128 times, uint128 lastIndex)
|
||||
```
|
||||
|
||||
Mapping from L1 message hash to replay state.
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _0 | bytes32 | undefined |
|
||||
|
||||
#### Returns
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| times | uint128 | undefined |
|
||||
| lastIndex | uint128 | undefined |
|
||||
|
||||
### rollup
|
||||
|
||||
```solidity
|
||||
function rollup() external view returns (address)
|
||||
```
|
||||
|
||||
The address of Rollup contract.
|
||||
|
||||
|
||||
|
||||
|
||||
#### Returns
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _0 | address | undefined |
|
||||
|
||||
### sendMessage
|
||||
|
||||
```solidity
|
||||
function sendMessage(address _to, uint256 _value, bytes _message, uint256 _gasLimit, address _refundAddress) external payable
|
||||
```
|
||||
|
||||
Send cross chain message from L1 to L2 or L2 to L1.
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _to | address | undefined |
|
||||
| _value | uint256 | undefined |
|
||||
| _message | bytes | undefined |
|
||||
| _gasLimit | uint256 | undefined |
|
||||
| _refundAddress | address | undefined |
|
||||
|
||||
### sendMessage
|
||||
|
||||
```solidity
|
||||
function sendMessage(address _to, uint256 _value, bytes _message, uint256 _gasLimit) external payable
|
||||
```
|
||||
|
||||
Send cross chain message from L1 to L2 or L2 to L1.
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _to | address | undefined |
|
||||
| _value | uint256 | undefined |
|
||||
| _message | bytes | undefined |
|
||||
| _gasLimit | uint256 | undefined |
|
||||
|
||||
### setPause
|
||||
|
||||
```solidity
|
||||
function setPause(bool _status) external nonpayable
|
||||
```
|
||||
|
||||
Pause the contract
|
||||
|
||||
*This function can only called by contract owner.*
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _status | bool | The pause status to update. |
|
||||
|
||||
### transferOwnership
|
||||
|
||||
```solidity
|
||||
function transferOwnership(address newOwner) external nonpayable
|
||||
```
|
||||
|
||||
|
||||
|
||||
*Transfers ownership of the contract to a new account (`newOwner`). Can only be called by the current owner.*
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| newOwner | address | undefined |
|
||||
|
||||
### updateFeeVault
|
||||
|
||||
```solidity
|
||||
function updateFeeVault(address _newFeeVault) external nonpayable
|
||||
```
|
||||
|
||||
Update fee vault contract.
|
||||
|
||||
*This function can only called by contract owner.*
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _newFeeVault | address | The address of new fee vault contract. |
|
||||
|
||||
### updateMaxReplayTimes
|
||||
|
||||
```solidity
|
||||
function updateMaxReplayTimes(uint256 _newMaxReplayTimes) external nonpayable
|
||||
```
|
||||
|
||||
Update max replay times.
|
||||
|
||||
*This function can only called by contract owner.*
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _newMaxReplayTimes | uint256 | The new max replay times. |
|
||||
|
||||
### xDomainMessageSender
|
||||
|
||||
```solidity
|
||||
function xDomainMessageSender() external view returns (address)
|
||||
```
|
||||
|
||||
See {IScrollMessenger-xDomainMessageSender}
|
||||
|
||||
|
||||
|
||||
|
||||
#### Returns
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _0 | address | undefined |
|
||||
|
||||
|
||||
|
||||
## Events
|
||||
|
||||
### FailedRelayedMessage
|
||||
|
||||
```solidity
|
||||
event FailedRelayedMessage(bytes32 indexed messageHash)
|
||||
```
|
||||
|
||||
Emitted when a cross domain message is failed to relay.
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| messageHash `indexed` | bytes32 | The hash of the message. |
|
||||
|
||||
### Initialized
|
||||
|
||||
```solidity
|
||||
event Initialized(uint8 version)
|
||||
```
|
||||
|
||||
|
||||
|
||||
*Triggered when the contract has been initialized or reinitialized.*
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| version | uint8 | undefined |
|
||||
|
||||
### OwnershipTransferred
|
||||
|
||||
```solidity
|
||||
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner)
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| previousOwner `indexed` | address | undefined |
|
||||
| newOwner `indexed` | address | undefined |
|
||||
|
||||
### Paused
|
||||
|
||||
```solidity
|
||||
event Paused(address account)
|
||||
```
|
||||
|
||||
|
||||
|
||||
*Emitted when the pause is triggered by `account`.*
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| account | address | undefined |
|
||||
|
||||
### RelayedMessage
|
||||
|
||||
```solidity
|
||||
event RelayedMessage(bytes32 indexed messageHash)
|
||||
```
|
||||
|
||||
Emitted when a cross domain message is relayed successfully.
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| messageHash `indexed` | bytes32 | The hash of the message. |
|
||||
|
||||
### SentMessage
|
||||
|
||||
```solidity
|
||||
event SentMessage(address indexed sender, address indexed target, uint256 value, uint256 messageNonce, uint256 gasLimit, bytes message)
|
||||
```
|
||||
|
||||
Emitted when a cross domain message is sent.
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| sender `indexed` | address | The address of the sender who initiates the message. |
|
||||
| target `indexed` | address | The address of target contract to call. |
|
||||
| value | uint256 | The amount of value passed to the target contract. |
|
||||
| messageNonce | uint256 | The nonce of the message. |
|
||||
| gasLimit | uint256 | The optional gas limit passed to L1 or L2. |
|
||||
| message | bytes | The calldata passed to the target contract. |
|
||||
|
||||
### Unpaused
|
||||
|
||||
```solidity
|
||||
event Unpaused(address account)
|
||||
```
|
||||
|
||||
|
||||
|
||||
*Emitted when the pause is lifted by `account`.*
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| account | address | undefined |
|
||||
|
||||
### UpdateFeeVault
|
||||
|
||||
```solidity
|
||||
event UpdateFeeVault(address _oldFeeVault, address _newFeeVault)
|
||||
```
|
||||
|
||||
Emitted when owner updates fee vault contract.
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _oldFeeVault | address | The address of old fee vault contract. |
|
||||
| _newFeeVault | address | The address of new fee vault contract. |
|
||||
|
||||
### UpdateMaxReplayTimes
|
||||
|
||||
```solidity
|
||||
event UpdateMaxReplayTimes(uint256 oldMaxReplayTimes, uint256 newMaxReplayTimes)
|
||||
```
|
||||
|
||||
Emitted when the maximum number of times each message can be replayed is updated.
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| oldMaxReplayTimes | uint256 | The old maximum number of times each message can be replayed. |
|
||||
| newMaxReplayTimes | uint256 | The new maximum number of times each message can be replayed. |
|
||||
|
||||
|
||||
|
||||
## Errors
|
||||
|
||||
### ErrorZeroAddress
|
||||
|
||||
```solidity
|
||||
error ErrorZeroAddress()
|
||||
```
|
||||
|
||||
|
||||
|
||||
*Thrown when the given address is `address(0)`.*
|
||||
|
||||
|
||||
|
||||
423
contracts/docs/apis/L1StandardERC20Gateway.md
Normal file
423
contracts/docs/apis/L1StandardERC20Gateway.md
Normal file
@@ -0,0 +1,423 @@
|
||||
# L1StandardERC20Gateway
|
||||
|
||||
|
||||
|
||||
> L1StandardERC20Gateway
|
||||
|
||||
The `L1StandardERC20Gateway` is used to deposit standard ERC20 tokens on layer 1 and finalize withdraw the tokens from layer 2.
|
||||
|
||||
*The deposited ERC20 tokens are held in this gateway. On finalizing withdraw, the corresponding token will be transfer to the recipient directly. Any ERC20 that requires non-standard functionality should use a separate gateway.*
|
||||
|
||||
## Methods
|
||||
|
||||
### counterpart
|
||||
|
||||
```solidity
|
||||
function counterpart() external view returns (address)
|
||||
```
|
||||
|
||||
The address of corresponding L1/L2 Gateway contract.
|
||||
|
||||
|
||||
|
||||
|
||||
#### Returns
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _0 | address | undefined |
|
||||
|
||||
### depositERC20
|
||||
|
||||
```solidity
|
||||
function depositERC20(address _token, uint256 _amount, uint256 _gasLimit) external payable
|
||||
```
|
||||
|
||||
Deposit some token to a caller's account on L2.
|
||||
|
||||
*Make this function payable to send relayer fee in Ether.*
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _token | address | The address of token in L1. |
|
||||
| _amount | uint256 | The amount of token to transfer. |
|
||||
| _gasLimit | uint256 | Gas limit required to complete the deposit on L2. |
|
||||
|
||||
### depositERC20
|
||||
|
||||
```solidity
|
||||
function depositERC20(address _token, address _to, uint256 _amount, uint256 _gasLimit) external payable
|
||||
```
|
||||
|
||||
Deposit some token to a recipient's account on L2.
|
||||
|
||||
*Make this function payable to send relayer fee in Ether.*
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _token | address | The address of token in L1. |
|
||||
| _to | address | The address of recipient's account on L2. |
|
||||
| _amount | uint256 | The amount of token to transfer. |
|
||||
| _gasLimit | uint256 | Gas limit required to complete the deposit on L2. |
|
||||
|
||||
### depositERC20AndCall
|
||||
|
||||
```solidity
|
||||
function depositERC20AndCall(address _token, address _to, uint256 _amount, bytes _data, uint256 _gasLimit) external payable
|
||||
```
|
||||
|
||||
Deposit some token to a recipient's account on L2 and call.
|
||||
|
||||
*Make this function payable to send relayer fee in Ether.*
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _token | address | The address of token in L1. |
|
||||
| _to | address | The address of recipient's account on L2. |
|
||||
| _amount | uint256 | The amount of token to transfer. |
|
||||
| _data | bytes | Optional data to forward to recipient's account. |
|
||||
| _gasLimit | uint256 | Gas limit required to complete the deposit on L2. |
|
||||
|
||||
### finalizeWithdrawERC20
|
||||
|
||||
```solidity
|
||||
function finalizeWithdrawERC20(address _l1Token, address _l2Token, address _from, address _to, uint256 _amount, bytes _data) external payable
|
||||
```
|
||||
|
||||
Complete ERC20 withdraw from L2 to L1 and send fund to recipient's account in L1.
|
||||
|
||||
*Make this function payable to handle WETH deposit/withdraw. The function should only be called by L1ScrollMessenger. The function should also only be called by L2ERC20Gateway in L2.*
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _l1Token | address | The address of corresponding L1 token. |
|
||||
| _l2Token | address | The address of corresponding L2 token. |
|
||||
| _from | address | The address of account who withdraw the token in L2. |
|
||||
| _to | address | The address of recipient in L1 to receive the token. |
|
||||
| _amount | uint256 | The amount of the token to withdraw. |
|
||||
| _data | bytes | Optional data to forward to recipient's account. |
|
||||
|
||||
### getL2ERC20Address
|
||||
|
||||
```solidity
|
||||
function getL2ERC20Address(address _l1Token) external view returns (address)
|
||||
```
|
||||
|
||||
Return the corresponding l2 token address given l1 token address.
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _l1Token | address | The address of l1 token. |
|
||||
|
||||
#### Returns
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _0 | address | undefined |
|
||||
|
||||
### initialize
|
||||
|
||||
```solidity
|
||||
function initialize(address _counterpart, address _router, address _messenger, address, address) external nonpayable
|
||||
```
|
||||
|
||||
Initialize the storage of L1StandardERC20Gateway.
|
||||
|
||||
*The parameters `_counterpart`, `_router`, `_messenger`, `_l2TokenImplementation` and `_l2TokenFactory` are no longer used.*
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _counterpart | address | The address of L2StandardERC20Gateway in L2. |
|
||||
| _router | address | The address of L1GatewayRouter in L1. |
|
||||
| _messenger | address | The address of L1ScrollMessenger in L1. |
|
||||
| _3 | address | undefined |
|
||||
| _4 | address | undefined |
|
||||
|
||||
### l2TokenFactory
|
||||
|
||||
```solidity
|
||||
function l2TokenFactory() external view returns (address)
|
||||
```
|
||||
|
||||
The address of ScrollStandardERC20Factory contract in L2.
|
||||
|
||||
|
||||
|
||||
|
||||
#### Returns
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _0 | address | undefined |
|
||||
|
||||
### l2TokenImplementation
|
||||
|
||||
```solidity
|
||||
function l2TokenImplementation() external view returns (address)
|
||||
```
|
||||
|
||||
The address of ScrollStandardERC20 implementation in L2.
|
||||
|
||||
|
||||
|
||||
|
||||
#### Returns
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _0 | address | undefined |
|
||||
|
||||
### messenger
|
||||
|
||||
```solidity
|
||||
function messenger() external view returns (address)
|
||||
```
|
||||
|
||||
The address of corresponding L1ScrollMessenger/L2ScrollMessenger contract.
|
||||
|
||||
|
||||
|
||||
|
||||
#### Returns
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _0 | address | undefined |
|
||||
|
||||
### onDropMessage
|
||||
|
||||
```solidity
|
||||
function onDropMessage(bytes _message) external payable
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _message | bytes | undefined |
|
||||
|
||||
### owner
|
||||
|
||||
```solidity
|
||||
function owner() external view returns (address)
|
||||
```
|
||||
|
||||
|
||||
|
||||
*Returns the address of the current owner.*
|
||||
|
||||
|
||||
#### Returns
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _0 | address | undefined |
|
||||
|
||||
### renounceOwnership
|
||||
|
||||
```solidity
|
||||
function renounceOwnership() external nonpayable
|
||||
```
|
||||
|
||||
|
||||
|
||||
*Leaves the contract without owner. It will not be possible to call `onlyOwner` functions. Can only be called by the current owner. NOTE: Renouncing ownership will leave the contract without an owner, thereby disabling any functionality that is only available to the owner.*
|
||||
|
||||
|
||||
### router
|
||||
|
||||
```solidity
|
||||
function router() external view returns (address)
|
||||
```
|
||||
|
||||
The address of L1GatewayRouter/L2GatewayRouter contract.
|
||||
|
||||
|
||||
|
||||
|
||||
#### Returns
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _0 | address | undefined |
|
||||
|
||||
### transferOwnership
|
||||
|
||||
```solidity
|
||||
function transferOwnership(address newOwner) external nonpayable
|
||||
```
|
||||
|
||||
|
||||
|
||||
*Transfers ownership of the contract to a new account (`newOwner`). Can only be called by the current owner.*
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| newOwner | address | undefined |
|
||||
|
||||
|
||||
|
||||
## Events
|
||||
|
||||
### DepositERC20
|
||||
|
||||
```solidity
|
||||
event DepositERC20(address indexed l1Token, address indexed l2Token, address indexed from, address to, uint256 amount, bytes data)
|
||||
```
|
||||
|
||||
Emitted when someone deposit ERC20 token from L1 to L2.
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| l1Token `indexed` | address | The address of the token in L1. |
|
||||
| l2Token `indexed` | address | The address of the token in L2. |
|
||||
| from `indexed` | address | The address of sender in L1. |
|
||||
| to | address | The address of recipient in L2. |
|
||||
| amount | uint256 | The amount of token will be deposited from L1 to L2. |
|
||||
| data | bytes | The optional calldata passed to recipient in L2. |
|
||||
|
||||
### FinalizeWithdrawERC20
|
||||
|
||||
```solidity
|
||||
event FinalizeWithdrawERC20(address indexed l1Token, address indexed l2Token, address indexed from, address to, uint256 amount, bytes data)
|
||||
```
|
||||
|
||||
Emitted when ERC20 token is withdrawn from L2 to L1 and transfer to recipient.
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| l1Token `indexed` | address | The address of the token in L1. |
|
||||
| l2Token `indexed` | address | The address of the token in L2. |
|
||||
| from `indexed` | address | The address of sender in L2. |
|
||||
| to | address | The address of recipient in L1. |
|
||||
| amount | uint256 | The amount of token withdrawn from L2 to L1. |
|
||||
| data | bytes | The optional calldata passed to recipient in L1. |
|
||||
|
||||
### Initialized
|
||||
|
||||
```solidity
|
||||
event Initialized(uint8 version)
|
||||
```
|
||||
|
||||
|
||||
|
||||
*Triggered when the contract has been initialized or reinitialized.*
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| version | uint8 | undefined |
|
||||
|
||||
### OwnershipTransferred
|
||||
|
||||
```solidity
|
||||
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner)
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| previousOwner `indexed` | address | undefined |
|
||||
| newOwner `indexed` | address | undefined |
|
||||
|
||||
### RefundERC20
|
||||
|
||||
```solidity
|
||||
event RefundERC20(address indexed token, address indexed recipient, uint256 amount)
|
||||
```
|
||||
|
||||
Emitted when some ERC20 token is refunded.
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| token `indexed` | address | The address of the token in L1. |
|
||||
| recipient `indexed` | address | The address of receiver in L1. |
|
||||
| amount | uint256 | The amount of token refunded to receiver. |
|
||||
|
||||
|
||||
|
||||
## Errors
|
||||
|
||||
### ErrorCallerIsNotCounterpartGateway
|
||||
|
||||
```solidity
|
||||
error ErrorCallerIsNotCounterpartGateway()
|
||||
```
|
||||
|
||||
|
||||
|
||||
*Thrown when the cross chain sender is not the counterpart gateway contract.*
|
||||
|
||||
|
||||
### ErrorCallerIsNotMessenger
|
||||
|
||||
```solidity
|
||||
error ErrorCallerIsNotMessenger()
|
||||
```
|
||||
|
||||
|
||||
|
||||
*Thrown when the caller is not corresponding `L1ScrollMessenger` or `L2ScrollMessenger`.*
|
||||
|
||||
|
||||
### ErrorNotInDropMessageContext
|
||||
|
||||
```solidity
|
||||
error ErrorNotInDropMessageContext()
|
||||
```
|
||||
|
||||
|
||||
|
||||
*Thrown when ScrollMessenger is not dropping message.*
|
||||
|
||||
|
||||
### ErrorZeroAddress
|
||||
|
||||
```solidity
|
||||
error ErrorZeroAddress()
|
||||
```
|
||||
|
||||
|
||||
|
||||
*Thrown when the given address is `address(0)`.*
|
||||
|
||||
|
||||
|
||||
421
contracts/docs/apis/L1WETHGateway.md
Normal file
421
contracts/docs/apis/L1WETHGateway.md
Normal file
@@ -0,0 +1,421 @@
|
||||
# L1WETHGateway
|
||||
|
||||
|
||||
|
||||
> L1WETHGateway
|
||||
|
||||
The `L1WETHGateway` contract is used to deposit `WETH` token on layer 1 and finalize withdraw `WETH` from layer 2.
|
||||
|
||||
*The deposited WETH tokens are not held in the gateway. It will first be unwrapped as Ether and then the Ether will be sent to the `L1ScrollMessenger` contract. On finalizing withdraw, the Ether will be transferred from `L1ScrollMessenger`, then wrapped as WETH and finally transfer to recipient.*
|
||||
|
||||
## Methods
|
||||
|
||||
### WETH
|
||||
|
||||
```solidity
|
||||
function WETH() external view returns (address)
|
||||
```
|
||||
|
||||
The address of L1 WETH address.
|
||||
|
||||
|
||||
|
||||
|
||||
#### Returns
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _0 | address | undefined |
|
||||
|
||||
### counterpart
|
||||
|
||||
```solidity
|
||||
function counterpart() external view returns (address)
|
||||
```
|
||||
|
||||
The address of corresponding L1/L2 Gateway contract.
|
||||
|
||||
|
||||
|
||||
|
||||
#### Returns
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _0 | address | undefined |
|
||||
|
||||
### depositERC20
|
||||
|
||||
```solidity
|
||||
function depositERC20(address _token, uint256 _amount, uint256 _gasLimit) external payable
|
||||
```
|
||||
|
||||
Deposit some token to a caller's account on L2.
|
||||
|
||||
*Make this function payable to send relayer fee in Ether.*
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _token | address | The address of token in L1. |
|
||||
| _amount | uint256 | The amount of token to transfer. |
|
||||
| _gasLimit | uint256 | Gas limit required to complete the deposit on L2. |
|
||||
|
||||
### depositERC20
|
||||
|
||||
```solidity
|
||||
function depositERC20(address _token, address _to, uint256 _amount, uint256 _gasLimit) external payable
|
||||
```
|
||||
|
||||
Deposit some token to a recipient's account on L2.
|
||||
|
||||
*Make this function payable to send relayer fee in Ether.*
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _token | address | The address of token in L1. |
|
||||
| _to | address | The address of recipient's account on L2. |
|
||||
| _amount | uint256 | The amount of token to transfer. |
|
||||
| _gasLimit | uint256 | Gas limit required to complete the deposit on L2. |
|
||||
|
||||
### depositERC20AndCall
|
||||
|
||||
```solidity
|
||||
function depositERC20AndCall(address _token, address _to, uint256 _amount, bytes _data, uint256 _gasLimit) external payable
|
||||
```
|
||||
|
||||
Deposit some token to a recipient's account on L2 and call.
|
||||
|
||||
*Make this function payable to send relayer fee in Ether.*
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _token | address | The address of token in L1. |
|
||||
| _to | address | The address of recipient's account on L2. |
|
||||
| _amount | uint256 | The amount of token to transfer. |
|
||||
| _data | bytes | Optional data to forward to recipient's account. |
|
||||
| _gasLimit | uint256 | Gas limit required to complete the deposit on L2. |
|
||||
|
||||
### finalizeWithdrawERC20
|
||||
|
||||
```solidity
|
||||
function finalizeWithdrawERC20(address _l1Token, address _l2Token, address _from, address _to, uint256 _amount, bytes _data) external payable
|
||||
```
|
||||
|
||||
Complete ERC20 withdraw from L2 to L1 and send fund to recipient's account in L1.
|
||||
|
||||
*Make this function payable to handle WETH deposit/withdraw. The function should only be called by L1ScrollMessenger. The function should also only be called by L2ERC20Gateway in L2.*
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _l1Token | address | The address of corresponding L1 token. |
|
||||
| _l2Token | address | The address of corresponding L2 token. |
|
||||
| _from | address | The address of account who withdraw the token in L2. |
|
||||
| _to | address | The address of recipient in L1 to receive the token. |
|
||||
| _amount | uint256 | The amount of the token to withdraw. |
|
||||
| _data | bytes | Optional data to forward to recipient's account. |
|
||||
|
||||
### getL2ERC20Address
|
||||
|
||||
```solidity
|
||||
function getL2ERC20Address(address) external view returns (address)
|
||||
```
|
||||
|
||||
Return the corresponding l2 token address given l1 token address.
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _0 | address | undefined |
|
||||
|
||||
#### Returns
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _0 | address | undefined |
|
||||
|
||||
### initialize
|
||||
|
||||
```solidity
|
||||
function initialize(address _counterpart, address _router, address _messenger) external nonpayable
|
||||
```
|
||||
|
||||
Initialize the storage of L1WETHGateway.
|
||||
|
||||
*The parameters `_counterpart`, `_router` and `_messenger` are no longer used.*
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _counterpart | address | The address of L2ETHGateway in L2. |
|
||||
| _router | address | The address of L1GatewayRouter in L1. |
|
||||
| _messenger | address | The address of L1ScrollMessenger in L1. |
|
||||
|
||||
### l2WETH
|
||||
|
||||
```solidity
|
||||
function l2WETH() external view returns (address)
|
||||
```
|
||||
|
||||
The address of L2 WETH address.
|
||||
|
||||
|
||||
|
||||
|
||||
#### Returns
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _0 | address | undefined |
|
||||
|
||||
### messenger
|
||||
|
||||
```solidity
|
||||
function messenger() external view returns (address)
|
||||
```
|
||||
|
||||
The address of corresponding L1ScrollMessenger/L2ScrollMessenger contract.
|
||||
|
||||
|
||||
|
||||
|
||||
#### Returns
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _0 | address | undefined |
|
||||
|
||||
### onDropMessage
|
||||
|
||||
```solidity
|
||||
function onDropMessage(bytes _message) external payable
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _message | bytes | undefined |
|
||||
|
||||
### owner
|
||||
|
||||
```solidity
|
||||
function owner() external view returns (address)
|
||||
```
|
||||
|
||||
|
||||
|
||||
*Returns the address of the current owner.*
|
||||
|
||||
|
||||
#### Returns
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _0 | address | undefined |
|
||||
|
||||
### renounceOwnership
|
||||
|
||||
```solidity
|
||||
function renounceOwnership() external nonpayable
|
||||
```
|
||||
|
||||
|
||||
|
||||
*Leaves the contract without owner. It will not be possible to call `onlyOwner` functions. Can only be called by the current owner. NOTE: Renouncing ownership will leave the contract without an owner, thereby disabling any functionality that is only available to the owner.*
|
||||
|
||||
|
||||
### router
|
||||
|
||||
```solidity
|
||||
function router() external view returns (address)
|
||||
```
|
||||
|
||||
The address of L1GatewayRouter/L2GatewayRouter contract.
|
||||
|
||||
|
||||
|
||||
|
||||
#### Returns
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _0 | address | undefined |
|
||||
|
||||
### transferOwnership
|
||||
|
||||
```solidity
|
||||
function transferOwnership(address newOwner) external nonpayable
|
||||
```
|
||||
|
||||
|
||||
|
||||
*Transfers ownership of the contract to a new account (`newOwner`). Can only be called by the current owner.*
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| newOwner | address | undefined |
|
||||
|
||||
|
||||
|
||||
## Events
|
||||
|
||||
### DepositERC20
|
||||
|
||||
```solidity
|
||||
event DepositERC20(address indexed l1Token, address indexed l2Token, address indexed from, address to, uint256 amount, bytes data)
|
||||
```
|
||||
|
||||
Emitted when someone deposit ERC20 token from L1 to L2.
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| l1Token `indexed` | address | The address of the token in L1. |
|
||||
| l2Token `indexed` | address | The address of the token in L2. |
|
||||
| from `indexed` | address | The address of sender in L1. |
|
||||
| to | address | The address of recipient in L2. |
|
||||
| amount | uint256 | The amount of token will be deposited from L1 to L2. |
|
||||
| data | bytes | The optional calldata passed to recipient in L2. |
|
||||
|
||||
### FinalizeWithdrawERC20
|
||||
|
||||
```solidity
|
||||
event FinalizeWithdrawERC20(address indexed l1Token, address indexed l2Token, address indexed from, address to, uint256 amount, bytes data)
|
||||
```
|
||||
|
||||
Emitted when ERC20 token is withdrawn from L2 to L1 and transfer to recipient.
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| l1Token `indexed` | address | The address of the token in L1. |
|
||||
| l2Token `indexed` | address | The address of the token in L2. |
|
||||
| from `indexed` | address | The address of sender in L2. |
|
||||
| to | address | The address of recipient in L1. |
|
||||
| amount | uint256 | The amount of token withdrawn from L2 to L1. |
|
||||
| data | bytes | The optional calldata passed to recipient in L1. |
|
||||
|
||||
### Initialized
|
||||
|
||||
```solidity
|
||||
event Initialized(uint8 version)
|
||||
```
|
||||
|
||||
|
||||
|
||||
*Triggered when the contract has been initialized or reinitialized.*
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| version | uint8 | undefined |
|
||||
|
||||
### OwnershipTransferred
|
||||
|
||||
```solidity
|
||||
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner)
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| previousOwner `indexed` | address | undefined |
|
||||
| newOwner `indexed` | address | undefined |
|
||||
|
||||
### RefundERC20
|
||||
|
||||
```solidity
|
||||
event RefundERC20(address indexed token, address indexed recipient, uint256 amount)
|
||||
```
|
||||
|
||||
Emitted when some ERC20 token is refunded.
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| token `indexed` | address | The address of the token in L1. |
|
||||
| recipient `indexed` | address | The address of receiver in L1. |
|
||||
| amount | uint256 | The amount of token refunded to receiver. |
|
||||
|
||||
|
||||
|
||||
## Errors
|
||||
|
||||
### ErrorCallerIsNotCounterpartGateway
|
||||
|
||||
```solidity
|
||||
error ErrorCallerIsNotCounterpartGateway()
|
||||
```
|
||||
|
||||
|
||||
|
||||
*Thrown when the cross chain sender is not the counterpart gateway contract.*
|
||||
|
||||
|
||||
### ErrorCallerIsNotMessenger
|
||||
|
||||
```solidity
|
||||
error ErrorCallerIsNotMessenger()
|
||||
```
|
||||
|
||||
|
||||
|
||||
*Thrown when the caller is not corresponding `L1ScrollMessenger` or `L2ScrollMessenger`.*
|
||||
|
||||
|
||||
### ErrorNotInDropMessageContext
|
||||
|
||||
```solidity
|
||||
error ErrorNotInDropMessageContext()
|
||||
```
|
||||
|
||||
|
||||
|
||||
*Thrown when ScrollMessenger is not dropping message.*
|
||||
|
||||
|
||||
### ErrorZeroAddress
|
||||
|
||||
```solidity
|
||||
error ErrorZeroAddress()
|
||||
```
|
||||
|
||||
|
||||
|
||||
*Thrown when the given address is `address(0)`.*
|
||||
|
||||
|
||||
|
||||
545
contracts/docs/apis/L2ERC1155Gateway.md
Normal file
545
contracts/docs/apis/L2ERC1155Gateway.md
Normal file
@@ -0,0 +1,545 @@
|
||||
# L2ERC1155Gateway
|
||||
|
||||
|
||||
|
||||
> L2ERC1155Gateway
|
||||
|
||||
The `L2ERC1155Gateway` is used to withdraw ERC1155 compatible NFTs on layer 2 and finalize deposit the NFTs from layer 1.
|
||||
|
||||
*The withdrawn NFTs tokens will be burned directly. On finalizing deposit, the corresponding NFT will be minted and transferred to the recipient. This will be changed if we have more specific scenarios.*
|
||||
|
||||
## Methods
|
||||
|
||||
### batchWithdrawERC1155
|
||||
|
||||
```solidity
|
||||
function batchWithdrawERC1155(address _token, uint256[] _tokenIds, uint256[] _amounts, uint256 _gasLimit) external payable
|
||||
```
|
||||
|
||||
Batch withdraw a list of ERC1155 NFT to caller's account on layer 1.
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _token | address | undefined |
|
||||
| _tokenIds | uint256[] | undefined |
|
||||
| _amounts | uint256[] | undefined |
|
||||
| _gasLimit | uint256 | undefined |
|
||||
|
||||
### batchWithdrawERC1155
|
||||
|
||||
```solidity
|
||||
function batchWithdrawERC1155(address _token, address _to, uint256[] _tokenIds, uint256[] _amounts, uint256 _gasLimit) external payable
|
||||
```
|
||||
|
||||
Batch withdraw a list of ERC1155 NFT to caller's account on layer 1.
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _token | address | undefined |
|
||||
| _to | address | undefined |
|
||||
| _tokenIds | uint256[] | undefined |
|
||||
| _amounts | uint256[] | undefined |
|
||||
| _gasLimit | uint256 | undefined |
|
||||
|
||||
### counterpart
|
||||
|
||||
```solidity
|
||||
function counterpart() external view returns (address)
|
||||
```
|
||||
|
||||
The address of corresponding L1/L2 Gateway contract.
|
||||
|
||||
|
||||
|
||||
|
||||
#### Returns
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _0 | address | undefined |
|
||||
|
||||
### finalizeBatchDepositERC1155
|
||||
|
||||
```solidity
|
||||
function finalizeBatchDepositERC1155(address _l1Token, address _l2Token, address _from, address _to, uint256[] _tokenIds, uint256[] _amounts) external nonpayable
|
||||
```
|
||||
|
||||
Complete ERC1155 deposit from layer 1 to layer 2 and send NFT to recipient's account on layer 2.
|
||||
|
||||
*Requirements: - The function should only be called by L2ScrollMessenger. - The function should also only be called by L1ERC1155Gateway on layer 1.*
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _l1Token | address | undefined |
|
||||
| _l2Token | address | undefined |
|
||||
| _from | address | undefined |
|
||||
| _to | address | undefined |
|
||||
| _tokenIds | uint256[] | undefined |
|
||||
| _amounts | uint256[] | undefined |
|
||||
|
||||
### finalizeDepositERC1155
|
||||
|
||||
```solidity
|
||||
function finalizeDepositERC1155(address _l1Token, address _l2Token, address _from, address _to, uint256 _tokenId, uint256 _amount) external nonpayable
|
||||
```
|
||||
|
||||
Complete ERC1155 deposit from layer 1 to layer 2 and send NFT to recipient's account on layer 2.
|
||||
|
||||
*Requirements: - The function should only be called by L2ScrollMessenger. - The function should also only be called by L1ERC1155Gateway on layer 1.*
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _l1Token | address | undefined |
|
||||
| _l2Token | address | undefined |
|
||||
| _from | address | undefined |
|
||||
| _to | address | undefined |
|
||||
| _tokenId | uint256 | undefined |
|
||||
| _amount | uint256 | undefined |
|
||||
|
||||
### initialize
|
||||
|
||||
```solidity
|
||||
function initialize(address _counterpart, address _messenger) external nonpayable
|
||||
```
|
||||
|
||||
Initialize the storage of `L2ERC1155Gateway`.
|
||||
|
||||
*The parameters `_counterpart` and `_messenger` are no longer used.*
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _counterpart | address | The address of `L1ERC1155Gateway` contract in L1. |
|
||||
| _messenger | address | The address of `L2ScrollMessenger` contract in L2. |
|
||||
|
||||
### messenger
|
||||
|
||||
```solidity
|
||||
function messenger() external view returns (address)
|
||||
```
|
||||
|
||||
The address of corresponding L1ScrollMessenger/L2ScrollMessenger contract.
|
||||
|
||||
|
||||
|
||||
|
||||
#### Returns
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _0 | address | undefined |
|
||||
|
||||
### onERC1155BatchReceived
|
||||
|
||||
```solidity
|
||||
function onERC1155BatchReceived(address, address, uint256[], uint256[], bytes) external nonpayable returns (bytes4)
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _0 | address | undefined |
|
||||
| _1 | address | undefined |
|
||||
| _2 | uint256[] | undefined |
|
||||
| _3 | uint256[] | undefined |
|
||||
| _4 | bytes | undefined |
|
||||
|
||||
#### Returns
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _0 | bytes4 | undefined |
|
||||
|
||||
### onERC1155Received
|
||||
|
||||
```solidity
|
||||
function onERC1155Received(address, address, uint256, uint256, bytes) external nonpayable returns (bytes4)
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _0 | address | undefined |
|
||||
| _1 | address | undefined |
|
||||
| _2 | uint256 | undefined |
|
||||
| _3 | uint256 | undefined |
|
||||
| _4 | bytes | undefined |
|
||||
|
||||
#### Returns
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _0 | bytes4 | undefined |
|
||||
|
||||
### owner
|
||||
|
||||
```solidity
|
||||
function owner() external view returns (address)
|
||||
```
|
||||
|
||||
|
||||
|
||||
*Returns the address of the current owner.*
|
||||
|
||||
|
||||
#### Returns
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _0 | address | undefined |
|
||||
|
||||
### renounceOwnership
|
||||
|
||||
```solidity
|
||||
function renounceOwnership() external nonpayable
|
||||
```
|
||||
|
||||
|
||||
|
||||
*Leaves the contract without owner. It will not be possible to call `onlyOwner` functions. Can only be called by the current owner. NOTE: Renouncing ownership will leave the contract without an owner, thereby disabling any functionality that is only available to the owner.*
|
||||
|
||||
|
||||
### router
|
||||
|
||||
```solidity
|
||||
function router() external view returns (address)
|
||||
```
|
||||
|
||||
The address of L1GatewayRouter/L2GatewayRouter contract.
|
||||
|
||||
|
||||
|
||||
|
||||
#### Returns
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _0 | address | undefined |
|
||||
|
||||
### supportsInterface
|
||||
|
||||
```solidity
|
||||
function supportsInterface(bytes4 interfaceId) external view returns (bool)
|
||||
```
|
||||
|
||||
|
||||
|
||||
*See {IERC165-supportsInterface}.*
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| interfaceId | bytes4 | undefined |
|
||||
|
||||
#### Returns
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _0 | bool | undefined |
|
||||
|
||||
### tokenMapping
|
||||
|
||||
```solidity
|
||||
function tokenMapping(address) external view returns (address)
|
||||
```
|
||||
|
||||
Mapping from layer 2 token address to layer 1 token address for ERC1155 NFT.
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _0 | address | undefined |
|
||||
|
||||
#### Returns
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _0 | address | undefined |
|
||||
|
||||
### transferOwnership
|
||||
|
||||
```solidity
|
||||
function transferOwnership(address newOwner) external nonpayable
|
||||
```
|
||||
|
||||
|
||||
|
||||
*Transfers ownership of the contract to a new account (`newOwner`). Can only be called by the current owner.*
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| newOwner | address | undefined |
|
||||
|
||||
### updateTokenMapping
|
||||
|
||||
```solidity
|
||||
function updateTokenMapping(address _l2Token, address _l1Token) external nonpayable
|
||||
```
|
||||
|
||||
Update layer 2 to layer 1 token mapping.
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _l2Token | address | The address of corresponding ERC1155 token on layer 2. |
|
||||
| _l1Token | address | The address of ERC1155 token on layer 1. |
|
||||
|
||||
### withdrawERC1155
|
||||
|
||||
```solidity
|
||||
function withdrawERC1155(address _token, uint256 _tokenId, uint256 _amount, uint256 _gasLimit) external payable
|
||||
```
|
||||
|
||||
Withdraw some ERC1155 NFT to caller's account on layer 1.
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _token | address | undefined |
|
||||
| _tokenId | uint256 | undefined |
|
||||
| _amount | uint256 | undefined |
|
||||
| _gasLimit | uint256 | undefined |
|
||||
|
||||
### withdrawERC1155
|
||||
|
||||
```solidity
|
||||
function withdrawERC1155(address _token, address _to, uint256 _tokenId, uint256 _amount, uint256 _gasLimit) external payable
|
||||
```
|
||||
|
||||
Withdraw some ERC1155 NFT to caller's account on layer 1.
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _token | address | undefined |
|
||||
| _to | address | undefined |
|
||||
| _tokenId | uint256 | undefined |
|
||||
| _amount | uint256 | undefined |
|
||||
| _gasLimit | uint256 | undefined |
|
||||
|
||||
|
||||
|
||||
## Events
|
||||
|
||||
### BatchWithdrawERC1155
|
||||
|
||||
```solidity
|
||||
event BatchWithdrawERC1155(address indexed l1Token, address indexed l2Token, address indexed from, address to, uint256[] tokenIds, uint256[] amounts)
|
||||
```
|
||||
|
||||
Emitted when the ERC1155 NFT is batch transferred to gateway on layer 2.
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| l1Token `indexed` | address | The address of ERC1155 NFT on layer 1. |
|
||||
| l2Token `indexed` | address | The address of ERC1155 NFT on layer 2. |
|
||||
| from `indexed` | address | The address of sender on layer 2. |
|
||||
| to | address | The address of recipient on layer 1. |
|
||||
| tokenIds | uint256[] | The list of token ids of the ERC1155 NFT to withdraw on layer 2. |
|
||||
| amounts | uint256[] | The list of corresponding amounts to withdraw. |
|
||||
|
||||
### FinalizeBatchDepositERC1155
|
||||
|
||||
```solidity
|
||||
event FinalizeBatchDepositERC1155(address indexed l1Token, address indexed l2Token, address indexed from, address to, uint256[] tokenIds, uint256[] amounts)
|
||||
```
|
||||
|
||||
Emitted when the ERC1155 NFT is batch transferred to recipient on layer 2.
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| l1Token `indexed` | address | The address of ERC1155 NFT on layer 1. |
|
||||
| l2Token `indexed` | address | The address of ERC1155 NFT on layer 2. |
|
||||
| from `indexed` | address | The address of sender on layer 1. |
|
||||
| to | address | The address of recipient on layer 2. |
|
||||
| tokenIds | uint256[] | The list of token ids of the ERC1155 NFT deposited on layer 1. |
|
||||
| amounts | uint256[] | The list of corresponding amounts deposited. |
|
||||
|
||||
### FinalizeDepositERC1155
|
||||
|
||||
```solidity
|
||||
event FinalizeDepositERC1155(address indexed l1Token, address indexed l2Token, address indexed from, address to, uint256 tokenId, uint256 amount)
|
||||
```
|
||||
|
||||
Emitted when the ERC1155 NFT is transferred to recipient on layer 2.
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| l1Token `indexed` | address | The address of ERC1155 NFT on layer 1. |
|
||||
| l2Token `indexed` | address | The address of ERC1155 NFT on layer 2. |
|
||||
| from `indexed` | address | The address of sender on layer 1. |
|
||||
| to | address | The address of recipient on layer 2. |
|
||||
| tokenId | uint256 | The token id of the ERC1155 NFT deposited on layer 1. |
|
||||
| amount | uint256 | The amount of token deposited. |
|
||||
|
||||
### Initialized
|
||||
|
||||
```solidity
|
||||
event Initialized(uint8 version)
|
||||
```
|
||||
|
||||
|
||||
|
||||
*Triggered when the contract has been initialized or reinitialized.*
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| version | uint8 | undefined |
|
||||
|
||||
### OwnershipTransferred
|
||||
|
||||
```solidity
|
||||
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner)
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| previousOwner `indexed` | address | undefined |
|
||||
| newOwner `indexed` | address | undefined |
|
||||
|
||||
### UpdateTokenMapping
|
||||
|
||||
```solidity
|
||||
event UpdateTokenMapping(address indexed l2Token, address indexed oldL1Token, address indexed newL1Token)
|
||||
```
|
||||
|
||||
Emitted when token mapping for ERC1155 token is updated.
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| l2Token `indexed` | address | The address of corresponding ERC1155 token in layer 2. |
|
||||
| oldL1Token `indexed` | address | The address of the old corresponding ERC1155 token in layer 1. |
|
||||
| newL1Token `indexed` | address | The address of the new corresponding ERC1155 token in layer 1. |
|
||||
|
||||
### WithdrawERC1155
|
||||
|
||||
```solidity
|
||||
event WithdrawERC1155(address indexed l1Token, address indexed l2Token, address indexed from, address to, uint256 tokenId, uint256 amount)
|
||||
```
|
||||
|
||||
Emitted when the ERC1155 NFT is transferred to gateway on layer 2.
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| l1Token `indexed` | address | The address of ERC1155 NFT on layer 1. |
|
||||
| l2Token `indexed` | address | The address of ERC1155 NFT on layer 2. |
|
||||
| from `indexed` | address | The address of sender on layer 2. |
|
||||
| to | address | The address of recipient on layer 1. |
|
||||
| tokenId | uint256 | The token id of the ERC1155 NFT to withdraw on layer 2. |
|
||||
| amount | uint256 | The amount of token to withdraw. |
|
||||
|
||||
|
||||
|
||||
## Errors
|
||||
|
||||
### ErrorCallerIsNotCounterpartGateway
|
||||
|
||||
```solidity
|
||||
error ErrorCallerIsNotCounterpartGateway()
|
||||
```
|
||||
|
||||
|
||||
|
||||
*Thrown when the cross chain sender is not the counterpart gateway contract.*
|
||||
|
||||
|
||||
### ErrorCallerIsNotMessenger
|
||||
|
||||
```solidity
|
||||
error ErrorCallerIsNotMessenger()
|
||||
```
|
||||
|
||||
|
||||
|
||||
*Thrown when the caller is not corresponding `L1ScrollMessenger` or `L2ScrollMessenger`.*
|
||||
|
||||
|
||||
### ErrorNotInDropMessageContext
|
||||
|
||||
```solidity
|
||||
error ErrorNotInDropMessageContext()
|
||||
```
|
||||
|
||||
|
||||
|
||||
*Thrown when ScrollMessenger is not dropping message.*
|
||||
|
||||
|
||||
### ErrorZeroAddress
|
||||
|
||||
```solidity
|
||||
error ErrorZeroAddress()
|
||||
```
|
||||
|
||||
|
||||
|
||||
*Thrown when the given address is `address(0)`.*
|
||||
|
||||
|
||||
|
||||
486
contracts/docs/apis/L2ERC721Gateway.md
Normal file
486
contracts/docs/apis/L2ERC721Gateway.md
Normal file
@@ -0,0 +1,486 @@
|
||||
# L2ERC721Gateway
|
||||
|
||||
|
||||
|
||||
> L2ERC721Gateway
|
||||
|
||||
The `L2ERC721Gateway` is used to withdraw ERC721 compatible NFTs on layer 2 and finalize deposit the NFTs from layer 1.
|
||||
|
||||
*The withdrawn NFTs tokens will be burned directly. On finalizing deposit, the corresponding NFT will be minted and transferred to the recipient. This will be changed if we have more specific scenarios.*
|
||||
|
||||
## Methods
|
||||
|
||||
### batchWithdrawERC721
|
||||
|
||||
```solidity
|
||||
function batchWithdrawERC721(address _token, uint256[] _tokenIds, uint256 _gasLimit) external payable
|
||||
```
|
||||
|
||||
Batch withdraw a list of ERC721 NFT to caller's account on layer 1.
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _token | address | undefined |
|
||||
| _tokenIds | uint256[] | undefined |
|
||||
| _gasLimit | uint256 | undefined |
|
||||
|
||||
### batchWithdrawERC721
|
||||
|
||||
```solidity
|
||||
function batchWithdrawERC721(address _token, address _to, uint256[] _tokenIds, uint256 _gasLimit) external payable
|
||||
```
|
||||
|
||||
Batch withdraw a list of ERC721 NFT to caller's account on layer 1.
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _token | address | undefined |
|
||||
| _to | address | undefined |
|
||||
| _tokenIds | uint256[] | undefined |
|
||||
| _gasLimit | uint256 | undefined |
|
||||
|
||||
### counterpart
|
||||
|
||||
```solidity
|
||||
function counterpart() external view returns (address)
|
||||
```
|
||||
|
||||
The address of corresponding L1/L2 Gateway contract.
|
||||
|
||||
|
||||
|
||||
|
||||
#### Returns
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _0 | address | undefined |
|
||||
|
||||
### finalizeBatchDepositERC721
|
||||
|
||||
```solidity
|
||||
function finalizeBatchDepositERC721(address _l1Token, address _l2Token, address _from, address _to, uint256[] _tokenIds) external nonpayable
|
||||
```
|
||||
|
||||
Complete ERC721 deposit from layer 1 to layer 2 and send NFT to recipient's account on layer 2.
|
||||
|
||||
*Requirements: - The function should only be called by L2ScrollMessenger. - The function should also only be called by L1ERC721Gateway on layer 1.*
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _l1Token | address | undefined |
|
||||
| _l2Token | address | undefined |
|
||||
| _from | address | undefined |
|
||||
| _to | address | undefined |
|
||||
| _tokenIds | uint256[] | undefined |
|
||||
|
||||
### finalizeDepositERC721
|
||||
|
||||
```solidity
|
||||
function finalizeDepositERC721(address _l1Token, address _l2Token, address _from, address _to, uint256 _tokenId) external nonpayable
|
||||
```
|
||||
|
||||
Complete ERC721 deposit from layer 1 to layer 2 and send NFT to recipient's account on layer 2.
|
||||
|
||||
*Requirements: - The function should only be called by L2ScrollMessenger. - The function should also only be called by L1ERC721Gateway on layer 1.*
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _l1Token | address | undefined |
|
||||
| _l2Token | address | undefined |
|
||||
| _from | address | undefined |
|
||||
| _to | address | undefined |
|
||||
| _tokenId | uint256 | undefined |
|
||||
|
||||
### initialize
|
||||
|
||||
```solidity
|
||||
function initialize(address _counterpart, address _messenger) external nonpayable
|
||||
```
|
||||
|
||||
Initialize the storage of `L2ERC721Gateway`.
|
||||
|
||||
*The parameters `_counterpart` and `_messenger` are no longer used.*
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _counterpart | address | The address of `L1ERC721Gateway` contract in L1. |
|
||||
| _messenger | address | The address of `L2ScrollMessenger` contract in L2. |
|
||||
|
||||
### messenger
|
||||
|
||||
```solidity
|
||||
function messenger() external view returns (address)
|
||||
```
|
||||
|
||||
The address of corresponding L1ScrollMessenger/L2ScrollMessenger contract.
|
||||
|
||||
|
||||
|
||||
|
||||
#### Returns
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _0 | address | undefined |
|
||||
|
||||
### onERC721Received
|
||||
|
||||
```solidity
|
||||
function onERC721Received(address, address, uint256, bytes) external nonpayable returns (bytes4)
|
||||
```
|
||||
|
||||
|
||||
|
||||
*See {IERC721Receiver-onERC721Received}. Always returns `IERC721Receiver.onERC721Received.selector`.*
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _0 | address | undefined |
|
||||
| _1 | address | undefined |
|
||||
| _2 | uint256 | undefined |
|
||||
| _3 | bytes | undefined |
|
||||
|
||||
#### Returns
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _0 | bytes4 | undefined |
|
||||
|
||||
### owner
|
||||
|
||||
```solidity
|
||||
function owner() external view returns (address)
|
||||
```
|
||||
|
||||
|
||||
|
||||
*Returns the address of the current owner.*
|
||||
|
||||
|
||||
#### Returns
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _0 | address | undefined |
|
||||
|
||||
### renounceOwnership
|
||||
|
||||
```solidity
|
||||
function renounceOwnership() external nonpayable
|
||||
```
|
||||
|
||||
|
||||
|
||||
*Leaves the contract without owner. It will not be possible to call `onlyOwner` functions. Can only be called by the current owner. NOTE: Renouncing ownership will leave the contract without an owner, thereby disabling any functionality that is only available to the owner.*
|
||||
|
||||
|
||||
### router
|
||||
|
||||
```solidity
|
||||
function router() external view returns (address)
|
||||
```
|
||||
|
||||
The address of L1GatewayRouter/L2GatewayRouter contract.
|
||||
|
||||
|
||||
|
||||
|
||||
#### Returns
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _0 | address | undefined |
|
||||
|
||||
### tokenMapping
|
||||
|
||||
```solidity
|
||||
function tokenMapping(address) external view returns (address)
|
||||
```
|
||||
|
||||
Mapping from layer 2 token address to layer 1 token address for ERC721 NFT.
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _0 | address | undefined |
|
||||
|
||||
#### Returns
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _0 | address | undefined |
|
||||
|
||||
### transferOwnership
|
||||
|
||||
```solidity
|
||||
function transferOwnership(address newOwner) external nonpayable
|
||||
```
|
||||
|
||||
|
||||
|
||||
*Transfers ownership of the contract to a new account (`newOwner`). Can only be called by the current owner.*
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| newOwner | address | undefined |
|
||||
|
||||
### updateTokenMapping
|
||||
|
||||
```solidity
|
||||
function updateTokenMapping(address _l2Token, address _l1Token) external nonpayable
|
||||
```
|
||||
|
||||
Update layer 2 to layer 1 token mapping.
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _l2Token | address | The address of corresponding ERC721 token on layer 2. |
|
||||
| _l1Token | address | The address of ERC721 token on layer 1. |
|
||||
|
||||
### withdrawERC721
|
||||
|
||||
```solidity
|
||||
function withdrawERC721(address _token, uint256 _tokenId, uint256 _gasLimit) external payable
|
||||
```
|
||||
|
||||
Withdraw some ERC721 NFT to caller's account on layer 1.
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _token | address | undefined |
|
||||
| _tokenId | uint256 | undefined |
|
||||
| _gasLimit | uint256 | undefined |
|
||||
|
||||
### withdrawERC721
|
||||
|
||||
```solidity
|
||||
function withdrawERC721(address _token, address _to, uint256 _tokenId, uint256 _gasLimit) external payable
|
||||
```
|
||||
|
||||
Withdraw some ERC721 NFT to caller's account on layer 1.
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _token | address | undefined |
|
||||
| _to | address | undefined |
|
||||
| _tokenId | uint256 | undefined |
|
||||
| _gasLimit | uint256 | undefined |
|
||||
|
||||
|
||||
|
||||
## Events
|
||||
|
||||
### BatchWithdrawERC721
|
||||
|
||||
```solidity
|
||||
event BatchWithdrawERC721(address indexed l1Token, address indexed l2Token, address indexed from, address to, uint256[] tokenIds)
|
||||
```
|
||||
|
||||
Emitted when the ERC721 NFT is batch transferred to gateway on layer 2.
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| l1Token `indexed` | address | The address of ERC721 NFT on layer 1. |
|
||||
| l2Token `indexed` | address | The address of ERC721 NFT on layer 2. |
|
||||
| from `indexed` | address | The address of sender on layer 2. |
|
||||
| to | address | The address of recipient on layer 1. |
|
||||
| tokenIds | uint256[] | The list of token ids of the ERC721 NFT to withdraw on layer 2. |
|
||||
|
||||
### FinalizeBatchDepositERC721
|
||||
|
||||
```solidity
|
||||
event FinalizeBatchDepositERC721(address indexed l1Token, address indexed l2Token, address indexed from, address to, uint256[] tokenIds)
|
||||
```
|
||||
|
||||
Emitted when the ERC721 NFT is batch transferred to recipient on layer 2.
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| l1Token `indexed` | address | The address of ERC721 NFT on layer 1. |
|
||||
| l2Token `indexed` | address | The address of ERC721 NFT on layer 2. |
|
||||
| from `indexed` | address | The address of sender on layer 1. |
|
||||
| to | address | The address of recipient on layer 2. |
|
||||
| tokenIds | uint256[] | The list of token ids of the ERC721 NFT deposited on layer 1. |
|
||||
|
||||
### FinalizeDepositERC721
|
||||
|
||||
```solidity
|
||||
event FinalizeDepositERC721(address indexed l1Token, address indexed l2Token, address indexed from, address to, uint256 tokenId)
|
||||
```
|
||||
|
||||
Emitted when the ERC721 NFT is transferred to recipient on layer 2.
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| l1Token `indexed` | address | The address of ERC721 NFT on layer 1. |
|
||||
| l2Token `indexed` | address | The address of ERC721 NFT on layer 2. |
|
||||
| from `indexed` | address | The address of sender on layer 1. |
|
||||
| to | address | The address of recipient on layer 2. |
|
||||
| tokenId | uint256 | The token id of the ERC721 NFT deposited on layer 1. |
|
||||
|
||||
### Initialized
|
||||
|
||||
```solidity
|
||||
event Initialized(uint8 version)
|
||||
```
|
||||
|
||||
|
||||
|
||||
*Triggered when the contract has been initialized or reinitialized.*
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| version | uint8 | undefined |
|
||||
|
||||
### OwnershipTransferred
|
||||
|
||||
```solidity
|
||||
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner)
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| previousOwner `indexed` | address | undefined |
|
||||
| newOwner `indexed` | address | undefined |
|
||||
|
||||
### UpdateTokenMapping
|
||||
|
||||
```solidity
|
||||
event UpdateTokenMapping(address indexed l2Token, address indexed oldL1Token, address indexed newL1Token)
|
||||
```
|
||||
|
||||
Emitted when token mapping for ERC721 token is updated.
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| l2Token `indexed` | address | The address of corresponding ERC721 token in layer 2. |
|
||||
| oldL1Token `indexed` | address | The address of the old corresponding ERC721 token in layer 1. |
|
||||
| newL1Token `indexed` | address | The address of the new corresponding ERC721 token in layer 1. |
|
||||
|
||||
### WithdrawERC721
|
||||
|
||||
```solidity
|
||||
event WithdrawERC721(address indexed l1Token, address indexed l2Token, address indexed from, address to, uint256 tokenId)
|
||||
```
|
||||
|
||||
Emitted when the ERC721 NFT is transferred to gateway on layer 2.
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| l1Token `indexed` | address | The address of ERC721 NFT on layer 1. |
|
||||
| l2Token `indexed` | address | The address of ERC721 NFT on layer 2. |
|
||||
| from `indexed` | address | The address of sender on layer 2. |
|
||||
| to | address | The address of recipient on layer 1. |
|
||||
| tokenId | uint256 | The token id of the ERC721 NFT to withdraw on layer 2. |
|
||||
|
||||
|
||||
|
||||
## Errors
|
||||
|
||||
### ErrorCallerIsNotCounterpartGateway
|
||||
|
||||
```solidity
|
||||
error ErrorCallerIsNotCounterpartGateway()
|
||||
```
|
||||
|
||||
|
||||
|
||||
*Thrown when the cross chain sender is not the counterpart gateway contract.*
|
||||
|
||||
|
||||
### ErrorCallerIsNotMessenger
|
||||
|
||||
```solidity
|
||||
error ErrorCallerIsNotMessenger()
|
||||
```
|
||||
|
||||
|
||||
|
||||
*Thrown when the caller is not corresponding `L1ScrollMessenger` or `L2ScrollMessenger`.*
|
||||
|
||||
|
||||
### ErrorNotInDropMessageContext
|
||||
|
||||
```solidity
|
||||
error ErrorNotInDropMessageContext()
|
||||
```
|
||||
|
||||
|
||||
|
||||
*Thrown when ScrollMessenger is not dropping message.*
|
||||
|
||||
|
||||
### ErrorZeroAddress
|
||||
|
||||
```solidity
|
||||
error ErrorZeroAddress()
|
||||
```
|
||||
|
||||
|
||||
|
||||
*Thrown when the given address is `address(0)`.*
|
||||
|
||||
|
||||
|
||||
566
contracts/docs/apis/L2GatewayRouter.md
Normal file
566
contracts/docs/apis/L2GatewayRouter.md
Normal file
@@ -0,0 +1,566 @@
|
||||
# L2GatewayRouter
|
||||
|
||||
|
||||
|
||||
> L2GatewayRouter
|
||||
|
||||
The `L2GatewayRouter` is the main entry for withdrawing Ether and ERC20 tokens. All deposited tokens are routed to corresponding gateways.
|
||||
|
||||
*One can also use this contract to query L1/L2 token address mapping. In the future, ERC-721 and ERC-1155 tokens will be added to the router too.*
|
||||
|
||||
## Methods
|
||||
|
||||
### ERC20Gateway
|
||||
|
||||
```solidity
|
||||
function ERC20Gateway(address) external view returns (address)
|
||||
```
|
||||
|
||||
Mapping from L2 ERC20 token address to corresponding L2ERC20Gateway.
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _0 | address | undefined |
|
||||
|
||||
#### Returns
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _0 | address | undefined |
|
||||
|
||||
### defaultERC20Gateway
|
||||
|
||||
```solidity
|
||||
function defaultERC20Gateway() external view returns (address)
|
||||
```
|
||||
|
||||
The addess of default L2 ERC20 gateway, normally the L2StandardERC20Gateway contract.
|
||||
|
||||
|
||||
|
||||
|
||||
#### Returns
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _0 | address | undefined |
|
||||
|
||||
### ethGateway
|
||||
|
||||
```solidity
|
||||
function ethGateway() external view returns (address)
|
||||
```
|
||||
|
||||
The address of L2ETHGateway.
|
||||
|
||||
|
||||
|
||||
|
||||
#### Returns
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _0 | address | undefined |
|
||||
|
||||
### finalizeDepositERC20
|
||||
|
||||
```solidity
|
||||
function finalizeDepositERC20(address, address, address, address, uint256, bytes) external payable
|
||||
```
|
||||
|
||||
Complete a deposit from L1 to L2 and send fund to recipient's account in L2.
|
||||
|
||||
*Make this function payable to handle WETH deposit/withdraw. The function should only be called by L2ScrollMessenger. The function should also only be called by L1ERC20Gateway in L1.*
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _0 | address | undefined |
|
||||
| _1 | address | undefined |
|
||||
| _2 | address | undefined |
|
||||
| _3 | address | undefined |
|
||||
| _4 | uint256 | undefined |
|
||||
| _5 | bytes | undefined |
|
||||
|
||||
### finalizeDepositETH
|
||||
|
||||
```solidity
|
||||
function finalizeDepositETH(address, address, uint256, bytes) external payable
|
||||
```
|
||||
|
||||
Complete ETH deposit from L1 to L2 and send fund to recipient's account in L2.
|
||||
|
||||
*This function should only be called by L2ScrollMessenger. This function should also only be called by L1GatewayRouter in L1.*
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _0 | address | undefined |
|
||||
| _1 | address | undefined |
|
||||
| _2 | uint256 | undefined |
|
||||
| _3 | bytes | undefined |
|
||||
|
||||
### getERC20Gateway
|
||||
|
||||
```solidity
|
||||
function getERC20Gateway(address _token) external view returns (address)
|
||||
```
|
||||
|
||||
Return the corresponding gateway address for given token address.
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _token | address | The address of token to query. |
|
||||
|
||||
#### Returns
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _0 | address | undefined |
|
||||
|
||||
### getL1ERC20Address
|
||||
|
||||
```solidity
|
||||
function getL1ERC20Address(address _l2Address) external view returns (address)
|
||||
```
|
||||
|
||||
Return the corresponding l1 token address given l2 token address.
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _l2Address | address | undefined |
|
||||
|
||||
#### Returns
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _0 | address | undefined |
|
||||
|
||||
### getL2ERC20Address
|
||||
|
||||
```solidity
|
||||
function getL2ERC20Address(address) external pure returns (address)
|
||||
```
|
||||
|
||||
Return the corresponding l2 token address given l1 token address.
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _0 | address | undefined |
|
||||
|
||||
#### Returns
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _0 | address | undefined |
|
||||
|
||||
### initialize
|
||||
|
||||
```solidity
|
||||
function initialize(address _ethGateway, address _defaultERC20Gateway) external nonpayable
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _ethGateway | address | undefined |
|
||||
| _defaultERC20Gateway | address | undefined |
|
||||
|
||||
### owner
|
||||
|
||||
```solidity
|
||||
function owner() external view returns (address)
|
||||
```
|
||||
|
||||
|
||||
|
||||
*Returns the address of the current owner.*
|
||||
|
||||
|
||||
#### Returns
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _0 | address | undefined |
|
||||
|
||||
### renounceOwnership
|
||||
|
||||
```solidity
|
||||
function renounceOwnership() external nonpayable
|
||||
```
|
||||
|
||||
|
||||
|
||||
*Leaves the contract without owner. It will not be possible to call `onlyOwner` functions. Can only be called by the current owner. NOTE: Renouncing ownership will leave the contract without an owner, thereby disabling any functionality that is only available to the owner.*
|
||||
|
||||
|
||||
### setDefaultERC20Gateway
|
||||
|
||||
```solidity
|
||||
function setDefaultERC20Gateway(address _newDefaultERC20Gateway) external nonpayable
|
||||
```
|
||||
|
||||
Update the address of default ERC20 gateway contract.
|
||||
|
||||
*This function should only be called by contract owner.*
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _newDefaultERC20Gateway | address | The address to update. |
|
||||
|
||||
### setERC20Gateway
|
||||
|
||||
```solidity
|
||||
function setERC20Gateway(address[] _tokens, address[] _gateways) external nonpayable
|
||||
```
|
||||
|
||||
Update the mapping from token address to gateway address.
|
||||
|
||||
*This function should only be called by contract owner.*
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _tokens | address[] | The list of addresses of tokens to update. |
|
||||
| _gateways | address[] | The list of addresses of gateways to update. |
|
||||
|
||||
### setETHGateway
|
||||
|
||||
```solidity
|
||||
function setETHGateway(address _newEthGateway) external nonpayable
|
||||
```
|
||||
|
||||
Update the address of ETH gateway contract.
|
||||
|
||||
*This function should only be called by contract owner.*
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _newEthGateway | address | The address to update. |
|
||||
|
||||
### transferOwnership
|
||||
|
||||
```solidity
|
||||
function transferOwnership(address newOwner) external nonpayable
|
||||
```
|
||||
|
||||
|
||||
|
||||
*Transfers ownership of the contract to a new account (`newOwner`). Can only be called by the current owner.*
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| newOwner | address | undefined |
|
||||
|
||||
### withdrawERC20
|
||||
|
||||
```solidity
|
||||
function withdrawERC20(address _token, uint256 _amount, uint256 _gasLimit) external payable
|
||||
```
|
||||
|
||||
Withdraw of some token to a caller's account on L1.
|
||||
|
||||
*Make this function payable to send relayer fee in Ether.*
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _token | address | undefined |
|
||||
| _amount | uint256 | undefined |
|
||||
| _gasLimit | uint256 | undefined |
|
||||
|
||||
### withdrawERC20
|
||||
|
||||
```solidity
|
||||
function withdrawERC20(address _token, address _to, uint256 _amount, uint256 _gasLimit) external payable
|
||||
```
|
||||
|
||||
Withdraw of some token to a recipient's account on L1.
|
||||
|
||||
*Make this function payable to send relayer fee in Ether.*
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _token | address | undefined |
|
||||
| _to | address | undefined |
|
||||
| _amount | uint256 | undefined |
|
||||
| _gasLimit | uint256 | undefined |
|
||||
|
||||
### withdrawERC20AndCall
|
||||
|
||||
```solidity
|
||||
function withdrawERC20AndCall(address _token, address _to, uint256 _amount, bytes _data, uint256 _gasLimit) external payable
|
||||
```
|
||||
|
||||
Withdraw of some token to a recipient's account on L1 and call.
|
||||
|
||||
*Make this function payable to send relayer fee in Ether.*
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _token | address | undefined |
|
||||
| _to | address | undefined |
|
||||
| _amount | uint256 | undefined |
|
||||
| _data | bytes | undefined |
|
||||
| _gasLimit | uint256 | undefined |
|
||||
|
||||
### withdrawETH
|
||||
|
||||
```solidity
|
||||
function withdrawETH(address _to, uint256 _amount, uint256 _gasLimit) external payable
|
||||
```
|
||||
|
||||
Withdraw ETH to caller's account in L1.
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _to | address | undefined |
|
||||
| _amount | uint256 | undefined |
|
||||
| _gasLimit | uint256 | undefined |
|
||||
|
||||
### withdrawETH
|
||||
|
||||
```solidity
|
||||
function withdrawETH(uint256 _amount, uint256 _gasLimit) external payable
|
||||
```
|
||||
|
||||
Withdraw ETH to caller's account in L1.
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _amount | uint256 | undefined |
|
||||
| _gasLimit | uint256 | undefined |
|
||||
|
||||
### withdrawETHAndCall
|
||||
|
||||
```solidity
|
||||
function withdrawETHAndCall(address _to, uint256 _amount, bytes _data, uint256 _gasLimit) external payable
|
||||
```
|
||||
|
||||
Withdraw ETH to caller's account in L1.
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _to | address | undefined |
|
||||
| _amount | uint256 | undefined |
|
||||
| _data | bytes | undefined |
|
||||
| _gasLimit | uint256 | undefined |
|
||||
|
||||
|
||||
|
||||
## Events
|
||||
|
||||
### FinalizeDepositERC20
|
||||
|
||||
```solidity
|
||||
event FinalizeDepositERC20(address indexed l1Token, address indexed l2Token, address indexed from, address to, uint256 amount, bytes data)
|
||||
```
|
||||
|
||||
Emitted when ERC20 token is deposited from L1 to L2 and transfer to recipient.
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| l1Token `indexed` | address | The address of the token in L1. |
|
||||
| l2Token `indexed` | address | The address of the token in L2. |
|
||||
| from `indexed` | address | The address of sender in L1. |
|
||||
| to | address | The address of recipient in L2. |
|
||||
| amount | uint256 | The amount of token withdrawn from L1 to L2. |
|
||||
| data | bytes | The optional calldata passed to recipient in L2. |
|
||||
|
||||
### FinalizeDepositETH
|
||||
|
||||
```solidity
|
||||
event FinalizeDepositETH(address indexed from, address indexed to, uint256 amount, bytes data)
|
||||
```
|
||||
|
||||
Emitted when ETH is deposited from L1 to L2 and transfer to recipient.
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| from `indexed` | address | The address of sender in L1. |
|
||||
| to `indexed` | address | The address of recipient in L2. |
|
||||
| amount | uint256 | The amount of ETH deposited from L1 to L2. |
|
||||
| data | bytes | The optional calldata passed to recipient in L2. |
|
||||
|
||||
### Initialized
|
||||
|
||||
```solidity
|
||||
event Initialized(uint8 version)
|
||||
```
|
||||
|
||||
|
||||
|
||||
*Triggered when the contract has been initialized or reinitialized.*
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| version | uint8 | undefined |
|
||||
|
||||
### OwnershipTransferred
|
||||
|
||||
```solidity
|
||||
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner)
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| previousOwner `indexed` | address | undefined |
|
||||
| newOwner `indexed` | address | undefined |
|
||||
|
||||
### SetDefaultERC20Gateway
|
||||
|
||||
```solidity
|
||||
event SetDefaultERC20Gateway(address indexed oldDefaultERC20Gateway, address indexed newDefaultERC20Gateway)
|
||||
```
|
||||
|
||||
Emitted when the address of default ERC20 Gateway is updated.
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| oldDefaultERC20Gateway `indexed` | address | The address of the old default ERC20 Gateway. |
|
||||
| newDefaultERC20Gateway `indexed` | address | The address of the new default ERC20 Gateway. |
|
||||
|
||||
### SetERC20Gateway
|
||||
|
||||
```solidity
|
||||
event SetERC20Gateway(address indexed token, address indexed oldGateway, address indexed newGateway)
|
||||
```
|
||||
|
||||
Emitted when the `gateway` for `token` is updated.
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| token `indexed` | address | The address of token updated. |
|
||||
| oldGateway `indexed` | address | The corresponding address of the old gateway. |
|
||||
| newGateway `indexed` | address | The corresponding address of the new gateway. |
|
||||
|
||||
### SetETHGateway
|
||||
|
||||
```solidity
|
||||
event SetETHGateway(address indexed oldETHGateway, address indexed newEthGateway)
|
||||
```
|
||||
|
||||
Emitted when the address of ETH Gateway is updated.
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| oldETHGateway `indexed` | address | The address of the old ETH Gateway. |
|
||||
| newEthGateway `indexed` | address | The address of the new ETH Gateway. |
|
||||
|
||||
### WithdrawERC20
|
||||
|
||||
```solidity
|
||||
event WithdrawERC20(address indexed l1Token, address indexed l2Token, address indexed from, address to, uint256 amount, bytes data)
|
||||
```
|
||||
|
||||
Emitted when someone withdraw ERC20 token from L2 to L1.
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| l1Token `indexed` | address | The address of the token in L1. |
|
||||
| l2Token `indexed` | address | The address of the token in L2. |
|
||||
| from `indexed` | address | The address of sender in L2. |
|
||||
| to | address | The address of recipient in L1. |
|
||||
| amount | uint256 | The amount of token will be deposited from L2 to L1. |
|
||||
| data | bytes | The optional calldata passed to recipient in L1. |
|
||||
|
||||
### WithdrawETH
|
||||
|
||||
```solidity
|
||||
event WithdrawETH(address indexed from, address indexed to, uint256 amount, bytes data)
|
||||
```
|
||||
|
||||
Emitted when someone withdraw ETH from L2 to L1.
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| from `indexed` | address | The address of sender in L2. |
|
||||
| to `indexed` | address | The address of recipient in L1. |
|
||||
| amount | uint256 | The amount of ETH will be deposited from L2 to L1. |
|
||||
| data | bytes | The optional calldata passed to recipient in L1. |
|
||||
|
||||
|
||||
|
||||
464
contracts/docs/apis/L2ScrollMessenger.md
Normal file
464
contracts/docs/apis/L2ScrollMessenger.md
Normal file
@@ -0,0 +1,464 @@
|
||||
# L2ScrollMessenger
|
||||
|
||||
|
||||
|
||||
> L2ScrollMessenger
|
||||
|
||||
The `L2ScrollMessenger` contract can: 1. send messages from layer 2 to layer 1; 2. relay messages from layer 1 layer 2; 3. drop expired message due to sequencer problems.
|
||||
|
||||
*It should be a predeployed contract on layer 2 and should hold infinite amount of Ether (Specifically, `uint256(-1)`), which can be initialized in Genesis Block.*
|
||||
|
||||
## Methods
|
||||
|
||||
### counterpart
|
||||
|
||||
```solidity
|
||||
function counterpart() external view returns (address)
|
||||
```
|
||||
|
||||
The address of counterpart ScrollMessenger contract in L1/L2.
|
||||
|
||||
|
||||
|
||||
|
||||
#### Returns
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _0 | address | undefined |
|
||||
|
||||
### feeVault
|
||||
|
||||
```solidity
|
||||
function feeVault() external view returns (address)
|
||||
```
|
||||
|
||||
The address of fee vault, collecting cross domain messaging fee.
|
||||
|
||||
|
||||
|
||||
|
||||
#### Returns
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _0 | address | undefined |
|
||||
|
||||
### initialize
|
||||
|
||||
```solidity
|
||||
function initialize(address) external nonpayable
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _0 | address | undefined |
|
||||
|
||||
### isL1MessageExecuted
|
||||
|
||||
```solidity
|
||||
function isL1MessageExecuted(bytes32) external view returns (bool)
|
||||
```
|
||||
|
||||
Mapping from L1 message hash to a boolean value indicating if the message has been successfully executed.
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _0 | bytes32 | undefined |
|
||||
|
||||
#### Returns
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _0 | bool | undefined |
|
||||
|
||||
### messageQueue
|
||||
|
||||
```solidity
|
||||
function messageQueue() external view returns (address)
|
||||
```
|
||||
|
||||
The address of L2MessageQueue.
|
||||
|
||||
|
||||
|
||||
|
||||
#### Returns
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _0 | address | undefined |
|
||||
|
||||
### messageSendTimestamp
|
||||
|
||||
```solidity
|
||||
function messageSendTimestamp(bytes32) external view returns (uint256)
|
||||
```
|
||||
|
||||
Mapping from L2 message hash to the timestamp when the message is sent.
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _0 | bytes32 | undefined |
|
||||
|
||||
#### Returns
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _0 | uint256 | undefined |
|
||||
|
||||
### owner
|
||||
|
||||
```solidity
|
||||
function owner() external view returns (address)
|
||||
```
|
||||
|
||||
|
||||
|
||||
*Returns the address of the current owner.*
|
||||
|
||||
|
||||
#### Returns
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _0 | address | undefined |
|
||||
|
||||
### paused
|
||||
|
||||
```solidity
|
||||
function paused() external view returns (bool)
|
||||
```
|
||||
|
||||
|
||||
|
||||
*Returns true if the contract is paused, and false otherwise.*
|
||||
|
||||
|
||||
#### Returns
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _0 | bool | undefined |
|
||||
|
||||
### relayMessage
|
||||
|
||||
```solidity
|
||||
function relayMessage(address _from, address _to, uint256 _value, uint256 _nonce, bytes _message) external nonpayable
|
||||
```
|
||||
|
||||
execute L1 => L2 message
|
||||
|
||||
*Make sure this is only called by privileged accounts.*
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _from | address | undefined |
|
||||
| _to | address | undefined |
|
||||
| _value | uint256 | undefined |
|
||||
| _nonce | uint256 | undefined |
|
||||
| _message | bytes | undefined |
|
||||
|
||||
### renounceOwnership
|
||||
|
||||
```solidity
|
||||
function renounceOwnership() external nonpayable
|
||||
```
|
||||
|
||||
|
||||
|
||||
*Leaves the contract without owner. It will not be possible to call `onlyOwner` functions. Can only be called by the current owner. NOTE: Renouncing ownership will leave the contract without an owner, thereby disabling any functionality that is only available to the owner.*
|
||||
|
||||
|
||||
### sendMessage
|
||||
|
||||
```solidity
|
||||
function sendMessage(address _to, uint256 _value, bytes _message, uint256 _gasLimit, address) external payable
|
||||
```
|
||||
|
||||
Send cross chain message from L1 to L2 or L2 to L1.
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _to | address | undefined |
|
||||
| _value | uint256 | undefined |
|
||||
| _message | bytes | undefined |
|
||||
| _gasLimit | uint256 | undefined |
|
||||
| _4 | address | undefined |
|
||||
|
||||
### sendMessage
|
||||
|
||||
```solidity
|
||||
function sendMessage(address _to, uint256 _value, bytes _message, uint256 _gasLimit) external payable
|
||||
```
|
||||
|
||||
Send cross chain message from L1 to L2 or L2 to L1.
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _to | address | undefined |
|
||||
| _value | uint256 | undefined |
|
||||
| _message | bytes | undefined |
|
||||
| _gasLimit | uint256 | undefined |
|
||||
|
||||
### setPause
|
||||
|
||||
```solidity
|
||||
function setPause(bool _status) external nonpayable
|
||||
```
|
||||
|
||||
Pause the contract
|
||||
|
||||
*This function can only called by contract owner.*
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _status | bool | The pause status to update. |
|
||||
|
||||
### transferOwnership
|
||||
|
||||
```solidity
|
||||
function transferOwnership(address newOwner) external nonpayable
|
||||
```
|
||||
|
||||
|
||||
|
||||
*Transfers ownership of the contract to a new account (`newOwner`). Can only be called by the current owner.*
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| newOwner | address | undefined |
|
||||
|
||||
### updateFeeVault
|
||||
|
||||
```solidity
|
||||
function updateFeeVault(address _newFeeVault) external nonpayable
|
||||
```
|
||||
|
||||
Update fee vault contract.
|
||||
|
||||
*This function can only called by contract owner.*
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _newFeeVault | address | The address of new fee vault contract. |
|
||||
|
||||
### xDomainMessageSender
|
||||
|
||||
```solidity
|
||||
function xDomainMessageSender() external view returns (address)
|
||||
```
|
||||
|
||||
See {IScrollMessenger-xDomainMessageSender}
|
||||
|
||||
|
||||
|
||||
|
||||
#### Returns
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _0 | address | undefined |
|
||||
|
||||
|
||||
|
||||
## Events
|
||||
|
||||
### FailedRelayedMessage
|
||||
|
||||
```solidity
|
||||
event FailedRelayedMessage(bytes32 indexed messageHash)
|
||||
```
|
||||
|
||||
Emitted when a cross domain message is failed to relay.
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| messageHash `indexed` | bytes32 | The hash of the message. |
|
||||
|
||||
### Initialized
|
||||
|
||||
```solidity
|
||||
event Initialized(uint8 version)
|
||||
```
|
||||
|
||||
|
||||
|
||||
*Triggered when the contract has been initialized or reinitialized.*
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| version | uint8 | undefined |
|
||||
|
||||
### OwnershipTransferred
|
||||
|
||||
```solidity
|
||||
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner)
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| previousOwner `indexed` | address | undefined |
|
||||
| newOwner `indexed` | address | undefined |
|
||||
|
||||
### Paused
|
||||
|
||||
```solidity
|
||||
event Paused(address account)
|
||||
```
|
||||
|
||||
|
||||
|
||||
*Emitted when the pause is triggered by `account`.*
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| account | address | undefined |
|
||||
|
||||
### RelayedMessage
|
||||
|
||||
```solidity
|
||||
event RelayedMessage(bytes32 indexed messageHash)
|
||||
```
|
||||
|
||||
Emitted when a cross domain message is relayed successfully.
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| messageHash `indexed` | bytes32 | The hash of the message. |
|
||||
|
||||
### SentMessage
|
||||
|
||||
```solidity
|
||||
event SentMessage(address indexed sender, address indexed target, uint256 value, uint256 messageNonce, uint256 gasLimit, bytes message)
|
||||
```
|
||||
|
||||
Emitted when a cross domain message is sent.
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| sender `indexed` | address | The address of the sender who initiates the message. |
|
||||
| target `indexed` | address | The address of target contract to call. |
|
||||
| value | uint256 | The amount of value passed to the target contract. |
|
||||
| messageNonce | uint256 | The nonce of the message. |
|
||||
| gasLimit | uint256 | The optional gas limit passed to L1 or L2. |
|
||||
| message | bytes | The calldata passed to the target contract. |
|
||||
|
||||
### Unpaused
|
||||
|
||||
```solidity
|
||||
event Unpaused(address account)
|
||||
```
|
||||
|
||||
|
||||
|
||||
*Emitted when the pause is lifted by `account`.*
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| account | address | undefined |
|
||||
|
||||
### UpdateFeeVault
|
||||
|
||||
```solidity
|
||||
event UpdateFeeVault(address _oldFeeVault, address _newFeeVault)
|
||||
```
|
||||
|
||||
Emitted when owner updates fee vault contract.
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _oldFeeVault | address | The address of old fee vault contract. |
|
||||
| _newFeeVault | address | The address of new fee vault contract. |
|
||||
|
||||
### UpdateMaxFailedExecutionTimes
|
||||
|
||||
```solidity
|
||||
event UpdateMaxFailedExecutionTimes(uint256 oldMaxFailedExecutionTimes, uint256 newMaxFailedExecutionTimes)
|
||||
```
|
||||
|
||||
Emitted when the maximum number of times each message can fail in L2 is updated.
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| oldMaxFailedExecutionTimes | uint256 | The old maximum number of times each message can fail in L2. |
|
||||
| newMaxFailedExecutionTimes | uint256 | The new maximum number of times each message can fail in L2. |
|
||||
|
||||
|
||||
|
||||
## Errors
|
||||
|
||||
### ErrorZeroAddress
|
||||
|
||||
```solidity
|
||||
error ErrorZeroAddress()
|
||||
```
|
||||
|
||||
|
||||
|
||||
*Thrown when the given address is `address(0)`.*
|
||||
|
||||
|
||||
|
||||
393
contracts/docs/apis/L2StandardERC20Gateway.md
Normal file
393
contracts/docs/apis/L2StandardERC20Gateway.md
Normal file
@@ -0,0 +1,393 @@
|
||||
# L2StandardERC20Gateway
|
||||
|
||||
|
||||
|
||||
> L2StandardERC20Gateway
|
||||
|
||||
The `L2StandardERC20Gateway` is used to withdraw standard ERC20 tokens on layer 2 and finalize deposit the tokens from layer 1.
|
||||
|
||||
*The withdrawn ERC20 tokens will be burned directly. On finalizing deposit, the corresponding token will be minted and transferred to the recipient. Any ERC20 that requires non-standard functionality should use a separate gateway.*
|
||||
|
||||
## Methods
|
||||
|
||||
### counterpart
|
||||
|
||||
```solidity
|
||||
function counterpart() external view returns (address)
|
||||
```
|
||||
|
||||
The address of corresponding L1/L2 Gateway contract.
|
||||
|
||||
|
||||
|
||||
|
||||
#### Returns
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _0 | address | undefined |
|
||||
|
||||
### finalizeDepositERC20
|
||||
|
||||
```solidity
|
||||
function finalizeDepositERC20(address _l1Token, address _l2Token, address _from, address _to, uint256 _amount, bytes _data) external payable
|
||||
```
|
||||
|
||||
Complete a deposit from L1 to L2 and send fund to recipient's account in L2.
|
||||
|
||||
*Make this function payable to handle WETH deposit/withdraw. The function should only be called by L2ScrollMessenger. The function should also only be called by L1ERC20Gateway in L1.*
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _l1Token | address | undefined |
|
||||
| _l2Token | address | undefined |
|
||||
| _from | address | undefined |
|
||||
| _to | address | undefined |
|
||||
| _amount | uint256 | undefined |
|
||||
| _data | bytes | undefined |
|
||||
|
||||
### getL1ERC20Address
|
||||
|
||||
```solidity
|
||||
function getL1ERC20Address(address _l2Token) external view returns (address)
|
||||
```
|
||||
|
||||
Return the corresponding l1 token address given l2 token address.
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _l2Token | address | undefined |
|
||||
|
||||
#### Returns
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _0 | address | undefined |
|
||||
|
||||
### getL2ERC20Address
|
||||
|
||||
```solidity
|
||||
function getL2ERC20Address(address _l1Token) external view returns (address)
|
||||
```
|
||||
|
||||
Return the corresponding l2 token address given l1 token address.
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _l1Token | address | undefined |
|
||||
|
||||
#### Returns
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _0 | address | undefined |
|
||||
|
||||
### initialize
|
||||
|
||||
```solidity
|
||||
function initialize(address _counterpart, address _router, address _messenger, address) external nonpayable
|
||||
```
|
||||
|
||||
Initialize the storage of L2StandardERC20Gateway.
|
||||
|
||||
*The parameters `_counterpart`, `_router`, `_messenger` and `_tokenFactory` are no longer used.*
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _counterpart | address | The address of `L1StandardERC20Gateway` contract in L1. |
|
||||
| _router | address | The address of `L2GatewayRouter` contract in L2. |
|
||||
| _messenger | address | The address of `L2ScrollMessenger` contract in L2. |
|
||||
| _3 | address | undefined |
|
||||
|
||||
### messenger
|
||||
|
||||
```solidity
|
||||
function messenger() external view returns (address)
|
||||
```
|
||||
|
||||
The address of corresponding L1ScrollMessenger/L2ScrollMessenger contract.
|
||||
|
||||
|
||||
|
||||
|
||||
#### Returns
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _0 | address | undefined |
|
||||
|
||||
### owner
|
||||
|
||||
```solidity
|
||||
function owner() external view returns (address)
|
||||
```
|
||||
|
||||
|
||||
|
||||
*Returns the address of the current owner.*
|
||||
|
||||
|
||||
#### Returns
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _0 | address | undefined |
|
||||
|
||||
### renounceOwnership
|
||||
|
||||
```solidity
|
||||
function renounceOwnership() external nonpayable
|
||||
```
|
||||
|
||||
|
||||
|
||||
*Leaves the contract without owner. It will not be possible to call `onlyOwner` functions. Can only be called by the current owner. NOTE: Renouncing ownership will leave the contract without an owner, thereby disabling any functionality that is only available to the owner.*
|
||||
|
||||
|
||||
### router
|
||||
|
||||
```solidity
|
||||
function router() external view returns (address)
|
||||
```
|
||||
|
||||
The address of L1GatewayRouter/L2GatewayRouter contract.
|
||||
|
||||
|
||||
|
||||
|
||||
#### Returns
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _0 | address | undefined |
|
||||
|
||||
### tokenFactory
|
||||
|
||||
```solidity
|
||||
function tokenFactory() external view returns (address)
|
||||
```
|
||||
|
||||
The address of ScrollStandardERC20Factory.
|
||||
|
||||
|
||||
|
||||
|
||||
#### Returns
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _0 | address | undefined |
|
||||
|
||||
### transferOwnership
|
||||
|
||||
```solidity
|
||||
function transferOwnership(address newOwner) external nonpayable
|
||||
```
|
||||
|
||||
|
||||
|
||||
*Transfers ownership of the contract to a new account (`newOwner`). Can only be called by the current owner.*
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| newOwner | address | undefined |
|
||||
|
||||
### withdrawERC20
|
||||
|
||||
```solidity
|
||||
function withdrawERC20(address _token, uint256 _amount, uint256 _gasLimit) external payable
|
||||
```
|
||||
|
||||
Withdraw of some token to a caller's account on L1.
|
||||
|
||||
*Make this function payable to send relayer fee in Ether.*
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _token | address | undefined |
|
||||
| _amount | uint256 | undefined |
|
||||
| _gasLimit | uint256 | undefined |
|
||||
|
||||
### withdrawERC20
|
||||
|
||||
```solidity
|
||||
function withdrawERC20(address _token, address _to, uint256 _amount, uint256 _gasLimit) external payable
|
||||
```
|
||||
|
||||
Withdraw of some token to a recipient's account on L1.
|
||||
|
||||
*Make this function payable to send relayer fee in Ether.*
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _token | address | undefined |
|
||||
| _to | address | undefined |
|
||||
| _amount | uint256 | undefined |
|
||||
| _gasLimit | uint256 | undefined |
|
||||
|
||||
### withdrawERC20AndCall
|
||||
|
||||
```solidity
|
||||
function withdrawERC20AndCall(address _token, address _to, uint256 _amount, bytes _data, uint256 _gasLimit) external payable
|
||||
```
|
||||
|
||||
Withdraw of some token to a recipient's account on L1 and call.
|
||||
|
||||
*Make this function payable to send relayer fee in Ether.*
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _token | address | undefined |
|
||||
| _to | address | undefined |
|
||||
| _amount | uint256 | undefined |
|
||||
| _data | bytes | undefined |
|
||||
| _gasLimit | uint256 | undefined |
|
||||
|
||||
|
||||
|
||||
## Events
|
||||
|
||||
### FinalizeDepositERC20
|
||||
|
||||
```solidity
|
||||
event FinalizeDepositERC20(address indexed l1Token, address indexed l2Token, address indexed from, address to, uint256 amount, bytes data)
|
||||
```
|
||||
|
||||
Emitted when ERC20 token is deposited from L1 to L2 and transfer to recipient.
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| l1Token `indexed` | address | The address of the token in L1. |
|
||||
| l2Token `indexed` | address | The address of the token in L2. |
|
||||
| from `indexed` | address | The address of sender in L1. |
|
||||
| to | address | The address of recipient in L2. |
|
||||
| amount | uint256 | The amount of token withdrawn from L1 to L2. |
|
||||
| data | bytes | The optional calldata passed to recipient in L2. |
|
||||
|
||||
### Initialized
|
||||
|
||||
```solidity
|
||||
event Initialized(uint8 version)
|
||||
```
|
||||
|
||||
|
||||
|
||||
*Triggered when the contract has been initialized or reinitialized.*
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| version | uint8 | undefined |
|
||||
|
||||
### OwnershipTransferred
|
||||
|
||||
```solidity
|
||||
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner)
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| previousOwner `indexed` | address | undefined |
|
||||
| newOwner `indexed` | address | undefined |
|
||||
|
||||
### WithdrawERC20
|
||||
|
||||
```solidity
|
||||
event WithdrawERC20(address indexed l1Token, address indexed l2Token, address indexed from, address to, uint256 amount, bytes data)
|
||||
```
|
||||
|
||||
Emitted when someone withdraw ERC20 token from L2 to L1.
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| l1Token `indexed` | address | The address of the token in L1. |
|
||||
| l2Token `indexed` | address | The address of the token in L2. |
|
||||
| from `indexed` | address | The address of sender in L2. |
|
||||
| to | address | The address of recipient in L1. |
|
||||
| amount | uint256 | The amount of token will be deposited from L2 to L1. |
|
||||
| data | bytes | The optional calldata passed to recipient in L1. |
|
||||
|
||||
|
||||
|
||||
## Errors
|
||||
|
||||
### ErrorCallerIsNotCounterpartGateway
|
||||
|
||||
```solidity
|
||||
error ErrorCallerIsNotCounterpartGateway()
|
||||
```
|
||||
|
||||
|
||||
|
||||
*Thrown when the cross chain sender is not the counterpart gateway contract.*
|
||||
|
||||
|
||||
### ErrorCallerIsNotMessenger
|
||||
|
||||
```solidity
|
||||
error ErrorCallerIsNotMessenger()
|
||||
```
|
||||
|
||||
|
||||
|
||||
*Thrown when the caller is not corresponding `L1ScrollMessenger` or `L2ScrollMessenger`.*
|
||||
|
||||
|
||||
### ErrorNotInDropMessageContext
|
||||
|
||||
```solidity
|
||||
error ErrorNotInDropMessageContext()
|
||||
```
|
||||
|
||||
|
||||
|
||||
*Thrown when ScrollMessenger is not dropping message.*
|
||||
|
||||
|
||||
### ErrorZeroAddress
|
||||
|
||||
```solidity
|
||||
error ErrorZeroAddress()
|
||||
```
|
||||
|
||||
|
||||
|
||||
*Thrown when the given address is `address(0)`.*
|
||||
|
||||
|
||||
|
||||
409
contracts/docs/apis/L2WETHGateway.md
Normal file
409
contracts/docs/apis/L2WETHGateway.md
Normal file
@@ -0,0 +1,409 @@
|
||||
# L2WETHGateway
|
||||
|
||||
|
||||
|
||||
> L2WETHGateway
|
||||
|
||||
The `L2WETHGateway` contract is used to withdraw `WETH` token on layer 2 and finalize deposit `WETH` from layer 1.
|
||||
|
||||
*The WETH tokens are not held in the gateway. It will first be unwrapped as Ether and then the Ether will be sent to the `L2ScrollMessenger` contract. On finalizing deposit, the Ether will be transferred from `L2ScrollMessenger`, then wrapped as WETH and finally transfer to recipient.*
|
||||
|
||||
## Methods
|
||||
|
||||
### WETH
|
||||
|
||||
```solidity
|
||||
function WETH() external view returns (address)
|
||||
```
|
||||
|
||||
The address of L2 WETH address.
|
||||
|
||||
|
||||
|
||||
|
||||
#### Returns
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _0 | address | undefined |
|
||||
|
||||
### counterpart
|
||||
|
||||
```solidity
|
||||
function counterpart() external view returns (address)
|
||||
```
|
||||
|
||||
The address of corresponding L1/L2 Gateway contract.
|
||||
|
||||
|
||||
|
||||
|
||||
#### Returns
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _0 | address | undefined |
|
||||
|
||||
### finalizeDepositERC20
|
||||
|
||||
```solidity
|
||||
function finalizeDepositERC20(address _l1Token, address _l2Token, address _from, address _to, uint256 _amount, bytes _data) external payable
|
||||
```
|
||||
|
||||
Complete a deposit from L1 to L2 and send fund to recipient's account in L2.
|
||||
|
||||
*Make this function payable to handle WETH deposit/withdraw. The function should only be called by L2ScrollMessenger. The function should also only be called by L1ERC20Gateway in L1.*
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _l1Token | address | undefined |
|
||||
| _l2Token | address | undefined |
|
||||
| _from | address | undefined |
|
||||
| _to | address | undefined |
|
||||
| _amount | uint256 | undefined |
|
||||
| _data | bytes | undefined |
|
||||
|
||||
### getL1ERC20Address
|
||||
|
||||
```solidity
|
||||
function getL1ERC20Address(address) external view returns (address)
|
||||
```
|
||||
|
||||
Return the corresponding l1 token address given l2 token address.
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _0 | address | undefined |
|
||||
|
||||
#### Returns
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _0 | address | undefined |
|
||||
|
||||
### getL2ERC20Address
|
||||
|
||||
```solidity
|
||||
function getL2ERC20Address(address) external view returns (address)
|
||||
```
|
||||
|
||||
Return the corresponding l2 token address given l1 token address.
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _0 | address | undefined |
|
||||
|
||||
#### Returns
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _0 | address | undefined |
|
||||
|
||||
### initialize
|
||||
|
||||
```solidity
|
||||
function initialize(address _counterpart, address _router, address _messenger) external nonpayable
|
||||
```
|
||||
|
||||
Initialize the storage of `L2WETHGateway`.
|
||||
|
||||
*The parameters `_counterpart`, `_router` and `_messenger` are no longer used.*
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _counterpart | address | The address of `L1WETHGateway` contract in L1. |
|
||||
| _router | address | The address of `L2GatewayRouter` contract in L2. |
|
||||
| _messenger | address | The address of `L2ScrollMessenger` contract in L2. |
|
||||
|
||||
### l1WETH
|
||||
|
||||
```solidity
|
||||
function l1WETH() external view returns (address)
|
||||
```
|
||||
|
||||
The address of L1 WETH address.
|
||||
|
||||
|
||||
|
||||
|
||||
#### Returns
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _0 | address | undefined |
|
||||
|
||||
### messenger
|
||||
|
||||
```solidity
|
||||
function messenger() external view returns (address)
|
||||
```
|
||||
|
||||
The address of corresponding L1ScrollMessenger/L2ScrollMessenger contract.
|
||||
|
||||
|
||||
|
||||
|
||||
#### Returns
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _0 | address | undefined |
|
||||
|
||||
### owner
|
||||
|
||||
```solidity
|
||||
function owner() external view returns (address)
|
||||
```
|
||||
|
||||
|
||||
|
||||
*Returns the address of the current owner.*
|
||||
|
||||
|
||||
#### Returns
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _0 | address | undefined |
|
||||
|
||||
### renounceOwnership
|
||||
|
||||
```solidity
|
||||
function renounceOwnership() external nonpayable
|
||||
```
|
||||
|
||||
|
||||
|
||||
*Leaves the contract without owner. It will not be possible to call `onlyOwner` functions. Can only be called by the current owner. NOTE: Renouncing ownership will leave the contract without an owner, thereby disabling any functionality that is only available to the owner.*
|
||||
|
||||
|
||||
### router
|
||||
|
||||
```solidity
|
||||
function router() external view returns (address)
|
||||
```
|
||||
|
||||
The address of L1GatewayRouter/L2GatewayRouter contract.
|
||||
|
||||
|
||||
|
||||
|
||||
#### Returns
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _0 | address | undefined |
|
||||
|
||||
### transferOwnership
|
||||
|
||||
```solidity
|
||||
function transferOwnership(address newOwner) external nonpayable
|
||||
```
|
||||
|
||||
|
||||
|
||||
*Transfers ownership of the contract to a new account (`newOwner`). Can only be called by the current owner.*
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| newOwner | address | undefined |
|
||||
|
||||
### withdrawERC20
|
||||
|
||||
```solidity
|
||||
function withdrawERC20(address _token, uint256 _amount, uint256 _gasLimit) external payable
|
||||
```
|
||||
|
||||
Withdraw of some token to a caller's account on L1.
|
||||
|
||||
*Make this function payable to send relayer fee in Ether.*
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _token | address | undefined |
|
||||
| _amount | uint256 | undefined |
|
||||
| _gasLimit | uint256 | undefined |
|
||||
|
||||
### withdrawERC20
|
||||
|
||||
```solidity
|
||||
function withdrawERC20(address _token, address _to, uint256 _amount, uint256 _gasLimit) external payable
|
||||
```
|
||||
|
||||
Withdraw of some token to a recipient's account on L1.
|
||||
|
||||
*Make this function payable to send relayer fee in Ether.*
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _token | address | undefined |
|
||||
| _to | address | undefined |
|
||||
| _amount | uint256 | undefined |
|
||||
| _gasLimit | uint256 | undefined |
|
||||
|
||||
### withdrawERC20AndCall
|
||||
|
||||
```solidity
|
||||
function withdrawERC20AndCall(address _token, address _to, uint256 _amount, bytes _data, uint256 _gasLimit) external payable
|
||||
```
|
||||
|
||||
Withdraw of some token to a recipient's account on L1 and call.
|
||||
|
||||
*Make this function payable to send relayer fee in Ether.*
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _token | address | undefined |
|
||||
| _to | address | undefined |
|
||||
| _amount | uint256 | undefined |
|
||||
| _data | bytes | undefined |
|
||||
| _gasLimit | uint256 | undefined |
|
||||
|
||||
|
||||
|
||||
## Events
|
||||
|
||||
### FinalizeDepositERC20
|
||||
|
||||
```solidity
|
||||
event FinalizeDepositERC20(address indexed l1Token, address indexed l2Token, address indexed from, address to, uint256 amount, bytes data)
|
||||
```
|
||||
|
||||
Emitted when ERC20 token is deposited from L1 to L2 and transfer to recipient.
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| l1Token `indexed` | address | The address of the token in L1. |
|
||||
| l2Token `indexed` | address | The address of the token in L2. |
|
||||
| from `indexed` | address | The address of sender in L1. |
|
||||
| to | address | The address of recipient in L2. |
|
||||
| amount | uint256 | The amount of token withdrawn from L1 to L2. |
|
||||
| data | bytes | The optional calldata passed to recipient in L2. |
|
||||
|
||||
### Initialized
|
||||
|
||||
```solidity
|
||||
event Initialized(uint8 version)
|
||||
```
|
||||
|
||||
|
||||
|
||||
*Triggered when the contract has been initialized or reinitialized.*
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| version | uint8 | undefined |
|
||||
|
||||
### OwnershipTransferred
|
||||
|
||||
```solidity
|
||||
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner)
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| previousOwner `indexed` | address | undefined |
|
||||
| newOwner `indexed` | address | undefined |
|
||||
|
||||
### WithdrawERC20
|
||||
|
||||
```solidity
|
||||
event WithdrawERC20(address indexed l1Token, address indexed l2Token, address indexed from, address to, uint256 amount, bytes data)
|
||||
```
|
||||
|
||||
Emitted when someone withdraw ERC20 token from L2 to L1.
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| l1Token `indexed` | address | The address of the token in L1. |
|
||||
| l2Token `indexed` | address | The address of the token in L2. |
|
||||
| from `indexed` | address | The address of sender in L2. |
|
||||
| to | address | The address of recipient in L1. |
|
||||
| amount | uint256 | The amount of token will be deposited from L2 to L1. |
|
||||
| data | bytes | The optional calldata passed to recipient in L1. |
|
||||
|
||||
|
||||
|
||||
## Errors
|
||||
|
||||
### ErrorCallerIsNotCounterpartGateway
|
||||
|
||||
```solidity
|
||||
error ErrorCallerIsNotCounterpartGateway()
|
||||
```
|
||||
|
||||
|
||||
|
||||
*Thrown when the cross chain sender is not the counterpart gateway contract.*
|
||||
|
||||
|
||||
### ErrorCallerIsNotMessenger
|
||||
|
||||
```solidity
|
||||
error ErrorCallerIsNotMessenger()
|
||||
```
|
||||
|
||||
|
||||
|
||||
*Thrown when the caller is not corresponding `L1ScrollMessenger` or `L2ScrollMessenger`.*
|
||||
|
||||
|
||||
### ErrorNotInDropMessageContext
|
||||
|
||||
```solidity
|
||||
error ErrorNotInDropMessageContext()
|
||||
```
|
||||
|
||||
|
||||
|
||||
*Thrown when ScrollMessenger is not dropping message.*
|
||||
|
||||
|
||||
### ErrorZeroAddress
|
||||
|
||||
```solidity
|
||||
error ErrorZeroAddress()
|
||||
```
|
||||
|
||||
|
||||
|
||||
*Thrown when the given address is `address(0)`.*
|
||||
|
||||
|
||||
|
||||
1056
contracts/docs/apis/ScrollChain.md
Normal file
1056
contracts/docs/apis/ScrollChain.md
Normal file
File diff suppressed because it is too large
Load Diff
159
contracts/docs/apis/ScrollStandardERC20Factory.md
Normal file
159
contracts/docs/apis/ScrollStandardERC20Factory.md
Normal file
@@ -0,0 +1,159 @@
|
||||
# ScrollStandardERC20Factory
|
||||
|
||||
|
||||
|
||||
> ScrollStandardERC20Factory
|
||||
|
||||
The `ScrollStandardERC20Factory` is used to deploy `ScrollStandardERC20` for `L2StandardERC20Gateway`. It uses the `Clones` contract to deploy contract with minimum gas usage.
|
||||
|
||||
*The implementation of deployed token is non-upgradable. This design may be changed in the future.*
|
||||
|
||||
## Methods
|
||||
|
||||
### computeL2TokenAddress
|
||||
|
||||
```solidity
|
||||
function computeL2TokenAddress(address _gateway, address _l1Token) external view returns (address)
|
||||
```
|
||||
|
||||
Compute the corresponding l2 token address given l1 token address.
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _gateway | address | The address of gateway contract. |
|
||||
| _l1Token | address | The address of l1 token. |
|
||||
|
||||
#### Returns
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _0 | address | undefined |
|
||||
|
||||
### deployL2Token
|
||||
|
||||
```solidity
|
||||
function deployL2Token(address _gateway, address _l1Token) external nonpayable returns (address)
|
||||
```
|
||||
|
||||
Deploy the corresponding l2 token address given l1 token address.
|
||||
|
||||
*This function should only be called by owner to avoid DDoS attack on StandardTokenBridge.*
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _gateway | address | The address of gateway contract. |
|
||||
| _l1Token | address | The address of l1 token. |
|
||||
|
||||
#### Returns
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _0 | address | undefined |
|
||||
|
||||
### implementation
|
||||
|
||||
```solidity
|
||||
function implementation() external view returns (address)
|
||||
```
|
||||
|
||||
The address of `ScrollStandardERC20` implementation.
|
||||
|
||||
|
||||
|
||||
|
||||
#### Returns
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _0 | address | undefined |
|
||||
|
||||
### owner
|
||||
|
||||
```solidity
|
||||
function owner() external view returns (address)
|
||||
```
|
||||
|
||||
|
||||
|
||||
*Returns the address of the current owner.*
|
||||
|
||||
|
||||
#### Returns
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _0 | address | undefined |
|
||||
|
||||
### renounceOwnership
|
||||
|
||||
```solidity
|
||||
function renounceOwnership() external nonpayable
|
||||
```
|
||||
|
||||
|
||||
|
||||
*Leaves the contract without owner. It will not be possible to call `onlyOwner` functions. Can only be called by the current owner. NOTE: Renouncing ownership will leave the contract without an owner, thereby disabling any functionality that is only available to the owner.*
|
||||
|
||||
|
||||
### transferOwnership
|
||||
|
||||
```solidity
|
||||
function transferOwnership(address newOwner) external nonpayable
|
||||
```
|
||||
|
||||
|
||||
|
||||
*Transfers ownership of the contract to a new account (`newOwner`). Can only be called by the current owner.*
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| newOwner | address | undefined |
|
||||
|
||||
|
||||
|
||||
## Events
|
||||
|
||||
### DeployToken
|
||||
|
||||
```solidity
|
||||
event DeployToken(address indexed _l1Token, address indexed _l2Token)
|
||||
```
|
||||
|
||||
Emitted when a l2 token is deployed.
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _l1Token `indexed` | address | The address of the l1 token. |
|
||||
| _l2Token `indexed` | address | The address of the l2 token. |
|
||||
|
||||
### OwnershipTransferred
|
||||
|
||||
```solidity
|
||||
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner)
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| previousOwner `indexed` | address | undefined |
|
||||
| newOwner `indexed` | address | undefined |
|
||||
|
||||
|
||||
|
||||
30
contracts/foundry.toml
Normal file
30
contracts/foundry.toml
Normal file
@@ -0,0 +1,30 @@
|
||||
[profile.default]
|
||||
src = 'src' # the source directory
|
||||
test = 'src/test' # the test directory
|
||||
script = 'scripts' # the script directory
|
||||
out = 'artifacts/src' # the output directory (for artifacts)
|
||||
libs = [] # a list of library directories
|
||||
remappings = [] # a list of remappings
|
||||
libraries = [] # a list of deployed libraries to link against
|
||||
cache = true # whether to cache builds or not
|
||||
force = true # whether to ignore the cache (clean build)
|
||||
evm_version = 'cancun' # the evm version (by hardfork name)
|
||||
solc_version = '0.8.24' # override for the solc version (setting this ignores `auto_detect_solc`)
|
||||
optimizer = true # enable or disable the solc optimizer
|
||||
optimizer_runs = 200 # the number of optimizer runs
|
||||
verbosity = 2 # the verbosity of tests
|
||||
ignored_error_codes = [] # a list of ignored solc error codes
|
||||
fuzz_runs = 256 # the number of fuzz runs for tests
|
||||
ffi = false # whether to enable ffi or not
|
||||
sender = '0x00a329c0648769a73afac7f9381e08fb43dbea72' # the address of `msg.sender` in tests
|
||||
tx_origin = '0x00a329c0648769a73afac7f9381e08fb43dbea72' # the address of `tx.origin` in tests
|
||||
initial_balance = '0xffffffffffffffffffffffff' # the initial balance of the test contract
|
||||
block_number = 0 # the block number we are at in tests
|
||||
gas_limit = 9223372036854775807 # the gas limit in tests
|
||||
gas_price = 0 # the gas price (in wei) in tests
|
||||
block_base_fee_per_gas = 0 # the base fee (in wei) in tests
|
||||
block_coinbase = '0x0000000000000000000000000000000000000000' # the address of `block.coinbase` in tests
|
||||
block_timestamp = 0 # the value of `block.timestamp` in tests
|
||||
block_difficulty = 0 # the value of `block.difficulty` in tests
|
||||
|
||||
gas_reports = ["L2GasPriceOracle"]
|
||||
10
contracts/genesis.json.example
Normal file
10
contracts/genesis.json.example
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"blockHash": "0x3e721eda79f26bf40cd915aad0c85d501849215ad907d2e38acff524847300ab",
|
||||
"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"baseFee": "0x3b9aca00",
|
||||
"stateRoot": "0x183cbfdab83f8884b7cfbe234cb99bbd654d4fb18bd9c9f01e94ebf859957739",
|
||||
"blockHeight": 0,
|
||||
"gasUsed": 0,
|
||||
"timestamp": "0x61bc34a0",
|
||||
"extraData": "0x00000000000000000000000000000000000000000000000000000000000000004cb1ab63af5d8931ce09673ebd8ae2ce16fd6571adf5218f7ca8c80d90ff63af5fef486af57c20960000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
|
||||
}
|
||||
151
contracts/hardhat.config.ts
Normal file
151
contracts/hardhat.config.ts
Normal file
@@ -0,0 +1,151 @@
|
||||
import * as dotenv from "dotenv";
|
||||
|
||||
import { HardhatUserConfig, subtask } from "hardhat/config";
|
||||
import * as toml from "toml";
|
||||
import "@nomicfoundation/hardhat-verify";
|
||||
import "@nomicfoundation/hardhat-ethers";
|
||||
import "@nomicfoundation/hardhat-chai-matchers";
|
||||
import "@typechain/hardhat";
|
||||
import "@primitivefi/hardhat-dodoc";
|
||||
import "hardhat-gas-reporter";
|
||||
import "solidity-coverage";
|
||||
import { readFileSync } from "fs";
|
||||
import { TASK_COMPILE_SOLIDITY_GET_SOURCE_PATHS } from "hardhat/builtin-tasks/task-names";
|
||||
|
||||
dotenv.config();
|
||||
|
||||
const L1_DEPLOYER_PRIVATE_KEY = process.env.L1_DEPLOYER_PRIVATE_KEY || "1".repeat(64);
|
||||
const L2_DEPLOYER_PRIVATE_KEY = process.env.L2_DEPLOYER_PRIVATE_KEY || "1".repeat(64);
|
||||
|
||||
const SOLC_DEFAULT = "0.8.24";
|
||||
|
||||
// try use forge config
|
||||
let foundry: any;
|
||||
try {
|
||||
foundry = toml.parse(readFileSync("./foundry.toml").toString());
|
||||
foundry.default.solc = foundry.default["solc-version"] ? foundry.default["solc-version"] : SOLC_DEFAULT;
|
||||
} catch (error) {
|
||||
foundry = {
|
||||
default: {
|
||||
solc: SOLC_DEFAULT,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
// prune forge style tests from hardhat paths
|
||||
subtask(TASK_COMPILE_SOLIDITY_GET_SOURCE_PATHS).setAction(async (_, __, runSuper) => {
|
||||
const paths = await runSuper();
|
||||
return paths.filter((p: string) => !p.endsWith(".t.sol")).filter((p: string) => !p.includes("test/mocks"));
|
||||
});
|
||||
|
||||
const config: HardhatUserConfig = {
|
||||
solidity: {
|
||||
version: foundry.default?.solc_version || SOLC_DEFAULT,
|
||||
settings: {
|
||||
optimizer: {
|
||||
enabled: foundry.default?.optimizer || true,
|
||||
runs: foundry.default?.optimizer_runs || 200,
|
||||
},
|
||||
evmVersion: "cancun",
|
||||
},
|
||||
},
|
||||
networks: {
|
||||
ethereum: {
|
||||
url: "https://1rpc.io/eth",
|
||||
accounts: [L1_DEPLOYER_PRIVATE_KEY],
|
||||
},
|
||||
sepolia: {
|
||||
url: "https://1rpc.io/sepolia",
|
||||
accounts: [L1_DEPLOYER_PRIVATE_KEY],
|
||||
},
|
||||
scroll: {
|
||||
url: "https://rpc.scroll.io",
|
||||
accounts: [L2_DEPLOYER_PRIVATE_KEY],
|
||||
},
|
||||
scroll_sepolia: {
|
||||
url: "https://sepolia-rpc.scroll.io",
|
||||
accounts: [L2_DEPLOYER_PRIVATE_KEY],
|
||||
},
|
||||
},
|
||||
paths: {
|
||||
cache: "./cache-hardhat",
|
||||
sources: "./src",
|
||||
tests: "./integration-test",
|
||||
},
|
||||
typechain: {
|
||||
outDir: "./typechain",
|
||||
target: "ethers-v6",
|
||||
},
|
||||
gasReporter: {
|
||||
enabled: process.env.REPORT_GAS !== undefined,
|
||||
excludeContracts: ["src/test"],
|
||||
currency: "USD",
|
||||
},
|
||||
etherscan: {
|
||||
apiKey: {
|
||||
ethereum: process.env.ETHERSCAN_API_KEY || "",
|
||||
sepolia: process.env.ETHERSCAN_API_KEY || "",
|
||||
scroll: process.env.SCROLLSCAN_API_KEY || "",
|
||||
scroll_sepolia: process.env.SCROLLSCAN_API_KEY || "",
|
||||
},
|
||||
customChains: [
|
||||
{
|
||||
network: "scroll",
|
||||
chainId: 534352,
|
||||
urls: {
|
||||
apiURL: "https://api.scrollscan.com/api",
|
||||
browserURL: "https://www.scrollscan.com/",
|
||||
},
|
||||
},
|
||||
{
|
||||
network: "scroll_sepolia",
|
||||
chainId: 534351,
|
||||
urls: {
|
||||
apiURL: "https://api-sepolia.scrollscan.com/api",
|
||||
browserURL: "https://sepolia.scrollscan.com/",
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
mocha: {
|
||||
timeout: 10000000,
|
||||
},
|
||||
dodoc: {
|
||||
runOnCompile: true,
|
||||
keepFileStructure: false,
|
||||
include: [
|
||||
"ScrollChain",
|
||||
"L1ScrollMessenger",
|
||||
"L2ScrollMessenger",
|
||||
"L1GatewayRouter",
|
||||
"L2GatewayRouter",
|
||||
"L1StandardERC20Gateway",
|
||||
"L2StandardERC20Gateway",
|
||||
"L1ERC721Gateway",
|
||||
"L2ERC721Gateway",
|
||||
"L1ERC1155Gateway",
|
||||
"L2ERC1155Gateway",
|
||||
"L1WETHGateway",
|
||||
"L2WETHGateway",
|
||||
"ScrollStandardERC20Factory",
|
||||
],
|
||||
outputDir: "docs/apis",
|
||||
exclude: [
|
||||
"IERC677Receiver",
|
||||
"IL1ScrollMessenger",
|
||||
"IL2ScrollMessenger",
|
||||
"IL1GatewayRouter",
|
||||
"IL2GatewayRouter",
|
||||
"IL1ERC721Gateway",
|
||||
"IL2ERC721Gateway",
|
||||
"IL1ERC1155Gateway",
|
||||
"IL2ERC1155Gateway",
|
||||
"IScrollStandardERC20Factory",
|
||||
"IScrollChain",
|
||||
"ScrollChainCommitmentVerifier",
|
||||
"WETH9",
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
export default config;
|
||||
455
contracts/integration-test/EnforcedTxGateway.spec.ts
Normal file
455
contracts/integration-test/EnforcedTxGateway.spec.ts
Normal file
@@ -0,0 +1,455 @@
|
||||
/* eslint-disable node/no-unpublished-import */
|
||||
/* eslint-disable node/no-missing-import */
|
||||
import { HardhatEthersSigner, SignerWithAddress } from "@nomicfoundation/hardhat-ethers/signers";
|
||||
import { expect } from "chai";
|
||||
import { BigNumberish, BytesLike, MaxUint256, ZeroAddress, getBytes } from "ethers";
|
||||
import { ethers } from "hardhat";
|
||||
|
||||
import { EnforcedTxGateway, L1MessageQueue, L2GasPriceOracle, MockCaller } from "../typechain";
|
||||
|
||||
describe("EnforcedTxGateway.spec", async () => {
|
||||
let deployer: HardhatEthersSigner;
|
||||
let feeVault: HardhatEthersSigner;
|
||||
let signer: HardhatEthersSigner;
|
||||
|
||||
let caller: MockCaller;
|
||||
let gateway: EnforcedTxGateway;
|
||||
let oracle: L2GasPriceOracle;
|
||||
let queue: L1MessageQueue;
|
||||
|
||||
const deployProxy = async (name: string, admin: string, args: any[]): Promise<string> => {
|
||||
const TransparentUpgradeableProxy = await ethers.getContractFactory("TransparentUpgradeableProxy", deployer);
|
||||
const Factory = await ethers.getContractFactory(name, deployer);
|
||||
const impl = args.length > 0 ? await Factory.deploy(...args) : await Factory.deploy();
|
||||
const proxy = await TransparentUpgradeableProxy.deploy(impl.getAddress(), admin, "0x");
|
||||
return proxy.getAddress();
|
||||
};
|
||||
|
||||
beforeEach(async () => {
|
||||
[deployer, feeVault, signer] = await ethers.getSigners();
|
||||
|
||||
const ProxyAdmin = await ethers.getContractFactory("ProxyAdmin", deployer);
|
||||
const admin = await ProxyAdmin.deploy();
|
||||
|
||||
gateway = await ethers.getContractAt(
|
||||
"EnforcedTxGateway",
|
||||
await deployProxy("EnforcedTxGateway", await admin.getAddress(), []),
|
||||
deployer
|
||||
);
|
||||
|
||||
queue = await ethers.getContractAt(
|
||||
"L1MessageQueue",
|
||||
await deployProxy("L1MessageQueue", await admin.getAddress(), [
|
||||
deployer.address,
|
||||
deployer.address,
|
||||
await gateway.getAddress(),
|
||||
]),
|
||||
deployer
|
||||
);
|
||||
|
||||
oracle = await ethers.getContractAt(
|
||||
"L2GasPriceOracle",
|
||||
await deployProxy("L2GasPriceOracle", await admin.getAddress(), []),
|
||||
deployer
|
||||
);
|
||||
|
||||
const MockCaller = await ethers.getContractFactory("MockCaller", deployer);
|
||||
caller = await MockCaller.deploy();
|
||||
|
||||
await queue.initialize(ZeroAddress, ZeroAddress, ZeroAddress, oracle.getAddress(), 10000000);
|
||||
await gateway.initialize(queue.getAddress(), feeVault.address);
|
||||
await oracle.initialize(21000, 51000, 8, 16);
|
||||
|
||||
const Whitelist = await ethers.getContractFactory("Whitelist", deployer);
|
||||
const whitelist = await Whitelist.deploy(deployer.address);
|
||||
|
||||
await whitelist.updateWhitelistStatus([deployer.address], true);
|
||||
await oracle.updateWhitelist(whitelist.getAddress());
|
||||
await oracle.setL2BaseFee(1);
|
||||
});
|
||||
|
||||
context("auth", async () => {
|
||||
it("should initialize correctly", async () => {
|
||||
expect(await gateway.owner()).to.eq(deployer.address);
|
||||
expect(await gateway.messageQueue()).to.eq(await queue.getAddress());
|
||||
expect(await gateway.feeVault()).to.eq(feeVault.address);
|
||||
expect(await gateway.paused()).to.eq(false);
|
||||
});
|
||||
|
||||
it("should revert, when initialize again", async () => {
|
||||
await expect(gateway.initialize(ZeroAddress, ZeroAddress)).to.revertedWith(
|
||||
"Initializable: contract is already initialized"
|
||||
);
|
||||
});
|
||||
|
||||
context("#updateFeeVault", async () => {
|
||||
it("should revert, when non-owner call", async () => {
|
||||
await expect(gateway.connect(signer).updateFeeVault(ZeroAddress)).to.revertedWith(
|
||||
"Ownable: caller is not the owner"
|
||||
);
|
||||
});
|
||||
|
||||
it("should succeed", async () => {
|
||||
expect(await gateway.feeVault()).to.eq(feeVault.address);
|
||||
await expect(gateway.updateFeeVault(deployer.address))
|
||||
.to.emit(gateway, "UpdateFeeVault")
|
||||
.withArgs(feeVault.address, deployer.address);
|
||||
expect(await gateway.feeVault()).to.eq(deployer.address);
|
||||
});
|
||||
});
|
||||
|
||||
context("#setPause", async () => {
|
||||
it("should revert, when non-owner call", async () => {
|
||||
await expect(gateway.connect(signer).setPause(false)).to.revertedWith("Ownable: caller is not the owner");
|
||||
});
|
||||
|
||||
it("should succeed", async () => {
|
||||
expect(await gateway.paused()).to.eq(false);
|
||||
await expect(gateway.setPause(true)).to.emit(gateway, "Paused").withArgs(deployer.address);
|
||||
expect(await gateway.paused()).to.eq(true);
|
||||
await expect(gateway.setPause(false)).to.emit(gateway, "Unpaused").withArgs(deployer.address);
|
||||
expect(await gateway.paused()).to.eq(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
context("#sendTransaction, by EOA", async () => {
|
||||
it("should revert, when contract is paused", async () => {
|
||||
await gateway.setPause(true);
|
||||
await expect(
|
||||
gateway.connect(signer)["sendTransaction(address,uint256,uint256,bytes)"](signer.address, 0, 0, "0x")
|
||||
).to.revertedWith("Pausable: paused");
|
||||
});
|
||||
|
||||
it("should revert, when call is not EOA", async () => {
|
||||
const calldata = gateway.interface.encodeFunctionData("sendTransaction(address,uint256,uint256,bytes)", [
|
||||
signer.address,
|
||||
0,
|
||||
0,
|
||||
"0x",
|
||||
]);
|
||||
await expect(caller.callTarget(gateway.getAddress(), calldata)).to.revertedWith(
|
||||
"Only EOA senders are allowed to send enforced transaction"
|
||||
);
|
||||
});
|
||||
|
||||
it("should revert, when insufficient value for fee", async () => {
|
||||
const fee = await queue.estimateCrossDomainMessageFee(1000000);
|
||||
await expect(
|
||||
gateway
|
||||
.connect(signer)
|
||||
["sendTransaction(address,uint256,uint256,bytes)"](signer.address, 0, 1000000, "0x", { value: fee - 1n })
|
||||
).to.revertedWith("Insufficient value for fee");
|
||||
});
|
||||
|
||||
it("should revert, when failed to deduct the fee", async () => {
|
||||
await gateway.updateFeeVault(gateway.getAddress());
|
||||
const fee = await queue.estimateCrossDomainMessageFee(1000000);
|
||||
await expect(
|
||||
gateway
|
||||
.connect(signer)
|
||||
["sendTransaction(address,uint256,uint256,bytes)"](signer.address, 0, 1000000, "0x", { value: fee })
|
||||
).to.revertedWith("Failed to deduct the fee");
|
||||
});
|
||||
|
||||
it("should succeed, no refund", async () => {
|
||||
const fee = await queue.estimateCrossDomainMessageFee(1000000);
|
||||
const feeVaultBalanceBefore = await ethers.provider.getBalance(feeVault.address);
|
||||
await expect(
|
||||
gateway
|
||||
.connect(signer)
|
||||
["sendTransaction(address,uint256,uint256,bytes)"](deployer.address, 0, 1000000, "0x", { value: fee })
|
||||
)
|
||||
.to.emit(queue, "QueueTransaction")
|
||||
.withArgs(signer.address, deployer.address, 0, 0, 1000000, "0x");
|
||||
const feeVaultBalanceAfter = await ethers.provider.getBalance(feeVault.address);
|
||||
expect(feeVaultBalanceAfter - feeVaultBalanceBefore).to.eq(fee);
|
||||
});
|
||||
|
||||
it("should succeed, with refund", async () => {
|
||||
const fee = await queue.estimateCrossDomainMessageFee(1000000);
|
||||
const feeVaultBalanceBefore = await ethers.provider.getBalance(feeVault.address);
|
||||
const signerBalanceBefore = await ethers.provider.getBalance(signer.address);
|
||||
const tx = await gateway
|
||||
.connect(signer)
|
||||
["sendTransaction(address,uint256,uint256,bytes)"](deployer.address, 0, 1000000, "0x", { value: fee + 100n });
|
||||
await expect(tx)
|
||||
.to.emit(queue, "QueueTransaction")
|
||||
.withArgs(signer.address, deployer.address, 0, 0, 1000000, "0x");
|
||||
const receipt = await tx.wait();
|
||||
const feeVaultBalanceAfter = await ethers.provider.getBalance(feeVault.address);
|
||||
const signerBalanceAfter = await ethers.provider.getBalance(signer.address);
|
||||
expect(feeVaultBalanceAfter - feeVaultBalanceBefore).to.eq(fee);
|
||||
expect(signerBalanceBefore - signerBalanceAfter).to.eq(receipt!.gasUsed * receipt!.gasPrice + fee);
|
||||
});
|
||||
});
|
||||
|
||||
context("#sendTransaction, with signatures", async () => {
|
||||
const getSignature = async (
|
||||
signer: SignerWithAddress,
|
||||
target: string,
|
||||
value: BigNumberish,
|
||||
gasLimit: BigNumberish,
|
||||
data: BytesLike
|
||||
) => {
|
||||
const enforcedTx = {
|
||||
sender: signer.address,
|
||||
target,
|
||||
value,
|
||||
gasLimit,
|
||||
data: getBytes(data),
|
||||
nonce: await gateway.nonces(signer.address),
|
||||
deadline: MaxUint256,
|
||||
};
|
||||
|
||||
const domain = {
|
||||
name: "EnforcedTxGateway",
|
||||
version: "1",
|
||||
chainId: (await ethers.provider.getNetwork()).chainId,
|
||||
verifyingContract: await gateway.getAddress(),
|
||||
};
|
||||
|
||||
const types = {
|
||||
EnforcedTransaction: [
|
||||
{
|
||||
name: "sender",
|
||||
type: "address",
|
||||
},
|
||||
{
|
||||
name: "target",
|
||||
type: "address",
|
||||
},
|
||||
{
|
||||
name: "value",
|
||||
type: "uint256",
|
||||
},
|
||||
{
|
||||
name: "gasLimit",
|
||||
type: "uint256",
|
||||
},
|
||||
{
|
||||
name: "data",
|
||||
type: "bytes",
|
||||
},
|
||||
{
|
||||
name: "nonce",
|
||||
type: "uint256",
|
||||
},
|
||||
{
|
||||
name: "deadline",
|
||||
type: "uint256",
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const signature = await signer.signTypedData(domain, types, enforcedTx);
|
||||
return signature;
|
||||
};
|
||||
|
||||
it("should revert, when contract is paused", async () => {
|
||||
await gateway.setPause(true);
|
||||
await expect(
|
||||
gateway
|
||||
.connect(deployer)
|
||||
["sendTransaction(address,address,uint256,uint256,bytes,uint256,bytes,address)"](
|
||||
signer.address,
|
||||
signer.address,
|
||||
0,
|
||||
0,
|
||||
"0x",
|
||||
MaxUint256,
|
||||
"0x",
|
||||
ZeroAddress
|
||||
)
|
||||
).to.revertedWith("Pausable: paused");
|
||||
});
|
||||
|
||||
it("should revert, when signature expired", async () => {
|
||||
const timestamp = (await ethers.provider.getBlock("latest"))!.timestamp;
|
||||
await expect(
|
||||
gateway
|
||||
.connect(deployer)
|
||||
["sendTransaction(address,address,uint256,uint256,bytes,uint256,bytes,address)"](
|
||||
signer.address,
|
||||
signer.address,
|
||||
0,
|
||||
0,
|
||||
"0x",
|
||||
timestamp - 1,
|
||||
"0x",
|
||||
ZeroAddress
|
||||
)
|
||||
).to.revertedWith("signature expired");
|
||||
});
|
||||
|
||||
it("should revert, when signature is wrong", async () => {
|
||||
const signature = await signer.signMessage("0x00");
|
||||
await expect(
|
||||
gateway
|
||||
.connect(deployer)
|
||||
["sendTransaction(address,address,uint256,uint256,bytes,uint256,bytes,address)"](
|
||||
signer.address,
|
||||
signer.address,
|
||||
0,
|
||||
0,
|
||||
"0x",
|
||||
MaxUint256,
|
||||
signature,
|
||||
ZeroAddress
|
||||
)
|
||||
).to.revertedWith("Incorrect signature");
|
||||
});
|
||||
|
||||
it("should revert, when insufficient value for fee", async () => {
|
||||
const signature = await getSignature(signer, signer.address, 0, 1000000, "0x");
|
||||
const fee = await queue.estimateCrossDomainMessageFee(1000000);
|
||||
await expect(
|
||||
gateway
|
||||
.connect(deployer)
|
||||
["sendTransaction(address,address,uint256,uint256,bytes,uint256,bytes,address)"](
|
||||
signer.address,
|
||||
signer.address,
|
||||
0,
|
||||
1000000,
|
||||
"0x",
|
||||
MaxUint256,
|
||||
signature,
|
||||
signer.address,
|
||||
{ value: fee - 1n }
|
||||
)
|
||||
).to.revertedWith("Insufficient value for fee");
|
||||
});
|
||||
|
||||
it("should revert, when failed to deduct the fee", async () => {
|
||||
await gateway.updateFeeVault(gateway.getAddress());
|
||||
const signature = await getSignature(signer, signer.address, 0, 1000000, "0x");
|
||||
const fee = await queue.estimateCrossDomainMessageFee(1000000);
|
||||
await expect(
|
||||
gateway
|
||||
.connect(deployer)
|
||||
["sendTransaction(address,address,uint256,uint256,bytes,uint256,bytes,address)"](
|
||||
signer.address,
|
||||
signer.address,
|
||||
0,
|
||||
1000000,
|
||||
"0x",
|
||||
MaxUint256,
|
||||
signature,
|
||||
signer.address,
|
||||
{ value: fee }
|
||||
)
|
||||
).to.revertedWith("Failed to deduct the fee");
|
||||
});
|
||||
|
||||
it("should succeed, no refund", async () => {
|
||||
const signature = await getSignature(signer, deployer.address, 0, 1000000, "0x");
|
||||
const fee = await queue.estimateCrossDomainMessageFee(1000000);
|
||||
const feeVaultBalanceBefore = await ethers.provider.getBalance(feeVault.address);
|
||||
expect(await gateway.nonces(signer.address)).to.eq(0);
|
||||
await expect(
|
||||
gateway
|
||||
.connect(deployer)
|
||||
["sendTransaction(address,address,uint256,uint256,bytes,uint256,bytes,address)"](
|
||||
signer.address,
|
||||
deployer.address,
|
||||
0,
|
||||
1000000,
|
||||
"0x",
|
||||
MaxUint256,
|
||||
signature,
|
||||
signer.address,
|
||||
{ value: fee }
|
||||
)
|
||||
)
|
||||
.to.emit(queue, "QueueTransaction")
|
||||
.withArgs(signer.address, deployer.address, 0, 0, 1000000, "0x");
|
||||
expect(await gateway.nonces(signer.address)).to.eq(1);
|
||||
const feeVaultBalanceAfter = await ethers.provider.getBalance(feeVault.address);
|
||||
expect(feeVaultBalanceAfter - feeVaultBalanceBefore).to.eq(fee);
|
||||
|
||||
// use the same nonce to sign should fail
|
||||
await expect(
|
||||
gateway
|
||||
.connect(deployer)
|
||||
["sendTransaction(address,address,uint256,uint256,bytes,uint256,bytes,address)"](
|
||||
signer.address,
|
||||
deployer.address,
|
||||
0,
|
||||
1000000,
|
||||
"0x",
|
||||
MaxUint256,
|
||||
signature,
|
||||
signer.address,
|
||||
{ value: fee }
|
||||
)
|
||||
).to.revertedWith("Incorrect signature");
|
||||
});
|
||||
|
||||
it("should succeed, with refund", async () => {
|
||||
const signature = await getSignature(signer, deployer.address, 0, 1000000, "0x");
|
||||
const fee = await queue.estimateCrossDomainMessageFee(1000000);
|
||||
const feeVaultBalanceBefore = await ethers.provider.getBalance(feeVault.address);
|
||||
const signerBalanceBefore = await ethers.provider.getBalance(signer.address);
|
||||
expect(await gateway.nonces(signer.address)).to.eq(0);
|
||||
await expect(
|
||||
gateway
|
||||
.connect(deployer)
|
||||
["sendTransaction(address,address,uint256,uint256,bytes,uint256,bytes,address)"](
|
||||
signer.address,
|
||||
deployer.address,
|
||||
0,
|
||||
1000000,
|
||||
"0x",
|
||||
MaxUint256,
|
||||
signature,
|
||||
signer.address,
|
||||
{ value: fee + 100n }
|
||||
)
|
||||
)
|
||||
.to.emit(queue, "QueueTransaction")
|
||||
.withArgs(signer.address, deployer.address, 0, 0, 1000000, "0x");
|
||||
expect(await gateway.nonces(signer.address)).to.eq(1);
|
||||
const feeVaultBalanceAfter = await ethers.provider.getBalance(feeVault.address);
|
||||
const signerBalanceAfter = await ethers.provider.getBalance(signer.address);
|
||||
expect(feeVaultBalanceAfter - feeVaultBalanceBefore).to.eq(fee);
|
||||
expect(signerBalanceAfter - signerBalanceBefore).to.eq(100n);
|
||||
|
||||
// use the same nonce to sign should fail
|
||||
await expect(
|
||||
gateway
|
||||
.connect(deployer)
|
||||
["sendTransaction(address,address,uint256,uint256,bytes,uint256,bytes,address)"](
|
||||
signer.address,
|
||||
deployer.address,
|
||||
0,
|
||||
1000000,
|
||||
"0x",
|
||||
MaxUint256,
|
||||
signature,
|
||||
signer.address,
|
||||
{ value: fee + 100n }
|
||||
)
|
||||
).to.revertedWith("Incorrect signature");
|
||||
});
|
||||
|
||||
it("should revert, when refund failed", async () => {
|
||||
const signature = await getSignature(signer, signer.address, 0, 1000000, "0x1234");
|
||||
const fee = await queue.estimateCrossDomainMessageFee(1000000);
|
||||
await expect(
|
||||
gateway
|
||||
.connect(deployer)
|
||||
["sendTransaction(address,address,uint256,uint256,bytes,uint256,bytes,address)"](
|
||||
signer.address,
|
||||
signer.address,
|
||||
0,
|
||||
1000000,
|
||||
"0x1234",
|
||||
MaxUint256,
|
||||
signature,
|
||||
gateway.getAddress(),
|
||||
{ value: fee + 100n }
|
||||
)
|
||||
).to.revertedWith("Failed to refund the fee");
|
||||
});
|
||||
});
|
||||
});
|
||||
661
contracts/integration-test/GasOptimizationUpgrade.spec.ts
Normal file
661
contracts/integration-test/GasOptimizationUpgrade.spec.ts
Normal file
@@ -0,0 +1,661 @@
|
||||
/* eslint-disable node/no-missing-import */
|
||||
/* eslint-disable node/no-unpublished-import */
|
||||
import { HardhatEthersSigner } from "@nomicfoundation/hardhat-ethers/signers";
|
||||
import { expect } from "chai";
|
||||
import { BigNumberish, ContractTransactionResponse, MaxUint256, keccak256, toQuantity } from "ethers";
|
||||
import { ethers, network } from "hardhat";
|
||||
|
||||
import {
|
||||
ProxyAdmin,
|
||||
L1GatewayRouter,
|
||||
L2ScrollMessenger,
|
||||
L1ScrollMessenger,
|
||||
L1MessageQueueWithGasPriceOracle,
|
||||
L2GatewayRouter,
|
||||
} from "../typechain";
|
||||
|
||||
describe("GasOptimizationUpgrade.spec", async () => {
|
||||
const L1_ROUTER = "0xF8B1378579659D8F7EE5f3C929c2f3E332E41Fd6";
|
||||
const L2_ROUTER = "0x4C0926FF5252A435FD19e10ED15e5a249Ba19d79";
|
||||
const L1_MESSENGER = "0x6774Bcbd5ceCeF1336b5300fb5186a12DDD8b367";
|
||||
const L2_MESSENGER = "0x781e90f1c8Fc4611c9b7497C3B47F99Ef6969CbC";
|
||||
const L1_MESSAGE_QUEUE = "0x0d7E906BD9cAFa154b048cFa766Cc1E54E39AF9B";
|
||||
const L2_MESSAGE_QUEUE = "0x5300000000000000000000000000000000000000";
|
||||
const SCROLL_CHAIN = "0xa13BAF47339d63B743e7Da8741db5456DAc1E556";
|
||||
|
||||
let deployer: HardhatEthersSigner;
|
||||
|
||||
let proxyAdmin: ProxyAdmin;
|
||||
|
||||
const mockERC20Balance = async (tokenAddress: string, balance: bigint, slot: BigNumberish) => {
|
||||
const storageSlot = keccak256(
|
||||
ethers.AbiCoder.defaultAbiCoder().encode(["address", "uint256"], [deployer.address, slot])
|
||||
);
|
||||
await ethers.provider.send("hardhat_setStorageAt", [tokenAddress, storageSlot, toQuantity(balance)]);
|
||||
const token = await ethers.getContractAt("MockERC20", tokenAddress, deployer);
|
||||
expect(await token.balanceOf(deployer.address)).to.eq(balance);
|
||||
};
|
||||
|
||||
const mockETHBalance = async (balance: bigint) => {
|
||||
await network.provider.send("hardhat_setBalance", [deployer.address, toQuantity(balance)]);
|
||||
expect(await ethers.provider.getBalance(deployer.address)).to.eq(balance);
|
||||
};
|
||||
|
||||
const showGasUsage = async (tx: ContractTransactionResponse, desc: string) => {
|
||||
const receipt = await tx.wait();
|
||||
console.log(`${desc}: GasUsed[${receipt!.gasUsed}]`);
|
||||
};
|
||||
|
||||
context("L1 upgrade", async () => {
|
||||
let forkBlock: number;
|
||||
let router: L1GatewayRouter;
|
||||
let messenger: L1ScrollMessenger;
|
||||
let queue: L1MessageQueueWithGasPriceOracle;
|
||||
|
||||
beforeEach(async () => {
|
||||
// fork network
|
||||
const provider = new ethers.JsonRpcProvider("https://rpc.ankr.com/eth");
|
||||
if (!forkBlock) {
|
||||
forkBlock = (await provider.getBlockNumber()) - 10;
|
||||
}
|
||||
await network.provider.request({
|
||||
method: "hardhat_reset",
|
||||
params: [
|
||||
{
|
||||
forking: {
|
||||
jsonRpcUrl: "https://rpc.ankr.com/eth",
|
||||
blockNumber: forkBlock,
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
await network.provider.request({
|
||||
method: "hardhat_impersonateAccount",
|
||||
params: ["0x1100000000000000000000000000000000000011"],
|
||||
});
|
||||
|
||||
// mock eth balance
|
||||
deployer = await ethers.getSigner("0x1100000000000000000000000000000000000011");
|
||||
await mockETHBalance(ethers.parseEther("1000"));
|
||||
|
||||
// mock owner of proxy admin
|
||||
proxyAdmin = await ethers.getContractAt("ProxyAdmin", "0xEB803eb3F501998126bf37bB823646Ed3D59d072", deployer);
|
||||
await ethers.provider.send("hardhat_setStorageAt", [
|
||||
await proxyAdmin.getAddress(),
|
||||
"0x0",
|
||||
ethers.AbiCoder.defaultAbiCoder().encode(["address"], [deployer.address]),
|
||||
]);
|
||||
expect(await proxyAdmin.owner()).to.eq(deployer.address);
|
||||
|
||||
router = await ethers.getContractAt("L1GatewayRouter", L1_ROUTER, deployer);
|
||||
messenger = await ethers.getContractAt("L1ScrollMessenger", L1_MESSENGER, deployer);
|
||||
queue = await ethers.getContractAt("L1MessageQueueWithGasPriceOracle", L1_MESSAGE_QUEUE, deployer);
|
||||
});
|
||||
|
||||
const upgradeL1 = async (proxy: string, impl: string) => {
|
||||
await proxyAdmin.upgrade(proxy, impl);
|
||||
const L1ScrollMessenger = await ethers.getContractFactory("L1ScrollMessenger", deployer);
|
||||
const L1MessageQueueWithGasPriceOracle = await ethers.getContractFactory(
|
||||
"L1MessageQueueWithGasPriceOracle",
|
||||
deployer
|
||||
);
|
||||
const ScrollChain = await ethers.getContractFactory("ScrollChain", deployer);
|
||||
await proxyAdmin.upgrade(
|
||||
L1_MESSENGER,
|
||||
(await L1ScrollMessenger.deploy(L2_MESSENGER, SCROLL_CHAIN, L1_MESSAGE_QUEUE)).getAddress()
|
||||
);
|
||||
await proxyAdmin.upgrade(
|
||||
L1_MESSAGE_QUEUE,
|
||||
(
|
||||
await L1MessageQueueWithGasPriceOracle.deploy(
|
||||
L1_MESSENGER,
|
||||
SCROLL_CHAIN,
|
||||
"0x72CAcBcfDe2d1e19122F8A36a4d6676cd39d7A5d"
|
||||
)
|
||||
).getAddress()
|
||||
);
|
||||
await queue.initializeV2();
|
||||
await proxyAdmin.upgrade(
|
||||
SCROLL_CHAIN,
|
||||
(await ScrollChain.deploy(534352, L1_MESSAGE_QUEUE, "0xA2Ab526e5C5491F10FC05A55F064BF9F7CEf32a0")).getAddress()
|
||||
);
|
||||
};
|
||||
|
||||
it.skip("should succeed on L1ETHGateway", async () => {
|
||||
const L1_GATEWAY = "0x7F2b8C31F88B6006c382775eea88297Ec1e3E905";
|
||||
const L2_GATEWAY = "0x6EA73e05AdC79974B931123675ea8F78FfdacDF0";
|
||||
const L1ETHGateway = await ethers.getContractFactory("L1ETHGateway", deployer);
|
||||
const impl = await L1ETHGateway.deploy(L2_GATEWAY, L1_ROUTER, L1_MESSENGER);
|
||||
const gateway = await ethers.getContractAt("L1ETHGateway", L1_GATEWAY, deployer);
|
||||
const amountIn = ethers.parseEther("1");
|
||||
const fee = await queue.estimateCrossDomainMessageFee(1e6);
|
||||
|
||||
// before upgrade
|
||||
await showGasUsage(
|
||||
await gateway["depositETH(uint256,uint256)"](amountIn, 1e6, { value: amountIn + fee }),
|
||||
"L1ETHGateway.depositETH before upgrade"
|
||||
);
|
||||
await showGasUsage(
|
||||
await router["depositETH(uint256,uint256)"](amountIn, 1e6, { value: amountIn + fee }),
|
||||
"L1GatewayRouter.depositETH before upgrade"
|
||||
);
|
||||
await showGasUsage(
|
||||
await messenger["sendMessage(address,uint256,bytes,uint256)"](deployer.address, amountIn, "0x", 1e6, {
|
||||
value: amountIn + fee,
|
||||
}),
|
||||
"L1ScrollMessenger.sendMessage before upgrade"
|
||||
);
|
||||
|
||||
// do upgrade
|
||||
await upgradeL1(L1_GATEWAY, await impl.getAddress());
|
||||
|
||||
// after upgrade
|
||||
await showGasUsage(
|
||||
await gateway["depositETH(uint256,uint256)"](amountIn, 1e6, { value: amountIn + fee }),
|
||||
"L1ETHGateway.depositETH after upgrade"
|
||||
);
|
||||
await showGasUsage(
|
||||
await router["depositETH(uint256,uint256)"](amountIn, 1e6, { value: amountIn + fee }),
|
||||
"L1GatewayRouter.depositETH after upgrade"
|
||||
);
|
||||
await showGasUsage(
|
||||
await messenger["sendMessage(address,uint256,bytes,uint256)"](deployer.address, amountIn, "0x", 1e6, {
|
||||
value: amountIn + fee,
|
||||
}),
|
||||
"L1ScrollMessenger.sendMessage after upgrade"
|
||||
);
|
||||
});
|
||||
|
||||
it.skip("should succeed on L1WETHGateway", async () => {
|
||||
const L1_WETH = "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2";
|
||||
const L2_WETH = "0x5300000000000000000000000000000000000004";
|
||||
const L1_GATEWAY = "0x7AC440cAe8EB6328de4fA621163a792c1EA9D4fE";
|
||||
const L2_GATEWAY = "0x7003E7B7186f0E6601203b99F7B8DECBfA391cf9";
|
||||
const L1WETHGateway = await ethers.getContractFactory("L1WETHGateway", deployer);
|
||||
const impl = await L1WETHGateway.deploy(L1_WETH, L2_WETH, L2_GATEWAY, L1_ROUTER, L1_MESSENGER);
|
||||
const gateway = await ethers.getContractAt("L1WETHGateway", L1_GATEWAY, deployer);
|
||||
const amountIn = ethers.parseEther("1");
|
||||
const fee = await queue.estimateCrossDomainMessageFee(1e6);
|
||||
const token = await ethers.getContractAt("MockERC20", L1_WETH, deployer);
|
||||
await mockERC20Balance(await token.getAddress(), amountIn * 10n, 3);
|
||||
await token.approve(L1_GATEWAY, MaxUint256);
|
||||
await token.approve(L1_ROUTER, MaxUint256);
|
||||
|
||||
// before upgrade
|
||||
await showGasUsage(
|
||||
await gateway["depositERC20(address,uint256,uint256)"](L1_WETH, amountIn, 1e6, { value: fee }),
|
||||
"L1WETHGateway.depositERC20 WETH before upgrade"
|
||||
);
|
||||
await showGasUsage(
|
||||
await router["depositERC20(address,uint256,uint256)"](L1_WETH, amountIn, 1e6, { value: fee }),
|
||||
"L1GatewayRouter.depositERC20 WETH before upgrade"
|
||||
);
|
||||
|
||||
// do upgrade
|
||||
await upgradeL1(L1_GATEWAY, await impl.getAddress());
|
||||
|
||||
// after upgrade
|
||||
await showGasUsage(
|
||||
await gateway["depositERC20(address,uint256,uint256)"](L1_WETH, amountIn, 1e6, { value: fee }),
|
||||
"L1WETHGateway.depositERC20 WETH after upgrade"
|
||||
);
|
||||
await showGasUsage(
|
||||
await router["depositERC20(address,uint256,uint256)"](L1_WETH, amountIn, 1e6, { value: fee }),
|
||||
"L1GatewayRouter.depositERC20 WETH after upgrade"
|
||||
);
|
||||
});
|
||||
|
||||
it.skip("should succeed on L1StandardERC20Gateway", async () => {
|
||||
const L1_USDT = "0xdAC17F958D2ee523a2206206994597C13D831ec7";
|
||||
const L1_GATEWAY = "0xD8A791fE2bE73eb6E6cF1eb0cb3F36adC9B3F8f9";
|
||||
const L2_GATEWAY = "0xE2b4795039517653c5Ae8C2A9BFdd783b48f447A";
|
||||
const L1StandardERC20Gateway = await ethers.getContractFactory("L1StandardERC20Gateway", deployer);
|
||||
const impl = await L1StandardERC20Gateway.deploy(
|
||||
L2_GATEWAY,
|
||||
L1_ROUTER,
|
||||
L1_MESSENGER,
|
||||
"0xC7d86908ccf644Db7C69437D5852CedBC1aD3f69",
|
||||
"0x66e5312EDeEAef6e80759A0F789e7914Fb401484"
|
||||
);
|
||||
const gateway = await ethers.getContractAt("L1StandardERC20Gateway", L1_GATEWAY, deployer);
|
||||
const amountIn = ethers.parseUnits("1", 6);
|
||||
const fee = await queue.estimateCrossDomainMessageFee(1e6);
|
||||
const token = await ethers.getContractAt("MockERC20", L1_USDT, deployer);
|
||||
await mockERC20Balance(await token.getAddress(), amountIn * 10n, 2);
|
||||
await token.approve(L1_GATEWAY, MaxUint256);
|
||||
await token.approve(L1_ROUTER, MaxUint256);
|
||||
|
||||
// before upgrade
|
||||
await showGasUsage(
|
||||
await gateway["depositERC20(address,uint256,uint256)"](L1_USDT, amountIn, 1e6, { value: fee }),
|
||||
"L1StandardERC20Gateway.depositERC20 USDT before upgrade"
|
||||
);
|
||||
await showGasUsage(
|
||||
await router["depositERC20(address,uint256,uint256)"](L1_USDT, amountIn, 1e6, { value: fee }),
|
||||
"L1GatewayRouter.depositERC20 USDT before upgrade"
|
||||
);
|
||||
|
||||
// do upgrade
|
||||
await upgradeL1(L1_GATEWAY, await impl.getAddress());
|
||||
|
||||
// after upgrade
|
||||
await showGasUsage(
|
||||
await gateway["depositERC20(address,uint256,uint256)"](L1_USDT, amountIn, 1e6, { value: fee }),
|
||||
"L1StandardERC20Gateway.depositERC20 USDT after upgrade"
|
||||
);
|
||||
await showGasUsage(
|
||||
await router["depositERC20(address,uint256,uint256)"](L1_USDT, amountIn, 1e6, { value: fee }),
|
||||
"L1GatewayRouter.depositERC20 USDT after upgrade"
|
||||
);
|
||||
});
|
||||
|
||||
it.skip("should succeed on L1CustomERC20Gateway", async () => {
|
||||
const L1_DAI = "0x6B175474E89094C44Da98b954EedeAC495271d0F";
|
||||
const L1_GATEWAY = "0x67260A8B73C5B77B55c1805218A42A7A6F98F515";
|
||||
const L2_GATEWAY = "0xaC78dff3A87b5b534e366A93E785a0ce8fA6Cc62";
|
||||
const L1CustomERC20Gateway = await ethers.getContractFactory("L1CustomERC20Gateway", deployer);
|
||||
const impl = await L1CustomERC20Gateway.deploy(L2_GATEWAY, L1_ROUTER, L1_MESSENGER);
|
||||
const gateway = await ethers.getContractAt("L1CustomERC20Gateway", L1_GATEWAY, deployer);
|
||||
const amountIn = ethers.parseUnits("1", 18);
|
||||
const fee = await queue.estimateCrossDomainMessageFee(1e6);
|
||||
const token = await ethers.getContractAt("MockERC20", L1_DAI, deployer);
|
||||
await mockERC20Balance(await token.getAddress(), amountIn * 10n, 2);
|
||||
await token.approve(L1_GATEWAY, MaxUint256);
|
||||
await token.approve(L1_ROUTER, MaxUint256);
|
||||
|
||||
// before upgrade
|
||||
await showGasUsage(
|
||||
await gateway["depositERC20(address,uint256,uint256)"](L1_DAI, amountIn, 1e6, { value: fee }),
|
||||
"L1CustomERC20Gateway.depositERC20 DAI before upgrade"
|
||||
);
|
||||
await showGasUsage(
|
||||
await router["depositERC20(address,uint256,uint256)"](L1_DAI, amountIn, 1e6, { value: fee }),
|
||||
"L1GatewayRouter.depositERC20 DAI before upgrade"
|
||||
);
|
||||
|
||||
// do upgrade
|
||||
await upgradeL1(L1_GATEWAY, await impl.getAddress());
|
||||
|
||||
// after upgrade
|
||||
await showGasUsage(
|
||||
await gateway["depositERC20(address,uint256,uint256)"](L1_DAI, amountIn, 1e6, { value: fee }),
|
||||
"L1CustomERC20Gateway.depositERC20 DAI after upgrade"
|
||||
);
|
||||
await showGasUsage(
|
||||
await router["depositERC20(address,uint256,uint256)"](L1_DAI, amountIn, 1e6, { value: fee }),
|
||||
"L1GatewayRouter.depositERC20 DAI after upgrade"
|
||||
);
|
||||
});
|
||||
|
||||
it.skip("should succeed on L1USDCGateway", async () => {
|
||||
const L1_USDC = "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48";
|
||||
const L2_USDC = "0x06eFdBFf2a14a7c8E15944D1F4A48F9F95F663A4";
|
||||
const L1_GATEWAY = "0xf1AF3b23DE0A5Ca3CAb7261cb0061C0D779A5c7B";
|
||||
const L2_GATEWAY = "0x33B60d5Dd260d453cAC3782b0bDC01ce84672142";
|
||||
const L1USDCGateway = await ethers.getContractFactory("L1USDCGateway", deployer);
|
||||
const impl = await L1USDCGateway.deploy(L1_USDC, L2_USDC, L2_GATEWAY, L1_ROUTER, L1_MESSENGER);
|
||||
const gateway = await ethers.getContractAt("L1USDCGateway", L1_GATEWAY, deployer);
|
||||
const amountIn = ethers.parseUnits("1", 6);
|
||||
const fee = await queue.estimateCrossDomainMessageFee(1e6);
|
||||
const token = await ethers.getContractAt("MockERC20", L1_USDC, deployer);
|
||||
await mockERC20Balance(await token.getAddress(), amountIn * 10n, 9);
|
||||
await token.approve(L1_GATEWAY, MaxUint256);
|
||||
await token.approve(L1_ROUTER, MaxUint256);
|
||||
|
||||
// before upgrade
|
||||
await showGasUsage(
|
||||
await gateway["depositERC20(address,uint256,uint256)"](L1_USDC, amountIn, 1e6, { value: fee }),
|
||||
"L1USDCGateway.depositERC20 USDC before upgrade"
|
||||
);
|
||||
await showGasUsage(
|
||||
await router["depositERC20(address,uint256,uint256)"](L1_USDC, amountIn, 1e6, { value: fee }),
|
||||
"L1GatewayRouter.depositERC20 USDC before upgrade"
|
||||
);
|
||||
|
||||
// do upgrade
|
||||
await upgradeL1(L1_GATEWAY, await impl.getAddress());
|
||||
|
||||
// after upgrade
|
||||
await showGasUsage(
|
||||
await gateway["depositERC20(address,uint256,uint256)"](L1_USDC, amountIn, 1e6, { value: fee }),
|
||||
"L1USDCGateway.depositERC20 USDC after upgrade"
|
||||
);
|
||||
await showGasUsage(
|
||||
await router["depositERC20(address,uint256,uint256)"](L1_USDC, amountIn, 1e6, { value: fee }),
|
||||
"L1GatewayRouter.depositERC20 USDC after upgrade"
|
||||
);
|
||||
});
|
||||
|
||||
it.skip("should succeed on L1LidoGateway", async () => {
|
||||
const L1_WSTETH = "0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0";
|
||||
const L2_WSTETH = "0xf610A9dfB7C89644979b4A0f27063E9e7d7Cda32";
|
||||
const L1_GATEWAY = "0x6625C6332c9F91F2D27c304E729B86db87A3f504";
|
||||
const L2_GATEWAY = "0x8aE8f22226B9d789A36AC81474e633f8bE2856c9";
|
||||
const L1LidoGateway = await ethers.getContractFactory("L1LidoGateway", deployer);
|
||||
const impl = await L1LidoGateway.deploy(L1_WSTETH, L2_WSTETH, L2_GATEWAY, L1_ROUTER, L1_MESSENGER);
|
||||
const gateway = await ethers.getContractAt("L1LidoGateway", L1_GATEWAY, deployer);
|
||||
const amountIn = ethers.parseUnits("1", 6);
|
||||
const fee = await queue.estimateCrossDomainMessageFee(1e6);
|
||||
const token = await ethers.getContractAt("MockERC20", L1_WSTETH, deployer);
|
||||
await mockERC20Balance(await token.getAddress(), amountIn * 10n, 0);
|
||||
await token.approve(L1_GATEWAY, MaxUint256);
|
||||
await token.approve(L1_ROUTER, MaxUint256);
|
||||
|
||||
// before upgrade
|
||||
await showGasUsage(
|
||||
await gateway["depositERC20(address,uint256,uint256)"](L1_WSTETH, amountIn, 1e6, { value: fee }),
|
||||
"L1LidoGateway.depositERC20 wstETH before upgrade"
|
||||
);
|
||||
await showGasUsage(
|
||||
await router["depositERC20(address,uint256,uint256)"](L1_WSTETH, amountIn, 1e6, { value: fee }),
|
||||
"L1GatewayRouter.depositERC20 wstETH before upgrade"
|
||||
);
|
||||
|
||||
// do upgrade
|
||||
await upgradeL1(L1_GATEWAY, await impl.getAddress());
|
||||
await gateway.initializeV2(deployer.address, deployer.address, deployer.address, deployer.address);
|
||||
|
||||
// after upgrade
|
||||
await showGasUsage(
|
||||
await gateway["depositERC20(address,uint256,uint256)"](L1_WSTETH, amountIn, 1e6, { value: fee }),
|
||||
"L1LidoGateway.depositERC20 wstETH after upgrade"
|
||||
);
|
||||
await showGasUsage(
|
||||
await router["depositERC20(address,uint256,uint256)"](L1_WSTETH, amountIn, 1e6, { value: fee }),
|
||||
"L1GatewayRouter.depositERC20 wstETH after upgrade"
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
context("L2 upgrade", async () => {
|
||||
let forkBlock: number;
|
||||
let router: L2GatewayRouter;
|
||||
let messenger: L2ScrollMessenger;
|
||||
|
||||
beforeEach(async () => {
|
||||
// fork network
|
||||
const provider = new ethers.JsonRpcProvider("https://rpc.scroll.io");
|
||||
if (!forkBlock) {
|
||||
forkBlock = (await provider.getBlockNumber()) - 31;
|
||||
}
|
||||
await network.provider.request({
|
||||
method: "hardhat_reset",
|
||||
params: [
|
||||
{
|
||||
forking: {
|
||||
jsonRpcUrl: "https://rpc.scroll.io",
|
||||
blockNumber: forkBlock,
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
await network.provider.request({
|
||||
method: "hardhat_impersonateAccount",
|
||||
params: ["0x1100000000000000000000000000000000000011"],
|
||||
});
|
||||
|
||||
// mock eth balance
|
||||
deployer = await ethers.getSigner("0x1100000000000000000000000000000000000011");
|
||||
await mockETHBalance(ethers.parseEther("1000"));
|
||||
|
||||
// mock owner of proxy admin
|
||||
proxyAdmin = await ethers.getContractAt("ProxyAdmin", "0xA76acF000C890b0DD7AEEf57627d9899F955d026", deployer);
|
||||
await ethers.provider.send("hardhat_setStorageAt", [
|
||||
await proxyAdmin.getAddress(),
|
||||
"0x0",
|
||||
ethers.AbiCoder.defaultAbiCoder().encode(["address"], [deployer.address]),
|
||||
]);
|
||||
expect(await proxyAdmin.owner()).to.eq(deployer.address);
|
||||
|
||||
router = await ethers.getContractAt("L2GatewayRouter", L2_ROUTER, deployer);
|
||||
messenger = await ethers.getContractAt("L2ScrollMessenger", L2_MESSENGER, deployer);
|
||||
});
|
||||
|
||||
const upgradeL2 = async (proxy: string, impl: string) => {
|
||||
await proxyAdmin.upgrade(proxy, impl);
|
||||
const L2ScrollMessenger = await ethers.getContractFactory("L2ScrollMessenger", deployer);
|
||||
await proxyAdmin.upgrade(
|
||||
L2_MESSENGER,
|
||||
(await L2ScrollMessenger.deploy(L1_MESSENGER, L2_MESSAGE_QUEUE)).getAddress()
|
||||
);
|
||||
};
|
||||
|
||||
it.skip("should succeed on L2ETHGateway", async () => {
|
||||
const L1_GATEWAY = "0x7F2b8C31F88B6006c382775eea88297Ec1e3E905";
|
||||
const L2_GATEWAY = "0x6EA73e05AdC79974B931123675ea8F78FfdacDF0";
|
||||
const L2ETHGateway = await ethers.getContractFactory("L2ETHGateway", deployer);
|
||||
const impl = await L2ETHGateway.deploy(L1_GATEWAY, L2_ROUTER, L2_MESSENGER);
|
||||
const gateway = await ethers.getContractAt("L2ETHGateway", L2_GATEWAY, deployer);
|
||||
const amountIn = ethers.parseEther("1");
|
||||
|
||||
// before upgrade
|
||||
await showGasUsage(
|
||||
await gateway["withdrawETH(uint256,uint256)"](amountIn, 1e6, { value: amountIn }),
|
||||
"L2ETHGateway.withdrawETH before upgrade"
|
||||
);
|
||||
await showGasUsage(
|
||||
await router["withdrawETH(uint256,uint256)"](amountIn, 1e6, { value: amountIn }),
|
||||
"L2GatewayRouter.withdrawETH before upgrade"
|
||||
);
|
||||
await showGasUsage(
|
||||
await messenger["sendMessage(address,uint256,bytes,uint256)"](deployer.address, amountIn, "0x", 1e6, {
|
||||
value: amountIn,
|
||||
}),
|
||||
"L2ScrollMessenger.sendMessage before upgrade"
|
||||
);
|
||||
|
||||
// do upgrade
|
||||
await upgradeL2(L2_GATEWAY, await impl.getAddress());
|
||||
|
||||
// after upgrade
|
||||
await showGasUsage(
|
||||
await gateway["withdrawETH(uint256,uint256)"](amountIn, 1e6, { value: amountIn }),
|
||||
"L2ETHGateway.withdrawETH after upgrade"
|
||||
);
|
||||
await showGasUsage(
|
||||
await router["withdrawETH(uint256,uint256)"](amountIn, 1e6, { value: amountIn }),
|
||||
"L2GatewayRouter.withdrawETH after upgrade"
|
||||
);
|
||||
await showGasUsage(
|
||||
await messenger["sendMessage(address,uint256,bytes,uint256)"](deployer.address, amountIn, "0x", 1e6, {
|
||||
value: amountIn,
|
||||
}),
|
||||
"L2ScrollMessenger.sendMessage after upgrade"
|
||||
);
|
||||
});
|
||||
|
||||
it.skip("should succeed on L2WETHGateway", async () => {
|
||||
const L1_WETH = "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2";
|
||||
const L2_WETH = "0x5300000000000000000000000000000000000004";
|
||||
const L1_GATEWAY = "0x7AC440cAe8EB6328de4fA621163a792c1EA9D4fE";
|
||||
const L2_GATEWAY = "0x7003E7B7186f0E6601203b99F7B8DECBfA391cf9";
|
||||
const L2WETHGateway = await ethers.getContractFactory("L2WETHGateway", deployer);
|
||||
const impl = await L2WETHGateway.deploy(L2_WETH, L1_WETH, L1_GATEWAY, L2_ROUTER, L2_MESSENGER);
|
||||
const gateway = await ethers.getContractAt("L2WETHGateway", L2_GATEWAY, deployer);
|
||||
const amountIn = ethers.parseEther("1");
|
||||
const token = await ethers.getContractAt("MockERC20", L2_WETH, deployer);
|
||||
await mockERC20Balance(await token.getAddress(), amountIn * 10n, 0);
|
||||
await token.approve(L2_GATEWAY, MaxUint256);
|
||||
await token.approve(L2_ROUTER, MaxUint256);
|
||||
|
||||
// before upgrade
|
||||
await showGasUsage(
|
||||
await gateway["withdrawERC20(address,uint256,uint256)"](L2_WETH, amountIn, 1e6),
|
||||
"L2WETHGateway.withdrawERC20 WETH before upgrade"
|
||||
);
|
||||
await showGasUsage(
|
||||
await router["withdrawERC20(address,uint256,uint256)"](L2_WETH, amountIn, 1e6),
|
||||
"L2GatewayRouter.withdrawERC20 WETH before upgrade"
|
||||
);
|
||||
|
||||
// do upgrade
|
||||
await upgradeL2(L2_GATEWAY, await impl.getAddress());
|
||||
|
||||
// after upgrade
|
||||
await showGasUsage(
|
||||
await gateway["withdrawERC20(address,uint256,uint256)"](L2_WETH, amountIn, 1e6),
|
||||
"L2WETHGateway.withdrawERC20 WETH after upgrade"
|
||||
);
|
||||
await showGasUsage(
|
||||
await router["withdrawERC20(address,uint256,uint256)"](L2_WETH, amountIn, 1e6),
|
||||
"L2GatewayRouter.withdrawERC20 WETH after upgrade"
|
||||
);
|
||||
});
|
||||
|
||||
it.skip("should succeed on L2StandardERC20Gateway", async () => {
|
||||
const L2_USDT = "0xf55BEC9cafDbE8730f096Aa55dad6D22d44099Df";
|
||||
const L1_GATEWAY = "0xD8A791fE2bE73eb6E6cF1eb0cb3F36adC9B3F8f9";
|
||||
const L2_GATEWAY = "0xE2b4795039517653c5Ae8C2A9BFdd783b48f447A";
|
||||
const L2StandardERC20Gateway = await ethers.getContractFactory("L2StandardERC20Gateway", deployer);
|
||||
const impl = await L2StandardERC20Gateway.deploy(
|
||||
L1_GATEWAY,
|
||||
L2_ROUTER,
|
||||
L2_MESSENGER,
|
||||
"0x66e5312EDeEAef6e80759A0F789e7914Fb401484"
|
||||
);
|
||||
const gateway = await ethers.getContractAt("L2StandardERC20Gateway", L2_GATEWAY, deployer);
|
||||
const amountIn = ethers.parseUnits("1", 6);
|
||||
const token = await ethers.getContractAt("MockERC20", L2_USDT, deployer);
|
||||
await mockERC20Balance(await token.getAddress(), amountIn * 10n, 51);
|
||||
await token.approve(L2_GATEWAY, MaxUint256);
|
||||
await token.approve(L2_ROUTER, MaxUint256);
|
||||
|
||||
// before upgrade
|
||||
await showGasUsage(
|
||||
await gateway["withdrawERC20(address,uint256,uint256)"](L2_USDT, amountIn, 1e6),
|
||||
"L2StandardERC20Gateway.withdrawERC20 USDT before upgrade"
|
||||
);
|
||||
await showGasUsage(
|
||||
await router["withdrawERC20(address,uint256,uint256)"](L2_USDT, amountIn, 1e6),
|
||||
"L2GatewayRouter.withdrawERC20 USDT before upgrade"
|
||||
);
|
||||
|
||||
// do upgrade
|
||||
await upgradeL2(L2_GATEWAY, await impl.getAddress());
|
||||
|
||||
// after upgrade
|
||||
await showGasUsage(
|
||||
await gateway["withdrawERC20(address,uint256,uint256)"](L2_USDT, amountIn, 1e6),
|
||||
"L2StandardERC20Gateway.withdrawERC20 USDT after upgrade"
|
||||
);
|
||||
await showGasUsage(
|
||||
await router["withdrawERC20(address,uint256,uint256)"](L2_USDT, amountIn, 1e6),
|
||||
"L2GatewayRouter.withdrawERC20 USDT after upgrade"
|
||||
);
|
||||
});
|
||||
|
||||
it.skip("should succeed on L2CustomERC20Gateway", async () => {
|
||||
const L2_DAI = "0xcA77eB3fEFe3725Dc33bccB54eDEFc3D9f764f97";
|
||||
const L1_GATEWAY = "0x67260A8B73C5B77B55c1805218A42A7A6F98F515";
|
||||
const L2_GATEWAY = "0xaC78dff3A87b5b534e366A93E785a0ce8fA6Cc62";
|
||||
const L2CustomERC20Gateway = await ethers.getContractFactory("L2CustomERC20Gateway", deployer);
|
||||
const impl = await L2CustomERC20Gateway.deploy(L1_GATEWAY, L2_ROUTER, L2_MESSENGER);
|
||||
const gateway = await ethers.getContractAt("L2CustomERC20Gateway", L2_GATEWAY, deployer);
|
||||
const amountIn = ethers.parseUnits("1", 18);
|
||||
const token = await ethers.getContractAt("MockERC20", L2_DAI, deployer);
|
||||
await mockERC20Balance(await token.getAddress(), amountIn * 10n, 51);
|
||||
await token.approve(L1_GATEWAY, MaxUint256);
|
||||
await token.approve(L1_ROUTER, MaxUint256);
|
||||
|
||||
// before upgrade
|
||||
await showGasUsage(
|
||||
await gateway["withdrawERC20(address,uint256,uint256)"](L2_DAI, amountIn, 1e6),
|
||||
"L2CustomERC20Gateway.withdrawERC20 DAI before upgrade"
|
||||
);
|
||||
await showGasUsage(
|
||||
await router["withdrawERC20(address,uint256,uint256)"](L2_DAI, amountIn, 1e6),
|
||||
"L2GatewayRouter.withdrawERC20 DAI before upgrade"
|
||||
);
|
||||
|
||||
// do upgrade
|
||||
await upgradeL2(L2_GATEWAY, await impl.getAddress());
|
||||
|
||||
// after upgrade
|
||||
await showGasUsage(
|
||||
await gateway["withdrawERC20(address,uint256,uint256)"](L2_DAI, amountIn, 1e6),
|
||||
"L2CustomERC20Gateway.withdrawERC20 DAI after upgrade"
|
||||
);
|
||||
await showGasUsage(
|
||||
await router["withdrawERC20(address,uint256,uint256)"](L2_DAI, amountIn, 1e6),
|
||||
"L2GatewayRouter.withdrawERC20 DAI after upgrade"
|
||||
);
|
||||
});
|
||||
|
||||
it.skip("should succeed on L2USDCGateway", async () => {
|
||||
const L1_USDC = "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48";
|
||||
const L2_USDC = "0x06eFdBFf2a14a7c8E15944D1F4A48F9F95F663A4";
|
||||
const L1_GATEWAY = "0xf1AF3b23DE0A5Ca3CAb7261cb0061C0D779A5c7B";
|
||||
const L2_GATEWAY = "0x33B60d5Dd260d453cAC3782b0bDC01ce84672142";
|
||||
const L2USDCGateway = await ethers.getContractFactory("L2USDCGateway", deployer);
|
||||
const impl = await L2USDCGateway.deploy(L1_USDC, L2_USDC, L1_GATEWAY, L2_ROUTER, L2_MESSENGER);
|
||||
const gateway = await ethers.getContractAt("L2USDCGateway", L2_GATEWAY, deployer);
|
||||
const amountIn = ethers.parseUnits("1", 6);
|
||||
const token = await ethers.getContractAt("MockERC20", L2_USDC, deployer);
|
||||
await mockERC20Balance(await token.getAddress(), amountIn * 10n, 9);
|
||||
await token.approve(L2_GATEWAY, MaxUint256);
|
||||
await token.approve(L2_ROUTER, MaxUint256);
|
||||
|
||||
// before upgrade
|
||||
await showGasUsage(
|
||||
await gateway["withdrawERC20(address,uint256,uint256)"](L2_USDC, amountIn, 1e6),
|
||||
"L2USDCGateway.withdrawERC20 USDC before upgrade"
|
||||
);
|
||||
await showGasUsage(
|
||||
await router["withdrawERC20(address,uint256,uint256)"](L2_USDC, amountIn, 1e6),
|
||||
"L2GatewayRouter.withdrawERC20 USDC before upgrade"
|
||||
);
|
||||
|
||||
// do upgrade
|
||||
await upgradeL2(L2_GATEWAY, await impl.getAddress());
|
||||
|
||||
// after upgrade
|
||||
await showGasUsage(
|
||||
await gateway["withdrawERC20(address,uint256,uint256)"](L2_USDC, amountIn, 1e6),
|
||||
"L2USDCGateway.withdrawERC20 USDC after upgrade"
|
||||
);
|
||||
await showGasUsage(
|
||||
await router["withdrawERC20(address,uint256,uint256)"](L2_USDC, amountIn, 1e6),
|
||||
"L2GatewayRouter.withdrawERC20 USDC after upgrade"
|
||||
);
|
||||
});
|
||||
|
||||
it.skip("should succeed on L2LidoGateway", async () => {
|
||||
const L1_WSTETH = "0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0";
|
||||
const L2_WSTETH = "0xf610A9dfB7C89644979b4A0f27063E9e7d7Cda32";
|
||||
const L1_GATEWAY = "0x6625C6332c9F91F2D27c304E729B86db87A3f504";
|
||||
const L2_GATEWAY = "0x8aE8f22226B9d789A36AC81474e633f8bE2856c9";
|
||||
const L2LidoGateway = await ethers.getContractFactory("L2LidoGateway", deployer);
|
||||
const impl = await L2LidoGateway.deploy(L1_WSTETH, L2_WSTETH, L1_GATEWAY, L2_ROUTER, L2_MESSENGER);
|
||||
const gateway = await ethers.getContractAt("L2LidoGateway", L2_GATEWAY, deployer);
|
||||
const amountIn = ethers.parseUnits("1", 6);
|
||||
const token = await ethers.getContractAt("MockERC20", L2_WSTETH, deployer);
|
||||
await mockERC20Balance(await token.getAddress(), amountIn * 10n, 51);
|
||||
await token.approve(L2_GATEWAY, MaxUint256);
|
||||
await token.approve(L2_ROUTER, MaxUint256);
|
||||
|
||||
// before upgrade
|
||||
await showGasUsage(
|
||||
await gateway["withdrawERC20(address,uint256,uint256)"](L2_WSTETH, amountIn, 1e6),
|
||||
"L2LidoGateway.withdrawERC20 wstETH before upgrade"
|
||||
);
|
||||
await showGasUsage(
|
||||
await router["withdrawERC20(address,uint256,uint256)"](L2_WSTETH, amountIn, 1e6),
|
||||
"L2GatewayRouter.withdrawERC20 wstETH before upgrade"
|
||||
);
|
||||
|
||||
// do upgrade
|
||||
await upgradeL2(L2_GATEWAY, await impl.getAddress());
|
||||
await gateway.initializeV2(deployer.address, deployer.address, deployer.address, deployer.address);
|
||||
|
||||
// after upgrade
|
||||
await showGasUsage(
|
||||
await gateway["withdrawERC20(address,uint256,uint256)"](L2_WSTETH, amountIn, 1e6),
|
||||
"L2LidoGateway.withdrawERC20 wstETH after upgrade"
|
||||
);
|
||||
await showGasUsage(
|
||||
await router["withdrawERC20(address,uint256,uint256)"](L2_WSTETH, amountIn, 1e6),
|
||||
"L2GatewayRouter.withdrawERC20 wstETH after upgrade"
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
329
contracts/integration-test/GasSwap.spec.ts
Normal file
329
contracts/integration-test/GasSwap.spec.ts
Normal file
@@ -0,0 +1,329 @@
|
||||
/* eslint-disable node/no-unpublished-import */
|
||||
/* eslint-disable node/no-missing-import */
|
||||
import { HardhatEthersSigner } from "@nomicfoundation/hardhat-ethers/signers";
|
||||
import { expect } from "chai";
|
||||
import { MaxUint256, Signature, ZeroAddress, ZeroHash, toBigInt } from "ethers";
|
||||
import { ethers } from "hardhat";
|
||||
|
||||
import { GasSwap, ERC2771Forwarder, MockERC20, MockGasSwapTarget } from "../typechain";
|
||||
|
||||
describe("GasSwap.spec", async () => {
|
||||
let deployer: HardhatEthersSigner;
|
||||
let signer: HardhatEthersSigner;
|
||||
|
||||
let forwarder: ERC2771Forwarder;
|
||||
let swap: GasSwap;
|
||||
let target: MockGasSwapTarget;
|
||||
let token: MockERC20;
|
||||
|
||||
beforeEach(async () => {
|
||||
[deployer, signer] = await ethers.getSigners();
|
||||
|
||||
const ERC2771Forwarder = await ethers.getContractFactory("ERC2771Forwarder", deployer);
|
||||
forwarder = await ERC2771Forwarder.deploy("ERC2771Forwarder");
|
||||
|
||||
const GasSwap = await ethers.getContractFactory("GasSwap", deployer);
|
||||
swap = await GasSwap.deploy(forwarder.getAddress());
|
||||
|
||||
const MockGasSwapTarget = await ethers.getContractFactory("MockGasSwapTarget", deployer);
|
||||
target = await MockGasSwapTarget.deploy();
|
||||
|
||||
const MockERC20 = await ethers.getContractFactory("MockERC20", deployer);
|
||||
token = await MockERC20.deploy("x", "y", 18);
|
||||
});
|
||||
|
||||
context("auth", async () => {
|
||||
it("should initialize correctly", async () => {
|
||||
expect(await swap.owner()).to.eq(deployer.address);
|
||||
});
|
||||
|
||||
context("#updateFeeRatio", async () => {
|
||||
it("should revert, when non-owner call", async () => {
|
||||
await expect(swap.connect(signer).updateFeeRatio(1)).to.revertedWith("Ownable: caller is not the owner");
|
||||
});
|
||||
|
||||
it("should succeed", async () => {
|
||||
expect(await swap.feeRatio()).to.eq(ZeroAddress);
|
||||
await expect(swap.updateFeeRatio(100)).to.emit(swap, "UpdateFeeRatio").withArgs(100);
|
||||
expect(await swap.feeRatio()).to.eq(100);
|
||||
});
|
||||
});
|
||||
|
||||
context("#updateApprovedTarget", async () => {
|
||||
it("should revert, when non-owner call", async () => {
|
||||
await expect(swap.connect(signer).updateApprovedTarget(target.getAddress(), false)).to.revertedWith(
|
||||
"Ownable: caller is not the owner"
|
||||
);
|
||||
});
|
||||
|
||||
it("should succeed", async () => {
|
||||
expect(await swap.approvedTargets(target.getAddress())).to.eq(false);
|
||||
await expect(swap.updateApprovedTarget(target.getAddress(), true))
|
||||
.to.emit(swap, "UpdateApprovedTarget")
|
||||
.withArgs(await target.getAddress(), true);
|
||||
expect(await swap.approvedTargets(target.getAddress())).to.eq(true);
|
||||
await expect(swap.updateApprovedTarget(target.getAddress(), false))
|
||||
.to.emit(swap, "UpdateApprovedTarget")
|
||||
.withArgs(await target.getAddress(), false);
|
||||
expect(await swap.approvedTargets(target.getAddress())).to.eq(false);
|
||||
});
|
||||
});
|
||||
|
||||
context("#withdraw", async () => {
|
||||
it("should revert, when non-owner call", async () => {
|
||||
await expect(swap.connect(signer).withdraw(ZeroAddress, 0)).to.revertedWith("Ownable: caller is not the owner");
|
||||
});
|
||||
|
||||
it("should succeed, when withdraw ETH", async () => {
|
||||
await deployer.sendTransaction({ to: swap.getAddress(), value: ethers.parseEther("1") });
|
||||
const balanceBefore = await ethers.provider.getBalance(deployer.address);
|
||||
const tx = await swap.withdraw(ZeroAddress, ethers.parseEther("1"));
|
||||
const receipt = await tx.wait();
|
||||
const balanceAfter = await ethers.provider.getBalance(deployer.address);
|
||||
expect(balanceAfter - balanceBefore).to.eq(ethers.parseEther("1") - receipt!.gasUsed * receipt!.gasPrice);
|
||||
});
|
||||
|
||||
it("should succeed, when withdraw token", async () => {
|
||||
await token.mint(swap.getAddress(), ethers.parseEther("1"));
|
||||
const balanceBefore = await token.balanceOf(deployer.address);
|
||||
await swap.withdraw(token.getAddress(), ethers.parseEther("1"));
|
||||
const balanceAfter = await token.balanceOf(deployer.address);
|
||||
expect(balanceAfter - balanceBefore).to.eq(ethers.parseEther("1"));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
const permit = async (amount: bigint) => {
|
||||
const value = {
|
||||
owner: signer.address,
|
||||
spender: await swap.getAddress(),
|
||||
value: amount,
|
||||
nonce: await token.nonces(signer.address),
|
||||
deadline: MaxUint256,
|
||||
};
|
||||
|
||||
const domain = {
|
||||
name: await token.name(),
|
||||
version: "1",
|
||||
chainId: (await ethers.provider.getNetwork()).chainId,
|
||||
verifyingContract: await token.getAddress(),
|
||||
};
|
||||
|
||||
const types = {
|
||||
Permit: [
|
||||
{
|
||||
name: "owner",
|
||||
type: "address",
|
||||
},
|
||||
{
|
||||
name: "spender",
|
||||
type: "address",
|
||||
},
|
||||
{
|
||||
name: "value",
|
||||
type: "uint256",
|
||||
},
|
||||
{
|
||||
name: "nonce",
|
||||
type: "uint256",
|
||||
},
|
||||
{
|
||||
name: "deadline",
|
||||
type: "uint256",
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const signature = Signature.from(await signer.signTypedData(domain, types, value));
|
||||
return signature;
|
||||
};
|
||||
|
||||
context("swap", async () => {
|
||||
it("should revert, when target not approved", async () => {
|
||||
await expect(
|
||||
swap.swap(
|
||||
{
|
||||
token: token.getAddress(),
|
||||
value: 0,
|
||||
deadline: 0,
|
||||
r: ZeroHash,
|
||||
s: ZeroHash,
|
||||
v: 0,
|
||||
},
|
||||
{
|
||||
target: target.getAddress(),
|
||||
data: "0x",
|
||||
minOutput: 0,
|
||||
}
|
||||
)
|
||||
).to.revertedWith("target not approved");
|
||||
});
|
||||
|
||||
it("should revert, when insufficient output amount", async () => {
|
||||
const amountIn = ethers.parseEther("1");
|
||||
const amountOut = ethers.parseEther("2");
|
||||
await token.mint(signer.address, amountIn);
|
||||
await deployer.sendTransaction({ to: target.getAddress(), value: amountOut });
|
||||
const signature = await permit(amountIn);
|
||||
|
||||
await target.setToken(token.getAddress());
|
||||
await target.setAmountIn(amountIn);
|
||||
|
||||
await swap.updateApprovedTarget(target.getAddress(), true);
|
||||
await expect(
|
||||
swap.connect(signer).swap(
|
||||
{
|
||||
token: await token.getAddress(),
|
||||
value: amountIn,
|
||||
deadline: MaxUint256,
|
||||
r: signature.r,
|
||||
s: signature.s,
|
||||
v: signature.v,
|
||||
},
|
||||
{
|
||||
target: target.getAddress(),
|
||||
data: "0x8119c065",
|
||||
minOutput: amountOut + 1n,
|
||||
}
|
||||
)
|
||||
).to.revertedWith("insufficient output amount");
|
||||
});
|
||||
|
||||
for (const refundRatio of [0n, 1n, 5n]) {
|
||||
for (const feeRatio of ["0", "5", "50"]) {
|
||||
it(`should succeed, when swap by signer directly, with feeRatio[${feeRatio}%] refundRatio[${refundRatio}%]`, async () => {
|
||||
const amountIn = ethers.parseEther("1");
|
||||
const amountOut = ethers.parseEther("2");
|
||||
await token.mint(signer.address, amountIn);
|
||||
await deployer.sendTransaction({ to: target.getAddress(), value: amountOut });
|
||||
const signature = await permit(amountIn);
|
||||
|
||||
await target.setToken(token.getAddress());
|
||||
await target.setAmountIn(amountIn);
|
||||
await target.setRefund((amountIn * refundRatio) / 100n);
|
||||
|
||||
await swap.updateApprovedTarget(target.getAddress(), true);
|
||||
await swap.updateFeeRatio(ethers.parseEther(feeRatio) / 100n);
|
||||
const fee = (amountOut * toBigInt(feeRatio)) / 100n;
|
||||
|
||||
const balanceBefore = await ethers.provider.getBalance(signer.address);
|
||||
const tx = await swap.connect(signer).swap(
|
||||
{
|
||||
token: await token.getAddress(),
|
||||
value: amountIn,
|
||||
deadline: MaxUint256,
|
||||
r: signature.r,
|
||||
s: signature.s,
|
||||
v: signature.v,
|
||||
},
|
||||
{
|
||||
target: target.getAddress(),
|
||||
data: "0x8119c065",
|
||||
minOutput: amountOut - fee,
|
||||
}
|
||||
);
|
||||
const receipt = await tx.wait();
|
||||
const balanceAfter = await ethers.provider.getBalance(signer.address);
|
||||
expect(balanceAfter - balanceBefore).to.eq(amountOut - fee - receipt!.gasUsed * receipt!.gasPrice);
|
||||
expect(await token.balanceOf(signer.address)).to.eq((amountIn * refundRatio) / 100n);
|
||||
});
|
||||
|
||||
it(`should succeed, when swap by signer with forwarder, with feeRatio[${feeRatio}%] refundRatio[${refundRatio}%]`, async () => {
|
||||
const amountIn = ethers.parseEther("1");
|
||||
const amountOut = ethers.parseEther("2");
|
||||
await token.mint(signer.address, amountIn);
|
||||
await deployer.sendTransaction({ to: await target.getAddress(), value: amountOut });
|
||||
const permitSignature = await permit(amountIn);
|
||||
|
||||
await target.setToken(token.getAddress());
|
||||
await target.setAmountIn(amountIn);
|
||||
await target.setRefund((amountIn * refundRatio) / 100n);
|
||||
|
||||
await swap.updateApprovedTarget(target.getAddress(), true);
|
||||
await swap.updateFeeRatio(ethers.parseEther(feeRatio) / 100n);
|
||||
const fee = (amountOut * toBigInt(feeRatio)) / 100n;
|
||||
|
||||
const reqWithoutSignature = {
|
||||
from: signer.address,
|
||||
to: await swap.getAddress(),
|
||||
value: 0n,
|
||||
gas: 1000000,
|
||||
nonce: await forwarder.nonces(signer.address),
|
||||
deadline: 2000000000,
|
||||
data: swap.interface.encodeFunctionData("swap", [
|
||||
{
|
||||
token: await token.getAddress(),
|
||||
value: amountIn,
|
||||
deadline: MaxUint256,
|
||||
r: permitSignature.r,
|
||||
s: permitSignature.s,
|
||||
v: permitSignature.v,
|
||||
},
|
||||
{
|
||||
target: await target.getAddress(),
|
||||
data: "0x8119c065",
|
||||
minOutput: amountOut - fee,
|
||||
},
|
||||
]),
|
||||
};
|
||||
|
||||
const signature = await signer.signTypedData(
|
||||
{
|
||||
name: "ERC2771Forwarder",
|
||||
version: "1",
|
||||
chainId: (await ethers.provider.getNetwork()).chainId,
|
||||
verifyingContract: await forwarder.getAddress(),
|
||||
},
|
||||
{
|
||||
ForwardRequest: [
|
||||
{
|
||||
name: "from",
|
||||
type: "address",
|
||||
},
|
||||
{
|
||||
name: "to",
|
||||
type: "address",
|
||||
},
|
||||
{
|
||||
name: "value",
|
||||
type: "uint256",
|
||||
},
|
||||
{
|
||||
name: "gas",
|
||||
type: "uint256",
|
||||
},
|
||||
{
|
||||
name: "nonce",
|
||||
type: "uint256",
|
||||
},
|
||||
{
|
||||
name: "deadline",
|
||||
type: "uint48",
|
||||
},
|
||||
{
|
||||
name: "data",
|
||||
type: "bytes",
|
||||
},
|
||||
],
|
||||
},
|
||||
reqWithoutSignature
|
||||
);
|
||||
|
||||
const balanceBefore = await ethers.provider.getBalance(signer.address);
|
||||
await forwarder.execute({
|
||||
from: reqWithoutSignature.from,
|
||||
to: reqWithoutSignature.to,
|
||||
value: reqWithoutSignature.value,
|
||||
gas: reqWithoutSignature.gas,
|
||||
deadline: reqWithoutSignature.deadline,
|
||||
data: reqWithoutSignature.data,
|
||||
signature,
|
||||
});
|
||||
const balanceAfter = await ethers.provider.getBalance(signer.address);
|
||||
expect(balanceAfter - balanceBefore).to.eq(amountOut - fee);
|
||||
expect(await token.balanceOf(signer.address)).to.eq((amountIn * refundRatio) / 100n);
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
233
contracts/integration-test/L1BlockContainer.spec.ts
Normal file
233
contracts/integration-test/L1BlockContainer.spec.ts
Normal file
@@ -0,0 +1,233 @@
|
||||
/* eslint-disable node/no-unpublished-import */
|
||||
/* eslint-disable node/no-missing-import */
|
||||
import { expect } from "chai";
|
||||
import { BigNumberish, ZeroHash, concat, encodeRlp, toBeHex, toBigInt } from "ethers";
|
||||
import { ethers } from "hardhat";
|
||||
|
||||
import { L1BlockContainer } from "../typechain";
|
||||
|
||||
interface IImportTestConfig {
|
||||
hash: string;
|
||||
parentHash: string;
|
||||
uncleHash: string;
|
||||
coinbase: string;
|
||||
stateRoot: string;
|
||||
transactionsRoot: string;
|
||||
receiptsRoot: string;
|
||||
logsBloom: string;
|
||||
difficulty: BigNumberish;
|
||||
blockHeight: number;
|
||||
gasLimit: BigNumberish;
|
||||
gasUsed: BigNumberish;
|
||||
blockTimestamp: number;
|
||||
extraData: string;
|
||||
mixHash: string;
|
||||
blockNonce: string;
|
||||
baseFee: BigNumberish;
|
||||
}
|
||||
|
||||
const testcases: Array<IImportTestConfig> = [
|
||||
{
|
||||
hash: "0x02250e97ef862444dd1d70acbe925c289bb2acf20a808cb8f4d1409d3adcfa1b",
|
||||
parentHash: "0x95e612b2a734f5a8c6aad3f6662b18f983ce8b653854d7c307bf999d9be323af",
|
||||
uncleHash: "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
|
||||
coinbase: "0x690b9a9e9aa1c9db991c7721a92d351db4fac990",
|
||||
stateRoot: "0x8d77db2a63cee63ae6d793f839a7513dfc50194f325b96a5326d724f5dc16320",
|
||||
transactionsRoot: "0xe4ce5f0e2fc5fd8a7ad55c2a31c522ded4054b89065c627d26230b45cd585fed",
|
||||
receiptsRoot: "0x10b2f34da3e6a1db9498ab36bb17b063763b8eb33492ccc621491b33bcb62bdd",
|
||||
logsBloom:
|
||||
"0x18b80159addab073ac340045c4ef982442653840c8074a50159bd9626ae0590740d07273d0c859005b634059c8ca9bb18364573e7ebe79a40aa08225942370c3dc6c0af2ea33cba07900961de2b011aabb8024270d4626d1028a2f0dcd780c60ce933b169b02c8c329c18b000aaf08c98245d8ad949e7d61102d5516489fa924f390c3a71642d7e6044c85a20952568d60cf24c38baff04c244b10eac87a6da8bb32c1535ea2613064a246d598c02444624a8d5a1b201a4270a7868a97aa4530838c2e7a192a88e329daf0334c728b7c057f684f1d28c07d0d2c1dc63868a1088010ae0b661073142e468ae062151e00e5108400e1a99c4111153828610874bb",
|
||||
difficulty: "0x0",
|
||||
blockHeight: 0xf766a8,
|
||||
gasLimit: "0x1c9c380",
|
||||
gasUsed: "0xe6f194",
|
||||
blockTimestamp: 0x639f69e3,
|
||||
extraData: "0x406275696c64657230783639",
|
||||
mixHash: "0xc1e37ce2b7ece4556ec87ea6d420a1a3610d49c58dfccec6998222fbf9cd64a2",
|
||||
blockNonce: "0x0000000000000000",
|
||||
baseFee: "0x2b96fa5cc",
|
||||
},
|
||||
{
|
||||
hash: "0x2da4bf7cef55d6207af2095db5543df16acbd95dc66eef02d9764277c5b0895d",
|
||||
parentHash: "0xde18012932b21820fbb48ef85b46774873383e75b062bc0c6a4761fbe87bad13",
|
||||
uncleHash: "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
|
||||
coinbase: "0x690b9a9e9aa1c9db991c7721a92d351db4fac990",
|
||||
stateRoot: "0x1f101f54c3df5630c9d45224c95d71a57479992e174cdbda0c4ada30e657a465",
|
||||
transactionsRoot: "0xc2b29438a5f55998879356cbc8006a90d2ba88a9841b3894c8da5840dd797f19",
|
||||
receiptsRoot: "0xbd3608b6af5464b446db44fd289a980f417447b31ff15dd6d48c72fc8f4fef8d",
|
||||
logsBloom:
|
||||
"0xd9e5f4f1e559388eb8193295ab2d3aab30c588d31e381c4060715d0a7ce607360b15d7a0d88e406c60135e0abcecd1d816c11f8cbbb2a80a9b4a00375d6cf356cb78f2934261ab09ea03df29dab5dbe4aefea506f7fd0eaa1a8b1fc8db5079613a49d80ca7e7997a20c7158399022c1dc9853f5b401b86587249fc96ca6fbc2dab1fdeb203ca258c94dd0bc821b38f9f60128591f3cd224c5c207b76b754e537bef8ebe731effae356235dd71bd7b5494bead124a8b5bb0ba02e46721d3ec3c20608880b1d35a17f6a1027d20c7b902e5d7b2ec8177b1aff9dcfbb4729d1e3201e78fa1b3c30e66a590cb5a7cac7afe0b0b1a6c94d5e39c9a20908358b805c81",
|
||||
difficulty: "0x0",
|
||||
blockHeight: 0xf766d8,
|
||||
gasLimit: "0x1c9c380",
|
||||
gasUsed: "0xf8adad",
|
||||
blockTimestamp: 0x639f6c23,
|
||||
extraData: "0x6275696c64657230783639",
|
||||
mixHash: "0x6066061b78b385483d960faa29ee40e79ea67769f5e697ecb70a0fce677804af",
|
||||
blockNonce: "0x0000000000000000",
|
||||
baseFee: "0x2aca8b608",
|
||||
},
|
||||
{
|
||||
hash: "0x4ddeee3e8d62e961080711e48d8083f164789e78cc90e4362c133063b566d64a",
|
||||
parentHash: "0x9d190c6d49352d628e321853967dd499d78c521daad73652ed1978db5652f58a",
|
||||
uncleHash: "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
|
||||
coinbase: "0xcd458d7f11023556cc9058f729831a038cb8df9c",
|
||||
stateRoot: "0x3620665f9d094aac16e0762b733e814f4e09177a232f85d406271b60e4f2b58f",
|
||||
transactionsRoot: "0x200f5acb65631c48c32c94ae95afe095134132939a01422da5c7c6d0e7f62cb3",
|
||||
receiptsRoot: "0xc140420782bc76ff326d18b13427c991e9434a554b9ae82bbf09cca7b6ae4036",
|
||||
logsBloom:
|
||||
"0x00a8cd20c1402037d2a51100c0895279410502288134d22313912bb7b42e504f850f417d9000000a41949b284b40210406019c0e28122d462c05c11120ac2c680800c0348066a23e7a9e042a9d20e4e0041114830d443160a46b5e02ec300d41330cf0652602140e1580b4c82d1228c000005be72c900f7152093d93ca4880062185952cacc6c8d1405a0c5823bb4284a04a44c92b41462c2420a870685438809a99850acc936c408c24e882a01517086a20a067a2e4e01a20e106078828706c7c00a0234e6830c80b911900291a134475208a4335ab0018a9048d4628186043303b722a79645a104c0e12a506404f45c428660a105d105010482852540b9a6b",
|
||||
difficulty: "0x2ae28b0d3154b6",
|
||||
blockHeight: 0xecb6fc,
|
||||
gasLimit: "0x1c9c30d",
|
||||
gasUsed: "0xb93955",
|
||||
blockTimestamp: 0x631d8207,
|
||||
extraData: "0x706f6f6c696e2e636f6d2050cabdd319bf3175",
|
||||
mixHash: "0x18d61005875e902e1bbba1045fd6701df170230c0ffb37f2e77fbc2051b987cf",
|
||||
blockNonce: "0xe8775f73466671e3",
|
||||
baseFee: "0x18c9de157",
|
||||
},
|
||||
];
|
||||
|
||||
function encodeHeader(test: IImportTestConfig): string {
|
||||
return encodeRlp([
|
||||
test.parentHash,
|
||||
test.uncleHash,
|
||||
test.coinbase,
|
||||
test.stateRoot,
|
||||
test.transactionsRoot,
|
||||
test.receiptsRoot,
|
||||
test.logsBloom,
|
||||
toBigInt(test.difficulty) === 0n ? "0x" : toBeHex(test.difficulty),
|
||||
toBeHex(test.blockHeight),
|
||||
toBeHex(test.gasLimit),
|
||||
toBeHex(test.gasUsed),
|
||||
toBeHex(test.blockTimestamp),
|
||||
test.extraData,
|
||||
test.mixHash,
|
||||
test.blockNonce,
|
||||
toBeHex(test.baseFee),
|
||||
]);
|
||||
}
|
||||
|
||||
describe("L1BlockContainer", async () => {
|
||||
let container: L1BlockContainer;
|
||||
|
||||
for (const test of testcases) {
|
||||
context(`import block[${test.hash}] height[${test.blockHeight}]`, async () => {
|
||||
beforeEach(async () => {
|
||||
const [deployer] = await ethers.getSigners();
|
||||
const L1BlockContainer = await ethers.getContractFactory("L1BlockContainer", deployer);
|
||||
container = await L1BlockContainer.deploy(deployer.address);
|
||||
|
||||
const Whitelist = await ethers.getContractFactory("Whitelist", deployer);
|
||||
const whitelist = await Whitelist.deploy(deployer.address);
|
||||
await whitelist.updateWhitelistStatus([deployer.address], true);
|
||||
|
||||
await container.updateWhitelist(whitelist.getAddress());
|
||||
});
|
||||
|
||||
it("should revert, when sender not allowed", async () => {
|
||||
const [, signer] = await ethers.getSigners();
|
||||
await container.initialize(
|
||||
test.parentHash,
|
||||
test.blockHeight - 1,
|
||||
test.blockTimestamp - 1,
|
||||
test.baseFee,
|
||||
test.stateRoot
|
||||
);
|
||||
|
||||
await expect(container.connect(signer).importBlockHeader(ZeroHash, "0x", false)).to.revertedWith(
|
||||
"Not whitelisted sender"
|
||||
);
|
||||
});
|
||||
|
||||
it("should revert, when block hash mismatch", async () => {
|
||||
await container.initialize(
|
||||
test.parentHash,
|
||||
test.blockHeight - 1,
|
||||
test.blockTimestamp - 1,
|
||||
test.baseFee,
|
||||
test.stateRoot
|
||||
);
|
||||
const headerRLP = encodeHeader(test);
|
||||
await expect(container.importBlockHeader(test.parentHash, headerRLP, false)).to.revertedWith(
|
||||
"Block hash mismatch"
|
||||
);
|
||||
});
|
||||
|
||||
it("should revert, when has extra bytes", async () => {
|
||||
await container.initialize(
|
||||
test.parentHash,
|
||||
test.blockHeight - 1,
|
||||
test.blockTimestamp - 1,
|
||||
test.baseFee,
|
||||
test.stateRoot
|
||||
);
|
||||
const headerRLP = encodeHeader(test);
|
||||
await expect(container.importBlockHeader(test.hash, concat([headerRLP, "0x00"]), false)).to.revertedWith(
|
||||
"Header RLP length mismatch"
|
||||
);
|
||||
});
|
||||
|
||||
it("should revert, when parent not imported", async () => {
|
||||
await container.initialize(
|
||||
ZeroHash,
|
||||
test.blockHeight - 1,
|
||||
test.blockTimestamp - 1,
|
||||
test.baseFee,
|
||||
test.stateRoot
|
||||
);
|
||||
const headerRLP = encodeHeader(test);
|
||||
await expect(container.importBlockHeader(test.hash, headerRLP, false)).to.revertedWith("Parent not imported");
|
||||
});
|
||||
|
||||
it("should revert, when block height mismatch", async () => {
|
||||
await container.initialize(
|
||||
test.parentHash,
|
||||
test.blockHeight,
|
||||
test.blockTimestamp - 1,
|
||||
test.baseFee,
|
||||
test.stateRoot
|
||||
);
|
||||
const headerRLP = encodeHeader(test);
|
||||
await expect(container.importBlockHeader(test.hash, headerRLP, false)).to.revertedWith("Block height mismatch");
|
||||
});
|
||||
|
||||
it("should revert, when parent block has larger timestamp", async () => {
|
||||
await container.initialize(
|
||||
test.parentHash,
|
||||
test.blockHeight - 1,
|
||||
test.blockTimestamp + 1,
|
||||
test.baseFee,
|
||||
test.stateRoot
|
||||
);
|
||||
const headerRLP = encodeHeader(test);
|
||||
await expect(container.importBlockHeader(test.hash, headerRLP, false)).to.revertedWith(
|
||||
"Parent block has larger timestamp"
|
||||
);
|
||||
});
|
||||
|
||||
it(`should succeed`, async () => {
|
||||
await container.initialize(
|
||||
test.parentHash,
|
||||
test.blockHeight - 1,
|
||||
test.blockTimestamp - 1,
|
||||
test.baseFee,
|
||||
test.stateRoot
|
||||
);
|
||||
expect(await container.latestBlockHash()).to.eq(test.parentHash);
|
||||
const headerRLP = encodeHeader(test);
|
||||
await expect(container.importBlockHeader(test.hash, headerRLP, false))
|
||||
.to.emit(container, "ImportBlock")
|
||||
.withArgs(test.hash, test.blockHeight, test.blockTimestamp, test.baseFee, test.stateRoot);
|
||||
expect(await container.getStateRoot(test.hash)).to.eq(test.stateRoot);
|
||||
expect(await container.getBlockTimestamp(test.hash)).to.eq(test.blockTimestamp);
|
||||
expect(await container.latestBlockHash()).to.eq(test.hash);
|
||||
expect(await container.latestBaseFee()).to.eq(test.baseFee);
|
||||
expect(await container.latestBlockNumber()).to.eq(test.blockHeight);
|
||||
expect(await container.latestBlockTimestamp()).to.eq(test.blockTimestamp);
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
393
contracts/integration-test/L1MessageQueue.spec.ts
Normal file
393
contracts/integration-test/L1MessageQueue.spec.ts
Normal file
@@ -0,0 +1,393 @@
|
||||
/* eslint-disable node/no-unpublished-import */
|
||||
/* eslint-disable node/no-missing-import */
|
||||
import { HardhatEthersSigner } from "@nomicfoundation/hardhat-ethers/signers";
|
||||
import { expect } from "chai";
|
||||
import { ethers } from "hardhat";
|
||||
|
||||
import { L1MessageQueue, L2GasPriceOracle } from "../typechain";
|
||||
import {
|
||||
MaxUint256,
|
||||
ZeroAddress,
|
||||
concat,
|
||||
encodeRlp,
|
||||
getAddress,
|
||||
hexlify,
|
||||
keccak256,
|
||||
randomBytes,
|
||||
toBeHex,
|
||||
toBigInt,
|
||||
} from "ethers";
|
||||
|
||||
describe("L1MessageQueue", async () => {
|
||||
let deployer: HardhatEthersSigner;
|
||||
let scrollChain: HardhatEthersSigner;
|
||||
let messenger: HardhatEthersSigner;
|
||||
let gateway: HardhatEthersSigner;
|
||||
let signer: HardhatEthersSigner;
|
||||
|
||||
let oracle: L2GasPriceOracle;
|
||||
let queue: L1MessageQueue;
|
||||
|
||||
const deployProxy = async (name: string, admin: string, args: any[]): Promise<string> => {
|
||||
const TransparentUpgradeableProxy = await ethers.getContractFactory("TransparentUpgradeableProxy", deployer);
|
||||
const Factory = await ethers.getContractFactory(name, deployer);
|
||||
const impl = args.length > 0 ? await Factory.deploy(...args) : await Factory.deploy();
|
||||
const proxy = await TransparentUpgradeableProxy.deploy(impl.getAddress(), admin, "0x");
|
||||
return proxy.getAddress();
|
||||
};
|
||||
|
||||
beforeEach(async () => {
|
||||
[deployer, scrollChain, messenger, gateway, signer] = await ethers.getSigners();
|
||||
|
||||
const ProxyAdmin = await ethers.getContractFactory("ProxyAdmin", deployer);
|
||||
const admin = await ProxyAdmin.deploy();
|
||||
|
||||
queue = await ethers.getContractAt(
|
||||
"L1MessageQueue",
|
||||
await deployProxy("L1MessageQueue", await admin.getAddress(), [
|
||||
messenger.address,
|
||||
scrollChain.address,
|
||||
gateway.address,
|
||||
]),
|
||||
deployer
|
||||
);
|
||||
|
||||
oracle = await ethers.getContractAt(
|
||||
"L2GasPriceOracle",
|
||||
await deployProxy("L2GasPriceOracle", await admin.getAddress(), []),
|
||||
deployer
|
||||
);
|
||||
|
||||
await oracle.initialize(21000, 50000, 8, 16);
|
||||
await queue.initialize(messenger.address, scrollChain.address, ZeroAddress, oracle.getAddress(), 10000000);
|
||||
});
|
||||
|
||||
context("auth", async () => {
|
||||
it("should initialize correctly", async () => {
|
||||
expect(await queue.owner()).to.eq(deployer.address);
|
||||
expect(await queue.messenger()).to.eq(messenger.address);
|
||||
expect(await queue.scrollChain()).to.eq(scrollChain.address);
|
||||
expect(await queue.enforcedTxGateway()).to.eq(gateway.address);
|
||||
expect(await queue.gasOracle()).to.eq(await oracle.getAddress());
|
||||
expect(await queue.maxGasLimit()).to.eq(10000000);
|
||||
});
|
||||
|
||||
it("should revert, when initialize again", async () => {
|
||||
await expect(queue.initialize(ZeroAddress, ZeroAddress, ZeroAddress, ZeroAddress, 0)).to.revertedWith(
|
||||
"Initializable: contract is already initialized"
|
||||
);
|
||||
});
|
||||
|
||||
context("#updateGasOracle", async () => {
|
||||
it("should revert, when non-owner call", async () => {
|
||||
await expect(queue.connect(signer).updateGasOracle(ZeroAddress)).to.revertedWith(
|
||||
"Ownable: caller is not the owner"
|
||||
);
|
||||
});
|
||||
|
||||
it("should succeed", async () => {
|
||||
expect(await queue.gasOracle()).to.eq(await oracle.getAddress());
|
||||
await expect(queue.updateGasOracle(deployer.address))
|
||||
.to.emit(queue, "UpdateGasOracle")
|
||||
.withArgs(await oracle.getAddress(), deployer.address);
|
||||
expect(await queue.gasOracle()).to.eq(deployer.address);
|
||||
});
|
||||
});
|
||||
|
||||
context("#updateMaxGasLimit", async () => {
|
||||
it("should revert, when non-owner call", async () => {
|
||||
await expect(queue.connect(signer).updateMaxGasLimit(0)).to.revertedWith("Ownable: caller is not the owner");
|
||||
});
|
||||
|
||||
it("should succeed", async () => {
|
||||
expect(await queue.maxGasLimit()).to.eq(10000000);
|
||||
await expect(queue.updateMaxGasLimit(0)).to.emit(queue, "UpdateMaxGasLimit").withArgs(10000000, 0);
|
||||
expect(await queue.maxGasLimit()).to.eq(0);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
context("#computeTransactionHash", async () => {
|
||||
it("should succeed", async () => {
|
||||
const sender = "0xb2a70fab1a45b1b9be443b6567849a1702bc1232";
|
||||
const target = "0xcb18150e4efefb6786130e289a5f61a82a5b86d7";
|
||||
const transactionType = "0x7E";
|
||||
|
||||
for (const nonce of [0n, 1n, 127n, 128n, 22334455n, MaxUint256]) {
|
||||
for (const value of [0n, 1n, 127n, 128n, 22334455n, MaxUint256]) {
|
||||
for (const gasLimit of [0n, 1n, 127n, 128n, 22334455n, MaxUint256]) {
|
||||
for (const dataLen of [0, 1, 2, 3, 4, 55, 56, 100]) {
|
||||
const tests = [randomBytes(dataLen)];
|
||||
if (dataLen === 1) {
|
||||
for (const byte of [0, 1, 127, 128]) {
|
||||
tests.push(Uint8Array.from([byte]));
|
||||
}
|
||||
}
|
||||
for (const data of tests) {
|
||||
const transactionPayload = encodeRlp([
|
||||
nonce === 0n ? "0x" : toBeHex(nonce),
|
||||
gasLimit === 0n ? "0x" : toBeHex(gasLimit),
|
||||
target,
|
||||
value === 0n ? "0x" : toBeHex(value),
|
||||
data,
|
||||
sender,
|
||||
]);
|
||||
const payload = concat([transactionType, transactionPayload]);
|
||||
const expectedHash = keccak256(payload);
|
||||
const computedHash = await queue.computeTransactionHash(sender, nonce, value, target, gasLimit, data);
|
||||
if (computedHash !== expectedHash) {
|
||||
console.log(hexlify(transactionPayload));
|
||||
console.log(nonce, gasLimit, target, value, data, sender);
|
||||
}
|
||||
expect(expectedHash).to.eq(computedHash);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
context("#appendCrossDomainMessage", async () => {
|
||||
it("should revert, when non-messenger call", async () => {
|
||||
await expect(queue.connect(signer).appendCrossDomainMessage(ZeroAddress, 0, "0x")).to.revertedWith(
|
||||
"Only callable by the L1ScrollMessenger"
|
||||
);
|
||||
});
|
||||
|
||||
it("should revert, when exceed maxGasLimit", async () => {
|
||||
await expect(queue.connect(messenger).appendCrossDomainMessage(ZeroAddress, 10000001, "0x")).to.revertedWith(
|
||||
"Gas limit must not exceed maxGasLimit"
|
||||
);
|
||||
});
|
||||
|
||||
it("should revert, when below intrinsic gas", async () => {
|
||||
await expect(queue.connect(messenger).appendCrossDomainMessage(ZeroAddress, 0, "0x")).to.revertedWith(
|
||||
"Insufficient gas limit, must be above intrinsic gas"
|
||||
);
|
||||
});
|
||||
|
||||
it("should succeed", async () => {
|
||||
expect(await queue.nextCrossDomainMessageIndex()).to.eq(0n);
|
||||
const sender = getAddress(
|
||||
toBeHex((toBigInt(messenger.address) + toBigInt("0x1111000000000000000000000000000000001111")) % 2n ** 160n)
|
||||
.slice(2)
|
||||
.padStart(40, "0")
|
||||
);
|
||||
const hash = await queue.computeTransactionHash(sender, 0, 0, signer.address, 100000, "0x01");
|
||||
await expect(queue.connect(messenger).appendCrossDomainMessage(signer.address, 100000, "0x01"))
|
||||
.to.emit(queue, "QueueTransaction")
|
||||
.withArgs(sender, signer.address, 0, 0, 100000, "0x01");
|
||||
expect(await queue.nextCrossDomainMessageIndex()).to.eq(1n);
|
||||
expect(await queue.getCrossDomainMessage(0)).to.eq(hash);
|
||||
});
|
||||
});
|
||||
|
||||
context("#appendEnforcedTransaction", async () => {
|
||||
it("should revert, when non-gateway call", async () => {
|
||||
await expect(
|
||||
queue.connect(signer).appendEnforcedTransaction(signer.address, ZeroAddress, 0, 0, "0x")
|
||||
).to.revertedWith("Only callable by the EnforcedTxGateway");
|
||||
});
|
||||
|
||||
it("should revert, when sender is not EOA", async () => {
|
||||
await expect(
|
||||
queue.connect(gateway).appendEnforcedTransaction(queue.getAddress(), ZeroAddress, 0, 0, "0x")
|
||||
).to.revertedWith("only EOA");
|
||||
});
|
||||
|
||||
it("should revert, when exceed maxGasLimit", async () => {
|
||||
await expect(
|
||||
queue.connect(gateway).appendEnforcedTransaction(signer.address, ZeroAddress, 0, 10000001, "0x")
|
||||
).to.revertedWith("Gas limit must not exceed maxGasLimit");
|
||||
});
|
||||
|
||||
it("should revert, when below intrinsic gas", async () => {
|
||||
await expect(
|
||||
queue.connect(gateway).appendEnforcedTransaction(signer.address, ZeroAddress, 0, 0, "0x")
|
||||
).to.revertedWith("Insufficient gas limit, must be above intrinsic gas");
|
||||
});
|
||||
|
||||
it("should succeed", async () => {
|
||||
expect(await queue.nextCrossDomainMessageIndex()).to.eq(0n);
|
||||
const sender = signer.address;
|
||||
const hash = await queue.computeTransactionHash(sender, 0, 200, signer.address, 100000, "0x01");
|
||||
await expect(
|
||||
queue.connect(gateway).appendEnforcedTransaction(signer.address, signer.address, 200, 100000, "0x01")
|
||||
)
|
||||
.to.emit(queue, "QueueTransaction")
|
||||
.withArgs(sender, signer.address, 200, 0, 100000, "0x01");
|
||||
expect(await queue.nextCrossDomainMessageIndex()).to.eq(1n);
|
||||
expect(await queue.getCrossDomainMessage(0)).to.eq(hash);
|
||||
});
|
||||
});
|
||||
|
||||
context("#popCrossDomainMessage", async () => {
|
||||
it("should revert, when non-scrollChain call", async () => {
|
||||
await expect(queue.connect(signer).popCrossDomainMessage(0, 0, 0)).to.revertedWith(
|
||||
"Only callable by the ScrollChain"
|
||||
);
|
||||
});
|
||||
|
||||
it("should revert, when pop too many messages", async () => {
|
||||
await expect(queue.connect(scrollChain).popCrossDomainMessage(0, 257, 0)).to.revertedWith(
|
||||
"pop too many messages"
|
||||
);
|
||||
});
|
||||
|
||||
it("should revert, when start index mismatch", async () => {
|
||||
await expect(queue.connect(scrollChain).popCrossDomainMessage(1, 256, 0)).to.revertedWith("start index mismatch");
|
||||
});
|
||||
|
||||
it("should succeed", async () => {
|
||||
// append 512 messages
|
||||
for (let i = 0; i < 256 * 2; i++) {
|
||||
await queue.connect(messenger).appendCrossDomainMessage(ZeroAddress, 1000000, "0x");
|
||||
}
|
||||
|
||||
// pop 50 messages with no skip
|
||||
await expect(queue.connect(scrollChain).popCrossDomainMessage(0, 50, 0))
|
||||
.to.emit(queue, "DequeueTransaction")
|
||||
.withArgs(0, 50, 0);
|
||||
for (let i = 0; i < 50; i++) {
|
||||
expect(await queue.isMessageSkipped(i)).to.eq(false);
|
||||
expect(await queue.isMessageDropped(i)).to.eq(false);
|
||||
}
|
||||
expect(await queue.pendingQueueIndex()).to.eq(50);
|
||||
|
||||
// pop 10 messages all skip
|
||||
await expect(queue.connect(scrollChain).popCrossDomainMessage(50, 10, 1023))
|
||||
.to.emit(queue, "DequeueTransaction")
|
||||
.withArgs(50, 10, 1023);
|
||||
expect(await queue.pendingQueueIndex()).to.eq(60);
|
||||
for (let i = 50; i < 60; i++) {
|
||||
expect(await queue.isMessageSkipped(i)).to.eq(true);
|
||||
expect(await queue.isMessageDropped(i)).to.eq(false);
|
||||
}
|
||||
|
||||
// pop 20 messages, skip first 5
|
||||
await expect(queue.connect(scrollChain).popCrossDomainMessage(60, 20, 31))
|
||||
.to.emit(queue, "DequeueTransaction")
|
||||
.withArgs(60, 20, 31);
|
||||
expect(await queue.pendingQueueIndex()).to.eq(80);
|
||||
for (let i = 60; i < 65; i++) {
|
||||
expect(await queue.isMessageSkipped(i)).to.eq(true);
|
||||
expect(await queue.isMessageDropped(i)).to.eq(false);
|
||||
}
|
||||
for (let i = 65; i < 80; i++) {
|
||||
expect(await queue.isMessageSkipped(i)).to.eq(false);
|
||||
expect(await queue.isMessageDropped(i)).to.eq(false);
|
||||
}
|
||||
|
||||
// pop 256 messages with random skip
|
||||
const bitmap = toBigInt("0x496525059c3f33758d17030403e45afe067b8a0ae1317cda0487fd2932cbea1a");
|
||||
const tx = await queue.connect(scrollChain).popCrossDomainMessage(80, 256, bitmap);
|
||||
await expect(tx).to.emit(queue, "DequeueTransaction").withArgs(80, 256, bitmap);
|
||||
console.log("gas used:", (await tx.wait())!.gasUsed.toString());
|
||||
for (let i = 80; i < 80 + 256; i++) {
|
||||
expect(await queue.isMessageSkipped(i)).to.eq(((bitmap >> toBigInt(i - 80)) & 1n) === 1n);
|
||||
expect(await queue.isMessageDropped(i)).to.eq(false);
|
||||
}
|
||||
});
|
||||
|
||||
// @note skip this random benchmark tests
|
||||
for (const count1 of [1, 2, 128, 129, 256]) {
|
||||
for (const count2 of [1, 2, 128, 129, 256]) {
|
||||
for (const count3 of [1, 2, 128, 129, 256]) {
|
||||
it.skip(`should succeed on random tests, pop three times each with ${count1} ${count2} ${count3} msgs`, async () => {
|
||||
// append count1 + count2 + count3 messages
|
||||
for (let i = 0; i < count1 + count2 + count3; i++) {
|
||||
await queue.connect(messenger).appendCrossDomainMessage(ZeroAddress, 1000000, "0x");
|
||||
}
|
||||
|
||||
// first pop `count1` messages
|
||||
const bitmap1 = toBigInt(randomBytes(32));
|
||||
let tx = await queue.connect(scrollChain).popCrossDomainMessage(0, count1, bitmap1);
|
||||
await expect(tx)
|
||||
.to.emit(queue, "DequeueTransaction")
|
||||
.withArgs(0, count1, bitmap1 & ((1n << toBigInt(count1)) - 1n));
|
||||
for (let i = 0; i < count1; i++) {
|
||||
expect(await queue.isMessageSkipped(i)).to.eq(((bitmap1 >> toBigInt(i)) & 1n) === 1n);
|
||||
expect(await queue.isMessageDropped(i)).to.eq(false);
|
||||
}
|
||||
|
||||
// then pop `count2` messages
|
||||
const bitmap2 = toBigInt(randomBytes(32));
|
||||
tx = await queue.connect(scrollChain).popCrossDomainMessage(count1, count2, bitmap2);
|
||||
await expect(tx)
|
||||
.to.emit(queue, "DequeueTransaction")
|
||||
.withArgs(count1, count2, bitmap2 & ((1n << toBigInt(count2)) - 1n));
|
||||
for (let i = 0; i < count2; i++) {
|
||||
expect(await queue.isMessageSkipped(i + count1)).to.eq(((bitmap2 >> toBigInt(i)) & 1n) === 1n);
|
||||
expect(await queue.isMessageDropped(i + count1)).to.eq(false);
|
||||
}
|
||||
|
||||
// last pop `count3` messages
|
||||
const bitmap3 = toBigInt(randomBytes(32));
|
||||
tx = await queue.connect(scrollChain).popCrossDomainMessage(count1 + count2, count3, bitmap3);
|
||||
await expect(tx)
|
||||
.to.emit(queue, "DequeueTransaction")
|
||||
.withArgs(count1 + count2, count3, bitmap3 & ((1n << toBigInt(count3)) - 1n));
|
||||
for (let i = 0; i < count3; i++) {
|
||||
expect(await queue.isMessageSkipped(i + count1 + count2)).to.eq(((bitmap3 >> toBigInt(i)) & 1n) === 1n);
|
||||
expect(await queue.isMessageDropped(i + count1 + count2)).to.eq(false);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
context("#dropCrossDomainMessage", async () => {
|
||||
it("should revert, when non-messenger call", async () => {
|
||||
await expect(queue.connect(signer).dropCrossDomainMessage(0)).to.revertedWith(
|
||||
"Only callable by the L1ScrollMessenger"
|
||||
);
|
||||
});
|
||||
|
||||
it("should revert, when drop non-skipped message", async () => {
|
||||
// append 10 messages
|
||||
for (let i = 0; i < 10; i++) {
|
||||
await queue.connect(messenger).appendCrossDomainMessage(ZeroAddress, 1000000, "0x");
|
||||
}
|
||||
// pop 5 messages with no skip
|
||||
await expect(queue.connect(scrollChain).popCrossDomainMessage(0, 5, 0))
|
||||
.to.emit(queue, "DequeueTransaction")
|
||||
.withArgs(0, 5, 0);
|
||||
for (let i = 0; i < 5; i++) {
|
||||
expect(await queue.isMessageSkipped(i)).to.eq(false);
|
||||
expect(await queue.isMessageDropped(i)).to.eq(false);
|
||||
}
|
||||
expect(await queue.pendingQueueIndex()).to.eq(5);
|
||||
|
||||
for (let i = 0; i < 5; i++) {
|
||||
await expect(queue.connect(messenger).dropCrossDomainMessage(i)).to.revertedWith("drop non-skipped message");
|
||||
}
|
||||
|
||||
// drop pending message
|
||||
for (let i = 6; i < 10; i++) {
|
||||
await expect(queue.connect(messenger).dropCrossDomainMessage(i)).to.revertedWith("cannot drop pending message");
|
||||
}
|
||||
});
|
||||
|
||||
it("should succeed", async () => {
|
||||
// append 10 messages
|
||||
for (let i = 0; i < 10; i++) {
|
||||
await queue.connect(messenger).appendCrossDomainMessage(ZeroAddress, 1000000, "0x");
|
||||
}
|
||||
// pop 10 messages, all skipped
|
||||
await expect(queue.connect(scrollChain).popCrossDomainMessage(0, 10, 0x3ff))
|
||||
.to.emit(queue, "DequeueTransaction")
|
||||
.withArgs(0, 10, 0x3ff);
|
||||
|
||||
for (let i = 0; i < 10; i++) {
|
||||
expect(await queue.isMessageSkipped(i)).to.eq(true);
|
||||
expect(await queue.isMessageDropped(i)).to.eq(false);
|
||||
await expect(queue.connect(messenger).dropCrossDomainMessage(i)).to.emit(queue, "DropTransaction").withArgs(i);
|
||||
await expect(queue.connect(messenger).dropCrossDomainMessage(i)).to.revertedWith("message already dropped");
|
||||
expect(await queue.isMessageSkipped(i)).to.eq(true);
|
||||
expect(await queue.isMessageDropped(i)).to.eq(true);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
143
contracts/integration-test/PatriciaMerkleTrieVerifier.spec.ts
Normal file
143
contracts/integration-test/PatriciaMerkleTrieVerifier.spec.ts
Normal file
@@ -0,0 +1,143 @@
|
||||
/* eslint-disable node/no-unpublished-import */
|
||||
/* eslint-disable node/no-missing-import */
|
||||
import { expect } from "chai";
|
||||
import { concat } from "ethers";
|
||||
import { ethers } from "hardhat";
|
||||
|
||||
import { MockPatriciaMerkleTrieVerifier } from "../typechain";
|
||||
|
||||
interface ITestConfig {
|
||||
block: number;
|
||||
account: string;
|
||||
storage: string;
|
||||
expectedRoot: string;
|
||||
expectedValue: string;
|
||||
accountProof: string[];
|
||||
storageProof: string[];
|
||||
}
|
||||
|
||||
const testcases: Array<ITestConfig> = [
|
||||
{
|
||||
block: 16212738,
|
||||
account: "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2",
|
||||
storage: "0xb17c5049c06186507ed9d55e735dc0342e08579866e7ed881de010624b3896dd",
|
||||
expectedRoot: "0x5dd9637058e605949321a683ab1e6c56ae6041a05cdf97355696f93309799391",
|
||||
expectedValue: "0x00000000000000000000000000000000000000000000000052ab3594ab17a60b",
|
||||
accountProof: [
|
||||
"0xf90211a04cfe239817b200a743356abfc6e5b08d9951e90f3932f57a7c12014d9968b040a02c94e10276ccd6a461e94da963f126e396d12f50a3389966705dbb0ece7f67aca0f28acd17ade90c99e92e3e155a46076ef89f51f22caf45ec8f5affc240073cf6a0f26e26128daf3ecbb7a37eb10afad22741725a1ce43819f1f573da6f1e6fc2c9a020e3325c4125cde3a948d7a68530a8f8979591c17f445bf96b4716d64833f6c8a0def41ac472c300aed57feb95cf7426fcca53d4c0007afabfb0d6c4d3b4ad95fea0a65435daeb1a371b29c3037a01230d19872e2bdb1a97aeafe610df01dd9937c3a0c4d93f1c9037597d4b07388551773f9578203a8abf4f3bfabd6eaf58070f32d5a0d008f86640c7313e00f897b2b9416da54ea2182fa98785e583367e42035fc0baa072981aa04d506601aeb2cf8689ff23dff82a52a29e1d401dfe96baa2550b977ea065a9e75f35c97436334ad2498ea3fe4296829ad7b005e65af34fd10ddb368631a0b326e41a44cadb3e78fd84571f5e0f9da6b5ee5dfcfb1c88a6b1fcdb13fe6beca0e32897d4de5966ed95729c2a68354d1ef7f27a9b8a5cdaec592965bcc5b339d3a0022b816b5afca265766e67427b45682ade004a780e7e3667b41930a1d087230ea0dc0eb205c8cc3642fe2f03252b238891819a8528f30fc0207c2271290e8de9a1a0554966428442b6b9188a4b4945aa550f32615e4b1b1d3776b07c9d18ba0146af80",
|
||||
"0xf90211a00ee4696104bbdba0094ca30daa4eae871b1dc0c2ccb07d8f24c7c89193904607a080893f1dc4ded5ddfa49eb36a618a0c3525c58890ae7e4be006e6988980cd15ca04ad58fd70d3cabb3d59144f729105997d3f07c0223a41dbc9b1507d1aa7825cba03bbe2d774e64d6577f1e90ef42b20664b4707649b00e957e369e97a1f03dc762a0107ec21d49839dbbb267fe5ca58c615af81df1752b7f49c8ce2da952a132cebba0d4bd3d22a406960040f86aa8fff6c9e29a2337560145730f9e3612844d67dd1ea09b1edb047a63e19ba02f894a19bfe2d4fcb9052e0dddd6d40dfa52351b3e973ea0a397a48dcdbeef118776a2cbd06fa400d1bedc99ed9f61d4f4513cc6aa7c29daa031f5b24b9027eef2c12015db45ef79c6f57681a6818173e00ddb1050567be4aea035748b7d80884cd8ee2d53523e9aa49186091b28dadd09e1a4f94b8ba3e3c995a055f851741c59287e048a908539c348c6555c098ac16fa074395d530b67f076b9a0f189025cd5b04a3b73bcdbdfa0d9637a0ff389f7b9a481efc2cb984484cb106ea0d7e874ea3b71239bbdb6f01287f58508816b270a218293987e42618f6b982777a0447c72ec8a23e35ba10b61462c11c654653556682994de6ea7866a538320fd3ea0d52ef935a9abaa771614224e75c9d06b8d94270a5ab11b95635f3d646bc7f80fa020d93fff55bcd20b764b2a4261b448cac23fa19dd64dbb7d33345a27b1c02dce80",
|
||||
"0xf90211a0aa579a2bef0815ecbe72dcc7a478494f4ddf6e6a821fed8b8e5e22f96be95fb1a0f7be1171a1b188f0159315731796369ea543043b3f2076ad688f2bda5315d4f6a0ac7901c3cece0eafdb607bf3f6981aac2741804c77b0db674d7bc69c6e0841d5a0c1bf87d0fc7ff63bc43bb453920d13b00ed2e126931fe431206519e47f2aff58a0fbb3f885d4e17a30daad80568b76ca24b70f95ddb3840598c9cbf5499caa13d2a009566520886f90ae776076398c3393585110ea164c8a1e6c47980ec67fbbbf9ea0709eec3f022710443237d2ee3d967abb9fe295b335dbc783768cc2396ba0b28ea02003180468280c9bf5819207be30c9f3176a0cd68a57b43fe353565a5d42b62aa09817a0745b614df9aa5268081c06eaa5d6c057c86e0253ee26f081b9fc5487a1a073265752f6c91428565dab106305f47b8c609522ee518b4f391c7f8951f5394fa03ef7529bb0ee4030c994910ba8d8cd0eafbfcc4d7f7a0fe9b528b09360ab12e0a093330c4eb263124f35f26572747b59957744f1c39cb91e413b599d27e07dcaf6a022dec6cd45c7db6901c364be4226d54fd74552af51d835d605d1efde50a374c0a0007c30f8707814de913a9edd9bf09fe614676b2ed5497ea06bd157e5ec1718c2a0e6d9335dee9c32e74ae736ddccb15bbbe3ca07c347e7d038a6103877d1cefd31a02d5576458404a2e48f2263741a2c5ff181ff03939e1952cd616412c98edacdae80",
|
||||
"0xf90211a0f10b8f4ec168083a8021ac8201365f45d63ad461fdf4cf8c50342499f197f5f3a02341a492492fa8323462dad1af3ab7094b76ae3666c4d081ec8d24c9e0da451da0017ce2794246eda28f5b1b3fee05dd269dabb29f71799ca7c3dca67764132c82a02b629e4b9b699796651ad13840a0d06721041de42d09f22ddf3e0f7c89ade82aa076d2c3f907c842c8e76454503b7ef1c9f52e93fc3830b4b8cd63dadeefa8fd4da09284abd6431d107e527627dd78d3cc2a655f7e364470ef620fb7fada3fcece73a00afefb47543ea7c9866f274ab4aa14ee261ffcd0c8b7c8c4e66f1ff02eda6ed3a02045ebe244660a6cae3467637f3e0b27c003cefe72681c47acb2e9766c1f17c7a08fc1ee83563261f1104687cefe451fedcff6caf2dae3f3a2a382b1a0bad7109ba00afa5fe38079cb86511e0842b62af452a78ecd43dc6c54351ed3ec923769088ca0a9c36efeb72874a37dd282f309ff318b6e9464ece30c63ba80bfbc5e5f76f163a030b918045e6233a81833658889f54cedef0f1052aa56e673649a955bc8fee94aa0eae7097667819b85f90f7d4a72d9a8147dccf5fbd744050a743f029e0a79c725a0671e20fc1d94cdb487e0a8cb8c752fd3b4c2f759b9a905134f7a880e1dcdc96da0425857c455a0e10c7cae230d3b3a3309ff5732b55ca2186cc9ddaecff5460490a0b10db994f51f52b29f43281c561f2c62f2be921c5f585fb441760ce9aa4d3d1a80",
|
||||
"0xf90211a0fd942eae2655a391e59dc2779f53209542fcc140b96e4b93cff3d8cb417e6efba0bd3535c9bfa5a7b939c7dff9307610a5958f8a785d2dcf7eeaf84624d0e457cca05ce0a4917922d7b302fca1badd446897f360b11d60be9802c45136166a81dc79a0731d140390c684a63ecf3ba9d392c73b8fb1bf2864d4b90eff813e953f66ac4aa010bb21166ea999880a179d6669704ecf6c50ea9e47eb674d9b077a7d4c4f9baba085dab7106099e19e2c978e8e814a7749af5bbdbe1131333713e612898a8d62c1a012720a68371573fe69f384950b871b09a44af5fe2c4870f231a58e07190c1b36a089e816024bd04ad03ca66e47323feaf5d975b3ec41b46fb124ba9a9299c26da7a0827ecf55875811b3b25696b3737ead4817641d29ed46d5c4892d098357b699e2a06450a823c9feb0adcd77aec2d3156057f2c93f83670da26afed344e2c6a8f5a7a045fd2f25ecd36a65186513e409fa3b3e3f3a0f7f60f5951c76d2ce10235db1bfa06819009da16eeacf224ce65fc7dc8052cc2f4dd32813441801ac3be9e9db98c5a0ae81fa6db4342f607a35aea6a10047c1848c9251d87140efd6c24685ab964b08a0ee867ebe92374b199244599920a3a0fd13ca24030ae6c1d1af1ac8523a8968faa007dcd579f048937f2bb7a388a158f565b3338e35d37f455d2d6861ca208183bea0dbc271c1b2865a38476161513c4a590807f8db6f2a4de8db1e9c142a8a15349580",
|
||||
"0xf90211a02b207484d2fd6781a1e4ae62c2c4171477bd5b929df2b14904cd4f36c61363cba04cbd3a34c4d4f60bc5590d8b5859da8ac83ea7a8a0197dbbc528434651b0f748a0beafa9a7e0b2073100526355a341de7a1a839c7f7322a594bdc9ed4d73d72283a0249717659c4e7adda14416a804ba5c9b305f9da2531a3ff6e6d74fca6380f4c2a09b5d4bcf5c805d1c38f283bca39ce28077cbe0daed23312d666cde49134a4d2da03930a91cdfb11a85632972832202e0ab4027f78049f828a099327513be660ed0a0ec6a17d51d787c382575d6798093a015e8383bb276b6fb291d529498789ada09a0f54c88077fa118092db43a93d89c86ec879da12d33e6e5dd89b10b7fb115bc54a0e1a3af76bd6a0b1f4419a62bc73439c641c612a912dc8d190e8e81c8c15dd561a097934d75e361d115ea93e2fdc0c91a54d59414f0daa2ac1991b6651ae6571f9ca009abf1666d7d9202849314692d5ce1e51e5629727701044b37532ab3f9be50c0a094561fbec829ff4807911e0169bcb59159bf8d478fe7116cd652c179c28342f1a058ea9466450f42b25cc3298911ebeb081b6bc73f3c414f0d36244d331cc18c5da0697343bd56fce1c2d34ebb3baa06b3f5aba4851e3b60436e545a2616ef47cb73a06ef38fec665b8eb25934622af1112b9a9d52408c94d2c0124d6e24b7ff4296c0a0451066ddc0cd1a63e22d096eab595e74c8e8509616650d76a0eedd35f0c228b180",
|
||||
"0xf8b1a02a85b6c4adf828a068d39f7bf4115a4544ebf32e007d63957a28ee21eb8dcd57a0344f34e01710ba897da06172844f373b281598b859086cf00c546594b955b870808080a0525e7dd1bf391cf7df9ffaaa07093363a2c7a1c7d467d01403e368bd8c1f4e5680808080808080a0235db60b9fecfc721d53cb6624da22433e765569a8312e86a6f0b47faf4a2a23a06c72cff8105f47b356034e5586745859f6290eb366bde35b9e819af9dcdfdd8d8080",
|
||||
"0xf8719d3da65bd257638cf8cf09b8238888947cc3c0bea2aa2cc3f1c4ac7a3002b851f84f018b03235ac0b3723f4d6c6f61a0f3ea73ed7d35e887e1b2b8ac13e8645eeec0da8210c16da47b0f3b0894011c3fa0d0a06b12ac47863b5c7be4185c2deaad1c61557033f56c7d4ea74429cbb25e23",
|
||||
],
|
||||
storageProof: [
|
||||
"0xf90211a04571622a123ea7cf0d9534115e5e6b2fd058f94306979a373b226979a8c83af3a0293a081f517366f69769840098d809396caf7ff3942c3b16aa641b23723301b4a0605ef8aa3eb98c75406d2781067f9d55804b4cd981614aa09f9f6cb0d87a91b0a09d7f20c3afe36c59119c1308a6d7a3efca7c6588acc14364c0e70b5f7f5ecf97a0ce1729eeec5fb5d9d3fed295e469da960bce62cbbd4540efbb0eaf470b0014a5a0a69bd31a7f4267359dd41b93f03b949bdf4de072651b6929ea4e756bc6f088b6a0801ba6fed2d48d4706569a62678fb93ca48dc159fd8659b7100bc4070e3f24f8a0a58273972230f9ef6f74f1d3d1baa8795f82d0bc2c2313b7522a35cfad25ca7aa0be46e098b427907021d82e9d1d45ca4ef6305e3adacb71683f94e4656718ba14a083808d1c8c0ca4a5668cbe6faba42d927ef8df07f3581d06a9381084f0590defa00b6eaadae4a3d219a0e090a56cfdb17e31326e9d60802cf3a36e8ed0f14490f0a00146a284e0a8245d2c1f51ee97fdf9f4231caee252aab01fcf3c4a619f39663fa00b68dbe3928080b43cfc2533fffee4ed91abff24109f08a3ba26e8aaae18c7cca0345de27acef95642cf996a0485bd0242281c7ed9fddd6bad6f55e6bff04588afa092099ec8d9e6dfea3ee5fe4ce7b18f9e513cd7229f7a8de6ebf93ff5ce757232a0963d3dcfec3a80dc1073eb2292be246d81b4462b8347511d335b4c537f87c29a80",
|
||||
"0xf90211a089a4ed194eaf9e272c155d2e692b5585c6a38bd04ae96e487bcc231771701f98a07a7de6dadac670c4062757c16976c4fd98c587a47a687b32b640375fd7e825b8a0da765585e24133176d2b38376f362b666800735c46e6358bdb526d03f068f97fa08acba1cd699af52508c374da47250b1d2be1a43a7d25aff247ec717b8a534213a0e74be231dfa53a30bd3157e6f702f14619887946e2a447d31dcac87f391a50c9a0b8448e3cc5dd4e9728c7fff44ec252bdade1618a63d363e86e0e6dc4c77de5f2a0f95aadc2a07fb025f3492fa7d15224bab718a908b1fdecec39900f905273d8fea0b76a4d3edfbf657e6d87e2e3920b478fb8f4bdba7844a7ab23798e1bed4abccba0fd70d97eaebf9d1b9e65dcb960bc1b7e96b03a40dfcd490ebf8bc5bab8c413b6a0fb3fecd1f77557f554c6d22b86e9dfb27fe644d13c8e53c24b64e7b3f3791cd9a039cce3c9632ea42f008bb8fd3412e94dea053d4a2baa41c4a2517b34ba8e4405a066b4b4db0e22d9fa76395494b571b7c0cc1cd18ccd332e8a59bfa03b2be2889aa0a80a5acaeeb595a5740f1844d32eab4d56fffe53176c21a464ff34a8cda84101a0f454d635fa0657c436c5fc2b6a071c62e4c01c139dc2ee544dd8997f2ee9242aa07fa5c3c8e2be0f1255f49383046703291953d29debf61376f862edd3c5b4cf76a0a30f1b5c1c3c4b307a2ac472c81f79283803e88403a5ccee7750ce7175c0b0d380",
|
||||
"0xf90211a083f3f2d187ac7939ccbb8690863f341b252909afec4dcce275a2e7318e1f15d2a08fdbf9e41ea870a7ec2aa31ce43a682b8e2fffd0988bb934c03dc14e1988952aa04b9e7db219d192320bfdac399670cff992e0aa5dc25d2f3de56f4f53e5373456a07f27f9e5efb3a92a1f2f3e6d8fd4bfaf9015b9fdad8715ba16d30c211aa0530aa07cc6af0533c32fe1af0e5d4b149186970040ac5c69c2db7805774a65532fa064a0f15e9c0dbdd4f935d3aa719506ae1fb7297258d18abe03111d9e5221d6bfb8cda04572757dae6365a28b493c63503809a9dd6927b6e6f11f791e9c2cec92b80513a0d1ac01dd696504ca20c087bea731dac1b8c48d26e5dad36d80e34496ee20b46fa02d879c981e1706e0720b3efa7093308a499d57ccbf9648cba78026b3e7883795a03f007ce733ee8a522776e46bbc5dd28ea33db0ae4702d733926d83b28c4d0181a01b1858a30125abe3a401112f676d6a4b669ac9495b34f89691c075ec7630a45da09d22b122a2fd0db8cc2397c0c8e05fe317e3bc8aa407af8b85ca300d9411dc0da04ad97d66e54c7a2a76bc6729384080115dc3ba5e6a7c5269470372ba6d22eeafa0dcfe09b848078f66db11284e093991436f85ef26ddb3dc2efcf56e4bf05e6101a0e641c7a710a5b8a3b465e05b09e4868d9e54353b50d29eeccc9e829ea314041da063ba309481ffd1118153e75496d66bc7a96d37f32c63f4e731e56abe4fa5f12880",
|
||||
"0xf90211a00a62828ba9909a92bad0ddff29537a58e176fb8af1d76292813a72f5661ea282a0f037cbce7cbacb3343cdf899fd145917e7cf18deddf5b2d8a94027968f9f1624a064774630a8d992b0888514b5e1dc2fdd37b8a214e6bd39d3689eaf74bf65bf68a0b6ee7661ab782818ac639c03784ab65eecbb06d79d251cd8c25627e51ba5b94da0c1dfabca29a2ae57d88e29f0ea94bb3a825d4b884c7f088ab4261b5900635ecba01bf409b8577e89fe49afa62ec117c32a9beac5f8e8cce54adeb3bd501c15cb80a08d7b60700564e51011a00159786683d707b676f41214b3e538b074fc79484748a08e58472318ad40f9498b98a599d260a80298a2cba39cf45d0bff8d91ae2e4852a04443244bd4654d707e3700d112783b837070111ba8a2f0f11781d623c3990754a0750eac11d5f2be0746f87df3cf9849ccb8f13c831936a745abd37fc464d758eea06311c8c2cbdfc4ff1a7e550477cf38ddc35cf57579d0f842801a9ad6fe50c45da0c6ceee02d855cef0db230d186d9e37b8777b8313a22b3dd6946143da503919d4a08669ea1760b9551901c57fd56411368ed8de861bb4602d26f93005d0101fd195a0285993aee29c28d2239022fbda7df02d06082e0246431b7671edda601c6e5cc6a047bfd76124562bb812ec81f5b286e09907eba7e9b1efa72d4ac7a49b82eed957a054bf6597873bf09bfd3df04d4fdff771c02f9d728d51ed1ef00f6b053f3282f280",
|
||||
"0xf901f1a0c5a1504268a750c1c90b7841d99e6934f977193c72d44ba456fc9a263fb3ea45a0924bbfcbd6d2e7a3f9bb5ec1898a1ec0b98880f747991e96696bd0b565e1f83aa07ccd4b2cea9ff079bea41f9d704c21e7f9d3fbaa83895f34970585873d5bd9e2a0b2e313a02508e8a0dfa115612c1400f8cf9d5cc23369b6aefd7c1fceca7dc943a0e19964c5618fe9f1f590eaddc17787071442649385109b9324beb8bf51a0d2d4a0b022d54d33a1c62278d7784996fddb4c7dcab2fc3c2287c6840edc3762e3d034a0a8381f53de80c0d06ca7288457d82fc1cef37af3e08abbed93a61d48d7c9ca1ba03f916faed29b999d16e22fcc2ad463681a42339b24fdca5a1323b5e55d5650f3a0eb6adbd0b998ec882b91b44ab6ccf20050962c45b68d4e42d2f0e3e1c9384952a009190c615b4dab60e7c1940f2b3b87e3636a655b29dd8b65b99f497ab4fbc395a0156deb01c2c14daf7c043555c077b4af3c5aac031d75cf9e4f704280983c67c8a09dd3b43b4514cfa57218538527defb69638f108383a9d95ad07a296d30bd5bbf80a01316d876cd6803dd122538f308cf116b79278393d979769a121f8354c925cda0a0324232c83f8194263838f7105b67fb93b805c027d6419a98f3c40937b9502132a0cf19102ca5c74f4e088ca39ded150e7a9d5d1bc5d9263012c7e843dfdec8386580",
|
||||
"0xf8718080808080a0795b2bc0fec80623a0785ed76761d1e9abbf37b806b4b1664a22c1dac557d79080a09831b7f896628cd55e9cec00f168d92c748a1dae2fc55774f0fdc80ae64294a08080808080a020edc6edb75de3cfde19500957b220fffbfc581e93b5b6e307fac078a8b14783808080",
|
||||
"0xe99e20e18d2fc45a3ea90621b218552f932e0a2a920a290d1c6bda98db9ab133898852ab3594ab17a60b",
|
||||
],
|
||||
},
|
||||
{
|
||||
block: 16212787,
|
||||
account: "0x9467a2d9c07cebce3708ca32eeb2b9219aeb31b8",
|
||||
storage: "0x000000000000000000000000000000000000000000000000000000000000000a",
|
||||
expectedRoot: "0x16b9e5246ca2dad361d440d5524cb431ca30d0575fc21f4e4242f7611fa2a212",
|
||||
expectedValue: "0x639f404f0000000000031d02a5d2b33515ec000000000000072629ee1252f3a0",
|
||||
accountProof: [
|
||||
"0xf90211a0aa686b484fd06fd6a76b4b37cbf3965553120d61b93dc354e1e32e3442fff947a0c8401b3aaef041fd79bcf69bc8eae7220b1932973d088c368422b43e7fa99d3ea03d14c01a86a93d483dae0f088ccd5f64ee3346bba6590bedcc6ed4975d36c0c6a0c64f3e49789294f22c3cb3bfdc78406933b8a47f743de5c999599f814cd8d166a080205a023284e4f9905946076d9dc0c029fca1452743becfba43ae49b0c09d18a04e13c9c6719f3519cb7828514f1b0e393398c7dfb0d703980062e52a3faffad1a0e806c685e60d3b312f1e740422728358f9992e4b7cf62c904c8c01265e88fac0a0f21e7ee12a407fe11cb0950f63ef5dcf62d26fa599f40136ec057c684ccaef73a0bde4594be3b1be7c4312c6ecf81ba8cd8057331563feddd4fdbabf3c67385fbba008ff9a89a68d8a8f6cec81a8553ff72043c4dcdc1ce784874c3fa5e76916f4eca01c5e489af3e55abfdee369a10075b761f58be65d5d589742ca8c6098db88e9c5a05b212b9a9b393541dec0d34c4908a194ccd8c6a21063429521308840c8b66d32a031052338c42361d910eee1c3ec4b7be3400c5cd97a7f8aabd3f5ac81da0c8395a0850317a18f8494eeab20c8015e5d863b43587a7dd3a7efd41a921ff62de926dda09e6e76b343415cf3105ecbd67e99f004b31eb7123f3e3a614ad808557d78c34fa030915874eb78ae682f3d74a727227fa86b204fa367256fd4a50767ed4c35bebb80",
|
||||
"0xf90211a0122c3b5a88702fe6bc3d3464e903d0d1aababc35f259eac6b9111e5b753de6a0a0bf670757a4652ae24e5bd2fe9cacbdda79924bd6091330b950b1473dfec103f3a090ee1dba46441ba0126608d28b0023f0ae8401eda749e90d8550f2d3ca4ccf1ca0deb3887fd765e1c5db19b353dca2ece691dfc2f2c7c0a1c298635e3264d8a05ba06af91d067bdae7d64e34b2d654b08815fc43bdc4193482e9aa58e1fd852841e2a02518d875bdeea78fc832724ad33bbc66a654a1670c6bdf544a060941f90a31d1a0d7e69dfbfc026a105ec5ec68062c6affc1115ae3ad7a70e4ab854f9c914f2cfba0611e45cb73f473325c3d0ad494927e1d1053614c17cec3dd04161248305b3c9ca09767470f4299e3dbea4978fc989ca44abdef26602e3351cea0ef2885dc0e66baa060176e7f197f28205684e6b5ccbb83c5494ac86ef5483094fa3480728b11bf63a0c038f27c7e94887708465bf77ff37de506f5cb29e9a355d4b16d426e12f2bf59a080a4b6849ca41469ec77dba2d4d3ba0b0da9a36e5a6c0451e588a31af5981179a0b7fc37446eafbe040ba963a25e907af5a5d1c584d31198c12e28499a8377b249a0550e5984cd4ee2beb3b1d2af589e0a4954d8da7167896ac12985e1d781e3e98da098ea9d1574fc5431dd7342ea8467c5369ddee70b33ca37f30230e21d9a995d7da06cece45972cba1083ea30c7563c9639d398749575ec229e634f79e1ab637dd6c80",
|
||||
"0xf90211a0a3afae41153cd80f43b9b413b8fb57481fac6882c1f6097117cde8f8aaed059ea0730760d301e2b18a9cd4b3f777d91bfff8424bf64c05adceb8160532728cb699a074588c944add6aba03154d7bd8b543f149dd9629f46d8da52abc9e41be988a74a0b8ae67ef514d0dad520cdc9103c2702ad40a7b0c343aab9be74d72d568902540a0345dfe1d6b3fbb5c9d0aa731fb083d5db76b4dfe22d5b1a789c78a921589082ea0cc5c0989644c549f573ead05887340e201e92f7a5bd9cfe7b57e3bb46d47613ba0002ae2795f3286b54b45e25fd66ed6173ba4bbe56393f7f27407cd559a2d259ea018cce2547825efce8cf5e6fe14d88cb7899a1d8768dae861c0e263a06640e5e0a05a6a075ccc448ab78a34ed3ee7d56a1b179a046be98a1831db18f43637638d04a0fe2b2ac494af3af2c28198dc97bfd165288108e0d2eff941cc5d115461c799fda02d1de5eb58ae72173353aa94335766bb360eef79b6925fe5f254f0e3caa8941ba0b63901c2fd1c61292d32f049dd699bf39c4019b1ac7ab12907804a1633d288b8a0071290317e54993ff32e0ab04d28b920105eeadc917e44449c4ca2fd80adf9aba0fd86afbc5d8ac6357d6ba6f13f0d08737d1f95d49bc1ef1d19ddee3dbc4188ffa0b1cf7db5488cd60ae077821f0aec741b51f8e8c553eaeed4524159373aa98d7fa0c695f9be60487243c29023e469d7af9e37661e325a577247516475e51d6757de80",
|
||||
"0xf90211a090b58facddd3e83bdf8b1553a2c42b07fac5c1da069c73be25f30619088cb480a03867abbc8789869f4b7b5cc4799980299cc3012ec7fce70fb7dea2e5995a9a2ca00c3948797fbbfd4879bc72b5ec1eeba993bdbf4f8b39ae8f63c94cb2dfb89916a00796ca2b7894372e41a3331413a5e776eaaffad05ec03e240966e7ba8330f045a0713935c0c8cfc67afb8a35c948b4239710a5e7d61b5bf9d4e3d6e88e4e7aa28ca036caba99dee8e52ccd1ed12972e6c3ce4a28e160bd7542349338b692c27b5a51a02d1d87889d5e1c16690ac8b7ff3642f6814e42fe6cd6e00e108b759555f2cca0a0cc4be174afaf83b4b1d4fa64374817759956315fb684326fafeb238a41fb0ec8a09dabf40050d9ed69f994f8b82f14e037dec59c6a2a24a9879e184b546ea71448a0c77815db0d8d7eda3df1b8354ac007fd93f6190f20616e7b93259d89f1b0ac6ca09c105e9c25f2f480ef8a50c31bfdd0eef120741c9a1caa6f2278ab7fff0e4651a045ef65a0c419433050e6cc57892fac712cd3cb835da30f2f8cc249b872d6274ea0a457eef99c7beaf2b365cfac520db40b375a0707a0aa7bf234a04ec5746e7daea0e4d2b13f79715813fafb715534ed0d1474e044c7521694ae3bb1475e7d570f42a034143e125fb181ec980641ba63a9d19a005eca2081bf1e1e77572c172c8481cca04747c648752a28511842c2d63410bc6a554ca6d13aa3541edd6e7759ed62b2ac80",
|
||||
"0xf90211a02cf6e48c3852fd7b3a31e6922cb756425da526a164faa2b32f19b21187503ce3a093f0f615e47ec246a5cae41dd6236374287e3efaa9c17611bed4f2621f5ea7e5a0d6c55b3818c48f66570964ab6f184094948ea1d808d26a66a6d0e8195674d143a0ac7dc18dead02fbd3763e5d5fee4d2c032ea207df6bdc26900f0d10ff2c47f8fa0c037ea2e7608348529093c9b9fec3b32d8288bd0b6ac3ae242443f4bda8e9eefa028ead29005c86ca93d969b2963b3eed06ec81dbe7c7c3064d79c6aa033de3246a0f24e9a73c866d6e7f1d411e98da53c76020db588f4b214d44ad6e536d2b7f1e7a0207fd73036d92ceddc5da5c0504448c6c2704735bc6470d10193861e15530708a020f669676f97c6585f7cbe5e405c4f9a4964fad36fe4dd6aa13c6b80a60d901ba061b56b1bcd12005d252197b44f28f611d2cf4448ca57784a8f17ac2b23cfd519a0aad0bfda854bfaef052cc6659d84e69e4b0325e6b8fa394961694e2c3b758203a09da958cb8bc74373e66cf40708a152f31d2c6ac305fcd1af07a25e3e34801227a0edfef4c130b1198a28da1ae2fd66c33d2d1e98725424b9383dee7136360c7036a04c64086b040c6a3701a1b2bedead55797c95c5d635699e66950fcf9c6215ee02a00320a92427efbd2cbe8f70c7c74aa5db0c145b75148808a317a2ccab2cf437f9a0884d942adaa313a922d0883e8139fc6a92acf16e95d2c7d06b4e53a08fdab69280",
|
||||
"0xf90211a037049228c0254f0105b8f461536b772d38df8e4b8bd7f908be72982a86a35961a0d23d1b2a16afe975ac636a8720e5d9fe14dd999e47f5d9e43fe86b2907134705a086cf6044b7e6be2a9c312cf4bf438d464f111fc19fc0abf80c8ab31644bebd06a05bc25ec41da09b0c76b897525589bd03dc90b482ec59e6a1ff14102217f2cd6ea086e9e5952917cf0e054e0e00e0085d7d3bb6a704e55ec5739b6705e4e6539d9fa0148e465f1f1f6095bbcb2feafc49ffd5f604b7439f9b4ab0437f8cd7acf1adf6a0bd2bb1bb25bf43758ed57d63ead3a619cc3a94d47be1b84b4208b24f5b80094ca037ad5b50e846bb85482548cc5a99a03e1db02aadbf61f1380f61bd9ad7ac4704a0a0967620f115f194f7a0c16c7e13492646507ac7dd8553e97b7ebf416228e1f0a0f42e67ae7d57f618596858a5a7239a6039b0dc751d42dbf47bfad47a36a5a59da0efbe74b7c05b343f3e29d1fbfcaab58789c99cd301b87442363efa0a2c7a395ba0c8b4d32dce4b607dc21e9c4ac3ed9757640c760582cc1ffa4679c4dbc2b2e0bfa057addd95ffe7c0de9774f2e3790a52f262515fa6a2a65a9fb785451a6e3ad2f4a094d55a6f5ae979bfc6c6f59928f2850206c5af3caedf39386939a053a2c7b79ea075b8f0a832023c355b067f3786edbea9547211d8cf2dca5f89f9a413b9b525c0a0757df921602607a9115e97c1ca0e4acbf0a2d4ff3bc6e7ae2b151b88359f190c80",
|
||||
"0xf9017180a051c6427ab0bc0d3b0db47b82e69a31fec1670e8ffe2ec57356a512c82083a6a5a0dd0af4a616a626aea8529e07f9017ae356087c45c92ef851aedd845987cccc46a0457441ca9402fb91326638832a9a169e021608db12c58d0e7778c1b13add1afea0db1a3351b7f76cb3170ecc91fd0c687ad46378dd392944612f4c68bb9fbe1050a000c1cb0f8f7bd89d04fe5ed1da96fc769c67a27b3c822a8653397e7da6a04730a0b63f0c4914683ae30b031264fef21806ac7a1a32ccfd05c011ddd0202e06b275a0ac66fa130cd31b0e4b15b08965686162a3efb93e3a07ce45859b34e9a2b4112e80a0dfbd89ded3590a54e3b47e540457b06c754b7b0d22cab361a79adbde4e3d96c980a0cb72d7bbf7aab515231c32e9399359c91aff95accd474e39a091fa2b9e71259b80a04a2be13b00b2032cc0c7112be04907d8d0fa0968932abe8dfdda6c6bb07813a680a010d29a9d3186ad1e4ad1c518be391c44180ba8ce1db0f09a2c9ed23ea017733980",
|
||||
"0xf8669d33239d97e43f5062453663ffd198f40e6120b1057a77480a17b59f8d8cb846f8440180a07a5f002403d62f9d1ab5b4684459d1a2e5170075efb41f51f94fdb30b5e6d46aa073f5b0f762a0557ec4b135108e719884532887167fa14c0d6b7807943d70d96d",
|
||||
],
|
||||
storageProof: [
|
||||
"0xf90171a0b5a85440d5fc74ec55facadb9dbc0cbf35ae1eacdb841b17d6943721a7028fe680a073d52ce999835ee363c087004b4de88b619f66f3dc94d35be5e0b17869d7ece2a042bf377671e60c1d6aad75c93a25c72f0a0c7c2fdaf732b1ae508dc937ebc0be8080a0a32f55598dbc06e6742074f3ad6812f923f9a9f991e597763520cb939c5440df80a01a7798f0e3bd3bcf90d8150e03e9220c1547aa70037856b2961b5fa8dcaaf974a0fed5524862371f728f0e99114f0a09685044436cf34c22cfe4401ec4ec03ffcda06bf06cedf7b90669bac0f199b18bceca612452bb315f1386645bfbd52205a476a04d2c61e0aa8cffbb121715c333a6289570d450cd77f44d327212f404bdc932b6a0af144ae5e9f31fe6da35eac694185fdf07aefb9da7f4c652645bd7f0c7253e85a014f49d31860c00b7dcc901e44c39f3050b2e3f3b8013c0af887778813da9b97b80a0ce3ae4b74569ec95d0d116928f28245839a0c0629d2ec86081ee4896f9a2785880",
|
||||
"0xf8518080a08bafc792d182fe0cac5c7dfb236bbc88dfd0ecf5505b681d1c256d75aa6858fa808080a03315f891bf9433a5415e982ba0f5b3d4497a2a44cb9a958d0830fe301fecae4d80808080808080808080",
|
||||
"0xf843a0205a7bb8d6351c1cf70c95a316cc6a92839c986682d98bc35f958f4883f9d2a8a1a0639f404f0000000000031d02a5d2b33515ec000000000000072629ee1252f3a0",
|
||||
],
|
||||
},
|
||||
{
|
||||
block: 16212808,
|
||||
account: "0x55e617b7456abc2545cbb547e0102279a6c430c3",
|
||||
storage: "0xa6bcd7cfb5e938d75f4330a273812b53f809408efd4332627beb0285fa4a8732",
|
||||
expectedRoot: "0xcb31a10f1562c0c36bd4ceadaa95dd6234fdc02e8cb9357339e507e6b24584bf",
|
||||
expectedValue: "0x0000000000000000000000000000000000000000000000000000000000000001",
|
||||
accountProof: [
|
||||
"0xf90211a000cc1eab958a3f1de15398fa2b27750166c045e8eceb809b9d4501b4e02b7ddfa04da48723172332e782e1bf0e4fd8b1e5f98401d48596abd9a9705496167d7027a0dac4dba16da7ed6cfcca82063ccfc4f47b6fc53451538f7d0d1c7938f038940ea046d8e39429c81dd993f99d3b11ff4cda11bb8c8696b9d93472e71356b8041832a00b940d003e8cf026d1ada0202aa2abcae53098c85486eb7a534af6b3004f8443a090045c5a2ffd3bd39f80bdfa1d6e5fcf75105c81484ddfbc5dd4b4d73f6b66a6a0e4832a0fde78437c8fbedb522d2910e707bd1cf80f2e10b9c6040da0b05105d6a0a0e93dc2989f5868d5cbdd62ec70157cfc4b2064daff79586208e60d68221aa4a0fc7fb69a47e3d6b002c776b83f17fe0c9afbd922544e49bc69118d4912f814d4a0521e58e73a9dbcef30b0c02af1283b7907abadad2531687321fe8ab200027879a04d23897e8ec61a693cab8d2252fa69ac45731de79e47e40711c363b1e7062fcea0290185b97c0ee9f00882f0c50b493205d1a22128338dbb6bc7aa6770c7badb8fa090b9f84dc7ffe1e953274bd3076e5ac2c6faa2ffe8335a394eafad186f9491a3a07e8faa0688cfc77a7cf1011832d69385499ece50ca53ed08fefcd4aa07ce4409a0dfc42b6dac4d479a49a3d2d18ccbc5bd9f98f055294ad62cab84cbc6267f85d8a0b2f0f894b7cfd6834f2c9b58cd5941c8477961169ff6579dbf026a28a871ae6080",
|
||||
"0xf90211a0cc88a0d04fc4367ca945630ce6266a93178092ce38ebd0d3976125c80d9e638ca0110ac16b660ba8dfc12258f9ade49be6245e7d229c4b40ad947c2bfe584a5ddca0b7884a63fdd62c909b9325f29ba55203c8368eb48c420e950354387594c4667ea01079982e5d8a202ed036f8bdd6ddc48b2eaa7c3e8c6efe8ac3369b997ddf2179a0210f2400b4faac315689001a789a6db9313cd835cdcd31df96eb65c433b115e6a089bb0553166bcb16346053be885e361d2d67cab44f7b959aa9cd826dd45ac61aa03b87244622f87055fd869434afd48c8b3ad5a9607b747f6c0d2a5f294e362ff8a06fc34c186c23de6726ff12f731925d0c022b1e28099c6ef1fa3f19423e974396a074eb379a4d71fa80108c16d71c9c9987bfe618f2f9c46dc42db411aa42984b78a01c679db1c89150fdf004859b6a69bed2045f4b8731b221e4a07eecf35539eb5aa0e5d137fd960b8cbb20606bf9e7e9fafbde54c409d1c4613dd80a17de5b47bc5ca037f5902b0eefe2f4d3a498af280683cbb6e24a257548f49c8a5541269da4960aa03ea41d2be7cbacac4f8ca44bf03d0bcd589a01c10a0bffafb8fb1da5a70e3068a0bb980af567ae4b71f44121bc9041c5e32d971511629ab7a40609a36f45981ccea0ff394894d8deeda5f8548486bb5feb71b870a8a431c0841886a38de9914bf188a05afa6d271d39956efa0b6a37f849587fc9ffdd0b21b0f03a7475075f3db941be80",
|
||||
"0xf90211a0074eb00b4c1e2c7113935bee95ed4348415dc85b368967d4d5c4d76196af424ca0813772f3b53979306c3b6099563da22debe31524b46c489b304f5dd00e38790aa06c3522ff7176e7802c0565d7c0861d3b3d84bd4cdc335af7515cff8d08ca7fb7a0c768ae9e22fa57009ecc980b0550fdc1c0b1b4347a505cc4f2305681480cc792a06163dac89c2f3a035f43a559f71c94c2ef275974bb653c51db896c3326c460e1a06c56dbb2e85d467a81935889edc1e1fbda078896de4e9c4ffd33ff780137ce24a0e0da97eccfc2ad11d6489af5e6c646bbe8fae20c85fd1614e84589ac69b7b110a03eb954e27f07ead9cc4013f091b2b3fca8163d3ff052c6a4741d7b652161e4b8a0d1318e44803ed8fb732a840a9cd71eb2d0dadf601f8b8b77251b6de06776513da0a14970d414825f655862751df3bbd7fcbe9903adb663690cee115b4fe880a7c2a02cbead1eab47e6575d0d9d488311b4f16199fb8acabc3bac662c698d471649bba06acca947c81f7bf0b05c8218e615ed3642d1e812c3c696b76d19d9e95207ff89a0486a337786d2e2c7b3e963a9efb9216a79ee5cf61675b9aacc9cf3f35c403559a0e3743c73438b616f23323e8722d90afed16956be9d9763d35968619ef644d893a0437723f6d8ed5906cfc7f1254f80504c15f394db51148357f4c7ef0ad01833cfa032e215e323cfca2dbdbcf7056012ddadaaf9f8b9a4269f451ec28a19018fc76d80",
|
||||
"0xf90211a079d20a2fe4ae7cb0a24db95f0cbb8a32bee53ee9910a9fe8959cea9d6d584993a01a486e762c0b7f5e99f02596a5250acb7d6d54d2626b7ba6c23d97931cbe3296a07b56e82ab24b02849378030bdca3ae3bfa19af23363c731537da3b47dc64c299a0a3c947fac18c8907db5321a2cf28e6fa0205d074db959c12e25fd0c9c64f64a1a09f658920397018751aa15e1feec3ec81dfd19988e590b663c6efefde407e2a3da0e5dcbae4c0fc4c9a050afb5ab81b71a76cd201d9ad724894518aecb7ae557079a02eedf89c6286ad0d5a8f24ead4c300646452191765d86b7217b7c503c9d93bdfa006d8c0bbf530c40ed8bcd89dcdb4cba927d3363c4eeb3fd7452c82f986506630a0fe7850edfeabfb584ab06d0a1599d64ae60b143cfb3bd8bd1cecd8e918b0c7f2a0d09c9c7f8b8280ec01c8fabdc75a5abfb9600e5961b3f1a2e62313e81bac9d26a03c5944032432601c395a4a4c31c3feed3606881df80407e7c6e45a82455f85b2a02dea3f595f1b07648456f39b39a6b337d5903373c5c194da04ecdbde82b40b41a08cff9a982b8e0fff7d588cf0fa0116f039db921c13fae79a5f7e8333ad4d3a18a043dac2f48ff878530faf63341dbe6baef3faddfd049f7db4c183079c77916b17a05e15585f071142178813285614aa8abd4c65a95f516df528ae2d3c6ee08521d6a0b0dfa07c70efbcc57f2b6cb7f77a7a20fc9537c0d984a676ec9926e55f71c77880",
|
||||
"0xf90211a0fb721ad628030689ef65168ed001f566cd190e9c4d0219c02afdaeb004d4e214a051531d55c79e21f006c4741486cce4d8a6e613d761b3bde9ae2c8040a76b307ea02213a6ad7395c88dbdf89f0b29acf67c6aa1dc0e374cc6a7d9b6ec3d9fb5f373a0686884cfda50455fdff45f4170feee963de6d591770c269f4241e34563d70f37a0bb97314a2c0642f5abc066b8d53634887234dc37d3f9538124fcd27225b75733a01a296ff7ac3bd812e706959caa4748f04cc0729fdfb14388e244347b4a3cb685a0888eadb1b0d48cf03e73398f2aaef32bb4ac265f10f76c504db269250e88fd55a0b9a2aca21bcd60c94c2a80fdade417a56fabd041b6c0379159f02ff2fec8ab87a0db49371306dcf9e9d4ae471429c2bd4affe09cfc065792ba6410595f8beea2c7a0bba4db70589218f90ea48d1f870db783f8aae6cda9dbf72235e1284b97313dc7a023658240a8e60035480607bd2e2c780d0a305909fb06e9c6befe7701e78b596fa0d6f93b95c1fe2238e73c72e96cece7d21189e5c8e839bf0d42bf226a105c08ada08ccf4640a918ae9ea713e739e62f7b5c5bee3864b57c32e29065593cc8457171a0ad5dd98fe06ccf15db195de3aa8d071be23965c64839e10d1e9721cd64f26382a0e5a987a544eac0a3abc6ef9ddd12d8450b3e11f36d6239cd799595535ea0431ea054db8f7995108a2c8bf8976723682ce513241f75da97518991c6b77c050d398280",
|
||||
"0xf90211a00dffb8e3f1d162560bd7fa2851c9475cd30bf41c78017372b8f5d40360831308a03348160896064725af3bb64dcf86a8fab726fdf442007fd3825c689553a314f8a0794309daeb0692594a7bdd16e884ebd75d598db16cd1005a9176fce869b3580aa01150f6cb195cd24622f9440d2ea824b33601d7d7983db0d925d39daa1695c950a04b61b2cd4bf2ec97550c27656b784df083bac7653352920b3bb0404bb09f1971a040e09010e7c233361e66eefeba4c03cd551580bf394ed6fb6cb8f921184a9f95a05ba6ce8c14236c7b63aedcf3f85603846062c43d165c207cb5418cb7f06dfafca0fb016acbbd9d14aa6bdb9b01e802ffe495032e97d124c9a0b65d10d4e715f39ca039c0a367372d7a14a34ecdc997bf67bc72755b4c7270effee6d90824aa15b087a0c7ddc7fc8c0341c56fc7e6228469b25f7af926b3fd099530c6097a02c869c41fa0ad11f0c6cad46f32f1ce178820941063777e2871fa38d5adfbd91672479213afa03b11a8fbd61e8e0f3f18a7c3573ec7a792edd83d3a6b8efac10ebb8b157ac17ea0ab266aa84b02ef61bc71faf1d261e2bb90cc21d6cbdf951b122f596f5eb3d90ba069b80832c46cf88b0ca1e64054d87f2e33f27df1f322c70af89f4ec909313bcea075068d344e56b3eada6312fb613925c3c9de369b328ee666121dae6c052103c4a0c3b65e68859146733573b921e8fb036ca7c9434b0f52412ac0cd169950f95a5580",
|
||||
"0xf8d1a0db401bdef3bd74dec5338135194e69ab43e15aa891e5de20ef3e57cde5366ab5808080a0621c1fbbb026eddb70a4c645e152dcf9b3f1b40b9a1bdc4398a22bee4a46aca380a05528de70186525019cdf0880afb77b33ae4871fbfaad3e8bccd7dcb6402d746580808080a020fa8ae1091998f03c979f94e94ff6c011427da2834f1dffaec815fd3c5fa6e080a0611ff1f45d926197480694e690227d603e84e7c44b520473b9786cd4fafaf613a012dfcd444d4948c86a3dbad8f4f1dad09c313a63e6f8bf0ecb7bd799908aa3248080",
|
||||
"0xf8518080808080a0cf86ad50e7ed35be6080c4cd74d835e58867b2e2ec03198baf29962de46a8cbe808080808080a03a5ec92acf98ebef8eeb621707a501ed0fd95186282ab1dcf8e7286a9142b90480808080",
|
||||
"0xf86e9d2019df8705960e4a0a7ac52ab662c57cddd5f60a7f75f0c117ae2e073fb84ef84c0188067eab853ae20000a0724a8bd0aaa1c991a445a1e974deecd8cfe4ba2040de2578e98238b9f963ba8aa01717795a0fbfac056a8306e5cb0ac160c3ad752357e0360a408e59acd35ebb1c",
|
||||
],
|
||||
storageProof: [
|
||||
"0xf90211a06a128b938cf5a3be9f5c7a8944945258db0b7a939cab65a4bda8fc4a8a2bf16aa0c61e8e76eede0e8a446743dde629574cd69dfe612aa0d30c6c8cafdb7f445214a084c1c16c0f4fae18501251afbc28ef21caf9b2f1b5a8f2f0b6b87d076f44f7bfa04ace3470f520e28ebdfa4e98a5ef51af05f647a3d1585f0d98f3393098839f17a0d0628e1db39bef70e79ceb5860a14b34b78eca696ec7910f3bfc91631a0abd50a0b718050b33452d627f87f02ba8b05f976e7eeb2c81cdd445770eeeefba236fa9a0f0a8fb4ce1456839b267d76b94838113ea18600fefa3617733888b1ce7da7ef7a034dd7e5a07aff6c7d141c66b4aab81f3f31363a92d48a9bc1fe072b94d69bf63a049c1f246035c714f4d6e8d81e7a20aef93140d067012314b37489a66f4e19db4a070279280c8be3e03684124acd488d9611ea5dbf62512280eb352980ec8334436a04e7d88090f29162b58e6fdd44446f90c5bc1c39c377d7c757c6010e9a63c738ca05eaab99620fe77019cac5ea6854f3efda933ea60f1326ecd03a32494850556a4a06b4116e3177b3012c5e06ab564d1a0611140ee2b81d50c8fd8c5aef333296965a00874454cb37dd61c28f8bb7da5d905f5dacf0b813914099244b65f536561e22aa073f2018c86cfe905a5bb8f69b43395c949714183a829990e0e33630431af8f86a03f36076859c730c0f5851ea263b5650dab7235f3c8ce258f74a3ae3b7d38add780",
|
||||
"0xf90211a036c69f765a83b393b27f21eeb941b8a2965ec7d436b3965a5bc40953a32884c9a04fd94c2ff0df3a8453b14a36a55ee9a15096180c12feaddb7c904016e0250491a00b3973a34de7950e6eed8e413dacd2414ef22a90ff9fd322501301e159a2c081a0f6926e67b5dbe04b3991297ca0bd8f1fe63b1f193e16621c901ac81ad9c25a85a023776d17051b8899483fa00c050cc50eae159dbbd7b59a35290b6d6b272e07c9a00900c56dcf2ae9bc0d19ec918cbd7fe63e7afb8aa2d962d1d5cf5886c763a7dfa01e52f9000865a4df376396fac674f061a61603647923a3a577387c54e1b32826a02373c893c5feb4c772f345f6609f9f9a6032c068f2453aad191626ce6a2d625ca09fdcde9e12f55bd9b3bfb323f1c9a7488f573e0b01d829d6f0ee716e92f0f248a0353975fd758f23275ce22c485c939c781ba31aa8c6026688931ac61d0f0d8013a04f0352b630e3ae315c64d02f85c4cfc255524b445046426c3e67f6608a9689f7a0d3b728caecb48e019db5f0144aa081ce5954c8acadeadd3df36d25b6e24a7e0fa0758800b10d88e8b477fc17a2094b5a41aa69c37740305e1956ed558dd5dcd86ba09f51f4aeb641e8c068dc1370a71942792b4d30a572ad0c09eeff206f7dbe3355a0c5d5fa6fa22f56ac27c0f6538f94615e0e7bb49243d888ec6b0c86f61dc6922ca03b7be4e1038893b7cfeab5a172995ac07e1e90142cc566ddc2b613e3b2a08c3880",
|
||||
"0xf901d1a086ece613a3028576c5e26a4ff50a9c3311c3bb3ca3751b8e52d2667b18917f4f80a0c54874707f838e0a2abf666fd3c50f900c9c0c38e9a69b37551b1711acef7eb1a0b7e0dc7b68d45f0f52e17301906d038323861fdb60583c6f505f76d304c73ea5a061a5e1481d528ed55ed1dafcbbbecc99276220ccce4ce56f50a05853638a3c4da08db8ab11699112f1f4cebece052af297997fcd361f5ceb88db4a7168e0366cdda0b1c641b80c0e5642b33866b899afc25070277d24665b6d73bc542543592c6eb2a069ae6c87a4a8692ea804b51379521e3856a6a980a1f6143f19ffaaa397c1699fa005e0523d440c3fb4654841a3d8ccce6e5eec4cd5f145668c0e95e847c9c4c39fa06c86477d3592a33fea0e7e425cef6b79610cd32b3bd17fa1318a5e20c9feb02fa0fae05cf440cf5cbb96e83bdd1828f5a582aec03edbb87e5035fd08660f09691980a0d91b6dc415a8c148823a7f865963d2b527c6a93bf882cd29da46f9a9594b4c41a03537d0ab40aa8b56059d99680365cc017a26fdf155fd6f2a7788311723b80738a0e38ba0e1b4f98b4b9f1925ca952a6a9076eda1bad2e36dbc80bc5135372a3feca086f2109580fb4d1a26bb9101b88c407eb13fade29243d68b83764716dd450e3980",
|
||||
"0xe19f36c2516eb411c7c89f75dcf98d8ff95555585215a5f6242b4f24adbcb7424901",
|
||||
],
|
||||
},
|
||||
{
|
||||
block: 17654287,
|
||||
account: "0x0068cf6ef4fdf5a95d0e2546dab76f679969f3f5",
|
||||
storage: "0x0000000000000000000000000000000000000000000000000000000000000000",
|
||||
expectedRoot: "0x6e0dbf614f46a7d99f42bb19b8d077852fe794a040ae62a4468810e3f0948bca",
|
||||
expectedValue: "0x0000000000000000000000000000000000000000000000000000000000000002",
|
||||
accountProof: [
|
||||
"0xf90211a01d16453323b30ed0475ac6e0d8498b3defee9b0a2a273208a37ddceb5e41f69ea09173547e094231c109ca45892dd38e73edeecbde5f89585c981ee7c6ac038a24a01980107b929796de0e9cc55bb7505c7adfd297758a257cb43b9af152d596856da00db006c2271b90391c0a1290bdba55f2b615eeb5307a8bbb4c8faeb15b8b7ce3a0b3ff04cb4685f72483f12c93de3354d621695c59a324e72e09f353af209888a9a0ba895b778ace696ec60b09f295ed885afaa027bd104e3fe58cf106471c71697ca0b8521df9c6de45143d29a6a1e1f855ea11d62a30ebf601914d3524bcdee2d6fda0515cd9a8cbcb46a715fb7ff67fcf72bb433a4c2bbe53c64d0d92d83d7e4bfb68a05a12f19c558e64b1cf5f404e8ec0fcebc0c3c6b05eb5b12bcd5366fe09107652a00e5b7619cff2463f4c063e6be5d511635cca7cff72c5ec8e2d6ab2feea7700e0a09181d13feeaa190bf4ae88de86b0adf2ad55a94864245c2d9f32ccba082e3d40a00c23af247cc206f2edaa46d98d290c8b49018909d6ed97b7346e7ef69e4fb5c4a03acdc865ba1b65c64f9c495fa01975869eb1472a9e87d321a8ffb8ea4dd53a33a00522f686e138ca2ae2b3063319e01b3caf8447d19a0a00affd567e673f57e3f1a048e346e25a5bba903ff0d73354f0289cd12adecef7a50f1a5e6b77fe840c3216a099820f0f4022552c5439640dfe42f18ac125ae827698341a20fc35fca1c9244680",
|
||||
"0xf90211a01ec95bbb5cf4dc39f63683626c7b0a773d55160908ec99e59a5326380c73203ea0c5a50a01b607a8d5eef6ab0876a506c461d1c598bc4836516421ed1019d56bfaa01a976d9c6cc14e1f6047cbc492985d4812b7ca2f93cf63a2b34200a8212d7a54a040b68773658d419c60e169a84ff4b45594909c4a5daf2793d4d5356bbf8b0e2fa013167a747e7a5a34c9f207f50c62c44b717818ac25c3fcc0f1ff27d7487c8504a0640b788ab79273cb8b6785d078799e71cecd9c209e26c6f870e757ab9defde6ca0de36a43a3e775e7ee817093b16f423dc995f9444a29c9cd06e2f8232254cb95da03c4820d01e2a9e74f3e6da9db1566f5e94b3a933b9864e1702666fbae3175359a0f65de5b5290317566435b695d805ae983e659c93066b72fa09d34114d7dcbdd8a09b2c0648e974edef55f325dedd496139f35bc377ed3e9be17433ee7e8dba5643a0a720648153362da9c1e5ea94416af5f0a069b493ffacbd1def2efa256ced334aa0c5cb7b88ef6fb88d93301bc182581b5680551d1e6d9c518ccbb78f9da0dbe9e9a08070a83e329446fb9a61cbd358b1a14e8f633b5980ed39018a39e856e29fd7c3a055541ec7a175eb2b357bfc608c8c41a313c0e7432b5db3a45eb332bf39ffc705a074a59d2b10b98d80424671e0fed8b95c02c63f007279c77c8637201c806024b8a0a0dd938f251e9e58f33c56842e54e70f6edaac451cdd4ff908a4a845b8a094e180",
|
||||
"0xf90211a05791255edb067e389d9230610cf6c0f2b5bdba04c787cc253b4408c0de058380a0f0e14c57af008db14bbd968eeeede1f66a277fbcf33d9d6dc7d7909269d31f69a0d63b643ad254d69b440f854ec3c29d0222093d6ee5c694ae130c9a2f30d750b0a0981b82957b34d3cdfcd9677c5c3e7e51f8907de9d62f4e2c1c7daabd53e98f18a0e1c921639a76503e3499702d6c7880c3dbc49e74e4f4e3145e897382819143dba06451b79e74690762041d77f207ae889e6d0379202f37591479e644dfe7e2ef3fa0d40d43938929bbc1656e2f5ad99476b953bb32ad8c81bc190650a34bad9b8befa0f2869cb5ace3192e29664e44073af68f0cee1c095baec010acba5eb710651841a0eb9cfad4c796fa13ad2692e3036e951480afb3b168fde14b59bd6ad5080a6922a0a7d8e8298485e3f6d2949c11ab2a5e2b5f685edf92e57fff7bbaec2d289fe150a08bb1562017cfe065095f8022e9c09e0e8dca556e37103f643f4ac7aa48ce6fa2a0801236ae1ab97c2ebd3d3d84a3649a70d947190a3bf03ff2e08c9566ccb48e96a0d677f601663075137b9a84af1134527bf8b1df1c7f02de4e6509be3892aad4e4a0b6c4e67c85d79a08878b349e1cce515d64fc28915ea3558053e1248ce70c5286a0d0a428122fb8105e813924660214896ec0851fd4f33e64851452476e817e2097a0727eeb8e9ea4e62815c0f46708a1527a9ff9fac9994c1442f9c118c0be8817b580",
|
||||
"0xf90211a0969453ccd835ca415f87e7f63eb2a2c3d349616589c9bea36e6d9503b1418aa0a0a73b67797d24c75dd716fe6779f8a462a1671efb1a2d1433089eb0e2a17d105ca042a06440c9d52f7d6ffe8ab7c3c453a05a0243ba5aee609819bd5dacd8363be2a00a70d832a68a496c174ca785ba4bdddd5052ca3fb2410e4b667851fa7fb5272fa0af4e35e3f9b0617d7ff80cb79e1ef0921f21a41279292176d9e117f422595eb8a0a103553baefb54481ff0ea34d75edad63879182dd595e4aa8f85ca185cfa1abba081b203264801d3b0fdbefd7954900b4165dadb47a6ea210b92d8233429501a64a0f8e5f8ae8ac56d69b2e9ab881a0b853277e92833e7067b40651719d7bba31bfda0ebda38384f871cf603a4f5ad2a265e818aa91cbb68b4de1c2e1aadef084f4ceda08fa0b8481c834c6b4cb1a85d49b3509632ae55f5d194a69c821ad9753c3a5500a0aca036de251523a82f8188ef0525cc3d2e776aa786cf3457d8a483c4d1cf88a5a04f817b7b1e70e186f6f9ab7cea8f7437f7efb3aeeed22ba6a6ea380bfcf962a4a0cc6653c620e174f2d3e3e0756cbdeebc2cbcc1aa1c67cbf1c2ff8aaca84823c8a094e265b2c06fa02987213ade5598826a29e1a24bb04df2b102a646cfcede6c90a0f021a62413e90e1e8eaa49dc399a48a9d5ec3f84dfdbaa0a3b4a419dd1bde199a0e79d5f428c71f7435fa18cc01a6484a30dd43c781a3e5f14c95136dddd5901c880",
|
||||
"0xf90211a05351d3596a31b5813aeed8088aec6f64b64ffb590a9b9a675e3c24917f1bd15ea00a098a769a5627b156bb55ef7d334a364443cbfe28431e2ff28165b44cb95542a01c7661008fe9ca32f0270d302d82979c1495343c9bf25e87dad3612929a5cb36a01f85cb40320b137c49e2ecb5aa3a3db85833c69747a86f2be7f4dc0d745742b2a03aa74296d38eb5c33bca5c94195da9f32a7217349e69575b84144268e6f1b2dca062ecf298a044531b19c8beea544f99197df6e8b54219a0f27dba4d4fa541babaa0b0cd63f95c67f0597165158d09c7c27d7d8202f9be608ae26dd5316433fe7b7ba0bf61c2af584a27b46bef9a14e527e7c0c2000e123d1bf39eccd59db47ecba01da0bf89e2fb3b1941518e2eb35824cdfa1245d6cb7bfbec99f6309a4d18fb9755a6a0a8b9e450a3d15bf70d4f9a6f6a3fd34dbd7eafcff3f0acb1d1ac6d162089b522a0250aa8ab557f89ffa83d661e8757f693b0d1315bca13d5bd1fc6897912a0ad45a0a962eba19068192509edcf9adf2b976ad84bd1bcd053bff075ec7ab214a80faaa0110825fe0f439d26bb6270e37fe89e8b9f9fab096420d5cbaddd04a349370209a0c7ff710535da560b7329183cd75aeeb34564ca01447eec54590bbdcfbdc8601ea09ff46c368e03322f356f1c5c863c4cf1aed1967bf39d020fb4bd0c281c68f0baa030a7ae32120f6c0a271f70f5323b5a4b7ec7c9b50eca8e62a9fe50b47b6fe09680",
|
||||
"0xf90211a005d90b43639d8703b5b46e1a300ee59e21bc329ace56f5fd40a49f8c98c997c4a02634774fbdaf6c1380337541329edb575ca40bdf38f99d22f20c6599fb70a915a02b80f43a33554844dc3ad3b346db70a2edd74985b440c22fe70f51918c6e1464a0a685cffee53f88bfcfdede63aaf73becc1f5621c08390c13b02dc9de8cfc0521a0bbd2a32a4b54ebf626031f190e39c90724ffd91b9474d841b6eb9c0f76bc8ce7a0c860455b9da06b1e69e4aa952c787761acdb1603913b4965fae684cf016bcbdca067e8f57fae01bfed4e1add6a0b9ac5641be21ddf24ef18289e87035d75b871f5a0adabd78fddeaa6c42803f81a23e7991eb611e9ec1c9071a24022aac0a71a8ceea07307279fbc13f2f29a5f6c21add5106efa24f73ccb7ca02d460196e3810c37afa0392aa0794df746a43cb59907b892bf5aa78051b45c7ca1112c5b68a523623295a0a5e09e62e5cfff36c2dd8e738762140f943b6c2c85d8b5385f121f74ae01282ca00943c8def2f6f51ef2e99cbe99c50eb5f599bccb039529a874c6b3de3e5cd2e2a082affeb98e43b37d23515983324bc459bbf503ddcd51e9457acd9b1ee47ce4a1a0a3dc55ef190ed6ba960abae03c755928f46eafd5fec04db7b78345eddc1e16d0a0d8e9e0f89f9729526f4ba732797d9bb81e6eccfcf5778cde7e99545a313c8697a097c3d5a698982821f3354cf5a20a6673b5300019af36518f85e4759e554e4def80",
|
||||
"0xf90171a0d346d1b6b8da1dfb0b97f26625ef03ef5636d748d022ce03898d32c8aeff119f80a0967b15d622a02ad2992db69e49b0460151757bf3b360df5fea408bea63c026cda09c6b26a5217537924d8783f57eaca4b17d0cf7bd2803ff372ca9e4c7c54bc29fa0cebf14dcf1027078e6c58277f932e1caa306aa29d12ebb690c54c5738124ae8880a05b45f21d20b4391a22b68e2d164a58c2a80d356968dfee8650c5e2516398ab8880a0e4b87f12645c511bcb763c404a18b754ee4644ae30097302385298a3f98aae10a056cf6e6079e53f30b464df39a4df44ef33d032009b46e60ad2204fdd5ea9033fa0fe4c7e738646adc940b306191f948c0c5cc7bd694d954c945d8c766d7ef34c92a0e8c65be6abb26a472102fc89faebc972b38d2badc20e7d7b16206d4b22f3462580a080b20dc002a994c21508d73e79464af914fa6d746bbba02477b512ad0eb7ea7f80a0c80aadfec76857d1cceeeec3cbd04f6923e36334fa394d20c0fa8e0da078e9e280",
|
||||
"0xe58313f4a7a02023e131c23f3ffcfdc667ddfb152602a5584a3bc89d5fc721273d06280756c4",
|
||||
"0xf851a0d19a48e137ace64957841715dac64aca2b13b67dcc281c40a5d0952ac474a61380808080808080808080808080a07028d519df1e68348cc0597fe6fa3335b181a3f0ddab251792916634c9d2ed9e8080",
|
||||
"0xf8639a3252ed22ad4e036cb1f5cf3d262d5438ece2fc3097ed10fb737bb846f8448080a011de7f0b3b50bbe96191c2bb22b22933a18739348bc469ef3f995cfaf66c2352a0c2d83c5e1e5dcb9487d2b2b5689520b4377d503cc54d63b144f88cb21835595c",
|
||||
],
|
||||
storageProof: [
|
||||
"0xf90111a0845a58d6992ac45fa0bcc607366bf7f88e0d03dc3dbce12a1cc4015c4d8abdeba0c26c8ac66961c484cbf850ff321be32b5ba99620fe480648db12d6783a17078aa04e918b76be51be2f02df0ac6191ec2765d401d2229e47291806815da755f5b5e80a06d7d944d988655e1fdc697223d3c3e115d005968e289f141c94f105d86c74196808080a0dc97b79c03ff591103b4961835f65de82a94c7166fc1e390f35deaa11b158c408080a057a2faf89e4b43c431600b5b6c687cdb6cbe5af08f9380158806b7e603da7b78a0f45cd6b758f905463cb8d116e78e191d983f7c26f98460306a7d6217c62da9778080a0a334cfbd70c0bfdfdce3d0aa560293be9cd496c2d47c8508c82f210b01dfc58680",
|
||||
"0xe2a0390decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e56302",
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
describe("PatriciaMerkleTrieVerifier", async () => {
|
||||
let verifier: MockPatriciaMerkleTrieVerifier;
|
||||
|
||||
beforeEach(async () => {
|
||||
const [deployer] = await ethers.getSigners();
|
||||
|
||||
const MockPatriciaMerkleTrieVerifier = await ethers.getContractFactory("MockPatriciaMerkleTrieVerifier", deployer);
|
||||
verifier = await MockPatriciaMerkleTrieVerifier.deploy();
|
||||
});
|
||||
|
||||
for (const test of testcases) {
|
||||
it(`should succeed for block[${test.block}] account[${test.account}] storage[${test.storage}]`, async () => {
|
||||
const proof = concat([
|
||||
`0x0${test.accountProof.length.toString(16)}`,
|
||||
...test.accountProof,
|
||||
`0x0${test.storageProof.length.toString(16)}`,
|
||||
...test.storageProof,
|
||||
]);
|
||||
const [root, value, gasUsed] = await verifier.verifyPatriciaProof(test.account, test.storage, proof);
|
||||
expect(test.expectedRoot).to.eq(root);
|
||||
expect(test.expectedValue).to.eq(value);
|
||||
console.log("gas usage:", gasUsed.toString());
|
||||
});
|
||||
}
|
||||
|
||||
// @todo add tests with invalid inputs
|
||||
});
|
||||
84
contracts/integration-test/PoseidonHash.spec.ts
Normal file
84
contracts/integration-test/PoseidonHash.spec.ts
Normal file
@@ -0,0 +1,84 @@
|
||||
/* eslint-disable node/no-missing-import */
|
||||
/* eslint-disable node/no-unpublished-import */
|
||||
import { expect } from "chai";
|
||||
import { randomBytes } from "crypto";
|
||||
import { Contract, toBigInt } from "ethers";
|
||||
import fs from "fs";
|
||||
import { ethers } from "hardhat";
|
||||
|
||||
import PoseidonWithoutDomain from "circomlib/src/poseidon_gencontract";
|
||||
import { generateABI, createCode } from "../scripts/poseidon";
|
||||
|
||||
describe("PoseidonHash.spec", async () => {
|
||||
// test against with circomlib's implementation.
|
||||
context("domain = zero", async () => {
|
||||
let poseidonCircom: Contract;
|
||||
let poseidon: Contract;
|
||||
|
||||
beforeEach(async () => {
|
||||
const [deployer] = await ethers.getSigners();
|
||||
|
||||
const PoseidonWithoutDomainFactory = new ethers.ContractFactory(
|
||||
PoseidonWithoutDomain.generateABI(2),
|
||||
PoseidonWithoutDomain.createCode(2),
|
||||
deployer
|
||||
);
|
||||
poseidonCircom = (await PoseidonWithoutDomainFactory.deploy()) as Contract;
|
||||
|
||||
const PoseidonWithDomainFactory = new ethers.ContractFactory(generateABI(2), createCode(2), deployer);
|
||||
poseidon = (await PoseidonWithDomainFactory.deploy()) as Contract;
|
||||
});
|
||||
|
||||
it("should succeed on zero inputs", async () => {
|
||||
expect(await poseidonCircom["poseidon(uint256[2])"]([0, 0])).to.eq(
|
||||
await poseidon["poseidon(uint256[2],uint256)"]([0, 0], 0)
|
||||
);
|
||||
});
|
||||
|
||||
it("should succeed on random inputs", async () => {
|
||||
for (let bytes = 1; bytes <= 32; ++bytes) {
|
||||
for (let i = 0; i < 5; ++i) {
|
||||
const a = toBigInt(randomBytes(bytes));
|
||||
const b = toBigInt(randomBytes(bytes));
|
||||
expect(await poseidonCircom["poseidon(uint256[2])"]([a, b])).to.eq(
|
||||
await poseidon["poseidon(uint256[2],uint256)"]([a, b], 0)
|
||||
);
|
||||
expect(await poseidonCircom["poseidon(uint256[2])"]([a, 0])).to.eq(
|
||||
await poseidon["poseidon(uint256[2],uint256)"]([a, 0], 0)
|
||||
);
|
||||
expect(await poseidonCircom["poseidon(uint256[2])"]([0, b])).to.eq(
|
||||
await poseidon["poseidon(uint256[2],uint256)"]([0, b], 0)
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// test against with scroll's go implementation.
|
||||
context("domain = nonzero", async () => {
|
||||
let poseidon: Contract;
|
||||
|
||||
beforeEach(async () => {
|
||||
const [deployer] = await ethers.getSigners();
|
||||
const PoseidonWithDomainFactory = new ethers.ContractFactory(generateABI(2), createCode(2), deployer);
|
||||
poseidon = (await PoseidonWithDomainFactory.deploy()) as Contract;
|
||||
});
|
||||
|
||||
it("should succeed on zero inputs", async () => {
|
||||
expect(await poseidon["poseidon(uint256[2],uint256)"]([0, 0], 6)).to.eq(
|
||||
toBigInt("17848312925884193353134534408113064827548730776291701343555436351962284922129")
|
||||
);
|
||||
expect(await poseidon["poseidon(uint256[2],uint256)"]([0, 0], 7)).to.eq(
|
||||
toBigInt("20994231331856095272861976502721128670019193481895476667943874333621461724676")
|
||||
);
|
||||
});
|
||||
|
||||
it("should succeed on random inputs", async () => {
|
||||
const lines = String(fs.readFileSync("./integration-test/testdata/poseidon_hash_with_domain.data")).split("\n");
|
||||
for (const line of lines) {
|
||||
const [domain, a, b, hash] = line.split(" ");
|
||||
expect(await poseidon["poseidon(uint256[2],uint256)"]([a, b], domain)).to.eq(toBigInt(hash));
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
149
contracts/integration-test/ScrollChain.blob.spec.ts
Normal file
149
contracts/integration-test/ScrollChain.blob.spec.ts
Normal file
@@ -0,0 +1,149 @@
|
||||
/* eslint-disable node/no-unpublished-import */
|
||||
/* eslint-disable node/no-missing-import */
|
||||
import { ZeroAddress } from "ethers";
|
||||
import { ethers } from "hardhat";
|
||||
|
||||
import { ScrollChain, L1MessageQueue } from "../typechain";
|
||||
import { HardhatEthersSigner } from "@nomicfoundation/hardhat-ethers/signers";
|
||||
import { randomBytes } from "crypto";
|
||||
import { expect } from "chai";
|
||||
|
||||
describe("ScrollChain.blob", async () => {
|
||||
let deployer: HardhatEthersSigner;
|
||||
let signer: HardhatEthersSigner;
|
||||
|
||||
let queue: L1MessageQueue;
|
||||
let chain: ScrollChain;
|
||||
|
||||
beforeEach(async () => {
|
||||
[deployer, signer] = await ethers.getSigners();
|
||||
|
||||
const EmptyContract = await ethers.getContractFactory("EmptyContract", deployer);
|
||||
const empty = await EmptyContract.deploy();
|
||||
|
||||
const ProxyAdmin = await ethers.getContractFactory("ProxyAdmin", deployer);
|
||||
const admin = await ProxyAdmin.deploy();
|
||||
|
||||
const TransparentUpgradeableProxy = await ethers.getContractFactory("TransparentUpgradeableProxy", deployer);
|
||||
const queueProxy = await TransparentUpgradeableProxy.deploy(empty.getAddress(), admin.getAddress(), "0x");
|
||||
const chainProxy = await TransparentUpgradeableProxy.deploy(empty.getAddress(), admin.getAddress(), "0x");
|
||||
|
||||
const L1MessageQueue = await ethers.getContractFactory("L1MessageQueue", deployer);
|
||||
const queueImpl = await L1MessageQueue.deploy(deployer.address, chainProxy.getAddress(), deployer.address);
|
||||
await admin.upgrade(queueProxy.getAddress(), queueImpl.getAddress());
|
||||
|
||||
const ScrollChain = await ethers.getContractFactory("ScrollChain", deployer);
|
||||
const chainImpl = await ScrollChain.deploy(0, queueProxy.getAddress(), deployer.address);
|
||||
await admin.upgrade(chainProxy.getAddress(), chainImpl.getAddress());
|
||||
|
||||
queue = await ethers.getContractAt("L1MessageQueue", await queueProxy.getAddress(), deployer);
|
||||
chain = await ethers.getContractAt("ScrollChain", await chainProxy.getAddress(), deployer);
|
||||
|
||||
await chain.initialize(queue.getAddress(), ZeroAddress, 100);
|
||||
await chain.addSequencer(deployer.address);
|
||||
await chain.addProver(deployer.address);
|
||||
await queue.initialize(deployer.address, chain.getAddress(), deployer.address, deployer.address, 10000000);
|
||||
});
|
||||
|
||||
context("commit batch", async () => {
|
||||
let batchHeader0: Uint8Array;
|
||||
|
||||
beforeEach(async () => {
|
||||
// import 10 L1 messages
|
||||
for (let i = 0; i < 10; i++) {
|
||||
queue.appendCrossDomainMessage(deployer.address, 1000000, "0x");
|
||||
}
|
||||
|
||||
// import genesis batch first
|
||||
batchHeader0 = new Uint8Array(89);
|
||||
batchHeader0[25] = 1;
|
||||
await chain.importGenesisBatch(batchHeader0, randomBytes(32));
|
||||
});
|
||||
|
||||
it("should revert when caller is not sequencer", async () => {
|
||||
await expect(chain.connect(signer).commitBatch(1, batchHeader0, [], "0x")).to.revertedWithCustomError(
|
||||
chain,
|
||||
"ErrorCallerIsNotSequencer"
|
||||
);
|
||||
});
|
||||
|
||||
it("should revert when batch is empty", async () => {
|
||||
await expect(chain.commitBatch(1, batchHeader0, [], "0x")).to.revertedWithCustomError(chain, "ErrorBatchIsEmpty");
|
||||
});
|
||||
|
||||
it("should revert when batch header length too small", async () => {
|
||||
const header = new Uint8Array(120);
|
||||
header[0] = 1;
|
||||
await expect(chain.commitBatch(1, header, ["0x"], "0x")).to.revertedWithCustomError(
|
||||
chain,
|
||||
"ErrorBatchHeaderLengthTooSmall"
|
||||
);
|
||||
});
|
||||
|
||||
it("should revert when wrong bitmap length", async () => {
|
||||
const header = new Uint8Array(122);
|
||||
header[0] = 1;
|
||||
await expect(chain.commitBatch(1, header, ["0x"], "0x")).to.revertedWithCustomError(
|
||||
chain,
|
||||
"ErrorIncorrectBitmapLength"
|
||||
);
|
||||
});
|
||||
|
||||
it("should revert when incorrect parent batch hash", async () => {
|
||||
batchHeader0[25] = 2;
|
||||
await expect(chain.commitBatch(1, batchHeader0, ["0x"], "0x")).to.revertedWithCustomError(
|
||||
chain,
|
||||
"ErrorIncorrectBatchHash"
|
||||
);
|
||||
batchHeader0[25] = 1;
|
||||
});
|
||||
|
||||
it("should revert when ErrorNoBlobFound", async () => {
|
||||
await expect(chain.commitBatch(1, batchHeader0, ["0x"], "0x")).to.revertedWithCustomError(
|
||||
chain,
|
||||
"ErrorNoBlobFound"
|
||||
);
|
||||
});
|
||||
|
||||
/* Hardhat doesn't have support for EIP4844 yet.
|
||||
const makeTransaction = async (data: string, value: bigint, blobVersionedHashes: Array<string>) => {
|
||||
const tx = new Transaction();
|
||||
tx.type = 3;
|
||||
tx.to = await chain.getAddress();
|
||||
tx.data = data;
|
||||
tx.nonce = await deployer.getNonce();
|
||||
tx.gasLimit = 1000000;
|
||||
tx.maxPriorityFeePerGas = (await ethers.provider.getFeeData()).maxPriorityFeePerGas;
|
||||
tx.maxFeePerGas = (await ethers.provider.getFeeData()).maxFeePerGas;
|
||||
tx.value = value;
|
||||
tx.chainId = (await ethers.provider.getNetwork()).chainId;
|
||||
tx.maxFeePerBlobGas = ethers.parseUnits("1", "gwei");
|
||||
tx.blobVersionedHashes = blobVersionedHashes;
|
||||
return tx;
|
||||
};
|
||||
|
||||
it("should revert when ErrorFoundMultipleBlob", async () => {
|
||||
const data = chain.interface.encodeFunctionData("commitBatch", [1, batchHeader0, ["0x"], "0x"]);
|
||||
const tx = await makeTransaction(data, 0n, [ZeroHash, ZeroHash]);
|
||||
const signature = await deployer.signMessage(tx.unsignedHash);
|
||||
tx.signature = Signature.from(signature);
|
||||
const r = await ethers.provider.broadcastTransaction(tx.serialized);
|
||||
await expect(r).to.revertedWithCustomError(chain, "ErrorFoundMultipleBlob");
|
||||
});
|
||||
|
||||
it("should revert when ErrorNoBlockInChunk", async () => {});
|
||||
|
||||
it("should revert when ErrorIncorrectChunkLength", async () => {});
|
||||
|
||||
it("should revert when ErrorLastL1MessageSkipped", async () => {});
|
||||
|
||||
it("should revert when ErrorNumTxsLessThanNumL1Msgs", async () => {});
|
||||
|
||||
it("should revert when ErrorTooManyTxsInOneChunk", async () => {});
|
||||
|
||||
it("should revert when ErrorIncorrectBitmapLength", async () => {});
|
||||
|
||||
it("should succeed", async () => {});
|
||||
*/
|
||||
});
|
||||
});
|
||||
92
contracts/integration-test/ScrollChain.spec.ts
Normal file
92
contracts/integration-test/ScrollChain.spec.ts
Normal file
@@ -0,0 +1,92 @@
|
||||
/* eslint-disable node/no-unpublished-import */
|
||||
/* eslint-disable node/no-missing-import */
|
||||
import { ZeroAddress, concat, getBytes } from "ethers";
|
||||
import { ethers } from "hardhat";
|
||||
|
||||
import { ScrollChain, L1MessageQueue } from "../typechain";
|
||||
|
||||
describe("ScrollChain", async () => {
|
||||
let queue: L1MessageQueue;
|
||||
let chain: ScrollChain;
|
||||
|
||||
beforeEach(async () => {
|
||||
const [deployer] = await ethers.getSigners();
|
||||
|
||||
const EmptyContract = await ethers.getContractFactory("EmptyContract", deployer);
|
||||
const empty = await EmptyContract.deploy();
|
||||
|
||||
const ProxyAdmin = await ethers.getContractFactory("ProxyAdmin", deployer);
|
||||
const admin = await ProxyAdmin.deploy();
|
||||
|
||||
const TransparentUpgradeableProxy = await ethers.getContractFactory("TransparentUpgradeableProxy", deployer);
|
||||
const queueProxy = await TransparentUpgradeableProxy.deploy(empty.getAddress(), admin.getAddress(), "0x");
|
||||
const chainProxy = await TransparentUpgradeableProxy.deploy(empty.getAddress(), admin.getAddress(), "0x");
|
||||
|
||||
const L1MessageQueue = await ethers.getContractFactory("L1MessageQueue", deployer);
|
||||
const queueImpl = await L1MessageQueue.deploy(ZeroAddress, chainProxy.getAddress(), deployer.address);
|
||||
await admin.upgrade(queueProxy.getAddress(), queueImpl.getAddress());
|
||||
|
||||
const ScrollChain = await ethers.getContractFactory("ScrollChain", deployer);
|
||||
const chainImpl = await ScrollChain.deploy(0, queueProxy.getAddress(), deployer.address);
|
||||
await admin.upgrade(chainProxy.getAddress(), chainImpl.getAddress());
|
||||
|
||||
queue = await ethers.getContractAt("L1MessageQueue", await queueProxy.getAddress(), deployer);
|
||||
chain = await ethers.getContractAt("ScrollChain", await chainProxy.getAddress(), deployer);
|
||||
|
||||
await chain.initialize(queue.getAddress(), ZeroAddress, 100);
|
||||
await chain.addSequencer(deployer.address);
|
||||
await queue.initialize(ZeroAddress, chain.getAddress(), ZeroAddress, ZeroAddress, 10000000);
|
||||
});
|
||||
|
||||
// @note skip this benchmark tests
|
||||
it.skip("should succeed", async () => {
|
||||
const batchHeader0 = new Uint8Array(89);
|
||||
batchHeader0[25] = 1;
|
||||
await chain.importGenesisBatch(batchHeader0, "0x0000000000000000000000000000000000000000000000000000000000000001");
|
||||
const parentBatchHash = await chain.committedBatches(0);
|
||||
console.log("genesis batch hash:", parentBatchHash);
|
||||
console.log(`ChunkPerBatch`, `BlockPerChunk`, `TxPerBlock`, `BytesPerTx`, `TotalBytes`, `EstimateGas`);
|
||||
for (let numChunks = 3; numChunks <= 6; ++numChunks) {
|
||||
for (let numBlocks = 1; numBlocks <= 5; ++numBlocks) {
|
||||
for (let numTx = 20; numTx <= Math.min(30, 100 / numBlocks); ++numTx) {
|
||||
for (let txLength = 800; txLength <= 1000; txLength += 100) {
|
||||
const txs: Array<Uint8Array> = [];
|
||||
for (let i = 0; i < numTx; i++) {
|
||||
const tx = new Uint8Array(4 + txLength);
|
||||
let offset = 3;
|
||||
for (let x = txLength; x > 0; x = Math.floor(x / 256)) {
|
||||
tx[offset] = x % 256;
|
||||
offset -= 1;
|
||||
}
|
||||
tx.fill(1, 4);
|
||||
txs.push(tx);
|
||||
}
|
||||
const chunk = new Uint8Array(1 + 60 * numBlocks);
|
||||
chunk[0] = numBlocks;
|
||||
for (let i = 0; i < numBlocks; i++) {
|
||||
chunk[1 + i * 60 + 57] = numTx;
|
||||
}
|
||||
const chunks: Array<Uint8Array> = [];
|
||||
for (let i = 0; i < numChunks; i++) {
|
||||
const txsInChunk: Array<Uint8Array> = [];
|
||||
for (let j = 0; j < numBlocks; j++) {
|
||||
txsInChunk.push(getBytes(concat(txs)));
|
||||
}
|
||||
chunks.push(getBytes(concat([chunk, concat(txsInChunk)])));
|
||||
}
|
||||
|
||||
const estimateGas = await chain.commitBatch.estimateGas(0, batchHeader0, chunks, "0x");
|
||||
console.log(
|
||||
`${numChunks}`,
|
||||
`${numBlocks}`,
|
||||
`${numTx}`,
|
||||
`${txLength}`,
|
||||
`${numChunks * numBlocks * numTx * (txLength + 1)}`,
|
||||
`${estimateGas.toString()}`
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
45
contracts/integration-test/ZkEvmVerifierV1.spec.ts
Normal file
45
contracts/integration-test/ZkEvmVerifierV1.spec.ts
Normal file
@@ -0,0 +1,45 @@
|
||||
/* eslint-disable node/no-unpublished-import */
|
||||
/* eslint-disable node/no-missing-import */
|
||||
import { HardhatEthersSigner } from "@nomicfoundation/hardhat-ethers/signers";
|
||||
import { expect } from "chai";
|
||||
import { hexlify } from "ethers";
|
||||
import fs from "fs";
|
||||
import { ethers } from "hardhat";
|
||||
|
||||
import { ZkEvmVerifierV1 } from "../typechain";
|
||||
|
||||
describe("ZkEvmVerifierV1", async () => {
|
||||
let deployer: HardhatEthersSigner;
|
||||
|
||||
let zkEvmVerifier: ZkEvmVerifierV1;
|
||||
|
||||
beforeEach(async () => {
|
||||
[deployer] = await ethers.getSigners();
|
||||
|
||||
const bytecode = hexlify(fs.readFileSync("./src/libraries/verifier/plonk-verifier/plonk_verifier_0.9.8.bin"));
|
||||
const tx = await deployer.sendTransaction({ data: bytecode });
|
||||
const receipt = await tx.wait();
|
||||
|
||||
const ZkEvmVerifierV1 = await ethers.getContractFactory("ZkEvmVerifierV1", deployer);
|
||||
zkEvmVerifier = await ZkEvmVerifierV1.deploy(receipt!.contractAddress!);
|
||||
});
|
||||
|
||||
it("should succeed", async () => {
|
||||
const proof = hexlify(fs.readFileSync("./integration-test/testdata/plonk_verifier_0.9.8_proof.data"));
|
||||
const instances = fs.readFileSync("./integration-test/testdata/plonk_verifier_0.9.8_pi.data");
|
||||
|
||||
const publicInputHash = new Uint8Array(32);
|
||||
for (let i = 0; i < 32; i++) {
|
||||
publicInputHash[i] = instances[i * 32 + 31];
|
||||
}
|
||||
|
||||
expect(hexlify(publicInputHash)).to.eq("0x31b430667bc9e8a8b7eda5e5c76f2250c64023f5f8e0689ac9f4e53f5362da66");
|
||||
|
||||
// verify ok
|
||||
await zkEvmVerifier.verify(proof, publicInputHash);
|
||||
console.log("Gas Usage:", (await zkEvmVerifier.verify.estimateGas(proof, publicInputHash)).toString());
|
||||
|
||||
// verify failed
|
||||
await expect(zkEvmVerifier.verify(proof, publicInputHash.reverse())).to.reverted;
|
||||
});
|
||||
});
|
||||
604
contracts/integration-test/ZkTrieVerifier.spec.ts
Normal file
604
contracts/integration-test/ZkTrieVerifier.spec.ts
Normal file
@@ -0,0 +1,604 @@
|
||||
/* eslint-disable node/no-unpublished-import */
|
||||
/* eslint-disable node/no-missing-import */
|
||||
import { expect } from "chai";
|
||||
import { ethers } from "hardhat";
|
||||
|
||||
import { generateABI, createCode } from "../scripts/poseidon";
|
||||
import { MockZkTrieVerifier } from "../typechain";
|
||||
import { concat } from "ethers";
|
||||
|
||||
const chars = "0123456789abcdef";
|
||||
|
||||
interface ITestConfig {
|
||||
block: number;
|
||||
desc: string;
|
||||
account: string;
|
||||
storage: string;
|
||||
expectedRoot: string;
|
||||
expectedValue: string;
|
||||
accountProof: string[];
|
||||
storageProof: string[];
|
||||
}
|
||||
|
||||
const testcases: Array<ITestConfig> = [
|
||||
{
|
||||
// curl -H "content-type: application/json" -X POST --data '{"id":0,"jsonrpc":"2.0","method":"eth_getProof","params":["0x5300000000000000000000000000000000000004", ["0x8391082587ea494a8beba02cc40273f27e5477a967cd400736ac46950da0b378"], "0x1111ad"]}' https://rpc.scroll.io
|
||||
block: 1118637,
|
||||
desc: "WETH.balance[0xa7994f02237aed2c116a702a8f5322a1fb325b31]",
|
||||
account: "0x5300000000000000000000000000000000000004",
|
||||
storage: "0x8391082587ea494a8beba02cc40273f27e5477a967cd400736ac46950da0b378",
|
||||
expectedRoot: "0x1334a21a74914182745c1f5142e70b487262096784ae7669186657462c01b103",
|
||||
expectedValue: "0x00000000000000000000000000000000000000000000000000006239b5a2c000",
|
||||
accountProof: [
|
||||
"0x0907d980105678a2007eb5683d850f36a9caafe6e7fd3279987d7a94a13a360d3a1478f9a4c1f8c755227ee3544929bb0d7cfa2d999a48493d048ff0250bb002ab",
|
||||
"0x092b59a024f142555555c767842c4fcc3996686c57699791fcb10013f69ffd9b2507360087cb303767fd43f2650960621246a8d205d086e03d9c1626e4aaa5b143",
|
||||
"0x091f876342916ac1d5a14ef40cfc5644452170b16d1b045877f303cd52322ba1e00ba09f36443c2a63fbd7ff8feeb2c84e99fde6db08fd8e4c67ad061c482ff276",
|
||||
"0x09277b3069a4b944a45df222366aae727ec64efaf0a8ecb000645d0eea3a3fa93609b925158cc04f610f8c616369094683ca7a86239f49e97852aa286d148a3913",
|
||||
"0x092fb789200a7324067934da8be91c48f86c4e6f35fed6d1ce8ae4d7051f480bc0074019222c788b139b6919dfbc9d0b51f274e0ed3ea03553b8db30392ac05ce4",
|
||||
"0x092f79da8f9f2c3a3a3813580ff18d4619b95f54026b2f16ccbcca684d5e25e1f52912fa319d9a7ba537a52cc6571844b4d1aa99b8a78cea6f686a6279ade5dcae",
|
||||
"0x09249d249bcf92a369bd7715ec63a4b29d706a5dbb304efd678a2e5d7982e7fa9b202e3225c1031d83ab62d78516a4cbdbf2b22842c57182e7cb0dbb4303ac38c5",
|
||||
"0x0904837ebb85ceccab225d4d826fe57edca4b00862199b91082f65dfffa7669b90039c710273b02e60c2e74eb8b243721e852e0e56fa51668b6362fd920f817cb7",
|
||||
"0x090a36f6aabc3768a05dd8f93667a0eb2e5b63d94b5ce27132fb38d13c56d49cb4249c2013daee90184ae285226271f150f6a8f74f2c85dbd0721c5f583e620b10",
|
||||
"0x091b82f139a06af573e871fdd5f5ac18f17c568ffe1c9e271505b371ad7f0603e716b187804a49d2456a0baa7c2317c14d9aa7e58ad64df38bc6c1c7b86b072333",
|
||||
"0x0929668e59dfc2e2aef10194f5d287d8396e1a897d68f106bdb12b9541c0bab71d2bf910dea11e3209b3feff88d630af46006e402e935bc84c559694d88c117733",
|
||||
"0x0914231c92f09f56628c10603dc2d2120d9d11b27fa23753a14171127c3a1ee3dd0d6b9cbd11d031fe6e1b650023edc58aa580fa4f4aa1b30bf82e0e4c7a308bb9",
|
||||
"0x0914c1dd24c520d96aac93b7ef3062526067f1b15a080c482abf449d3c2cde781b195eb63b5e328572090319310914d81b2ca8350b6e15dc9d13e878f8c28c9d52",
|
||||
"0x0927cb93e3d9c144a5a3653c5cf2ed5940d64f461dd588cd192516ae7d855e9408166e85986d4c9836cd6cd822174ba9db9c7a043d73e86b5b2cfc0a2e082894c3",
|
||||
"0x090858bf8a0119626fe9339bd92116a070ba1a66423b0f7d3f4666b6851fdea01400f7f51eb22df168c41162d7f18f9d97155d87da523b05a1dde54e7a30a98c31",
|
||||
"0x0902776c1f5f93a95baea2e209ddb4a5e49dd1112a7f7d755a45addffe4a233dad0d8cc62b957d9b254fdc8199c720fcf8d5c65d14899911e991b4530710aca75e",
|
||||
"0x091d7fde5c78c88bbf6082a20a185cde96a203ea0d29c829c1ab9322fc3ca0ae3100ef7cba868cac216d365a0232ad6227ab1ef3290166bc6c19b719b79dbc17fc",
|
||||
"0x091690160269c53c6b74337a00d02cb40a88ea5eba06e1942088b619baee83279e12d96d62dda9c4b5897d58fea40b5825d87a5526dec37361ec7c93a3256ea76d",
|
||||
"0x091bccb091cde3f8ca7cfda1df379c9bfa412908c41037ae4ec0a20ce984e2c9a51d02c109d2e6e25dc60f10b1bc3b3f97ca1ce1aa025ce4f3146de3979403b99e",
|
||||
"0x0927083540af95e57acba69671a4a596f721432549b8760941f4251e0dd7a013a917cee0f60d333cf88e40ae8710fb1fd6e3920346a376b3ba6686a4b2020a043e",
|
||||
"0x082170b57b8f05f6990eec62e74cdb303741f6c464a85d68582c19c51e53f490000a5029a62ddc14c9c07c549db300bd308b6367454966c94b8526f4ceed5693b2",
|
||||
"0x0827a0b16ef333dcfe00610d19dc468b9e856f544c9b5e9b046357e0a38aedaeb90000000000000000000000000000000000000000000000000000000000000000",
|
||||
"0x06126f891e8753e67c5cbfa2a67e9d71942eab3a88cde86e97a4af94ea0dde497821fb69ccdb00e6eaeaf7fc1e73630f39f846970b72ac801e396da0033fb0c247",
|
||||
"0x0420e9fb498ff9c35246d527da24aa1710d2cc9b055ecf9a95a8a2a11d3d836cdf050800000000000000000000000000000000000000000000000016ef00000000000000000000000000000000000000000000000000000000000000600058d1a5ce14104d0dedcaecaab39b6e22c2608e40af67a71908e6e97bbf4a43c59c4537140c25a9e8c4073351c26b9831c1e5af153b9be4713a4af9edfdf32b58077b735e120f14136a7980da529d9e8d3a71433fc9dc5aa8c01e3a4eb60cb3a4f9cf9ca5c8e0be205300000000000000000000000000000000000004000000000000000000000000",
|
||||
"0x5448495320495320534f4d45204d4147494320425954455320464f5220534d54206d3172525867503278704449",
|
||||
],
|
||||
storageProof: [
|
||||
"0x09240ea2601c34d792a0a5a8a84d8e501cfdfdf2c10ef13ea560acac58661882dd1b3644d1d4f3e32fc78498a7ebeffac8c6a494ac6f36923ef1be476444c0d564",
|
||||
"0x0912af3ac8f8ea443e6d89d071fccaa2b3c8462220c1c2921234f613b41594f08f2a170e61f5f436b536c155b438044cf0d0f24b94b4c034ad22b3eae824998243",
|
||||
"0x0916011d547d7a54929c3515078f4f672c6b390ccdd4119f0776376910bc5a38da1a059ed9c504fadcc9f77e8a402175743bee1f5be27b7002b0f6c5b51070452c",
|
||||
"0x09017285edc268d979eb410b46627e541afda16cdb3577ce04c15dc14cc6609c60143f0c01e71e99b2efbe3d8e62a2c812889aa9fd88dd4b0ed8eadcf1ec9b096a",
|
||||
"0x0922901e65200b007ad8e1b972e90403b336e459e0cf9b9d68732da345b1b0f6872c9e3f3edacbd857b26d0a66a80aa56c6ebaa9849e9ea5a2b17fd59cabe138e4",
|
||||
"0x091b77a00164a72880eec6c18fc043fa99f922e20bbee156e1ebfd3a358bee6bbb24d97cfaa234befe197a567476cade91b7d97a1017b8d5286dae4dddadffe1cd",
|
||||
"0x09216f1c4d67a9a428885bb8d978ad369d2d69d4dcc1692c3a0c3ea05da7d6f0ac2d6dda722e76eb513c67718e7be0478851758be5547322473a53b5b2b67faf95",
|
||||
"0x091f56c6f18ceb7077125df1ed17a42a85956090594125c1b182161de20f8af6aa2e36977412f9ea2ad2c0951153969eca8408317558ff1b6b4ad731726235f606",
|
||||
"0x092ca197dda6c519d80296f4fcda2933df9608ec684ad000133259024041d070812d29b058a998cf7ffc647b2739041725d77889f58953799c6aba6d9e5b981fc8",
|
||||
"0x091c25a87d321a09ad2a149d1a7eaa77727c7feffb4c39caf44f8edd4377f7bd0c16d1091494d3c90d301c1cb4596692798e78e4cc3d53c3a08e2641de43f9da18",
|
||||
"0x092166058c98245eb85b08da1c569df11f86b00cc44212a9a8ee0d60556d05a8030942c68b535651e11af38264ecc89e5f79b66c3d9ce87233ad65d4894a3d1c3d",
|
||||
"0x0908c3b13b7400630170baec7448c7ec99fa9100cad373e189e42aca121e2c8f450f9e40d92d98bb0b1286a18581591fddfa8637fc941c1630237293d69e5cb98f",
|
||||
"0x091362d251bbd8b255d63cd91bcfc257b8fb3ea608ce652784e3db11b22ca86c0122a0068fa1f1d54f313bed9fd9209212af3f366e4ff28092bf42c4abebffe10a",
|
||||
"0x081d67961bb431a9da78eb976fabd641e20fbf4b7e32eb3faac7dfb5abb50f1faf1438d77000c1cf96c9d61347e1351eb0200260ebe523e69f6e9f334ec86e6b58",
|
||||
"0x0819324d2488778bdef23319a6832001ee85f578cc920670c81f3645f898a46ec62e00385c4416ca4ccbab237b13396e5e25e5da12101021c6a6f9ecfe7c7fed19",
|
||||
"0x041421380c36ea8ef65a9bdb0202b06d1e03f52857cdfea3795463653eaa3dd7d80101000000000000000000000000000000000000000000000000000000006239b5a2c000208391082587ea494a8beba02cc40273f27e5477a967cd400736ac46950da0b378",
|
||||
"0x5448495320495320534f4d45204d4147494320425954455320464f5220534d54206d3172525867503278704449",
|
||||
],
|
||||
},
|
||||
{
|
||||
// curl -H "content-type: application/json" -X POST --data '{"id":0,"jsonrpc":"2.0","method":"eth_getProof","params":["0x5300000000000000000000000000000000000004", ["0x0000000000000000000000000000000000000000000000000000000000000002"], "0x1111ad"]}' https://rpc.scroll.io
|
||||
block: 1118637,
|
||||
desc: "WETH.totalSupply",
|
||||
account: "0x5300000000000000000000000000000000000004",
|
||||
storage: "0x0000000000000000000000000000000000000000000000000000000000000002",
|
||||
expectedRoot: "0x1334a21a74914182745c1f5142e70b487262096784ae7669186657462c01b103",
|
||||
expectedValue: "0x0000000000000000000000000000000000000000000000600058d1a5ce14104d",
|
||||
accountProof: [
|
||||
"0x0907d980105678a2007eb5683d850f36a9caafe6e7fd3279987d7a94a13a360d3a1478f9a4c1f8c755227ee3544929bb0d7cfa2d999a48493d048ff0250bb002ab",
|
||||
"0x092b59a024f142555555c767842c4fcc3996686c57699791fcb10013f69ffd9b2507360087cb303767fd43f2650960621246a8d205d086e03d9c1626e4aaa5b143",
|
||||
"0x091f876342916ac1d5a14ef40cfc5644452170b16d1b045877f303cd52322ba1e00ba09f36443c2a63fbd7ff8feeb2c84e99fde6db08fd8e4c67ad061c482ff276",
|
||||
"0x09277b3069a4b944a45df222366aae727ec64efaf0a8ecb000645d0eea3a3fa93609b925158cc04f610f8c616369094683ca7a86239f49e97852aa286d148a3913",
|
||||
"0x092fb789200a7324067934da8be91c48f86c4e6f35fed6d1ce8ae4d7051f480bc0074019222c788b139b6919dfbc9d0b51f274e0ed3ea03553b8db30392ac05ce4",
|
||||
"0x092f79da8f9f2c3a3a3813580ff18d4619b95f54026b2f16ccbcca684d5e25e1f52912fa319d9a7ba537a52cc6571844b4d1aa99b8a78cea6f686a6279ade5dcae",
|
||||
"0x09249d249bcf92a369bd7715ec63a4b29d706a5dbb304efd678a2e5d7982e7fa9b202e3225c1031d83ab62d78516a4cbdbf2b22842c57182e7cb0dbb4303ac38c5",
|
||||
"0x0904837ebb85ceccab225d4d826fe57edca4b00862199b91082f65dfffa7669b90039c710273b02e60c2e74eb8b243721e852e0e56fa51668b6362fd920f817cb7",
|
||||
"0x090a36f6aabc3768a05dd8f93667a0eb2e5b63d94b5ce27132fb38d13c56d49cb4249c2013daee90184ae285226271f150f6a8f74f2c85dbd0721c5f583e620b10",
|
||||
"0x091b82f139a06af573e871fdd5f5ac18f17c568ffe1c9e271505b371ad7f0603e716b187804a49d2456a0baa7c2317c14d9aa7e58ad64df38bc6c1c7b86b072333",
|
||||
"0x0929668e59dfc2e2aef10194f5d287d8396e1a897d68f106bdb12b9541c0bab71d2bf910dea11e3209b3feff88d630af46006e402e935bc84c559694d88c117733",
|
||||
"0x0914231c92f09f56628c10603dc2d2120d9d11b27fa23753a14171127c3a1ee3dd0d6b9cbd11d031fe6e1b650023edc58aa580fa4f4aa1b30bf82e0e4c7a308bb9",
|
||||
"0x0914c1dd24c520d96aac93b7ef3062526067f1b15a080c482abf449d3c2cde781b195eb63b5e328572090319310914d81b2ca8350b6e15dc9d13e878f8c28c9d52",
|
||||
"0x0927cb93e3d9c144a5a3653c5cf2ed5940d64f461dd588cd192516ae7d855e9408166e85986d4c9836cd6cd822174ba9db9c7a043d73e86b5b2cfc0a2e082894c3",
|
||||
"0x090858bf8a0119626fe9339bd92116a070ba1a66423b0f7d3f4666b6851fdea01400f7f51eb22df168c41162d7f18f9d97155d87da523b05a1dde54e7a30a98c31",
|
||||
"0x0902776c1f5f93a95baea2e209ddb4a5e49dd1112a7f7d755a45addffe4a233dad0d8cc62b957d9b254fdc8199c720fcf8d5c65d14899911e991b4530710aca75e",
|
||||
"0x091d7fde5c78c88bbf6082a20a185cde96a203ea0d29c829c1ab9322fc3ca0ae3100ef7cba868cac216d365a0232ad6227ab1ef3290166bc6c19b719b79dbc17fc",
|
||||
"0x091690160269c53c6b74337a00d02cb40a88ea5eba06e1942088b619baee83279e12d96d62dda9c4b5897d58fea40b5825d87a5526dec37361ec7c93a3256ea76d",
|
||||
"0x091bccb091cde3f8ca7cfda1df379c9bfa412908c41037ae4ec0a20ce984e2c9a51d02c109d2e6e25dc60f10b1bc3b3f97ca1ce1aa025ce4f3146de3979403b99e",
|
||||
"0x0927083540af95e57acba69671a4a596f721432549b8760941f4251e0dd7a013a917cee0f60d333cf88e40ae8710fb1fd6e3920346a376b3ba6686a4b2020a043e",
|
||||
"0x082170b57b8f05f6990eec62e74cdb303741f6c464a85d68582c19c51e53f490000a5029a62ddc14c9c07c549db300bd308b6367454966c94b8526f4ceed5693b2",
|
||||
"0x0827a0b16ef333dcfe00610d19dc468b9e856f544c9b5e9b046357e0a38aedaeb90000000000000000000000000000000000000000000000000000000000000000",
|
||||
"0x06126f891e8753e67c5cbfa2a67e9d71942eab3a88cde86e97a4af94ea0dde497821fb69ccdb00e6eaeaf7fc1e73630f39f846970b72ac801e396da0033fb0c247",
|
||||
"0x0420e9fb498ff9c35246d527da24aa1710d2cc9b055ecf9a95a8a2a11d3d836cdf050800000000000000000000000000000000000000000000000016ef00000000000000000000000000000000000000000000000000000000000000600058d1a5ce14104d0dedcaecaab39b6e22c2608e40af67a71908e6e97bbf4a43c59c4537140c25a9e8c4073351c26b9831c1e5af153b9be4713a4af9edfdf32b58077b735e120f14136a7980da529d9e8d3a71433fc9dc5aa8c01e3a4eb60cb3a4f9cf9ca5c8e0be205300000000000000000000000000000000000004000000000000000000000000",
|
||||
"0x5448495320495320534f4d45204d4147494320425954455320464f5220534d54206d3172525867503278704449",
|
||||
],
|
||||
storageProof: [
|
||||
"0x09240ea2601c34d792a0a5a8a84d8e501cfdfdf2c10ef13ea560acac58661882dd1b3644d1d4f3e32fc78498a7ebeffac8c6a494ac6f36923ef1be476444c0d564",
|
||||
"0x0912af3ac8f8ea443e6d89d071fccaa2b3c8462220c1c2921234f613b41594f08f2a170e61f5f436b536c155b438044cf0d0f24b94b4c034ad22b3eae824998243",
|
||||
"0x0916011d547d7a54929c3515078f4f672c6b390ccdd4119f0776376910bc5a38da1a059ed9c504fadcc9f77e8a402175743bee1f5be27b7002b0f6c5b51070452c",
|
||||
"0x092293af71b7b9315c32d08f06e291b85e3b3dbba786dd31952369f666281aa21125ab35feae70aaca9349f6af48f7dcf2dee0324e4eae03e929963e7728b633a3",
|
||||
"0x090607033a4b976c1e4683298d66b88a95ed45033ff43dea0670d84a8c42d35bf12562869385c0e70f561f18be4b78e7276b837f140a45ab12ffef1ba4ad5faecb",
|
||||
"0x090abc5f713c2f58583114bb5081d00cbd01789d8efbd95e471b151c71c475142f0f52ad30f8a63288eb9dd12aca2a670de08c03f8384f55d730c943e1c472625b",
|
||||
"0x0905156e8704d6195f6ae562aed2072f4e32422c6dfd4840ca354b9c4d2de5ce760fca52b1e0689ad374bae9fbea262a929f919695149a083fe6bacb806dc02fca",
|
||||
"0x0917078d4c193a3fdbfe8ce3a235a0e1df89e626b5e91636097e299883fc2447892ad46eefbb27909544fe02c05e29760315749f6ce21c17c52158f5f5616c2dad",
|
||||
"0x0917d02e5da8bdb969149c9327b247a6aaa479bcda4a03665da5103c10e616d2f40ccabdacdd25b34235d26e50e7af5d8d312a2cafdcadd41cc589a71a322f254c",
|
||||
"0x090c62f5c476c1def8ed8a8c25ae54581690b39dfab4b0f3f78b93df96f626714328ea922a76a058087563bb5370664e9a1cebe3062f2d904bf5e3a018219d6563",
|
||||
"0x091e481971f770e587b1f62f1da9ac4687abc5b2a23097fc38332e15ab957ca0ab0ec0a95c15313887e0d2f166c100deaf17f2ce50767680e6e5b2e3068801c0cd",
|
||||
"0x0911799e186f1bd299dfa08c07404b9d28e2b179fb6ad523f1846872537b6db85f198b573ac1397048258de38b391fcc5e0c86a0f81f4ca607785fb37041ab8b4d",
|
||||
"0x092053a028cf3bfcdabcb58985efc39f078cb0bcae4439528a0b6fe4b24bbdbd2c019a04a54e9e96077f3c2c39c1602a83387018b6357ea4c28e96764865d1c8f3",
|
||||
"0x07303fad3e4628ccae4de1adb41996c9f38b22445b6525ff163b4c68cbde275b1a06111cae9b4d17b730d94f589e20c6ae2cb59bf0b40ad05bf58703ee6d46eac4",
|
||||
"0x0606bc3fca1f1b3c877aa01a765c18db8b0d7f0bc50bd99f21223055bf1595c84d04fdc0fd416d8402fde743d908d032a20af6f2e65cdc6cc289f72c04f1c2476f",
|
||||
"0x04020953ad52de135367a1ba2629636216ed5174cce5629d11b5d97fe733f07dcc010100000000000000000000000000000000000000000000000000600058d1a5ce14104d200000000000000000000000000000000000000000000000000000000000000002",
|
||||
"0x5448495320495320534f4d45204d4147494320425954455320464f5220534d54206d3172525867503278704449",
|
||||
],
|
||||
},
|
||||
{
|
||||
// curl -H "content-type: application/json" -X POST --data '{"id":0,"jsonrpc":"2.0","method":"eth_getProof","params":["0x5300000000000000000000000000000000000004", ["0x0000000000000000000000000000000000000000000000000000000000002222"], "0x1111ad"]}' https://rpc.scroll.io
|
||||
block: 1118637,
|
||||
desc: "random empty storage in WETH",
|
||||
account: "0x5300000000000000000000000000000000000004",
|
||||
storage: "0x0000000000000000000000000000000000000000000000000000000000002222",
|
||||
expectedRoot: "0x1334a21a74914182745c1f5142e70b487262096784ae7669186657462c01b103",
|
||||
expectedValue: "0x0000000000000000000000000000000000000000000000000000000000000000",
|
||||
accountProof: [
|
||||
"0x0907d980105678a2007eb5683d850f36a9caafe6e7fd3279987d7a94a13a360d3a1478f9a4c1f8c755227ee3544929bb0d7cfa2d999a48493d048ff0250bb002ab",
|
||||
"0x092b59a024f142555555c767842c4fcc3996686c57699791fcb10013f69ffd9b2507360087cb303767fd43f2650960621246a8d205d086e03d9c1626e4aaa5b143",
|
||||
"0x091f876342916ac1d5a14ef40cfc5644452170b16d1b045877f303cd52322ba1e00ba09f36443c2a63fbd7ff8feeb2c84e99fde6db08fd8e4c67ad061c482ff276",
|
||||
"0x09277b3069a4b944a45df222366aae727ec64efaf0a8ecb000645d0eea3a3fa93609b925158cc04f610f8c616369094683ca7a86239f49e97852aa286d148a3913",
|
||||
"0x092fb789200a7324067934da8be91c48f86c4e6f35fed6d1ce8ae4d7051f480bc0074019222c788b139b6919dfbc9d0b51f274e0ed3ea03553b8db30392ac05ce4",
|
||||
"0x092f79da8f9f2c3a3a3813580ff18d4619b95f54026b2f16ccbcca684d5e25e1f52912fa319d9a7ba537a52cc6571844b4d1aa99b8a78cea6f686a6279ade5dcae",
|
||||
"0x09249d249bcf92a369bd7715ec63a4b29d706a5dbb304efd678a2e5d7982e7fa9b202e3225c1031d83ab62d78516a4cbdbf2b22842c57182e7cb0dbb4303ac38c5",
|
||||
"0x0904837ebb85ceccab225d4d826fe57edca4b00862199b91082f65dfffa7669b90039c710273b02e60c2e74eb8b243721e852e0e56fa51668b6362fd920f817cb7",
|
||||
"0x090a36f6aabc3768a05dd8f93667a0eb2e5b63d94b5ce27132fb38d13c56d49cb4249c2013daee90184ae285226271f150f6a8f74f2c85dbd0721c5f583e620b10",
|
||||
"0x091b82f139a06af573e871fdd5f5ac18f17c568ffe1c9e271505b371ad7f0603e716b187804a49d2456a0baa7c2317c14d9aa7e58ad64df38bc6c1c7b86b072333",
|
||||
"0x0929668e59dfc2e2aef10194f5d287d8396e1a897d68f106bdb12b9541c0bab71d2bf910dea11e3209b3feff88d630af46006e402e935bc84c559694d88c117733",
|
||||
"0x0914231c92f09f56628c10603dc2d2120d9d11b27fa23753a14171127c3a1ee3dd0d6b9cbd11d031fe6e1b650023edc58aa580fa4f4aa1b30bf82e0e4c7a308bb9",
|
||||
"0x0914c1dd24c520d96aac93b7ef3062526067f1b15a080c482abf449d3c2cde781b195eb63b5e328572090319310914d81b2ca8350b6e15dc9d13e878f8c28c9d52",
|
||||
"0x0927cb93e3d9c144a5a3653c5cf2ed5940d64f461dd588cd192516ae7d855e9408166e85986d4c9836cd6cd822174ba9db9c7a043d73e86b5b2cfc0a2e082894c3",
|
||||
"0x090858bf8a0119626fe9339bd92116a070ba1a66423b0f7d3f4666b6851fdea01400f7f51eb22df168c41162d7f18f9d97155d87da523b05a1dde54e7a30a98c31",
|
||||
"0x0902776c1f5f93a95baea2e209ddb4a5e49dd1112a7f7d755a45addffe4a233dad0d8cc62b957d9b254fdc8199c720fcf8d5c65d14899911e991b4530710aca75e",
|
||||
"0x091d7fde5c78c88bbf6082a20a185cde96a203ea0d29c829c1ab9322fc3ca0ae3100ef7cba868cac216d365a0232ad6227ab1ef3290166bc6c19b719b79dbc17fc",
|
||||
"0x091690160269c53c6b74337a00d02cb40a88ea5eba06e1942088b619baee83279e12d96d62dda9c4b5897d58fea40b5825d87a5526dec37361ec7c93a3256ea76d",
|
||||
"0x091bccb091cde3f8ca7cfda1df379c9bfa412908c41037ae4ec0a20ce984e2c9a51d02c109d2e6e25dc60f10b1bc3b3f97ca1ce1aa025ce4f3146de3979403b99e",
|
||||
"0x0927083540af95e57acba69671a4a596f721432549b8760941f4251e0dd7a013a917cee0f60d333cf88e40ae8710fb1fd6e3920346a376b3ba6686a4b2020a043e",
|
||||
"0x082170b57b8f05f6990eec62e74cdb303741f6c464a85d68582c19c51e53f490000a5029a62ddc14c9c07c549db300bd308b6367454966c94b8526f4ceed5693b2",
|
||||
"0x0827a0b16ef333dcfe00610d19dc468b9e856f544c9b5e9b046357e0a38aedaeb90000000000000000000000000000000000000000000000000000000000000000",
|
||||
"0x06126f891e8753e67c5cbfa2a67e9d71942eab3a88cde86e97a4af94ea0dde497821fb69ccdb00e6eaeaf7fc1e73630f39f846970b72ac801e396da0033fb0c247",
|
||||
"0x0420e9fb498ff9c35246d527da24aa1710d2cc9b055ecf9a95a8a2a11d3d836cdf050800000000000000000000000000000000000000000000000016ef00000000000000000000000000000000000000000000000000000000000000600058d1a5ce14104d0dedcaecaab39b6e22c2608e40af67a71908e6e97bbf4a43c59c4537140c25a9e8c4073351c26b9831c1e5af153b9be4713a4af9edfdf32b58077b735e120f14136a7980da529d9e8d3a71433fc9dc5aa8c01e3a4eb60cb3a4f9cf9ca5c8e0be205300000000000000000000000000000000000004000000000000000000000000",
|
||||
"0x5448495320495320534f4d45204d4147494320425954455320464f5220534d54206d3172525867503278704449",
|
||||
],
|
||||
storageProof: [
|
||||
"0x09240ea2601c34d792a0a5a8a84d8e501cfdfdf2c10ef13ea560acac58661882dd1b3644d1d4f3e32fc78498a7ebeffac8c6a494ac6f36923ef1be476444c0d564",
|
||||
"0x092fa31ba6c9b8f291512a582ab446daf7aa3787e68f9628d08ec0db329027d9001af83d361b481ed4b943d988cb0191c350b8efc85cfceba74afb60783488d441",
|
||||
"0x092c2ec2d967208cb5088400d826b52113d606435be011b6c9f721f293fb12242515681c9016eb1c222dcdbeeeb9fd3a504caba892f4c1832741a2b17a7305598a",
|
||||
"0x090c7fe825c29bf5df80c7101ff8a372ba4f7b2ac37c16a3bbda38cc1e38e682460499b7e5d21d3784f496e747140f465eb1a39a019d2be8baf13a5e39f359a4ed",
|
||||
"0x092bb11ebbc7cd1e565b86498aecab16842ab3fa852c7943cfbc49ee4bc593b2f308a78e1bc555e07d36d5c812af57c18f67199197a52ff74bc4e32ca6b7fadf32",
|
||||
"0x092fd1e042080801034c6d6c79d462016c74b97dfbb1272cf606e638911a08f21c02434541eeed6d66002c69042f9354211e40518316a2d98cc0da0f19fb1ea013",
|
||||
"0x09024bd491ec707bc3e8bea6b2754f37b1e85903061aefabd945537eef2f4d38b4136b925b004d29603c5e6195e073322d27f0c6ea3fa1ea5c5b248ff60dda594c",
|
||||
"0x09269e1f468bd9bbde77a13562645a80a77d26d801781ca95d385bd59ee1b0890b03694bf9043190620265bf0bc3baa4d82cc82302ae0bbf33cfa48b0ec9d5ab25",
|
||||
"0x0924d8bf62b2a725684847208dc021d5aee9f3c8f14c14786bc9f93232dfd3e068120bb7d022bbb159b4b84bb9e36cd2fcd89d761e265c1b88c8bdb9745a51cb22",
|
||||
"0x092680f932920fd86de0b417cfdbeb2836a470213097ed5abb1a2b4deba8437f6825fd0ec614b97e6cfa4d50b08ad1e0fd8a5cd72db3a468128d1045d6a54e5e6e",
|
||||
"0x0909e630914cee4db538057a0218a72288b88b2603aee0f805254b865a03de87c92ce46c1aa77ee8c42bb60c4175826f4dbb89d6282c01ff3de654c961599e66c3",
|
||||
"0x091a17302d53ad1b7a4472d111fd27b35720d49ce27259b5e42f46339dddf235e82b973c29f44cf69b589f724d7d2fa54bf38b37bde3fc66c0d965a8c10df80caa",
|
||||
"0x0916572156ae22ae2b0bc84ff41d16668be7163da26db2b13b86c218e0516c97a4131b584b7192464dde26060f66f678b03c8db8f64f1cd7a1f98a22a90cce5850",
|
||||
"0x092c6ee2ca598c123445bbbd403ca3ab8a95ce2443f941ebdcf7bb035e2a3e38e22e8d5b222a1019b126f0ecf277c7fed881413e879cd4dc5df66634b6e9fb688d",
|
||||
"0x0700000000000000000000000000000000000000000000000000000000000000002822301c27c0bd26a8f361545a09d509a2feed981accf780de30244f0300321d",
|
||||
"0x05",
|
||||
"0x5448495320495320534f4d45204d4147494320425954455320464f5220534d54206d3172525867503278704449",
|
||||
],
|
||||
},
|
||||
{
|
||||
// curl -H "content-type: application/json" -X POST --data '{"id":0,"jsonrpc":"2.0","method":"eth_getProof","params":["0x5300000000000000000000000000000000000044", ["0x0000000000000000000000000000000000000000000000000000000000000000"], "0x1111ad"]}' https://rpc.scroll.io
|
||||
block: 1154766,
|
||||
desc: "random empty storage in some contract",
|
||||
account: "0x226D078166C78e00ce5E97d8f18CDc408512bb0F",
|
||||
storage: "0x0000000000000000000000000000000000000000000000000000000000000001",
|
||||
expectedRoot: "0x1e5cf13822e052084c315e944ca84f1ef375583e85e1508055123a182e415fab",
|
||||
expectedValue: "0x0000000000000000000000000000000000000000000000000000000000000000",
|
||||
accountProof: [
|
||||
"0x09062c633f6d7c7a157025fef8ab1c313a7caadda3a64b23664741f9de3b0478fe27571cf9b45d5f4deddf5f0b5354a613998fdcbe9249bb7cde92fd45513c5a99",
|
||||
"0x0920d6877efe14060018278754e91682430401880981fec1cd1b63610bed0c1e332a63aca7a8898b01983e2c53a7257310318da444fd6c8b705e488943205301a8",
|
||||
"0x090f6dadd53bbc0f5fa4fa03961aff0bf252ae335e11c1836253b6bc214d66759010b10d80991219a66f1eb7e07169b4cec4fa74b04edbdc08c3f238dfdf1d2fac",
|
||||
"0x0921ea10af71b5f3587ff9d42178a151427cbcde37b8bee6575463bf6b83110cca0520d5f97b44e7015453ec16d9c28980d2cec3df5c860eb8a455f49dcfa339be",
|
||||
"0x092d19cf96a7c129aac6f72f780703a9ef3233fc5124d592baee751a3550dd692a02c962b87efbba5aeea4856c3df29c1ea540e1fbc7a74529d5dc793fe8e490d8",
|
||||
"0x0922e20a087e600560007189ccc1a159e4fffeb1876a6de3772b7f450793a1c6620ada74791f3ecd25a650701578ef9661c64e75d836c681503e96228974a53903",
|
||||
"0x0924839671b636ebb56cb9a2860a3edf2a2875774e84dfcf8546135189f808d724260ac8be541ff088a9a1d2468c4c6e2faa793009be553a3cbca003649ee511db",
|
||||
"0x090cd8140d844f62e44ffe820c1b2b0d4aa8f0518c15ff61759d93d805cb017cb628d5b46a4c4ec0a10eb00155808890925050f7af2279b512c25005d963283262",
|
||||
"0x0913c0698673b0be011485eba05c61ac41bf14fc960ce5dbb6f5a021809eabbb0e18adaf85a3724e1a644268b845f5014b39e574928b9a01bfcd25d6fe1cf03e8f",
|
||||
"0x0912c2e7da4b091c52e0012e5c13baf07d9d9daed10a558262d2e700a7c823300e054dce1849561bbeede4368a3be06f5a2bae06bdb1bc2bcefdba84634fd1991c",
|
||||
"0x090b3e9c665497a0f9c1d3f1448c6d9144a287eb0accf86fea6f443f51986df7130392814f078a19643081787478ec3a010e2757a574877a194136c529813cf7ae",
|
||||
"0x09249a0e273abe79a0b99a55516e19213191b7f77ef34f8815edc4e1ede8711f7920615adbac1983d844c8a6ed50922562432c13d030069d8b3e92611b4fe39531",
|
||||
"0x09199575893e55d92fafb3b067130b9b6b5a46e7f6fb2d0af412d12591632dfe961adffb9dd1e7490095aac94bc1fcaeb591f4ba907fe2b882c9f6d8f7ab3a1809",
|
||||
"0x09259308e9398f029ebbe31a4b353f474622b4c96995b7365c3b13c392fcc3e7001be60286a497a3886aa9cff3ad6a5dc71504078eb7a44c43530b7b33eef4743f",
|
||||
"0x090709a21aaf18a1eaea3b925ab36f47a82095aa3e9ddbc4f01463005c4b64f6af0554d854637fcbfd9b1a4c2474de343950569e4f855d66f2ee14fcfb19ee17f5",
|
||||
"0x092d7319be75a70b8ea5f0acc6ab4a96971ec546f72b18bdc3e905ad6ea8a288f70626499aee389335559b1dd3cc8b6711f9fde0c517236190cba24fa87993877a",
|
||||
"0x09081b165a51e3081fc2e3e27d6fdb81134b65284851798de62899db3065a8c1fc040c8dce92508a510c2c34fc2949910dd41247c9f247cd216c03d9bb9d2881b4",
|
||||
"0x092a27c5be32e1ab6e85d1ac094bc1509d92285f45c63fca6dba9b14d485a94af326d44c1ff85666a4790182ddd7e51cbbe06af81d62082e6d79faec29a4501369",
|
||||
"0x091a46df6ffd6b439ffcd1b57e9548f5c4db26ade9e984efc8a91a01ab22134d3c1617b504ac2015793c5dac16d379b5ca6cb70c14243491bb68535ee686a3a553",
|
||||
"0x08180e90f9f9a4fd8065a5849539793bd9e9340b69770eff1716a733241e454c341641f913f1c32e2c652b876f902e5c2c8d51c482411ec44dae969bdc50264c42",
|
||||
"0x06273c162ecb059cd86ec0a01033dd61c39f59ee0a13eb41a28c0b2d49a45f6f94081be344adea9f54587a832b9efef6fc9ec010d86ec5fb2b53b5ff8dbabc4924",
|
||||
"0x040b792f5b15327fc37390341af919c991641846d380397e4c73cbb1298921a546050800000000000000000000000000000000000000000000000000fb0000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000be74cc05824041ef286fd08582cdfacec7784a35af72f937acf64ade5073da10889249d61c3649abf8749bf686a73f708d67726fada3e071b03d4541da9156b20226d078166c78e00ce5e97d8f18cdc408512bb0f000000000000000000000000",
|
||||
"0x5448495320495320534f4d45204d4147494320425954455320464f5220534d54206d3172525867503278704449",
|
||||
],
|
||||
storageProof: [
|
||||
"0x05",
|
||||
"0x5448495320495320534f4d45204d4147494320425954455320464f5220534d54206d3172525867503278704449",
|
||||
],
|
||||
},
|
||||
{
|
||||
// curl -H "content-type: application/json" -X POST --data '{"id":0,"jsonrpc":"2.0","method":"eth_getProof","params":["0xC73BfBD94fb1FD860997D4E76D116BDE0333BeEf", ["0x0000000000000000000000000000000000000000000000000000000000000000"], "0x2a7531"]}' https://sepolia-rpc.scroll.io
|
||||
block: 2782513,
|
||||
desc: "contract with only one storage entry",
|
||||
account: "0xC73BfBD94fb1FD860997D4E76D116BDE0333BeEf",
|
||||
storage: "0x0000000000000000000000000000000000000000000000000000000000000000",
|
||||
expectedRoot: "0x13c6008daf17807163a056504e562d4adf13870306814b1a3877cda5297d5ae9",
|
||||
expectedValue: "0x000000000000000000000000000000000000000000000000000000000000000c",
|
||||
accountProof: [
|
||||
"0x09272d92cb48d19e41ef64be1da3e10026eb87d227132becb4fba0dd1451783de425f66c55ff0bec0b012e11d64aaaa6c322566d58cf45525cb05302132518f23d",
|
||||
"0x0920908000907fe2260e41f8682510eee0572937459163ea1940c2eae8b2d5862e015e7c84f56f5948bfc9c242506d14f5c3c1b97bba1b262b40b108f5d7e69287",
|
||||
"0x09078402c38a02e2b3dda819b761ca6448029f3dd42ae7876ac0dba0d762e3ddb818d80485f0a15f54f110aad9a98b00bdf9ccb56bbcb069552c7f6c10be1b9c15",
|
||||
"0x09123243fe438606648fe3bcef5eb0165920315fb2b9316ce3ec0daac885577f190b84d9901fc150f52ed177f23ec31de4254b293c6eac2088009f3e13e3a08b78",
|
||||
"0x09053c59663d3eafad212f58c4834090db4bfd0ba2b13d3108e0acade089a5da9229a75e0b30abc41d4fb252faf9f3aa8ef750b780247d83186cdc333635c25038",
|
||||
"0x09163255ef0b1fdec7ec97c4e002cdeb6c963ca26d9d03ebdf78eb44dfdb57e4bd1fa9f68cc583c1e7019cc62133ede53e5636330de9a2c09e75f03760026e3729",
|
||||
"0x09296d3cb1c4fd539ed015f2853649d20f5db111ce13c30b7e6efa4c9468741d1e0eea62adcf73aa5bdb4868cd776df429d26787f424beeda38f4ad19aa83e43e4",
|
||||
"0x0908288df27fa423895de38ec5a52e809d99b683c5b32463501f5dad642b71387f0a3d37ae9df53b5cfdda0ac67765662e8a71a19b05d38f4a464596e129a35570",
|
||||
"0x091a774fef4e8294fcca57d213846e51bfcf71249680e937e14248e532b47abd762ad72878f07f4abbba8bd13da9b75f681f35a748bb8fc078913e16a91bce783e",
|
||||
"0x092799a146ba6b2bf4b6a24aef88c9590d9643d53f429438e348518a17af3d6e8d10e3b39898c3795c9386518438465581ca232445532fb549a8bddbdd6f4e0eed",
|
||||
"0x0914c654d53c9f8656b784709decbd12ba786800a77c929f3b4255d59138b42dff282005f8997b73d64eeb112775885c4c08d2ee4e356cc2db58154dde48a0a1e4",
|
||||
"0x091c71601a71f28ed0f6aeb59cf8a7bf29ce7dd3203352099920086e02007496260b811e85a0cd244d56f199b357d5c3a54f897fea21637698943679d07b33db8d",
|
||||
"0x092a66de31cef7b4b195772a2b96edba3ca7d97a5bbe974d071c37f0d0ca0545be0be9ca0dd4c9d62ec3ba0a404713fefe6b62391ba3f6d283a47e83fdb18c3a4e",
|
||||
"0x09093842042d196ae30784d31ed1526dd5d60cabe292eb5333e42936a2edbbaf1d237998efa424724063547c02cfa835ebfc24131315c34229b363f46fefda33ee",
|
||||
"0x0911637da97122f89f421a4564d5328893ff4b5de123aecad06e07ea45d9622b87096a296e974b5eda0f2d35cb5531c4a55f3c1e181a8bb4a0b33399e7c93853d4",
|
||||
"0x0921feeaba62a4ad78791d662737a3fa52a527dcd892f5d3af2cfbed4b6591d50f2fae639afb8ab4640a2d166616a4803442b26b9a8f5148a1c88adda1e2d911da",
|
||||
"0x090ddbe424e9368f262ef80a144383fc4f518b27200f7a61a996a075b3b84ab5041c755907f230eea27d060fa827a5743c7046cd0dc7487047bc3a7d222d65d2d7",
|
||||
"0x092d6e65349fd6751353b4b72fdd03d3ee4b1721efb434db76679c1c348b60fdc0177c7d961201138c98f85daf8a49b7a083a41e77dcd819d359b3db55c4a941a9",
|
||||
"0x090b0d48518cb602b73a86bd7b2294d401e6ad4851e3c7549fc7d23eea017eadd72e3245236b50c7f256de16bae063df6221b8331443c9d3a79e867fd77dd85cee",
|
||||
"0x07062bf32f202ec2afa65dfa84fffc76b5c05309768078544920f9b56d021606ce0b7371683425d088ad37f063ee847a9accac416314f1308cce69a8beeb2d2ab7",
|
||||
"0x090ffc989b8556e69159e246cb74cf7a2e30df63e9b7dba76ede73996ab60d9799063ca19e1d436cea189d17c5d93b8da0fa11b3ee88de1030602d1e8087cbb3da",
|
||||
"0x070000000000000000000000000000000000000000000000000000000000000000084f906a52b7da7bf35f3cc2431b40cfb90884c2ec0b579c9c096aea959509f7",
|
||||
"0x0620b6c0072d699768c0b52df46b97dae979a14788ed54dad1d7ce67db6e036a07291784b726760c2d728e4084d95df6d1534e27284c8ae2eeb56a80210f37da2b",
|
||||
"0x041245637ec55bae3c02f990e3cc3bf59cc05f515731cfa59ee55f8164953f8965050800000000000000000000000000000000000000000000000000ac000000000000000100000000000000000000000000000000000000000000000000000000000000000f68a43f5508e9c1f845406d9a507b612f97530746e59b93c8705f1a7cb0b93451e52f95aea13b1bc1f37dfbf797bfe7cea82a8c82da148f507e1ef2036fea8314b9fb07c4311e129d72b858c37b6bbe09c616f78416cb53d6e83360aff7b99c20c73bfbd94fb1fd860997d4e76d116bde0333beef000000000000000000000000",
|
||||
"0x5448495320495320534f4d45204d4147494320425954455320464f5220534d54206d3172525867503278704449",
|
||||
],
|
||||
storageProof: [
|
||||
"0x041d3c5f8c36e5da873d45bfa1d2399a572ac77493ec089cbf88a37b9e9442842201010000000000000000000000000000000000000000000000000000000000000000000c200000000000000000000000000000000000000000000000000000000000000000",
|
||||
"0x5448495320495320534f4d45204d4147494320425954455320464f5220534d54206d3172525867503278704449",
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
describe("ZkTrieVerifier", async () => {
|
||||
let verifier: MockZkTrieVerifier;
|
||||
|
||||
beforeEach(async () => {
|
||||
const [deployer] = await ethers.getSigners();
|
||||
|
||||
const PoseidonHashWithDomainFactory = new ethers.ContractFactory(generateABI(2), createCode(2), deployer);
|
||||
const poseidon = await PoseidonHashWithDomainFactory.deploy();
|
||||
|
||||
const MockZkTrieVerifier = await ethers.getContractFactory("MockZkTrieVerifier", deployer);
|
||||
verifier = await MockZkTrieVerifier.deploy(poseidon.getAddress());
|
||||
});
|
||||
|
||||
const shouldRevert = async (test: ITestConfig, reason: string, extra?: string) => {
|
||||
const proof = concat([
|
||||
`0x${test.accountProof.length.toString(16).padStart(2, "0")}`,
|
||||
...test.accountProof,
|
||||
`0x${test.storageProof.length.toString(16).padStart(2, "0")}`,
|
||||
...test.storageProof,
|
||||
extra || "0x",
|
||||
]);
|
||||
await expect(verifier.verifyZkTrieProof(test.account, test.storage, proof)).to.revertedWith(reason);
|
||||
};
|
||||
|
||||
for (const test of testcases) {
|
||||
it(`should succeed for block[${test.block}] desc[${test.desc}] account[${test.account}] storage[${test.storage}]`, async () => {
|
||||
const proof = concat([
|
||||
`0x${test.accountProof.length.toString(16).padStart(2, "0")}`,
|
||||
...test.accountProof,
|
||||
`0x${test.storageProof.length.toString(16).padStart(2, "0")}`,
|
||||
...test.storageProof,
|
||||
]);
|
||||
const [root, value, gasUsed] = await verifier.verifyZkTrieProof(test.account, test.storage, proof);
|
||||
expect(test.expectedRoot).to.eq(root);
|
||||
expect(test.expectedValue).to.eq(value);
|
||||
console.log("gas usage:", gasUsed.toString());
|
||||
});
|
||||
}
|
||||
|
||||
it("should revert, when InvalidNodeDepth", async () => {
|
||||
const test = testcases[0];
|
||||
{
|
||||
const proof = concat([
|
||||
`0xfa`,
|
||||
...test.accountProof,
|
||||
`0x${test.storageProof.length.toString(16).padStart(2, "0")}`,
|
||||
...test.storageProof,
|
||||
]);
|
||||
await expect(verifier.verifyZkTrieProof(test.account, test.storage, proof)).to.revertedWith("InvalidNodeDepth");
|
||||
}
|
||||
{
|
||||
const proof = concat([
|
||||
`0x${test.accountProof.length.toString(16).padStart(2, "0")}`,
|
||||
...test.accountProof,
|
||||
`0xfa`,
|
||||
...test.storageProof,
|
||||
]);
|
||||
await expect(verifier.verifyZkTrieProof(test.account, test.storage, proof)).to.revertedWith("InvalidNodeDepth");
|
||||
}
|
||||
});
|
||||
|
||||
it("should revert, when InvalidBranchNodeType", async () => {
|
||||
const test = testcases[0];
|
||||
for (const i of [0, 1, test.accountProof.length - 3]) {
|
||||
const correct = test.accountProof[i];
|
||||
const prefix = correct.slice(0, 4);
|
||||
for (let b = 0; b < 16; ++b) {
|
||||
if (b >= 6 && b < 10) continue;
|
||||
test.accountProof[i] = test.accountProof[i].replace(prefix, "0x" + chars[b >> 4] + chars[b % 16]);
|
||||
await shouldRevert(test, "InvalidBranchNodeType");
|
||||
test.accountProof[i] = correct;
|
||||
}
|
||||
}
|
||||
|
||||
for (const i of [0, 1, test.storageProof.length - 3]) {
|
||||
const correct = test.storageProof[i];
|
||||
const prefix = correct.slice(0, 4);
|
||||
for (let b = 0; b < 16; ++b) {
|
||||
if (b >= 6 && b < 10) continue;
|
||||
test.storageProof[i] = test.storageProof[i].replace(prefix, "0x" + chars[b >> 4] + chars[b % 16]);
|
||||
await shouldRevert(test, "InvalidBranchNodeType");
|
||||
test.storageProof[i] = correct;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
it("should revert, when BranchHashMismatch", async () => {
|
||||
const test = testcases[0];
|
||||
for (const i of [1, 2, test.accountProof.length - 3]) {
|
||||
const correct = test.accountProof[i];
|
||||
for (const p of [40, 98]) {
|
||||
const v = correct[p];
|
||||
for (let b = 0; b < 3; ++b) {
|
||||
if (v === chars[b]) continue;
|
||||
test.accountProof[i] = correct.slice(0, p) + chars[b] + correct.slice(p + 1);
|
||||
await shouldRevert(test, "BranchHashMismatch");
|
||||
test.accountProof[i] = correct;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (const i of [1, 2, test.storageProof.length - 3]) {
|
||||
const correct = test.storageProof[i];
|
||||
for (const p of [40, 98]) {
|
||||
const v = correct[p];
|
||||
for (let b = 0; b < 3; ++b) {
|
||||
if (v === chars[b]) continue;
|
||||
test.storageProof[i] = correct.slice(0, p) + chars[b] + correct.slice(p + 1);
|
||||
await shouldRevert(test, "BranchHashMismatch");
|
||||
test.storageProof[i] = correct;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
it("should revert, when InvalidAccountLeafNodeType", async () => {
|
||||
const test = testcases[0];
|
||||
const index = test.accountProof.length - 2;
|
||||
const correct = test.accountProof[index];
|
||||
const prefix = correct.slice(0, 4);
|
||||
for (let b = 0; b < 20; ++b) {
|
||||
if (b === 4 || b === 5) continue;
|
||||
test.accountProof[index] = test.accountProof[index].replace(prefix, "0x" + chars[b >> 4] + chars[b % 16]);
|
||||
await shouldRevert(test, "InvalidAccountLeafNodeType");
|
||||
test.accountProof[index] = correct;
|
||||
}
|
||||
});
|
||||
|
||||
it("should revert, when AccountKeyMismatch", async () => {
|
||||
const test = testcases[0];
|
||||
const index = test.accountProof.length - 2;
|
||||
const correct = test.accountProof[index];
|
||||
for (const p of [4, 10]) {
|
||||
const v = correct[p];
|
||||
for (let b = 0; b < 3; ++b) {
|
||||
if (v === chars[b]) continue;
|
||||
test.accountProof[index] = correct.slice(0, p) + chars[b] + correct.slice(p + 1);
|
||||
await shouldRevert(test, "AccountKeyMismatch");
|
||||
test.accountProof[index] = correct;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
it("should revert, when InvalidAccountCompressedFlag", async () => {
|
||||
const test = testcases[0];
|
||||
const index = test.accountProof.length - 2;
|
||||
const correct = test.accountProof[index];
|
||||
for (const replaced of ["01080000", "05010000"]) {
|
||||
test.accountProof[index] = test.accountProof[index].replace("05080000", replaced);
|
||||
await shouldRevert(test, "InvalidAccountCompressedFlag");
|
||||
test.accountProof[index] = correct;
|
||||
}
|
||||
});
|
||||
|
||||
it("should revert, when InvalidAccountLeafNodeHash", async () => {
|
||||
const test = testcases[0];
|
||||
const index = test.accountProof.length - 2;
|
||||
const correct = test.accountProof[index];
|
||||
for (const p of [80, 112, 144, 176, 208]) {
|
||||
const v = correct[p];
|
||||
for (let b = 0; b < 3; ++b) {
|
||||
if (v === chars[b]) continue;
|
||||
test.accountProof[index] = correct.slice(0, p) + chars[b] + correct.slice(p + 1);
|
||||
await shouldRevert(test, "InvalidAccountLeafNodeHash");
|
||||
test.accountProof[index] = correct;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
it("should revert, when InvalidAccountKeyPreimageLength", async () => {
|
||||
const test = testcases[0];
|
||||
const index = test.accountProof.length - 2;
|
||||
const correct = test.accountProof[index];
|
||||
for (const p of [396, 397]) {
|
||||
const v = correct[p];
|
||||
for (let b = 0; b < 3; ++b) {
|
||||
if (v === chars[b]) continue;
|
||||
test.accountProof[index] = correct.slice(0, p) + chars[b] + correct.slice(p + 1);
|
||||
await shouldRevert(test, "InvalidAccountKeyPreimageLength");
|
||||
test.accountProof[index] = correct;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
it("should revert, when InvalidAccountKeyPreimage", async () => {
|
||||
const test = testcases[0];
|
||||
const index = test.accountProof.length - 2;
|
||||
const correct = test.accountProof[index].slice();
|
||||
for (const p of [398, 438]) {
|
||||
const v = correct[p];
|
||||
for (let b = 0; b < 3; ++b) {
|
||||
if (v === chars[b]) continue;
|
||||
test.accountProof[index] = correct.slice(0, p) + chars[b] + correct.slice(p + 1);
|
||||
await shouldRevert(test, "InvalidAccountKeyPreimage");
|
||||
test.accountProof[index] = correct;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
it("should revert, when InvalidProofMagicBytes", async () => {
|
||||
const test = testcases[0];
|
||||
let index = test.accountProof.length - 1;
|
||||
let correct = test.accountProof[index].slice();
|
||||
for (const p of [2, 32, 91]) {
|
||||
const v = correct[p];
|
||||
for (let b = 0; b < 3; ++b) {
|
||||
if (v === chars[b]) continue;
|
||||
test.accountProof[index] = correct.slice(0, p) + chars[b] + correct.slice(p + 1);
|
||||
await shouldRevert(test, "InvalidProofMagicBytes");
|
||||
test.accountProof[index] = correct;
|
||||
}
|
||||
}
|
||||
|
||||
index = test.storageProof.length - 1;
|
||||
correct = test.storageProof[index].slice();
|
||||
for (const p of [2, 32, 91]) {
|
||||
const v = correct[p];
|
||||
for (let b = 0; b < 3; ++b) {
|
||||
if (v === chars[b]) continue;
|
||||
test.storageProof[index] = correct.slice(0, p) + chars[b] + correct.slice(p + 1);
|
||||
await shouldRevert(test, "InvalidProofMagicBytes");
|
||||
test.storageProof[index] = correct;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
it("should revert, when InvalidAccountLeafNodeHash", async () => {
|
||||
const test = testcases[0];
|
||||
const correct = test.accountProof[test.accountProof.length - 2];
|
||||
// change nonce
|
||||
test.accountProof[test.accountProof.length - 2] = correct.replace(
|
||||
"0x0420e9fb498ff9c35246d527da24aa1710d2cc9b055ecf9a95a8a2a11d3d836cdf050800000",
|
||||
"0x0420e9fb498ff9c35246d527da24aa1710d2cc9b055ecf9a95a8a2a11d3d836cdf050800001"
|
||||
);
|
||||
await shouldRevert(test, "InvalidAccountLeafNodeHash");
|
||||
test.accountProof[test.accountProof.length - 2] = correct;
|
||||
});
|
||||
|
||||
it("should revert, when InvalidStorageLeafNodeType", async () => {
|
||||
const test = testcases[0];
|
||||
const index = test.storageProof.length - 2;
|
||||
const correct = test.storageProof[index];
|
||||
const prefix = correct.slice(0, 4);
|
||||
for (let b = 0; b < 20; ++b) {
|
||||
if (b === 4 || b === 5) continue;
|
||||
test.storageProof[index] = test.storageProof[index].replace(prefix, "0x" + chars[b >> 4] + chars[b % 16]);
|
||||
await shouldRevert(test, "InvalidStorageLeafNodeType");
|
||||
test.storageProof[index] = correct;
|
||||
}
|
||||
});
|
||||
|
||||
it("should revert, when StorageKeyMismatch", async () => {
|
||||
const test = testcases[0];
|
||||
const index = test.storageProof.length - 2;
|
||||
const correct = test.storageProof[index];
|
||||
for (const p of [4, 10]) {
|
||||
const v = correct[p];
|
||||
for (let b = 0; b < 3; ++b) {
|
||||
if (v === chars[b]) continue;
|
||||
test.storageProof[index] = correct.slice(0, p) + chars[b] + correct.slice(p + 1);
|
||||
await shouldRevert(test, "StorageKeyMismatch");
|
||||
test.storageProof[index] = correct;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
it("should revert, when InvalidStorageCompressedFlag", async () => {
|
||||
const test = testcases[0];
|
||||
const index = test.storageProof.length - 2;
|
||||
const correct = test.storageProof[index];
|
||||
for (const replaced of ["00010000", "01000000"]) {
|
||||
test.storageProof[index] = test.storageProof[index].replace("01010000", replaced);
|
||||
await shouldRevert(test, "InvalidStorageCompressedFlag");
|
||||
test.storageProof[index] = correct;
|
||||
}
|
||||
});
|
||||
|
||||
it("should revert, when InvalidStorageLeafNodeHash", async () => {
|
||||
const test = testcases[0];
|
||||
const index = test.storageProof.length - 2;
|
||||
const correct = test.storageProof[index];
|
||||
for (const p of [100, 132]) {
|
||||
const v = correct[p];
|
||||
for (let b = 0; b < 3; ++b) {
|
||||
if (v === chars[b]) continue;
|
||||
test.storageProof[index] = correct.slice(0, p) + chars[b] + correct.slice(p + 1);
|
||||
await shouldRevert(test, "InvalidStorageLeafNodeHash");
|
||||
test.storageProof[index] = correct;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
it("should revert, when InvalidStorageKeyPreimageLength", async () => {
|
||||
const test = testcases[0];
|
||||
const index = test.storageProof.length - 2;
|
||||
const correct = test.storageProof[index];
|
||||
for (const p of [140, 141]) {
|
||||
const v = correct[p];
|
||||
for (let b = 0; b < 3; ++b) {
|
||||
if (v === chars[b]) continue;
|
||||
test.storageProof[index] = correct.slice(0, p) + chars[b] + correct.slice(p + 1);
|
||||
await shouldRevert(test, "InvalidStorageKeyPreimageLength");
|
||||
test.storageProof[index] = correct;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
it("should revert, when InvalidStorageKeyPreimage", async () => {
|
||||
const test = testcases[0];
|
||||
const index = test.storageProof.length - 2;
|
||||
const correct = test.storageProof[index];
|
||||
for (const p of [142, 205]) {
|
||||
const v = correct[p];
|
||||
for (let b = 0; b < 3; ++b) {
|
||||
if (v === chars[b]) continue;
|
||||
test.storageProof[index] = correct.slice(0, p) + chars[b] + correct.slice(p + 1);
|
||||
await shouldRevert(test, "InvalidStorageKeyPreimage");
|
||||
test.storageProof[index] = correct;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
it("should revert, when InvalidStorageEmptyLeafNodeHash", async () => {
|
||||
const test = testcases[0];
|
||||
const index = test.storageProof.length - 2;
|
||||
const correct = test.storageProof[index];
|
||||
test.storageProof[index] = "0x05";
|
||||
await shouldRevert(test, "InvalidStorageEmptyLeafNodeHash");
|
||||
test.storageProof[index] = correct;
|
||||
});
|
||||
|
||||
it("should revert, when ProofLengthMismatch", async () => {
|
||||
const test = testcases[0];
|
||||
await shouldRevert(test, "ProofLengthMismatch", "0x0000");
|
||||
});
|
||||
});
|
||||
BIN
contracts/integration-test/testdata/plonk_verifier_0.9.8_pi.data
vendored
Normal file
BIN
contracts/integration-test/testdata/plonk_verifier_0.9.8_pi.data
vendored
Normal file
Binary file not shown.
BIN
contracts/integration-test/testdata/plonk_verifier_0.9.8_proof.data
vendored
Normal file
BIN
contracts/integration-test/testdata/plonk_verifier_0.9.8_proof.data
vendored
Normal file
Binary file not shown.
1154
contracts/integration-test/testdata/poseidon_hash_with_domain.data
vendored
Normal file
1154
contracts/integration-test/testdata/poseidon_hash_with_domain.data
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1
contracts/lib/ds-test
Submodule
1
contracts/lib/ds-test
Submodule
Submodule contracts/lib/ds-test added at 9310e879db
1
contracts/lib/forge-std
Submodule
1
contracts/lib/forge-std
Submodule
Submodule contracts/lib/forge-std added at 662ae0d693
1
contracts/lib/solmate
Submodule
1
contracts/lib/solmate
Submodule
Submodule contracts/lib/solmate added at bff24e8351
73
contracts/package.json
Normal file
73
contracts/package.json
Normal file
@@ -0,0 +1,73 @@
|
||||
{
|
||||
"name": "scroll-contracts",
|
||||
"version": "1.0.0",
|
||||
"main": "index.js",
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"test:hardhat": "npx hardhat test",
|
||||
"test:forge": "forge test -vvv --evm-version cancun",
|
||||
"test": "yarn test:hardhat && yarn test:forge",
|
||||
"solhint": "./node_modules/.bin/solhint -f table 'src/**/*.sol'",
|
||||
"lint:sol": "./node_modules/.bin/prettier --write 'src/**/*.sol'",
|
||||
"lint:ts": "./node_modules/.bin/prettier --write 'integration-test/**/*.ts' 'scripts/**/*.ts' *.ts",
|
||||
"lint": "yarn lint:ts && yarn lint:sol",
|
||||
"coverage": "hardhat coverage",
|
||||
"coverage:forge": "forge coverage",
|
||||
"prepare": "cd .. && husky install contracts/.husky"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@nomicfoundation/hardhat-chai-matchers": "^2.0.6",
|
||||
"@nomicfoundation/hardhat-ethers": "^3.0.5",
|
||||
"@nomicfoundation/hardhat-verify": "^2.0.5",
|
||||
"@primitivefi/hardhat-dodoc": "^0.2.3",
|
||||
"@typechain/ethers-v6": "^0.5.1",
|
||||
"@typechain/hardhat": "^9.1.0",
|
||||
"@types/chai": "^4.2.21",
|
||||
"@types/edit-json-file": "^1.7.0",
|
||||
"@types/mocha": "^9.0.0",
|
||||
"@types/node": "^20.11.27",
|
||||
"@typescript-eslint/eslint-plugin": "^7.2.0",
|
||||
"@typescript-eslint/parser": "^7.2.0",
|
||||
"chai": "^4.2.0",
|
||||
"circom": "^0.5.46",
|
||||
"circomlib": "^0.5.0",
|
||||
"dotenv": "^10.0.0",
|
||||
"edit-json-file": "^1.7.0",
|
||||
"eslint": "^8.57.0",
|
||||
"eslint-config-prettier": "^8.3.0",
|
||||
"eslint-config-standard": "^17.1.0",
|
||||
"eslint-plugin-import": "^2.23.4",
|
||||
"eslint-plugin-n": "^16.6.2",
|
||||
"eslint-plugin-node": "^11.1.0",
|
||||
"eslint-plugin-prettier": "^3.4.0",
|
||||
"eslint-plugin-promise": "^6.1.1",
|
||||
"ethereum-waffle": "^3.0.0",
|
||||
"ethers": "^6.11.1",
|
||||
"hardhat": "^2.22.0",
|
||||
"hardhat-gas-reporter": "^1.0.4",
|
||||
"husky": "^8.0.1",
|
||||
"lint-staged": "^13.0.3",
|
||||
"lodash": "^4.17.21",
|
||||
"prettier": "^2.3.2",
|
||||
"prettier-plugin-solidity": "^1.0.0-beta.13",
|
||||
"solhint": "^3.3.6",
|
||||
"solidity-coverage": "^0.8.11",
|
||||
"squirrelly": "8.0.8",
|
||||
"toml": "^3.0.0",
|
||||
"ts-node": "^10.1.0",
|
||||
"typechain": "^8.3.2",
|
||||
"typescript": "^5.4.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"@openzeppelin/contracts": "^v4.9.3",
|
||||
"@openzeppelin/contracts-upgradeable": "^v4.9.3"
|
||||
},
|
||||
"lint-staged": {
|
||||
"*.{js,ts}": "npx eslint --cache --fix",
|
||||
"!(docs/apis/*).md": "prettier --ignore-unknown --write",
|
||||
"*.sol": "prettier --ignore-unknown --write"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10.4.0"
|
||||
}
|
||||
}
|
||||
5
contracts/remappings.txt
Normal file
5
contracts/remappings.txt
Normal file
@@ -0,0 +1,5 @@
|
||||
hardhat/=node_modules/hardhat/
|
||||
forge-std/=lib/forge-std/src/
|
||||
ds-test/=lib/ds-test/src/
|
||||
solmate/=lib/solmate/src/
|
||||
@openzeppelin/=node_modules/@openzeppelin
|
||||
104
contracts/scripts/README.md
Normal file
104
contracts/scripts/README.md
Normal file
@@ -0,0 +1,104 @@
|
||||
# Deployment scripts of Scroll contracts
|
||||
|
||||
## Deployment using Hardhat
|
||||
|
||||
The scripts should run as below sequence:
|
||||
|
||||
```bash
|
||||
export layer1=l1geth # change to actual network name
|
||||
export layer2=l2geth # change to actual network name
|
||||
export owner=0x0000000000000000000000000000000000000000 # change to actual owner
|
||||
|
||||
# deploy contracts in layer 1
|
||||
npx hardhat --network $layer1 run scripts/deploy_proxy_admin.ts
|
||||
npx hardhat --network $layer1 run scripts/deploy_scroll_chain.ts
|
||||
env CONTRACT_NAME=L1ScrollMessenger npx hardhat run --network $layer1 scripts/deploy_proxy_contract.ts
|
||||
env CONTRACT_NAME=L1GatewayRouter npx hardhat run --network $layer1 scripts/deploy_proxy_contract.ts
|
||||
env CONTRACT_NAME=L1StandardERC20Gateway npx hardhat run --network $layer1 scripts/deploy_proxy_contract.ts
|
||||
env CONTRACT_NAME=L1CustomERC20Gateway npx hardhat run --network $layer1 scripts/deploy_proxy_contract.ts
|
||||
env CONTRACT_NAME=L1ERC721Gateway npx hardhat run --network $layer1 scripts/deploy_proxy_contract.ts
|
||||
env CONTRACT_NAME=L1ERC1155Gateway npx hardhat run --network $layer1 scripts/deploy_proxy_contract.ts
|
||||
env CONTRACT_NAME=L1ETHGateway npx hardhat run --network $layer1 scripts/deploy_proxy_contract.ts
|
||||
env CONTRACT_NAME=L1WETHGateway npx hardhat run --network $layer1 scripts/deploy_proxy_contract.ts
|
||||
|
||||
# deploy contracts in layer 2, note: l2_messenger is predeployed
|
||||
npx hardhat --network $layer2 run scripts/deploy_proxy_admin.ts
|
||||
npx hardhat --network $layer2 run scripts/deploy_l2_messenger.ts
|
||||
npx hardhat --network $layer2 run scripts/deploy_l2_token_factory.ts
|
||||
env CONTRACT_NAME=L2GatewayRouter npx hardhat run --network $layer2 scripts/deploy_proxy_contract.ts
|
||||
env CONTRACT_NAME=L2StandardERC20Gateway npx hardhat run --network $layer2 scripts/deploy_proxy_contract.ts
|
||||
env CONTRACT_NAME=L2CustomERC20Gateway npx hardhat run --network $layer2 scripts/deploy_proxy_contract.ts
|
||||
env CONTRACT_NAME=L2ERC721Gateway npx hardhat run --network $layer2 scripts/deploy_proxy_contract.ts
|
||||
env CONTRACT_NAME=L2ERC1155Gateway npx hardhat run --network $layer2 scripts/deploy_proxy_contract.ts
|
||||
env CONTRACT_NAME=L2ETHGateway npx hardhat run --network $layer2 scripts/deploy_proxy_contract.ts
|
||||
env CONTRACT_NAME=L2WETHGateway npx hardhat run --network $layer2 scripts/deploy_proxy_contract.ts
|
||||
|
||||
# initialize contracts in layer 1, should set proper bash env variables first
|
||||
npx hardhat --network $layer1 run scripts/initialize_l1_erc20_gateway.ts
|
||||
npx hardhat --network $layer1 run scripts/initialize_l1_gateway_router.ts
|
||||
npx hardhat --network $layer1 run scripts/initialize_scroll_chain.ts
|
||||
npx hardhat --network $layer1 run scripts/initialize_l1_messenger.ts
|
||||
npx hardhat --network $layer1 run scripts/initialize_l1_custom_erc20_gateway.ts
|
||||
npx hardhat --network $layer1 run scripts/initialize_l1_erc1155_gateway.ts
|
||||
npx hardhat --network $layer1 run scripts/initialize_l1_erc721_gateway.ts
|
||||
|
||||
# initialize contracts in layer 2, should set proper bash env variables first
|
||||
npx hardhat --network $layer2 run scripts/initialize_l2_erc20_gateway.ts
|
||||
npx hardhat --network $layer2 run scripts/initialize_l2_gateway_router.ts
|
||||
npx hardhat --network $layer2 run scripts/initialize_l2_custom_erc20_gateway.ts
|
||||
npx hardhat --network $layer2 run scripts/initialize_l2_erc1155_gateway.ts
|
||||
npx hardhat --network $layer2 run scripts/initialize_l2_erc721_gateway.ts
|
||||
npx hardhat --network $layer2 run scripts/initialize_l2_token_factory.ts
|
||||
|
||||
# transfer ownership in layer 1
|
||||
env CONTRACT_NAME=ProxyAdmin CONTRACT_OWNER=$owner npx hardhat run --network $layer1 scripts/transfer_ownership.ts
|
||||
env CONTRACT_NAME=L1ScrollMessenger CONTRACT_OWNER=$owner npx hardhat run --network $layer1 scripts/transfer_ownership.ts
|
||||
env CONTRACT_NAME=ZKRollup CONTRACT_OWNER=$owner npx hardhat run --network $layer1 scripts/transfer_ownership.ts
|
||||
env CONTRACT_NAME=L1GatewayRouter CONTRACT_OWNER=$owner npx hardhat run --network $layer1 scripts/transfer_ownership.ts
|
||||
env CONTRACT_NAME=L1CustomERC20Gateway CONTRACT_OWNER=$owner npx hardhat run --network $layer1 scripts/transfer_ownership.ts
|
||||
env CONTRACT_NAME=L1ERC721Gateway CONTRACT_OWNER=$owner npx hardhat run --network $layer1 scripts/transfer_ownership.ts
|
||||
env CONTRACT_NAME=L1ERC1155Gateway CONTRACT_OWNER=$owner npx hardhat run --network $layer1 scripts/transfer_ownership.ts
|
||||
# transfer ownership in layer 2
|
||||
env CONTRACT_NAME=ProxyAdmin CONTRACT_OWNER=$owner npx hardhat run --network $layer2 scripts/transfer_ownership.ts
|
||||
env CONTRACT_NAME=L2ScrollMessenger CONTRACT_OWNER=$owner npx hardhat run --network $layer2 scripts/transfer_ownership.ts
|
||||
env CONTRACT_NAME=L2GatewayRouter CONTRACT_OWNER=$owner npx hardhat run --network $layer2 scripts/transfer_ownership.ts
|
||||
env CONTRACT_NAME=L2CustomERC20Gateway CONTRACT_OWNER=$owner npx hardhat run --network $layer2 scripts/transfer_ownership.ts
|
||||
env CONTRACT_NAME=L2ERC721Gateway CONTRACT_OWNER=$owner npx hardhat run --network $layer2 scripts/transfer_ownership.ts
|
||||
env CONTRACT_NAME=L2ERC1155Gateway CONTRACT_OWNER=$owner npx hardhat run --network $layer2 scripts/transfer_ownership.ts
|
||||
```
|
||||
|
||||
Reference testnet [run_deploy_contracts.sh](https://github.com/scroll-tech/testnet/blob/staging/run_deploy_contracts.sh) for details.
|
||||
|
||||
## Deployment using Foundry
|
||||
|
||||
Note: The Foundry scripts take parameters like `CHAIN_ID_L2` and `L1_SCROLL_CHAIN_PROXY_ADDR` as environment variables.
|
||||
|
||||
```bash
|
||||
# allexport
|
||||
$ set -a
|
||||
|
||||
$ cat .env
|
||||
CHAIN_ID_L2="5343541"
|
||||
SCROLL_L1_RPC="http://localhost:8543"
|
||||
SCROLL_L2_RPC="http://localhost:8545"
|
||||
L1_DEPLOYER_PRIVATE_KEY="0x0000000000000000000000000000000000000000000000000000000000000001"
|
||||
L2_DEPLOYER_PRIVATE_KEY="0x0000000000000000000000000000000000000000000000000000000000000002"
|
||||
L1_ROLLUP_OPERATOR_ADDR="0x1111111111111111111111111111111111111111"
|
||||
|
||||
$ source .env
|
||||
|
||||
# Deploy L1 contracts
|
||||
# Note: We extract the logged addresses as environment variables.
|
||||
$ OUTPUT=$(forge script scripts/foundry/DeployL1BridgeContracts.s.sol:DeployL1BridgeContracts --rpc-url $SCROLL_L1_RPC --broadcast); echo $OUTPUT
|
||||
$ echo "$OUTPUT" | grep -Eo "(L1)_.*" > .env.l1_addresses
|
||||
$ source .env.l1_addresses
|
||||
|
||||
# Deploy L2 contracts
|
||||
$ OUTPUT=$(forge script scripts/foundry/DeployL2BridgeContracts.s.sol:DeployL2BridgeContracts --rpc-url $SCROLL_L2_RPC --broadcast); echo $OUTPUT
|
||||
$ echo "$OUTPUT" | grep -Eo "(L2)_.*" > .env.l2_addresses
|
||||
$ source .env.l2_addresses
|
||||
|
||||
# Initialize contracts
|
||||
$ forge script scripts/foundry/InitializeL1BridgeContracts.s.sol:InitializeL1BridgeContracts --rpc-url $SCROLL_L1_RPC --broadcast
|
||||
$ forge script scripts/foundry/InitializeL2BridgeContracts.s.sol:InitializeL2BridgeContracts --rpc-url $SCROLL_L2_RPC --broadcast
|
||||
```
|
||||
40
contracts/scripts/ScrollChainCommitmentVerifier.deploy.ts
Normal file
40
contracts/scripts/ScrollChainCommitmentVerifier.deploy.ts
Normal file
@@ -0,0 +1,40 @@
|
||||
/* eslint-disable node/no-missing-import */
|
||||
import * as dotenv from "dotenv";
|
||||
|
||||
import { ethers } from "hardhat";
|
||||
import { generateABI, createCode } from "../scripts/poseidon";
|
||||
|
||||
dotenv.config();
|
||||
|
||||
async function main() {
|
||||
const [deployer] = await ethers.getSigners();
|
||||
|
||||
const ScrollChainCommitmentVerifier = await ethers.getContractFactory("ScrollChainCommitmentVerifier", deployer);
|
||||
|
||||
const L1ScrollChainAddress = process.env.L1_SCROLL_CHAIN_PROXY_ADDR!;
|
||||
let PoseidonUnit2Address = process.env.POSEIDON_UNIT2_ADDR;
|
||||
|
||||
if (!PoseidonUnit2Address) {
|
||||
const Poseidon2Elements = new ethers.ContractFactory(generateABI(2), createCode(2), deployer);
|
||||
|
||||
const poseidon = await Poseidon2Elements.deploy();
|
||||
console.log("Deploy PoseidonUnit2 contract, hash:", poseidon.deployTransaction.hash);
|
||||
const receipt = await poseidon.deployTransaction.wait();
|
||||
console.log(`✅ Deploy PoseidonUnit2 contract at: ${poseidon.address}, gas used: ${receipt.gasUsed}`);
|
||||
PoseidonUnit2Address = poseidon.address;
|
||||
}
|
||||
|
||||
const verifier = await ScrollChainCommitmentVerifier.deploy(PoseidonUnit2Address, L1ScrollChainAddress, {
|
||||
gasPrice: 1e9,
|
||||
});
|
||||
console.log("Deploy ScrollChainCommitmentVerifier contract, hash:", verifier.deployTransaction.hash);
|
||||
const receipt = await verifier.deployTransaction.wait();
|
||||
console.log(`✅ Deploy ScrollChainCommitmentVerifier contract at: ${verifier.address}, gas used: ${receipt.gasUsed}`);
|
||||
}
|
||||
|
||||
// We recommend this pattern to be able to use async/await everywhere
|
||||
// and properly handle errors.
|
||||
main().catch((error) => {
|
||||
console.error(error);
|
||||
process.exitCode = 1;
|
||||
});
|
||||
50
contracts/scripts/deploy_l2_messenger.ts
Normal file
50
contracts/scripts/deploy_l2_messenger.ts
Normal file
@@ -0,0 +1,50 @@
|
||||
/* eslint-disable node/no-missing-import */
|
||||
import * as hre from "hardhat";
|
||||
import { ethers } from "hardhat";
|
||||
import { selectAddressFile } from "./utils";
|
||||
|
||||
async function main() {
|
||||
const addressFile = selectAddressFile(hre.network.name);
|
||||
|
||||
const [deployer] = await ethers.getSigners();
|
||||
|
||||
const ProxyAdmin = await ethers.getContractAt("ProxyAdmin", addressFile.get("ProxyAdmin"), deployer);
|
||||
|
||||
const container = process.env.L1_BLOCK_CONTAINER_ADDR!;
|
||||
const queue = process.env.L2_MESSAGE_QUEUE_ADDR!;
|
||||
if (!addressFile.get("L2ScrollMessenger.implementation")) {
|
||||
console.log(">> Deploy L2ScrollMessenger implementation");
|
||||
const L2ScrollMessenger = await ethers.getContractFactory("L2ScrollMessenger", deployer);
|
||||
const impl = await L2ScrollMessenger.deploy(container, queue);
|
||||
console.log(`>> waiting for transaction: ${impl.deployTransaction.hash}`);
|
||||
await impl.deployed();
|
||||
console.log(`✅ L2ScrollMessenger implementation deployed at ${impl.address}`);
|
||||
addressFile.set("L2ScrollMessenger.implementation", impl.address);
|
||||
}
|
||||
|
||||
const impl = addressFile.get("L2ScrollMessenger.implementation") as string;
|
||||
|
||||
if (!addressFile.get("L2ScrollMessenger.proxy")) {
|
||||
console.log(">> Deploy L2ScrollMessenger proxy");
|
||||
const TransparentUpgradeableProxy = await ethers.getContractFactory("TransparentUpgradeableProxy", deployer);
|
||||
const proxy = await TransparentUpgradeableProxy.deploy(impl, ProxyAdmin.address, "0x");
|
||||
console.log(`>> waiting for transaction: ${proxy.deployTransaction.hash}`);
|
||||
await proxy.deployed();
|
||||
console.log(`✅ L2ScrollMessenger proxy deployed at ${proxy.address}`);
|
||||
addressFile.set(`L2ScrollMessenger.proxy`, proxy.address);
|
||||
}
|
||||
|
||||
// Export contract address to testnet.
|
||||
console.log(
|
||||
`testnet-export: ${addressFile.get("L2ScrollMessenger.implementation")};${addressFile.get(
|
||||
"L2ScrollMessenger.proxy"
|
||||
)}`
|
||||
);
|
||||
}
|
||||
|
||||
// We recommend this pattern to be able to use async/await everywhere
|
||||
// and properly handle errors.
|
||||
main().catch((error) => {
|
||||
console.error(error);
|
||||
process.exitCode = 1;
|
||||
});
|
||||
44
contracts/scripts/deploy_l2_token_factory.ts
Normal file
44
contracts/scripts/deploy_l2_token_factory.ts
Normal file
@@ -0,0 +1,44 @@
|
||||
/* eslint-disable node/no-missing-import */
|
||||
import * as hre from "hardhat";
|
||||
import { ethers } from "hardhat";
|
||||
import { selectAddressFile } from "./utils";
|
||||
|
||||
async function main() {
|
||||
const addressFile = selectAddressFile(hre.network.name);
|
||||
|
||||
const [deployer] = await ethers.getSigners();
|
||||
|
||||
if (!addressFile.get("ScrollStandardERC20")) {
|
||||
console.log(">> Deploy ScrollStandardERC20");
|
||||
const ScrollStandardERC20 = await ethers.getContractFactory("ScrollStandardERC20", deployer);
|
||||
const token = await ScrollStandardERC20.deploy();
|
||||
console.log(`>> waiting for transaction: ${token.deployTransaction.hash}`);
|
||||
await token.deployed();
|
||||
console.log(`✅ ScrollStandardERC20 deployed at ${token.address}`);
|
||||
addressFile.set("ScrollStandardERC20", token.address);
|
||||
}
|
||||
|
||||
const tokenImpl = addressFile.get("ScrollStandardERC20") as string;
|
||||
|
||||
if (!addressFile.get("ScrollStandardERC20Factory")) {
|
||||
console.log(">> Deploy ScrollStandardERC20Factory");
|
||||
const ScrollStandardERC20Factory = await ethers.getContractFactory("ScrollStandardERC20Factory", deployer);
|
||||
const token = await ScrollStandardERC20Factory.deploy(tokenImpl);
|
||||
console.log(`>> waiting for transaction: ${token.deployTransaction.hash}`);
|
||||
await token.deployed();
|
||||
console.log(`✅ ScrollStandardERC20Factory deployed at ${token.address}`);
|
||||
addressFile.set("ScrollStandardERC20Factory", token.address);
|
||||
}
|
||||
|
||||
// Export contract address to testnet.
|
||||
console.log(
|
||||
`testnet-export: ${addressFile.get("ScrollStandardERC20")};${addressFile.get("ScrollStandardERC20Factory")}`
|
||||
);
|
||||
}
|
||||
|
||||
// We recommend this pattern to be able to use async/await everywhere
|
||||
// and properly handle errors.
|
||||
main().catch((error) => {
|
||||
console.error(error);
|
||||
process.exitCode = 1;
|
||||
});
|
||||
30
contracts/scripts/deploy_proxy_admin.ts
Normal file
30
contracts/scripts/deploy_proxy_admin.ts
Normal file
@@ -0,0 +1,30 @@
|
||||
/* eslint-disable node/no-missing-import */
|
||||
import * as hre from "hardhat";
|
||||
import { ethers } from "hardhat";
|
||||
import { selectAddressFile } from "./utils";
|
||||
|
||||
async function main() {
|
||||
const addressFile = selectAddressFile(hre.network.name);
|
||||
|
||||
const [deployer] = await ethers.getSigners();
|
||||
|
||||
if (!addressFile.get("ProxyAdmin")) {
|
||||
console.log(">> Deploy ProxyAdmin");
|
||||
const ProxyAdmin = await ethers.getContractFactory("ProxyAdmin", deployer);
|
||||
const proxyAdmin = await ProxyAdmin.deploy();
|
||||
console.log(`>> waiting for transaction: ${proxyAdmin.deployTransaction.hash}`);
|
||||
await proxyAdmin.deployed();
|
||||
console.log(`✅ ProxyAdmin deployed at ${proxyAdmin.address}`);
|
||||
addressFile.set("ProxyAdmin", proxyAdmin.address);
|
||||
}
|
||||
|
||||
// Export contract address to testnet.
|
||||
console.log(`testnet-export: ${addressFile.get("ProxyAdmin")}`);
|
||||
}
|
||||
|
||||
// We recommend this pattern to be able to use async/await everywhere
|
||||
// and properly handle errors.
|
||||
main().catch((error) => {
|
||||
console.error(error);
|
||||
process.exitCode = 1;
|
||||
});
|
||||
54
contracts/scripts/deploy_proxy_contract.ts
Normal file
54
contracts/scripts/deploy_proxy_contract.ts
Normal file
@@ -0,0 +1,54 @@
|
||||
/* eslint-disable node/no-missing-import */
|
||||
import * as dotenv from "dotenv";
|
||||
import * as hre from "hardhat";
|
||||
import { ethers } from "hardhat";
|
||||
import { selectAddressFile } from "./utils";
|
||||
|
||||
dotenv.config();
|
||||
|
||||
async function main() {
|
||||
const addressFile = selectAddressFile(hre.network.name);
|
||||
|
||||
const [deployer] = await ethers.getSigners();
|
||||
|
||||
if (process.env.CONTRACT_NAME === undefined) {
|
||||
throw new Error("env CONTRACT_NAME undefined");
|
||||
}
|
||||
|
||||
const contractName = process.env.CONTRACT_NAME!;
|
||||
const ProxyAdmin = await ethers.getContractAt("ProxyAdmin", addressFile.get("ProxyAdmin"), deployer);
|
||||
|
||||
if (!addressFile.get(`${contractName}.implementation`)) {
|
||||
console.log(`>> Deploy ${contractName} implementation`);
|
||||
const ContractImpl = await ethers.getContractFactory(contractName, deployer);
|
||||
const impl = await ContractImpl.deploy();
|
||||
console.log(`>> waiting for transaction: ${impl.deployTransaction.hash}`);
|
||||
await impl.deployed();
|
||||
console.log(`✅ ${contractName} implementation deployed at ${impl.address}`);
|
||||
addressFile.set(`${contractName}.implementation`, impl.address);
|
||||
}
|
||||
|
||||
const impl = addressFile.get(`${contractName}.implementation`) as string;
|
||||
|
||||
if (!addressFile.get(`${contractName}.proxy`)) {
|
||||
console.log(`>> Deploy ${contractName} proxy`);
|
||||
const TransparentUpgradeableProxy = await ethers.getContractFactory("TransparentUpgradeableProxy", deployer);
|
||||
const proxy = await TransparentUpgradeableProxy.deploy(impl, ProxyAdmin.address, "0x");
|
||||
console.log(`>> waiting for transaction: ${proxy.deployTransaction.hash}`);
|
||||
await proxy.deployed();
|
||||
console.log(`✅ ${contractName} proxy deployed at ${proxy.address}`);
|
||||
addressFile.set(`${contractName}.proxy`, proxy.address);
|
||||
}
|
||||
|
||||
// Export contract address to testnet.
|
||||
console.log(
|
||||
`testnet-export: ${addressFile.get(`${contractName}.implementation`)};${addressFile.get(`${contractName}.proxy`)}`
|
||||
);
|
||||
}
|
||||
|
||||
// We recommend this pattern to be able to use async/await everywhere
|
||||
// and properly handle errors.
|
||||
main().catch((error) => {
|
||||
console.error(error);
|
||||
process.exitCode = 1;
|
||||
});
|
||||
66
contracts/scripts/deploy_scroll_chain.ts
Normal file
66
contracts/scripts/deploy_scroll_chain.ts
Normal file
@@ -0,0 +1,66 @@
|
||||
/* eslint-disable node/no-missing-import */
|
||||
import * as hre from "hardhat";
|
||||
import { ethers } from "hardhat";
|
||||
import { selectAddressFile } from "./utils";
|
||||
|
||||
async function main() {
|
||||
const addressFile = selectAddressFile(hre.network.name);
|
||||
|
||||
const [deployer] = await ethers.getSigners();
|
||||
|
||||
const CHAIN_ID_L2 = process.env.CHAIN_ID_L2 || "none";
|
||||
const MAX_TX_IN_BATCH = process.env.MAX_TX_IN_BATCH || 25;
|
||||
const PADDING_TX_HASH =
|
||||
process.env.PADDING_TX_HASH || "0xb5baa665b2664c3bfed7eb46e00ebc110ecf2ebd257854a9bf2b9dbc9b2c08f6";
|
||||
|
||||
const ProxyAdmin = await ethers.getContractAt("ProxyAdmin", addressFile.get("ProxyAdmin"), deployer);
|
||||
|
||||
if (!addressFile.get("ScrollChain.verifier")) {
|
||||
console.log(">> Deploy RollupVerifier");
|
||||
const RollupVerifier = await ethers.getContractFactory("RollupVerifier", deployer);
|
||||
const verifier = await RollupVerifier.deploy();
|
||||
console.log(`>> waiting for transaction: ${verifier.deployTransaction.hash}`);
|
||||
await verifier.deployed();
|
||||
console.log(`✅ RollupVerifier deployed at ${verifier.address}`);
|
||||
addressFile.set("ScrollChain.verifier", verifier.address);
|
||||
}
|
||||
|
||||
if (!addressFile.get("ScrollChain.implementation")) {
|
||||
console.log(">> Deploy ScrollChain implementation");
|
||||
const ScrollChain = await ethers.getContractFactory("ScrollChain", {
|
||||
libraries: {
|
||||
RollupVerifier: addressFile.get("ScrollChain.verifier"),
|
||||
},
|
||||
signer: deployer,
|
||||
});
|
||||
const impl = await ScrollChain.deploy(CHAIN_ID_L2, MAX_TX_IN_BATCH, PADDING_TX_HASH);
|
||||
console.log(`>> waiting for transaction: ${impl.deployTransaction.hash}`);
|
||||
await impl.deployed();
|
||||
console.log(`✅ ScrollChain implementation deployed at ${impl.address}`);
|
||||
addressFile.set("ScrollChain.implementation", impl.address);
|
||||
}
|
||||
|
||||
const impl = addressFile.get("ScrollChain.implementation") as string;
|
||||
|
||||
if (!addressFile.get("ScrollChain.proxy")) {
|
||||
console.log(">> Deploy ScrollChain proxy");
|
||||
const TransparentUpgradeableProxy = await ethers.getContractFactory("TransparentUpgradeableProxy", deployer);
|
||||
const proxy = await TransparentUpgradeableProxy.deploy(impl, ProxyAdmin.address, "0x");
|
||||
console.log(`>> waiting for transaction: ${proxy.deployTransaction.hash}`);
|
||||
await proxy.deployed();
|
||||
console.log(`✅ ScrollChain proxy deployed at ${proxy.address}`);
|
||||
addressFile.set("ScrollChain.proxy", proxy.address);
|
||||
}
|
||||
|
||||
// Export contract address to testnet.
|
||||
console.log(
|
||||
`testnet-export: ${addressFile.get("ScrollChain.implementation")};${addressFile.get("ScrollChain.proxy")}`
|
||||
);
|
||||
}
|
||||
|
||||
// We recommend this pattern to be able to use async/await everywhere
|
||||
// and properly handle errors.
|
||||
main().catch((error) => {
|
||||
console.error(error);
|
||||
process.exitCode = 1;
|
||||
});
|
||||
30
contracts/scripts/deploy_weth.ts
Normal file
30
contracts/scripts/deploy_weth.ts
Normal file
@@ -0,0 +1,30 @@
|
||||
/* eslint-disable node/no-missing-import */
|
||||
import * as hre from "hardhat";
|
||||
import { ethers } from "hardhat";
|
||||
import { selectAddressFile } from "./utils";
|
||||
|
||||
async function main() {
|
||||
const addressFile = selectAddressFile(hre.network.name);
|
||||
|
||||
const [deployer] = await ethers.getSigners();
|
||||
|
||||
if (!addressFile.get("WETH")) {
|
||||
console.log(">> Deploy WETH");
|
||||
const WrappedEther = await ethers.getContractFactory("WrappedEther", deployer);
|
||||
const weth = await WrappedEther.deploy();
|
||||
console.log(`>> waiting for transaction: ${weth.deployTransaction.hash}`);
|
||||
await weth.deployed();
|
||||
console.log(`✅ WETH deployed at ${weth.address}`);
|
||||
addressFile.set("WETH", weth.address);
|
||||
}
|
||||
|
||||
// Export contract address to testnet.
|
||||
console.log(`testnet-export: ${addressFile.get("WETH")}`);
|
||||
}
|
||||
|
||||
// We recommend this pattern to be able to use async/await everywhere
|
||||
// and properly handle errors.
|
||||
main().catch((error) => {
|
||||
console.error(error);
|
||||
process.exitCode = 1;
|
||||
});
|
||||
32
contracts/scripts/foundry/DeployFallbackContracts.s.sol
Normal file
32
contracts/scripts/foundry/DeployFallbackContracts.s.sol
Normal file
@@ -0,0 +1,32 @@
|
||||
// SPDX-License-Identifier: UNLICENSED
|
||||
pragma solidity =0.8.24;
|
||||
|
||||
// solhint-disable no-console
|
||||
|
||||
import {Script} from "forge-std/Script.sol";
|
||||
import {console} from "forge-std/console.sol";
|
||||
|
||||
import {Fallback} from "../../src/misc/Fallback.sol";
|
||||
|
||||
// solhint-disable state-visibility
|
||||
// solhint-disable var-name-mixedcase
|
||||
|
||||
contract DeployFallbackContracts is Script {
|
||||
uint256 DEPLOYER_PRIVATE_KEY = vm.envUint("DEPLOYER_PRIVATE_KEY");
|
||||
uint256 NUM_CONTRACTS = vm.envUint("NUM_CONTRACTS");
|
||||
|
||||
function run() external {
|
||||
vm.startBroadcast(DEPLOYER_PRIVATE_KEY);
|
||||
|
||||
for (uint256 ii = 0; ii < NUM_CONTRACTS; ++ii) {
|
||||
Fallback fallbackContract = new Fallback();
|
||||
logAddress("FALLBACK", address(fallbackContract));
|
||||
}
|
||||
|
||||
vm.stopBroadcast();
|
||||
}
|
||||
|
||||
function logAddress(string memory name, address addr) internal view {
|
||||
console.log(string(abi.encodePacked(name, "=", vm.toString(address(addr)))));
|
||||
}
|
||||
}
|
||||
233
contracts/scripts/foundry/DeployL1BridgeContracts.s.sol
Normal file
233
contracts/scripts/foundry/DeployL1BridgeContracts.s.sol
Normal file
@@ -0,0 +1,233 @@
|
||||
// SPDX-License-Identifier: UNLICENSED
|
||||
pragma solidity =0.8.24;
|
||||
|
||||
// solhint-disable no-console
|
||||
|
||||
import {Script} from "forge-std/Script.sol";
|
||||
import {console} from "forge-std/console.sol";
|
||||
|
||||
import {ProxyAdmin} from "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol";
|
||||
import {TransparentUpgradeableProxy} from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol";
|
||||
|
||||
import {EnforcedTxGateway} from "../../src/L1/gateways/EnforcedTxGateway.sol";
|
||||
import {L1CustomERC20Gateway} from "../../src/L1/gateways/L1CustomERC20Gateway.sol";
|
||||
import {L1ERC1155Gateway} from "../../src/L1/gateways/L1ERC1155Gateway.sol";
|
||||
import {L1ERC721Gateway} from "../../src/L1/gateways/L1ERC721Gateway.sol";
|
||||
import {L1ETHGateway} from "../../src/L1/gateways/L1ETHGateway.sol";
|
||||
import {L1GatewayRouter} from "../../src/L1/gateways/L1GatewayRouter.sol";
|
||||
import {L1MessageQueueWithGasPriceOracle} from "../../src/L1/rollup/L1MessageQueueWithGasPriceOracle.sol";
|
||||
import {L1ScrollMessenger} from "../../src/L1/L1ScrollMessenger.sol";
|
||||
import {L1StandardERC20Gateway} from "../../src/L1/gateways/L1StandardERC20Gateway.sol";
|
||||
import {L1WETHGateway} from "../../src/L1/gateways/L1WETHGateway.sol";
|
||||
import {L2GasPriceOracle} from "../../src/L1/rollup/L2GasPriceOracle.sol";
|
||||
import {MultipleVersionRollupVerifier} from "../../src/L1/rollup/MultipleVersionRollupVerifier.sol";
|
||||
import {ScrollChain} from "../../src/L1/rollup/ScrollChain.sol";
|
||||
import {Whitelist} from "../../src/L2/predeploys/Whitelist.sol";
|
||||
import {ZkEvmVerifierV1} from "../../src/libraries/verifier/ZkEvmVerifierV1.sol";
|
||||
|
||||
// solhint-disable max-states-count
|
||||
// solhint-disable state-visibility
|
||||
// solhint-disable var-name-mixedcase
|
||||
|
||||
contract DeployL1BridgeContracts is Script {
|
||||
uint256 L1_DEPLOYER_PRIVATE_KEY = vm.envUint("L1_DEPLOYER_PRIVATE_KEY");
|
||||
|
||||
uint64 CHAIN_ID_L2 = uint64(vm.envUint("CHAIN_ID_L2"));
|
||||
|
||||
address L1_WETH_ADDR = vm.envAddress("L1_WETH_ADDR");
|
||||
address L2_WETH_ADDR = vm.envAddress("L2_WETH_ADDR");
|
||||
|
||||
address L1_PLONK_VERIFIER_ADDR = vm.envAddress("L1_PLONK_VERIFIER_ADDR");
|
||||
|
||||
address L1_PROXY_ADMIN_ADDR = vm.envAddress("L1_PROXY_ADMIN_ADDR");
|
||||
|
||||
address L1_SCROLL_CHAIN_PROXY_ADDR = vm.envAddress("L1_SCROLL_CHAIN_PROXY_ADDR");
|
||||
address L1_MESSAGE_QUEUE_PROXY_ADDR = vm.envAddress("L1_MESSAGE_QUEUE_PROXY_ADDR");
|
||||
address L1_SCROLL_MESSENGER_PROXY_ADDR = vm.envAddress("L1_SCROLL_MESSENGER_PROXY_ADDR");
|
||||
|
||||
address L2_SCROLL_MESSENGER_PROXY_ADDR = vm.envAddress("L2_SCROLL_MESSENGER_PROXY_ADDR");
|
||||
address L2_CUSTOM_ERC20_GATEWAY_PROXY_ADDR = vm.envAddress("L2_CUSTOM_ERC20_GATEWAY_PROXY_ADDR");
|
||||
address L2_ERC721_GATEWAY_PROXY_ADDR = vm.envAddress("L2_ERC721_GATEWAY_PROXY_ADDR");
|
||||
address L2_ERC1155_GATEWAY_PROXY_ADDR = vm.envAddress("L2_ERC1155_GATEWAY_PROXY_ADDR");
|
||||
address L2_ETH_GATEWAY_PROXY_ADDR = vm.envAddress("L2_ETH_GATEWAY_PROXY_ADDR");
|
||||
address L2_STANDARD_ERC20_GATEWAY_PROXY_ADDR = vm.envAddress("L2_STANDARD_ERC20_GATEWAY_PROXY_ADDR");
|
||||
address L2_WETH_GATEWAY_PROXY_ADDR = vm.envAddress("L2_WETH_GATEWAY_PROXY_ADDR");
|
||||
address L2_SCROLL_STANDARD_ERC20_ADDR = vm.envAddress("L2_SCROLL_STANDARD_ERC20_ADDR");
|
||||
address L2_SCROLL_STANDARD_ERC20_FACTORY_ADDR = vm.envAddress("L2_SCROLL_STANDARD_ERC20_FACTORY_ADDR");
|
||||
|
||||
ZkEvmVerifierV1 zkEvmVerifierV1;
|
||||
MultipleVersionRollupVerifier rollupVerifier;
|
||||
EnforcedTxGateway enforcedTxGateway;
|
||||
ProxyAdmin proxyAdmin;
|
||||
L1GatewayRouter router;
|
||||
|
||||
function run() external {
|
||||
proxyAdmin = ProxyAdmin(L1_PROXY_ADMIN_ADDR);
|
||||
|
||||
vm.startBroadcast(L1_DEPLOYER_PRIVATE_KEY);
|
||||
|
||||
deployZkEvmVerifierV1();
|
||||
deployMultipleVersionRollupVerifier();
|
||||
deployL1Whitelist();
|
||||
deployEnforcedTxGateway();
|
||||
deployL1MessageQueue();
|
||||
deployL2GasPriceOracle();
|
||||
deployScrollChain();
|
||||
deployL1ScrollMessenger();
|
||||
deployL1GatewayRouter();
|
||||
deployL1ETHGateway();
|
||||
deployL1WETHGateway();
|
||||
deployL1StandardERC20Gateway();
|
||||
deployL1CustomERC20Gateway();
|
||||
deployL1ERC721Gateway();
|
||||
deployL1ERC1155Gateway();
|
||||
|
||||
vm.stopBroadcast();
|
||||
}
|
||||
|
||||
function deployZkEvmVerifierV1() internal {
|
||||
zkEvmVerifierV1 = new ZkEvmVerifierV1(L1_PLONK_VERIFIER_ADDR);
|
||||
|
||||
logAddress("L1_ZKEVM_VERIFIER_V1_ADDR", address(zkEvmVerifierV1));
|
||||
}
|
||||
|
||||
function deployMultipleVersionRollupVerifier() internal {
|
||||
uint256[] memory _versions = new uint256[](1);
|
||||
address[] memory _verifiers = new address[](1);
|
||||
_versions[0] = 0;
|
||||
_verifiers[0] = address(zkEvmVerifierV1);
|
||||
rollupVerifier = new MultipleVersionRollupVerifier(_versions, _verifiers);
|
||||
|
||||
logAddress("L1_MULTIPLE_VERSION_ROLLUP_VERIFIER_ADDR", address(rollupVerifier));
|
||||
}
|
||||
|
||||
function deployL1Whitelist() internal {
|
||||
address owner = vm.addr(L1_DEPLOYER_PRIVATE_KEY);
|
||||
Whitelist whitelist = new Whitelist(owner);
|
||||
|
||||
logAddress("L1_WHITELIST_ADDR", address(whitelist));
|
||||
}
|
||||
|
||||
function deployScrollChain() internal {
|
||||
ScrollChain impl = new ScrollChain(CHAIN_ID_L2, L1_MESSAGE_QUEUE_PROXY_ADDR, address(rollupVerifier));
|
||||
|
||||
logAddress("L1_SCROLL_CHAIN_IMPLEMENTATION_ADDR", address(impl));
|
||||
}
|
||||
|
||||
function deployL1MessageQueue() internal {
|
||||
L1MessageQueueWithGasPriceOracle impl = new L1MessageQueueWithGasPriceOracle(
|
||||
L1_SCROLL_MESSENGER_PROXY_ADDR,
|
||||
L1_SCROLL_CHAIN_PROXY_ADDR,
|
||||
address(enforcedTxGateway)
|
||||
);
|
||||
logAddress("L1_MESSAGE_QUEUE_IMPLEMENTATION_ADDR", address(impl));
|
||||
}
|
||||
|
||||
function deployL1ScrollMessenger() internal {
|
||||
L1ScrollMessenger impl = new L1ScrollMessenger(
|
||||
L2_SCROLL_MESSENGER_PROXY_ADDR,
|
||||
L1_SCROLL_CHAIN_PROXY_ADDR,
|
||||
L1_MESSAGE_QUEUE_PROXY_ADDR
|
||||
);
|
||||
|
||||
logAddress("L1_SCROLL_MESSENGER_IMPLEMENTATION_ADDR", address(impl));
|
||||
}
|
||||
|
||||
function deployL2GasPriceOracle() internal {
|
||||
L2GasPriceOracle impl = new L2GasPriceOracle();
|
||||
TransparentUpgradeableProxy proxy = new TransparentUpgradeableProxy(
|
||||
address(impl),
|
||||
address(proxyAdmin),
|
||||
new bytes(0)
|
||||
);
|
||||
logAddress("L2_GAS_PRICE_ORACLE_IMPLEMENTATION_ADDR", address(impl));
|
||||
logAddress("L2_GAS_PRICE_ORACLE_PROXY_ADDR", address(proxy));
|
||||
}
|
||||
|
||||
function deployL1GatewayRouter() internal {
|
||||
L1GatewayRouter impl = new L1GatewayRouter();
|
||||
TransparentUpgradeableProxy proxy = new TransparentUpgradeableProxy(
|
||||
address(impl),
|
||||
address(proxyAdmin),
|
||||
new bytes(0)
|
||||
);
|
||||
|
||||
logAddress("L1_GATEWAY_ROUTER_IMPLEMENTATION_ADDR", address(impl));
|
||||
logAddress("L1_GATEWAY_ROUTER_PROXY_ADDR", address(proxy));
|
||||
|
||||
router = L1GatewayRouter(address(proxy));
|
||||
}
|
||||
|
||||
function deployL1StandardERC20Gateway() internal {
|
||||
L1StandardERC20Gateway impl = new L1StandardERC20Gateway(
|
||||
L2_STANDARD_ERC20_GATEWAY_PROXY_ADDR,
|
||||
address(router),
|
||||
L1_SCROLL_MESSENGER_PROXY_ADDR,
|
||||
L2_SCROLL_STANDARD_ERC20_ADDR,
|
||||
L2_SCROLL_STANDARD_ERC20_FACTORY_ADDR
|
||||
);
|
||||
|
||||
logAddress("L1_STANDARD_ERC20_GATEWAY_IMPLEMENTATION_ADDR", address(impl));
|
||||
}
|
||||
|
||||
function deployL1ETHGateway() internal {
|
||||
L1ETHGateway impl = new L1ETHGateway(
|
||||
L2_ETH_GATEWAY_PROXY_ADDR,
|
||||
address(router),
|
||||
L1_SCROLL_MESSENGER_PROXY_ADDR
|
||||
);
|
||||
|
||||
logAddress("L1_ETH_GATEWAY_IMPLEMENTATION_ADDR", address(impl));
|
||||
}
|
||||
|
||||
function deployL1WETHGateway() internal {
|
||||
L1WETHGateway impl = new L1WETHGateway(
|
||||
L1_WETH_ADDR,
|
||||
L2_WETH_ADDR,
|
||||
L2_WETH_GATEWAY_PROXY_ADDR,
|
||||
address(router),
|
||||
L1_SCROLL_MESSENGER_PROXY_ADDR
|
||||
);
|
||||
|
||||
logAddress("L1_WETH_GATEWAY_IMPLEMENTATION_ADDR", address(impl));
|
||||
}
|
||||
|
||||
function deployL1CustomERC20Gateway() internal {
|
||||
L1CustomERC20Gateway impl = new L1CustomERC20Gateway(
|
||||
L2_CUSTOM_ERC20_GATEWAY_PROXY_ADDR,
|
||||
address(router),
|
||||
L1_SCROLL_MESSENGER_PROXY_ADDR
|
||||
);
|
||||
|
||||
logAddress("L1_CUSTOM_ERC20_GATEWAY_IMPLEMENTATION_ADDR", address(impl));
|
||||
}
|
||||
|
||||
function deployL1ERC721Gateway() internal {
|
||||
L1ERC721Gateway impl = new L1ERC721Gateway(L2_ERC721_GATEWAY_PROXY_ADDR, L1_SCROLL_MESSENGER_PROXY_ADDR);
|
||||
|
||||
logAddress("L1_ERC721_GATEWAY_IMPLEMENTATION_ADDR", address(impl));
|
||||
}
|
||||
|
||||
function deployL1ERC1155Gateway() internal {
|
||||
L1ERC1155Gateway impl = new L1ERC1155Gateway(L2_ERC1155_GATEWAY_PROXY_ADDR, L1_SCROLL_MESSENGER_PROXY_ADDR);
|
||||
|
||||
logAddress("L1_ERC1155_GATEWAY_IMPLEMENTATION_ADDR", address(impl));
|
||||
}
|
||||
|
||||
function deployEnforcedTxGateway() internal {
|
||||
EnforcedTxGateway impl = new EnforcedTxGateway();
|
||||
TransparentUpgradeableProxy proxy = new TransparentUpgradeableProxy(
|
||||
address(impl),
|
||||
address(proxyAdmin),
|
||||
new bytes(0)
|
||||
);
|
||||
|
||||
logAddress("L1_ENFORCED_TX_GATEWAY_IMPLEMENTATION_ADDR", address(impl));
|
||||
logAddress("L1_ENFORCED_TX_GATEWAY_PROXY_ADDR", address(proxy));
|
||||
enforcedTxGateway = EnforcedTxGateway(address(proxy));
|
||||
}
|
||||
|
||||
function logAddress(string memory name, address addr) internal view {
|
||||
console.log(string(abi.encodePacked(name, "=", vm.toString(address(addr)))));
|
||||
}
|
||||
}
|
||||
145
contracts/scripts/foundry/DeployL1BridgeProxyPlaceholder.s.sol
Normal file
145
contracts/scripts/foundry/DeployL1BridgeProxyPlaceholder.s.sol
Normal file
@@ -0,0 +1,145 @@
|
||||
// SPDX-License-Identifier: UNLICENSED
|
||||
pragma solidity =0.8.24;
|
||||
|
||||
// solhint-disable no-console
|
||||
|
||||
import {Script} from "forge-std/Script.sol";
|
||||
import {console} from "forge-std/console.sol";
|
||||
|
||||
import {ProxyAdmin} from "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol";
|
||||
import {TransparentUpgradeableProxy} from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol";
|
||||
|
||||
import {EmptyContract} from "../../src/misc/EmptyContract.sol";
|
||||
|
||||
// solhint-disable state-visibility
|
||||
// solhint-disable var-name-mixedcase
|
||||
|
||||
contract DeployL1BridgeProxyPlaceholder is Script {
|
||||
uint256 L1_DEPLOYER_PRIVATE_KEY = vm.envUint("L1_DEPLOYER_PRIVATE_KEY");
|
||||
|
||||
ProxyAdmin proxyAdmin;
|
||||
EmptyContract placeholder;
|
||||
|
||||
function run() external {
|
||||
vm.startBroadcast(L1_DEPLOYER_PRIVATE_KEY);
|
||||
|
||||
deployProxyAdmin();
|
||||
deployPlaceHolder();
|
||||
deployL1MessageQueue();
|
||||
deployScrollChain();
|
||||
deployL1ETHGateway();
|
||||
deployL1WETHGateway();
|
||||
deployL1StandardERC20Gateway();
|
||||
deployL1ScrollMessenger();
|
||||
deployL1CustomERC20Gateway();
|
||||
deployL1ERC721Gateway();
|
||||
deployL1ERC1155Gateway();
|
||||
|
||||
vm.stopBroadcast();
|
||||
}
|
||||
|
||||
function deployProxyAdmin() internal {
|
||||
proxyAdmin = new ProxyAdmin();
|
||||
|
||||
logAddress("L1_PROXY_ADMIN_ADDR", address(proxyAdmin));
|
||||
}
|
||||
|
||||
function deployPlaceHolder() internal {
|
||||
placeholder = new EmptyContract();
|
||||
|
||||
logAddress("L1_PROXY_IMPLEMENTATION_PLACEHOLDER_ADDR", address(placeholder));
|
||||
}
|
||||
|
||||
function deployScrollChain() internal {
|
||||
TransparentUpgradeableProxy proxy = new TransparentUpgradeableProxy(
|
||||
address(placeholder),
|
||||
address(proxyAdmin),
|
||||
new bytes(0)
|
||||
);
|
||||
|
||||
logAddress("L1_SCROLL_CHAIN_PROXY_ADDR", address(proxy));
|
||||
}
|
||||
|
||||
function deployL1MessageQueue() internal {
|
||||
TransparentUpgradeableProxy proxy = new TransparentUpgradeableProxy(
|
||||
address(placeholder),
|
||||
address(proxyAdmin),
|
||||
new bytes(0)
|
||||
);
|
||||
logAddress("L1_MESSAGE_QUEUE_PROXY_ADDR", address(proxy));
|
||||
}
|
||||
|
||||
function deployL1StandardERC20Gateway() internal {
|
||||
TransparentUpgradeableProxy proxy = new TransparentUpgradeableProxy(
|
||||
address(placeholder),
|
||||
address(proxyAdmin),
|
||||
new bytes(0)
|
||||
);
|
||||
|
||||
logAddress("L1_STANDARD_ERC20_GATEWAY_PROXY_ADDR", address(proxy));
|
||||
}
|
||||
|
||||
function deployL1ETHGateway() internal {
|
||||
TransparentUpgradeableProxy proxy = new TransparentUpgradeableProxy(
|
||||
address(placeholder),
|
||||
address(proxyAdmin),
|
||||
new bytes(0)
|
||||
);
|
||||
|
||||
logAddress("L1_ETH_GATEWAY_PROXY_ADDR", address(proxy));
|
||||
}
|
||||
|
||||
function deployL1WETHGateway() internal {
|
||||
TransparentUpgradeableProxy proxy = new TransparentUpgradeableProxy(
|
||||
address(placeholder),
|
||||
address(proxyAdmin),
|
||||
new bytes(0)
|
||||
);
|
||||
|
||||
logAddress("L1_WETH_GATEWAY_PROXY_ADDR", address(proxy));
|
||||
}
|
||||
|
||||
function deployL1ScrollMessenger() internal {
|
||||
TransparentUpgradeableProxy proxy = new TransparentUpgradeableProxy(
|
||||
address(placeholder),
|
||||
address(proxyAdmin),
|
||||
new bytes(0)
|
||||
);
|
||||
|
||||
logAddress("L1_SCROLL_MESSENGER_PROXY_ADDR", address(proxy));
|
||||
}
|
||||
|
||||
function deployL1CustomERC20Gateway() internal {
|
||||
TransparentUpgradeableProxy proxy = new TransparentUpgradeableProxy(
|
||||
address(placeholder),
|
||||
address(proxyAdmin),
|
||||
new bytes(0)
|
||||
);
|
||||
|
||||
logAddress("L1_CUSTOM_ERC20_GATEWAY_PROXY_ADDR", address(proxy));
|
||||
}
|
||||
|
||||
function deployL1ERC721Gateway() internal {
|
||||
TransparentUpgradeableProxy proxy = new TransparentUpgradeableProxy(
|
||||
address(placeholder),
|
||||
address(proxyAdmin),
|
||||
new bytes(0)
|
||||
);
|
||||
|
||||
logAddress("L1_ERC721_GATEWAY_PROXY_ADDR", address(proxy));
|
||||
}
|
||||
|
||||
function deployL1ERC1155Gateway() internal {
|
||||
TransparentUpgradeableProxy proxy = new TransparentUpgradeableProxy(
|
||||
address(placeholder),
|
||||
address(proxyAdmin),
|
||||
new bytes(0)
|
||||
);
|
||||
|
||||
logAddress("L1_ERC1155_GATEWAY_PROXY_ADDR", address(proxy));
|
||||
}
|
||||
|
||||
function logAddress(string memory name, address addr) internal view {
|
||||
console.log(string(abi.encodePacked(name, "=", vm.toString(address(addr)))));
|
||||
}
|
||||
}
|
||||
66
contracts/scripts/foundry/DeployL1ScrollOwner.s.sol
Normal file
66
contracts/scripts/foundry/DeployL1ScrollOwner.s.sol
Normal file
@@ -0,0 +1,66 @@
|
||||
// SPDX-License-Identifier: UNLICENSED
|
||||
pragma solidity =0.8.24;
|
||||
|
||||
import {Script} from "forge-std/Script.sol";
|
||||
import {console} from "forge-std/console.sol";
|
||||
|
||||
import {TimelockController} from "@openzeppelin/contracts/governance/TimelockController.sol";
|
||||
|
||||
import {ScrollOwner} from "../../src/misc/ScrollOwner.sol";
|
||||
|
||||
// solhint-disable state-visibility
|
||||
// solhint-disable var-name-mixedcase
|
||||
|
||||
contract DeployL1ScrollOwner is Script {
|
||||
string NETWORK = vm.envString("NETWORK");
|
||||
|
||||
uint256 L1_DEPLOYER_PRIVATE_KEY = vm.envUint("L1_DEPLOYER_PRIVATE_KEY");
|
||||
|
||||
address SCROLL_MULTISIG_ADDR = vm.envAddress("L1_SCROLL_MULTISIG_ADDR");
|
||||
|
||||
address SECURITY_COUNCIL_ADDR = vm.envAddress("L1_SECURITY_COUNCIL_ADDR");
|
||||
|
||||
address L1_PROPOSAL_EXECUTOR_ADDR = vm.envAddress("L1_PROPOSAL_EXECUTOR_ADDR");
|
||||
|
||||
function run() external {
|
||||
vm.startBroadcast(L1_DEPLOYER_PRIVATE_KEY);
|
||||
|
||||
deployScrollOwner();
|
||||
|
||||
if (keccak256(abi.encodePacked(NETWORK)) == keccak256(abi.encodePacked("sepolia"))) {
|
||||
// for sepolia
|
||||
deployTimelockController("1D", 1 minutes);
|
||||
deployTimelockController("7D", 7 minutes);
|
||||
deployTimelockController("14D", 14 minutes);
|
||||
} else if (keccak256(abi.encodePacked(NETWORK)) == keccak256(abi.encodePacked("mainnet"))) {
|
||||
// for mainnet
|
||||
deployTimelockController("1D", 1 days);
|
||||
deployTimelockController("7D", 7 days);
|
||||
deployTimelockController("14D", 14 days);
|
||||
}
|
||||
|
||||
vm.stopBroadcast();
|
||||
}
|
||||
|
||||
function deployScrollOwner() internal {
|
||||
ScrollOwner owner = new ScrollOwner();
|
||||
|
||||
logAddress("L1_SCROLL_OWNER_ADDR", address(owner));
|
||||
}
|
||||
|
||||
function deployTimelockController(string memory label, uint256 delay) internal {
|
||||
address[] memory proposers = new address[](1);
|
||||
address[] memory executors = new address[](1);
|
||||
|
||||
proposers[0] = SCROLL_MULTISIG_ADDR;
|
||||
executors[0] = L1_PROPOSAL_EXECUTOR_ADDR;
|
||||
|
||||
TimelockController timelock = new TimelockController(delay, proposers, executors, SECURITY_COUNCIL_ADDR);
|
||||
|
||||
logAddress(string(abi.encodePacked("L1_", label, "_TIMELOCK_ADDR")), address(timelock));
|
||||
}
|
||||
|
||||
function logAddress(string memory name, address addr) internal view {
|
||||
console.log(string(abi.encodePacked(name, "=", vm.toString(address(addr)))));
|
||||
}
|
||||
}
|
||||
222
contracts/scripts/foundry/DeployL2BridgeContracts.s.sol
Normal file
222
contracts/scripts/foundry/DeployL2BridgeContracts.s.sol
Normal file
@@ -0,0 +1,222 @@
|
||||
// SPDX-License-Identifier: UNLICENSED
|
||||
pragma solidity =0.8.24;
|
||||
|
||||
// solhint-disable no-console
|
||||
|
||||
import {Script} from "forge-std/Script.sol";
|
||||
import {console} from "forge-std/console.sol";
|
||||
|
||||
import {ProxyAdmin} from "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol";
|
||||
import {TransparentUpgradeableProxy} from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol";
|
||||
|
||||
import {L2CustomERC20Gateway} from "../../src/L2/gateways/L2CustomERC20Gateway.sol";
|
||||
import {L2ERC1155Gateway} from "../../src/L2/gateways/L2ERC1155Gateway.sol";
|
||||
import {L2ERC721Gateway} from "../../src/L2/gateways/L2ERC721Gateway.sol";
|
||||
import {L2ETHGateway} from "../../src/L2/gateways/L2ETHGateway.sol";
|
||||
import {L2GatewayRouter} from "../../src/L2/gateways/L2GatewayRouter.sol";
|
||||
import {L2ScrollMessenger} from "../../src/L2/L2ScrollMessenger.sol";
|
||||
import {L2StandardERC20Gateway} from "../../src/L2/gateways/L2StandardERC20Gateway.sol";
|
||||
import {L2WETHGateway} from "../../src/L2/gateways/L2WETHGateway.sol";
|
||||
import {L1GasPriceOracle} from "../../src/L2/predeploys/L1GasPriceOracle.sol";
|
||||
import {L2MessageQueue} from "../../src/L2/predeploys/L2MessageQueue.sol";
|
||||
import {L2TxFeeVault} from "../../src/L2/predeploys/L2TxFeeVault.sol";
|
||||
import {Whitelist} from "../../src/L2/predeploys/Whitelist.sol";
|
||||
import {ScrollStandardERC20} from "../../src/libraries/token/ScrollStandardERC20.sol";
|
||||
import {ScrollStandardERC20Factory} from "../../src/libraries/token/ScrollStandardERC20Factory.sol";
|
||||
|
||||
// solhint-disable max-states-count
|
||||
// solhint-disable state-visibility
|
||||
// solhint-disable var-name-mixedcase
|
||||
|
||||
contract DeployL2BridgeContracts is Script {
|
||||
uint256 L2_DEPLOYER_PRIVATE_KEY = vm.envUint("L2_DEPLOYER_PRIVATE_KEY");
|
||||
|
||||
address L2_PROXY_ADMIN_ADDR = vm.envAddress("L2_PROXY_ADMIN_ADDR");
|
||||
|
||||
address L1_TX_FEE_RECIPIENT_ADDR = vm.envAddress("L1_TX_FEE_RECIPIENT_ADDR");
|
||||
address L1_WETH_ADDR = vm.envAddress("L1_WETH_ADDR");
|
||||
address L2_WETH_ADDR = vm.envAddress("L2_WETH_ADDR");
|
||||
|
||||
L1GasPriceOracle oracle;
|
||||
L2MessageQueue queue;
|
||||
ProxyAdmin proxyAdmin;
|
||||
L2GatewayRouter router;
|
||||
ScrollStandardERC20Factory factory;
|
||||
|
||||
address L2_SCROLL_MESSENGER_PROXY_ADDR = vm.envAddress("L2_SCROLL_MESSENGER_PROXY_ADDR");
|
||||
|
||||
address L1_SCROLL_MESSENGER_PROXY_ADDR = vm.envAddress("L1_SCROLL_MESSENGER_PROXY_ADDR");
|
||||
address L1_CUSTOM_ERC20_GATEWAY_PROXY_ADDR = vm.envAddress("L1_CUSTOM_ERC20_GATEWAY_PROXY_ADDR");
|
||||
address L1_ERC721_GATEWAY_PROXY_ADDR = vm.envAddress("L1_ERC721_GATEWAY_PROXY_ADDR");
|
||||
address L1_ERC1155_GATEWAY_PROXY_ADDR = vm.envAddress("L1_ERC1155_GATEWAY_PROXY_ADDR");
|
||||
address L1_ETH_GATEWAY_PROXY_ADDR = vm.envAddress("L1_ETH_GATEWAY_PROXY_ADDR");
|
||||
address L1_STANDARD_ERC20_GATEWAY_PROXY_ADDR = vm.envAddress("L1_STANDARD_ERC20_GATEWAY_PROXY_ADDR");
|
||||
address L1_WETH_GATEWAY_PROXY_ADDR = vm.envAddress("L1_WETH_GATEWAY_PROXY_ADDR");
|
||||
|
||||
// predeploy contracts
|
||||
address L1_GAS_PRICE_ORACLE_PREDEPLOY_ADDR = vm.envOr("L1_GAS_PRICE_ORACLE_PREDEPLOY_ADDR", address(0));
|
||||
address L2_MESSAGE_QUEUE_PREDEPLOY_ADDR = vm.envOr("L2_MESSAGE_QUEUE_PREDEPLOY_ADDR", address(0));
|
||||
address L2_TX_FEE_VAULT_PREDEPLOY_ADDR = vm.envOr("L2_TX_FEE_VAULT_PREDEPLOY_ADDR", address(0));
|
||||
address L2_WHITELIST_PREDEPLOY_ADDR = vm.envOr("L2_WHITELIST_PREDEPLOY_ADDR", address(0));
|
||||
|
||||
function run() external {
|
||||
proxyAdmin = ProxyAdmin(L2_PROXY_ADMIN_ADDR);
|
||||
|
||||
vm.startBroadcast(L2_DEPLOYER_PRIVATE_KEY);
|
||||
|
||||
// predeploys
|
||||
deployL1GasPriceOracle();
|
||||
deployL2MessageQueue();
|
||||
deployTxFeeVault();
|
||||
deployL2Whitelist();
|
||||
|
||||
// upgradable
|
||||
deployL2ScrollMessenger();
|
||||
deployL2GatewayRouter();
|
||||
deployScrollStandardERC20Factory();
|
||||
deployL2StandardERC20Gateway();
|
||||
deployL2ETHGateway();
|
||||
deployL2WETHGateway();
|
||||
deployL2CustomERC20Gateway();
|
||||
deployL2ERC721Gateway();
|
||||
deployL2ERC1155Gateway();
|
||||
|
||||
vm.stopBroadcast();
|
||||
}
|
||||
|
||||
function deployL1GasPriceOracle() internal {
|
||||
if (L1_GAS_PRICE_ORACLE_PREDEPLOY_ADDR != address(0)) {
|
||||
oracle = L1GasPriceOracle(L1_GAS_PRICE_ORACLE_PREDEPLOY_ADDR);
|
||||
logAddress("L1_GAS_PRICE_ORACLE_ADDR", address(L1_GAS_PRICE_ORACLE_PREDEPLOY_ADDR));
|
||||
return;
|
||||
}
|
||||
|
||||
address owner = vm.addr(L2_DEPLOYER_PRIVATE_KEY);
|
||||
oracle = new L1GasPriceOracle(owner);
|
||||
|
||||
logAddress("L1_GAS_PRICE_ORACLE_ADDR", address(oracle));
|
||||
}
|
||||
|
||||
function deployL2MessageQueue() internal {
|
||||
if (L2_MESSAGE_QUEUE_PREDEPLOY_ADDR != address(0)) {
|
||||
queue = L2MessageQueue(L2_MESSAGE_QUEUE_PREDEPLOY_ADDR);
|
||||
logAddress("L2_MESSAGE_QUEUE_ADDR", address(L2_MESSAGE_QUEUE_PREDEPLOY_ADDR));
|
||||
return;
|
||||
}
|
||||
|
||||
address owner = vm.addr(L2_DEPLOYER_PRIVATE_KEY);
|
||||
queue = new L2MessageQueue(owner);
|
||||
|
||||
logAddress("L2_MESSAGE_QUEUE_ADDR", address(queue));
|
||||
}
|
||||
|
||||
function deployTxFeeVault() internal {
|
||||
if (L2_TX_FEE_VAULT_PREDEPLOY_ADDR != address(0)) {
|
||||
logAddress("L2_TX_FEE_VAULT_ADDR", address(L2_TX_FEE_VAULT_PREDEPLOY_ADDR));
|
||||
return;
|
||||
}
|
||||
|
||||
address owner = vm.addr(L2_DEPLOYER_PRIVATE_KEY);
|
||||
L2TxFeeVault feeVault = new L2TxFeeVault(address(owner), L1_TX_FEE_RECIPIENT_ADDR, 10 ether);
|
||||
|
||||
logAddress("L2_TX_FEE_VAULT_ADDR", address(feeVault));
|
||||
}
|
||||
|
||||
function deployL2Whitelist() internal {
|
||||
if (L2_WHITELIST_PREDEPLOY_ADDR != address(0)) {
|
||||
logAddress("L2_WHITELIST_ADDR", address(L2_WHITELIST_PREDEPLOY_ADDR));
|
||||
return;
|
||||
}
|
||||
|
||||
address owner = vm.addr(L2_DEPLOYER_PRIVATE_KEY);
|
||||
Whitelist whitelist = new Whitelist(owner);
|
||||
|
||||
logAddress("L2_WHITELIST_ADDR", address(whitelist));
|
||||
}
|
||||
|
||||
function deployL2ScrollMessenger() internal {
|
||||
L2ScrollMessenger impl = new L2ScrollMessenger(L1_SCROLL_MESSENGER_PROXY_ADDR, address(queue));
|
||||
|
||||
logAddress("L2_SCROLL_MESSENGER_IMPLEMENTATION_ADDR", address(impl));
|
||||
}
|
||||
|
||||
function deployL2GatewayRouter() internal {
|
||||
L2GatewayRouter impl = new L2GatewayRouter();
|
||||
TransparentUpgradeableProxy proxy = new TransparentUpgradeableProxy(
|
||||
address(impl),
|
||||
address(proxyAdmin),
|
||||
new bytes(0)
|
||||
);
|
||||
|
||||
logAddress("L2_GATEWAY_ROUTER_IMPLEMENTATION_ADDR", address(impl));
|
||||
logAddress("L2_GATEWAY_ROUTER_PROXY_ADDR", address(proxy));
|
||||
|
||||
router = L2GatewayRouter(address(proxy));
|
||||
}
|
||||
|
||||
function deployScrollStandardERC20Factory() internal {
|
||||
ScrollStandardERC20 tokenImpl = new ScrollStandardERC20();
|
||||
factory = new ScrollStandardERC20Factory(address(tokenImpl));
|
||||
|
||||
logAddress("L2_SCROLL_STANDARD_ERC20_ADDR", address(tokenImpl));
|
||||
logAddress("L2_SCROLL_STANDARD_ERC20_FACTORY_ADDR", address(factory));
|
||||
}
|
||||
|
||||
function deployL2StandardERC20Gateway() internal {
|
||||
L2StandardERC20Gateway impl = new L2StandardERC20Gateway(
|
||||
L1_STANDARD_ERC20_GATEWAY_PROXY_ADDR,
|
||||
address(router),
|
||||
L2_SCROLL_MESSENGER_PROXY_ADDR,
|
||||
address(factory)
|
||||
);
|
||||
|
||||
logAddress("L2_STANDARD_ERC20_GATEWAY_IMPLEMENTATION_ADDR", address(impl));
|
||||
}
|
||||
|
||||
function deployL2ETHGateway() internal {
|
||||
L2ETHGateway impl = new L2ETHGateway(
|
||||
L1_ETH_GATEWAY_PROXY_ADDR,
|
||||
address(router),
|
||||
L2_SCROLL_MESSENGER_PROXY_ADDR
|
||||
);
|
||||
|
||||
logAddress("L2_ETH_GATEWAY_IMPLEMENTATION_ADDR", address(impl));
|
||||
}
|
||||
|
||||
function deployL2WETHGateway() internal {
|
||||
L2WETHGateway impl = new L2WETHGateway(
|
||||
L2_WETH_ADDR,
|
||||
L1_WETH_ADDR,
|
||||
L1_WETH_GATEWAY_PROXY_ADDR,
|
||||
address(router),
|
||||
L2_SCROLL_MESSENGER_PROXY_ADDR
|
||||
);
|
||||
|
||||
logAddress("L2_WETH_GATEWAY_IMPLEMENTATION_ADDR", address(impl));
|
||||
}
|
||||
|
||||
function deployL2CustomERC20Gateway() internal {
|
||||
L2CustomERC20Gateway impl = new L2CustomERC20Gateway(
|
||||
L1_CUSTOM_ERC20_GATEWAY_PROXY_ADDR,
|
||||
address(router),
|
||||
L2_SCROLL_MESSENGER_PROXY_ADDR
|
||||
);
|
||||
|
||||
logAddress("L2_CUSTOM_ERC20_GATEWAY_IMPLEMENTATION_ADDR", address(impl));
|
||||
}
|
||||
|
||||
function deployL2ERC721Gateway() internal {
|
||||
L2ERC721Gateway impl = new L2ERC721Gateway(L1_ERC721_GATEWAY_PROXY_ADDR, L2_SCROLL_MESSENGER_PROXY_ADDR);
|
||||
|
||||
logAddress("L2_ERC721_GATEWAY_IMPLEMENTATION_ADDR", address(impl));
|
||||
}
|
||||
|
||||
function deployL2ERC1155Gateway() internal {
|
||||
L2ERC1155Gateway impl = new L2ERC1155Gateway(L1_ERC1155_GATEWAY_PROXY_ADDR, L2_SCROLL_MESSENGER_PROXY_ADDR);
|
||||
logAddress("L2_ERC1155_GATEWAY_IMPLEMENTATION_ADDR", address(impl));
|
||||
}
|
||||
|
||||
function logAddress(string memory name, address addr) internal view {
|
||||
console.log(string(abi.encodePacked(name, "=", vm.toString(address(addr)))));
|
||||
}
|
||||
}
|
||||
125
contracts/scripts/foundry/DeployL2BridgeProxyPlaceholder.s.sol
Normal file
125
contracts/scripts/foundry/DeployL2BridgeProxyPlaceholder.s.sol
Normal file
@@ -0,0 +1,125 @@
|
||||
// SPDX-License-Identifier: UNLICENSED
|
||||
pragma solidity =0.8.24;
|
||||
|
||||
// solhint-disable no-console
|
||||
|
||||
import {Script} from "forge-std/Script.sol";
|
||||
import {console} from "forge-std/console.sol";
|
||||
|
||||
import {ProxyAdmin} from "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol";
|
||||
import {TransparentUpgradeableProxy} from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol";
|
||||
|
||||
import {EmptyContract} from "../../src/misc/EmptyContract.sol";
|
||||
|
||||
// solhint-disable state-visibility
|
||||
// solhint-disable var-name-mixedcase
|
||||
|
||||
contract DeployL2BridgeProxyPlaceholder is Script {
|
||||
uint256 L2_DEPLOYER_PRIVATE_KEY = vm.envUint("L2_DEPLOYER_PRIVATE_KEY");
|
||||
|
||||
ProxyAdmin proxyAdmin;
|
||||
EmptyContract placeholder;
|
||||
|
||||
function run() external {
|
||||
vm.startBroadcast(L2_DEPLOYER_PRIVATE_KEY);
|
||||
|
||||
// upgradable
|
||||
deployProxyAdmin();
|
||||
deployPlaceHolder();
|
||||
deployL2ScrollMessenger();
|
||||
deployL2ETHGateway();
|
||||
deployL2WETHGateway();
|
||||
deployL2StandardERC20Gateway();
|
||||
deployL2CustomERC20Gateway();
|
||||
deployL2ERC721Gateway();
|
||||
deployL2ERC1155Gateway();
|
||||
|
||||
vm.stopBroadcast();
|
||||
}
|
||||
|
||||
function deployProxyAdmin() internal {
|
||||
proxyAdmin = new ProxyAdmin();
|
||||
|
||||
logAddress("L2_PROXY_ADMIN_ADDR", address(proxyAdmin));
|
||||
}
|
||||
|
||||
function deployPlaceHolder() internal {
|
||||
placeholder = new EmptyContract();
|
||||
|
||||
logAddress("L2_PROXY_IMPLEMENTATION_PLACEHOLDER_ADDR", address(placeholder));
|
||||
}
|
||||
|
||||
function deployL2ScrollMessenger() internal {
|
||||
TransparentUpgradeableProxy proxy = new TransparentUpgradeableProxy(
|
||||
address(placeholder),
|
||||
address(proxyAdmin),
|
||||
new bytes(0)
|
||||
);
|
||||
|
||||
logAddress("L2_SCROLL_MESSENGER_PROXY_ADDR", address(proxy));
|
||||
}
|
||||
|
||||
function deployL2StandardERC20Gateway() internal {
|
||||
TransparentUpgradeableProxy proxy = new TransparentUpgradeableProxy(
|
||||
address(placeholder),
|
||||
address(proxyAdmin),
|
||||
new bytes(0)
|
||||
);
|
||||
|
||||
logAddress("L2_STANDARD_ERC20_GATEWAY_PROXY_ADDR", address(proxy));
|
||||
}
|
||||
|
||||
function deployL2ETHGateway() internal {
|
||||
TransparentUpgradeableProxy proxy = new TransparentUpgradeableProxy(
|
||||
address(placeholder),
|
||||
address(proxyAdmin),
|
||||
new bytes(0)
|
||||
);
|
||||
|
||||
logAddress("L2_ETH_GATEWAY_PROXY_ADDR", address(proxy));
|
||||
}
|
||||
|
||||
function deployL2WETHGateway() internal {
|
||||
TransparentUpgradeableProxy proxy = new TransparentUpgradeableProxy(
|
||||
address(placeholder),
|
||||
address(proxyAdmin),
|
||||
new bytes(0)
|
||||
);
|
||||
|
||||
logAddress("L2_WETH_GATEWAY_PROXY_ADDR", address(proxy));
|
||||
}
|
||||
|
||||
function deployL2CustomERC20Gateway() internal {
|
||||
TransparentUpgradeableProxy proxy = new TransparentUpgradeableProxy(
|
||||
address(placeholder),
|
||||
address(proxyAdmin),
|
||||
new bytes(0)
|
||||
);
|
||||
|
||||
logAddress("L2_CUSTOM_ERC20_GATEWAY_PROXY_ADDR", address(proxy));
|
||||
}
|
||||
|
||||
function deployL2ERC721Gateway() internal {
|
||||
TransparentUpgradeableProxy proxy = new TransparentUpgradeableProxy(
|
||||
address(placeholder),
|
||||
address(proxyAdmin),
|
||||
new bytes(0)
|
||||
);
|
||||
|
||||
logAddress("L2_ERC721_GATEWAY_PROXY_ADDR", address(proxy));
|
||||
}
|
||||
|
||||
function deployL2ERC1155Gateway() internal {
|
||||
TransparentUpgradeableProxy proxy = new TransparentUpgradeableProxy(
|
||||
address(placeholder),
|
||||
address(proxyAdmin),
|
||||
new bytes(0)
|
||||
);
|
||||
|
||||
logAddress("L2_ERC1155_GATEWAY_PROXY_ADDR", address(proxy));
|
||||
}
|
||||
|
||||
function logAddress(string memory name, address addr) internal view {
|
||||
console.log(string(abi.encodePacked(name, "=", vm.toString(address(addr)))));
|
||||
}
|
||||
}
|
||||
66
contracts/scripts/foundry/DeployL2ScrollOwner.s.sol
Normal file
66
contracts/scripts/foundry/DeployL2ScrollOwner.s.sol
Normal file
@@ -0,0 +1,66 @@
|
||||
// SPDX-License-Identifier: UNLICENSED
|
||||
pragma solidity =0.8.24;
|
||||
|
||||
import {Script} from "forge-std/Script.sol";
|
||||
import {console} from "forge-std/console.sol";
|
||||
|
||||
import {TimelockController} from "@openzeppelin/contracts/governance/TimelockController.sol";
|
||||
|
||||
import {ScrollOwner} from "../../src/misc/ScrollOwner.sol";
|
||||
|
||||
// solhint-disable state-visibility
|
||||
// solhint-disable var-name-mixedcase
|
||||
|
||||
contract DeployL2ScrollOwner is Script {
|
||||
string NETWORK = vm.envString("NETWORK");
|
||||
|
||||
uint256 L2_DEPLOYER_PRIVATE_KEY = vm.envUint("L2_DEPLOYER_PRIVATE_KEY");
|
||||
|
||||
address SCROLL_MULTISIG_ADDR = vm.envAddress("L2_SCROLL_MULTISIG_ADDR");
|
||||
|
||||
address SECURITY_COUNCIL_ADDR = vm.envAddress("L2_SECURITY_COUNCIL_ADDR");
|
||||
|
||||
address L2_PROPOSAL_EXECUTOR_ADDR = vm.envAddress("L2_PROPOSAL_EXECUTOR_ADDR");
|
||||
|
||||
function run() external {
|
||||
vm.startBroadcast(L2_DEPLOYER_PRIVATE_KEY);
|
||||
|
||||
deployScrollOwner();
|
||||
|
||||
if (keccak256(abi.encodePacked(NETWORK)) == keccak256(abi.encodePacked("sepolia"))) {
|
||||
// for sepolia
|
||||
deployTimelockController("1D", 1 minutes);
|
||||
deployTimelockController("7D", 7 minutes);
|
||||
deployTimelockController("14D", 14 minutes);
|
||||
} else if (keccak256(abi.encodePacked(NETWORK)) == keccak256(abi.encodePacked("mainnet"))) {
|
||||
// for mainnet
|
||||
deployTimelockController("1D", 1 days);
|
||||
deployTimelockController("7D", 7 days);
|
||||
deployTimelockController("14D", 14 days);
|
||||
}
|
||||
|
||||
vm.stopBroadcast();
|
||||
}
|
||||
|
||||
function deployScrollOwner() internal {
|
||||
ScrollOwner owner = new ScrollOwner();
|
||||
|
||||
logAddress("L2_SCROLL_OWNER_ADDR", address(owner));
|
||||
}
|
||||
|
||||
function deployTimelockController(string memory label, uint256 delay) internal {
|
||||
address[] memory proposers = new address[](1);
|
||||
address[] memory executors = new address[](1);
|
||||
|
||||
proposers[0] = SCROLL_MULTISIG_ADDR;
|
||||
executors[0] = L2_PROPOSAL_EXECUTOR_ADDR;
|
||||
|
||||
TimelockController timelock = new TimelockController(delay, proposers, executors, SECURITY_COUNCIL_ADDR);
|
||||
|
||||
logAddress(string(abi.encodePacked("L2_", label, "_TIMELOCK_ADDR")), address(timelock));
|
||||
}
|
||||
|
||||
function logAddress(string memory name, address addr) internal view {
|
||||
console.log(string(abi.encodePacked(name, "=", vm.toString(address(addr)))));
|
||||
}
|
||||
}
|
||||
63
contracts/scripts/foundry/DeployLidoGateway.s.sol
Normal file
63
contracts/scripts/foundry/DeployLidoGateway.s.sol
Normal file
@@ -0,0 +1,63 @@
|
||||
// SPDX-License-Identifier: UNLICENSED
|
||||
pragma solidity ^0.8.10;
|
||||
|
||||
import {Script} from "forge-std/Script.sol";
|
||||
import {console} from "forge-std/console.sol";
|
||||
|
||||
import {L1LidoGateway} from "../../src/lido/L1LidoGateway.sol";
|
||||
import {L2LidoGateway} from "../../src/lido/L2LidoGateway.sol";
|
||||
|
||||
// solhint-disable state-visibility
|
||||
// solhint-disable var-name-mixedcase
|
||||
|
||||
contract DeployLidoGateway is Script {
|
||||
string NETWORK = vm.envString("NETWORK");
|
||||
|
||||
uint256 L1_DEPLOYER_PRIVATE_KEY = vm.envUint("L1_DEPLOYER_PRIVATE_KEY");
|
||||
|
||||
uint256 L2_DEPLOYER_PRIVATE_KEY = vm.envUint("L2_DEPLOYER_PRIVATE_KEY");
|
||||
|
||||
address L1_WSTETH_ADDR = vm.envAddress("L1_WSTETH_ADDR");
|
||||
|
||||
address L2_WSTETH_ADDR = vm.envAddress("L2_WSTETH_ADDR");
|
||||
|
||||
address L1_SCROLL_MESSENGER_PROXY_ADDR = vm.envAddress("L1_SCROLL_MESSENGER_PROXY_ADDR");
|
||||
address L1_GATEWAY_ROUTER_PROXY_ADDR = vm.envAddress("L1_GATEWAY_ROUTER_PROXY_ADDR");
|
||||
address L1_LIDO_GATEWAY_PROXY_ADDR = vm.envAddress("L1_LIDO_GATEWAY_PROXY_ADDR");
|
||||
|
||||
address L2_SCROLL_MESSENGER_PROXY_ADDR = vm.envAddress("L2_SCROLL_MESSENGER_PROXY_ADDR");
|
||||
address L2_GATEWAY_ROUTER_PROXY_ADDR = vm.envAddress("L2_GATEWAY_ROUTER_PROXY_ADDR");
|
||||
address L2_LIDO_GATEWAY_PROXY_ADDR = vm.envAddress("L2_LIDO_GATEWAY_PROXY_ADDR");
|
||||
|
||||
function run() external {
|
||||
vm.startBroadcast(L2_DEPLOYER_PRIVATE_KEY);
|
||||
|
||||
if (keccak256(abi.encodePacked(NETWORK)) == keccak256(abi.encodePacked("L1"))) {
|
||||
// deploy l1 lido gateway
|
||||
L1LidoGateway gateway = new L1LidoGateway(
|
||||
L1_WSTETH_ADDR,
|
||||
L2_WSTETH_ADDR,
|
||||
L2_LIDO_GATEWAY_PROXY_ADDR,
|
||||
L1_GATEWAY_ROUTER_PROXY_ADDR,
|
||||
L1_SCROLL_MESSENGER_PROXY_ADDR
|
||||
);
|
||||
logAddress("L1_LIDO_GATEWAY_IMPLEMENTATION_ADDR", address(gateway));
|
||||
} else if (keccak256(abi.encodePacked(NETWORK)) == keccak256(abi.encodePacked("L2"))) {
|
||||
// deploy l2 lido gateway
|
||||
L2LidoGateway gateway = new L2LidoGateway(
|
||||
L1_WSTETH_ADDR,
|
||||
L2_WSTETH_ADDR,
|
||||
L1_LIDO_GATEWAY_PROXY_ADDR,
|
||||
L2_GATEWAY_ROUTER_PROXY_ADDR,
|
||||
L2_SCROLL_MESSENGER_PROXY_ADDR
|
||||
);
|
||||
logAddress("L2_LIDO_GATEWAY_IMPLEMENTATION_ADDR", address(gateway));
|
||||
}
|
||||
|
||||
vm.stopBroadcast();
|
||||
}
|
||||
|
||||
function logAddress(string memory name, address addr) internal view {
|
||||
console.log(string(abi.encodePacked(name, "=", vm.toString(address(addr)))));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
// SPDX-License-Identifier: UNLICENSED
|
||||
pragma solidity =0.8.24;
|
||||
|
||||
import {Script} from "forge-std/Script.sol";
|
||||
import {console} from "forge-std/console.sol";
|
||||
|
||||
import {ScrollChainCommitmentVerifier} from "../../src/L1/rollup/ScrollChainCommitmentVerifier.sol";
|
||||
|
||||
contract DeployScrollChainCommitmentVerifier is Script {
|
||||
uint256 L1_DEPLOYER_PRIVATE_KEY = vm.envUint("L1_DEPLOYER_PRIVATE_KEY");
|
||||
|
||||
address L1_SCROLL_CHAIN_PROXY_ADDR = vm.envAddress("L1_SCROLL_CHAIN_PROXY_ADDR");
|
||||
|
||||
address POSEIDON_UNIT2_ADDR = vm.envAddress("POSEIDON_UNIT2_ADDR");
|
||||
|
||||
function run() external {
|
||||
vm.startBroadcast(L1_DEPLOYER_PRIVATE_KEY);
|
||||
|
||||
deployScrollChainCommitmentVerifier();
|
||||
|
||||
vm.stopBroadcast();
|
||||
}
|
||||
|
||||
function deployScrollChainCommitmentVerifier() internal {
|
||||
ScrollChainCommitmentVerifier verifier = new ScrollChainCommitmentVerifier(
|
||||
POSEIDON_UNIT2_ADDR,
|
||||
L1_SCROLL_CHAIN_PROXY_ADDR
|
||||
);
|
||||
|
||||
logAddress("L1_SCROLL_CHAIN_COMMITMENT_VERIFIER", address(verifier));
|
||||
}
|
||||
|
||||
function logAddress(string memory name, address addr) internal view {
|
||||
console.log(string(abi.encodePacked(name, "=", vm.toString(address(addr)))));
|
||||
}
|
||||
}
|
||||
30
contracts/scripts/foundry/DeployWeth.s.sol
Normal file
30
contracts/scripts/foundry/DeployWeth.s.sol
Normal file
@@ -0,0 +1,30 @@
|
||||
// SPDX-License-Identifier: UNLICENSED
|
||||
pragma solidity =0.8.24;
|
||||
|
||||
import {Script} from "forge-std/Script.sol";
|
||||
import {console} from "forge-std/console.sol";
|
||||
|
||||
import {WrappedEther} from "../../src/L2/predeploys/WrappedEther.sol";
|
||||
|
||||
contract DeployWeth is Script {
|
||||
address L1_WETH_ADDR = vm.envAddress("L1_WETH_ADDR");
|
||||
address L2_WETH_ADDR = vm.envAddress("L2_WETH_ADDR");
|
||||
|
||||
function run() external {
|
||||
// deploy weth only if we're running a private L1 network
|
||||
if (L1_WETH_ADDR == address(0)) {
|
||||
uint256 L1_WETH_DEPLOYER_PRIVATE_KEY = vm.envUint("L1_WETH_DEPLOYER_PRIVATE_KEY");
|
||||
vm.startBroadcast(L1_WETH_DEPLOYER_PRIVATE_KEY);
|
||||
WrappedEther weth = new WrappedEther();
|
||||
L1_WETH_ADDR = address(weth);
|
||||
vm.stopBroadcast();
|
||||
}
|
||||
|
||||
logAddress("L1_WETH_ADDR", L1_WETH_ADDR);
|
||||
logAddress("L2_WETH_ADDR", L2_WETH_ADDR);
|
||||
}
|
||||
|
||||
function logAddress(string memory name, address addr) internal view {
|
||||
console.log(string(abi.encodePacked(name, "=", vm.toString(address(addr)))));
|
||||
}
|
||||
}
|
||||
229
contracts/scripts/foundry/InitializeL1BridgeContracts.s.sol
Normal file
229
contracts/scripts/foundry/InitializeL1BridgeContracts.s.sol
Normal file
@@ -0,0 +1,229 @@
|
||||
// SPDX-License-Identifier: UNLICENSED
|
||||
pragma solidity =0.8.24;
|
||||
|
||||
import {Script} from "forge-std/Script.sol";
|
||||
|
||||
import {ProxyAdmin} from "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol";
|
||||
import {ITransparentUpgradeableProxy} from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol";
|
||||
|
||||
import {L1CustomERC20Gateway} from "../../src/L1/gateways/L1CustomERC20Gateway.sol";
|
||||
import {L1ERC1155Gateway} from "../../src/L1/gateways/L1ERC1155Gateway.sol";
|
||||
import {L1ERC721Gateway} from "../../src/L1/gateways/L1ERC721Gateway.sol";
|
||||
import {L1ETHGateway} from "../../src/L1/gateways/L1ETHGateway.sol";
|
||||
import {L1GatewayRouter} from "../../src/L1/gateways/L1GatewayRouter.sol";
|
||||
import {L1ScrollMessenger} from "../../src/L1/L1ScrollMessenger.sol";
|
||||
import {L1StandardERC20Gateway} from "../../src/L1/gateways/L1StandardERC20Gateway.sol";
|
||||
import {L1WETHGateway} from "../../src/L1/gateways/L1WETHGateway.sol";
|
||||
import {MultipleVersionRollupVerifier} from "../../src/L1/rollup/MultipleVersionRollupVerifier.sol";
|
||||
import {ScrollChain} from "../../src/L1/rollup/ScrollChain.sol";
|
||||
import {L1MessageQueue} from "../../src/L1/rollup/L1MessageQueue.sol";
|
||||
import {L1MessageQueueWithGasPriceOracle} from "../../src/L1/rollup/L1MessageQueueWithGasPriceOracle.sol";
|
||||
import {L2GasPriceOracle} from "../../src/L1/rollup/L2GasPriceOracle.sol";
|
||||
import {EnforcedTxGateway} from "../../src/L1/gateways/EnforcedTxGateway.sol";
|
||||
|
||||
// solhint-disable max-states-count
|
||||
// solhint-disable state-visibility
|
||||
// solhint-disable var-name-mixedcase
|
||||
|
||||
contract InitializeL1BridgeContracts is Script {
|
||||
uint256 L1_DEPLOYER_PRIVATE_KEY = vm.envUint("L1_DEPLOYER_PRIVATE_KEY");
|
||||
|
||||
uint256 CHAIN_ID_L2 = vm.envUint("CHAIN_ID_L2");
|
||||
uint256 MAX_TX_IN_CHUNK = vm.envUint("MAX_TX_IN_CHUNK");
|
||||
uint256 MAX_L1_MESSAGE_GAS_LIMIT = vm.envUint("MAX_L1_MESSAGE_GAS_LIMIT");
|
||||
address L1_COMMIT_SENDER_ADDRESS = vm.envAddress("L1_COMMIT_SENDER_ADDRESS");
|
||||
address L1_FINALIZE_SENDER_ADDRESS = vm.envAddress("L1_FINALIZE_SENDER_ADDRESS");
|
||||
address L1_FEE_VAULT_ADDR = vm.envAddress("L1_FEE_VAULT_ADDR");
|
||||
address L1_WETH_ADDR = vm.envAddress("L1_WETH_ADDR");
|
||||
|
||||
address L1_PROXY_ADMIN_ADDR = vm.envAddress("L1_PROXY_ADMIN_ADDR");
|
||||
|
||||
address L1_WHITELIST_ADDR = vm.envAddress("L1_WHITELIST_ADDR");
|
||||
address L1_SCROLL_CHAIN_PROXY_ADDR = vm.envAddress("L1_SCROLL_CHAIN_PROXY_ADDR");
|
||||
address L1_SCROLL_CHAIN_IMPLEMENTATION_ADDR = vm.envAddress("L1_SCROLL_CHAIN_IMPLEMENTATION_ADDR");
|
||||
address L1_MESSAGE_QUEUE_PROXY_ADDR = vm.envAddress("L1_MESSAGE_QUEUE_PROXY_ADDR");
|
||||
address L1_MESSAGE_QUEUE_IMPLEMENTATION_ADDR = vm.envAddress("L1_MESSAGE_QUEUE_IMPLEMENTATION_ADDR");
|
||||
address L2_GAS_PRICE_ORACLE_PROXY_ADDR = vm.envAddress("L2_GAS_PRICE_ORACLE_PROXY_ADDR");
|
||||
address L1_SCROLL_MESSENGER_PROXY_ADDR = vm.envAddress("L1_SCROLL_MESSENGER_PROXY_ADDR");
|
||||
address L1_SCROLL_MESSENGER_IMPLEMENTATION_ADDR = vm.envAddress("L1_SCROLL_MESSENGER_IMPLEMENTATION_ADDR");
|
||||
address L1_GATEWAY_ROUTER_PROXY_ADDR = vm.envAddress("L1_GATEWAY_ROUTER_PROXY_ADDR");
|
||||
address L1_CUSTOM_ERC20_GATEWAY_PROXY_ADDR = vm.envAddress("L1_CUSTOM_ERC20_GATEWAY_PROXY_ADDR");
|
||||
address L1_CUSTOM_ERC20_GATEWAY_IMPLEMENTATION_ADDR = vm.envAddress("L1_CUSTOM_ERC20_GATEWAY_IMPLEMENTATION_ADDR");
|
||||
address L1_ERC721_GATEWAY_PROXY_ADDR = vm.envAddress("L1_ERC721_GATEWAY_PROXY_ADDR");
|
||||
address L1_ERC721_GATEWAY_IMPLEMENTATION_ADDR = vm.envAddress("L1_ERC721_GATEWAY_IMPLEMENTATION_ADDR");
|
||||
address L1_ERC1155_GATEWAY_PROXY_ADDR = vm.envAddress("L1_ERC1155_GATEWAY_PROXY_ADDR");
|
||||
address L1_ERC1155_GATEWAY_IMPLEMENTATION_ADDR = vm.envAddress("L1_ERC1155_GATEWAY_IMPLEMENTATION_ADDR");
|
||||
address L1_ETH_GATEWAY_PROXY_ADDR = vm.envAddress("L1_ETH_GATEWAY_PROXY_ADDR");
|
||||
address L1_ETH_GATEWAY_IMPLEMENTATION_ADDR = vm.envAddress("L1_ETH_GATEWAY_IMPLEMENTATION_ADDR");
|
||||
address L1_STANDARD_ERC20_GATEWAY_PROXY_ADDR = vm.envAddress("L1_STANDARD_ERC20_GATEWAY_PROXY_ADDR");
|
||||
address L1_STANDARD_ERC20_GATEWAY_IMPLEMENTATION_ADDR =
|
||||
vm.envAddress("L1_STANDARD_ERC20_GATEWAY_IMPLEMENTATION_ADDR");
|
||||
address L1_WETH_GATEWAY_PROXY_ADDR = vm.envAddress("L1_WETH_GATEWAY_PROXY_ADDR");
|
||||
address L1_WETH_GATEWAY_IMPLEMENTATION_ADDR = vm.envAddress("L1_WETH_GATEWAY_IMPLEMENTATION_ADDR");
|
||||
address L1_MULTIPLE_VERSION_ROLLUP_VERIFIER_ADDR = vm.envAddress("L1_MULTIPLE_VERSION_ROLLUP_VERIFIER_ADDR");
|
||||
address L1_ENFORCED_TX_GATEWAY_PROXY_ADDR = vm.envAddress("L1_ENFORCED_TX_GATEWAY_PROXY_ADDR");
|
||||
|
||||
address L2_SCROLL_MESSENGER_PROXY_ADDR = vm.envAddress("L2_SCROLL_MESSENGER_PROXY_ADDR");
|
||||
address L2_CUSTOM_ERC20_GATEWAY_PROXY_ADDR = vm.envAddress("L2_CUSTOM_ERC20_GATEWAY_PROXY_ADDR");
|
||||
address L2_ERC721_GATEWAY_PROXY_ADDR = vm.envAddress("L2_ERC721_GATEWAY_PROXY_ADDR");
|
||||
address L2_ERC1155_GATEWAY_PROXY_ADDR = vm.envAddress("L2_ERC1155_GATEWAY_PROXY_ADDR");
|
||||
address L2_ETH_GATEWAY_PROXY_ADDR = vm.envAddress("L2_ETH_GATEWAY_PROXY_ADDR");
|
||||
address L2_STANDARD_ERC20_GATEWAY_PROXY_ADDR = vm.envAddress("L2_STANDARD_ERC20_GATEWAY_PROXY_ADDR");
|
||||
address L2_WETH_GATEWAY_PROXY_ADDR = vm.envAddress("L2_WETH_GATEWAY_PROXY_ADDR");
|
||||
address L2_SCROLL_STANDARD_ERC20_ADDR = vm.envAddress("L2_SCROLL_STANDARD_ERC20_ADDR");
|
||||
address L2_SCROLL_STANDARD_ERC20_FACTORY_ADDR = vm.envAddress("L2_SCROLL_STANDARD_ERC20_FACTORY_ADDR");
|
||||
|
||||
function run() external {
|
||||
ProxyAdmin proxyAdmin = ProxyAdmin(L1_PROXY_ADMIN_ADDR);
|
||||
|
||||
vm.startBroadcast(L1_DEPLOYER_PRIVATE_KEY);
|
||||
|
||||
// note: we use call upgrade(...) and initialize(...) instead of upgradeAndCall(...),
|
||||
// otherwise the contract owner would become ProxyAdmin.
|
||||
|
||||
// initialize ScrollChain
|
||||
proxyAdmin.upgrade(
|
||||
ITransparentUpgradeableProxy(L1_SCROLL_CHAIN_PROXY_ADDR),
|
||||
L1_SCROLL_CHAIN_IMPLEMENTATION_ADDR
|
||||
);
|
||||
|
||||
ScrollChain(L1_SCROLL_CHAIN_PROXY_ADDR).initialize(
|
||||
L1_MESSAGE_QUEUE_PROXY_ADDR,
|
||||
L1_MULTIPLE_VERSION_ROLLUP_VERIFIER_ADDR,
|
||||
MAX_TX_IN_CHUNK
|
||||
);
|
||||
|
||||
ScrollChain(L1_SCROLL_CHAIN_PROXY_ADDR).addSequencer(L1_COMMIT_SENDER_ADDRESS);
|
||||
ScrollChain(L1_SCROLL_CHAIN_PROXY_ADDR).addProver(L1_FINALIZE_SENDER_ADDRESS);
|
||||
|
||||
// initialize L2GasPriceOracle
|
||||
L2GasPriceOracle(L2_GAS_PRICE_ORACLE_PROXY_ADDR).initialize(
|
||||
21000, // _txGas
|
||||
53000, // _txGasContractCreation
|
||||
4, // _zeroGas
|
||||
16 // _nonZeroGas
|
||||
);
|
||||
L2GasPriceOracle(L2_GAS_PRICE_ORACLE_PROXY_ADDR).updateWhitelist(L1_WHITELIST_ADDR);
|
||||
|
||||
// initialize L1MessageQueueWithGasPriceOracle
|
||||
proxyAdmin.upgrade(
|
||||
ITransparentUpgradeableProxy(L1_MESSAGE_QUEUE_PROXY_ADDR),
|
||||
L1_MESSAGE_QUEUE_IMPLEMENTATION_ADDR
|
||||
);
|
||||
|
||||
L1MessageQueueWithGasPriceOracle(L1_MESSAGE_QUEUE_PROXY_ADDR).initialize(
|
||||
L1_SCROLL_MESSENGER_PROXY_ADDR,
|
||||
L1_SCROLL_CHAIN_PROXY_ADDR,
|
||||
L1_ENFORCED_TX_GATEWAY_PROXY_ADDR,
|
||||
L2_GAS_PRICE_ORACLE_PROXY_ADDR,
|
||||
MAX_L1_MESSAGE_GAS_LIMIT
|
||||
);
|
||||
|
||||
L1MessageQueueWithGasPriceOracle(L1_MESSAGE_QUEUE_PROXY_ADDR).initializeV2();
|
||||
|
||||
// initialize L1ScrollMessenger
|
||||
proxyAdmin.upgrade(
|
||||
ITransparentUpgradeableProxy(L1_SCROLL_MESSENGER_PROXY_ADDR),
|
||||
L1_SCROLL_MESSENGER_IMPLEMENTATION_ADDR
|
||||
);
|
||||
|
||||
L1ScrollMessenger(payable(L1_SCROLL_MESSENGER_PROXY_ADDR)).initialize(
|
||||
L2_SCROLL_MESSENGER_PROXY_ADDR,
|
||||
L1_FEE_VAULT_ADDR,
|
||||
L1_SCROLL_CHAIN_PROXY_ADDR,
|
||||
L1_MESSAGE_QUEUE_PROXY_ADDR
|
||||
);
|
||||
|
||||
// initialize EnforcedTxGateway
|
||||
EnforcedTxGateway(payable(L1_ENFORCED_TX_GATEWAY_PROXY_ADDR)).initialize(
|
||||
L1_MESSAGE_QUEUE_PROXY_ADDR,
|
||||
L1_FEE_VAULT_ADDR
|
||||
);
|
||||
|
||||
// initialize L1GatewayRouter
|
||||
L1GatewayRouter(L1_GATEWAY_ROUTER_PROXY_ADDR).initialize(
|
||||
L1_ETH_GATEWAY_PROXY_ADDR,
|
||||
L1_STANDARD_ERC20_GATEWAY_PROXY_ADDR
|
||||
);
|
||||
|
||||
// initialize L1CustomERC20Gateway
|
||||
proxyAdmin.upgrade(
|
||||
ITransparentUpgradeableProxy(L1_CUSTOM_ERC20_GATEWAY_PROXY_ADDR),
|
||||
L1_CUSTOM_ERC20_GATEWAY_IMPLEMENTATION_ADDR
|
||||
);
|
||||
|
||||
L1CustomERC20Gateway(L1_CUSTOM_ERC20_GATEWAY_PROXY_ADDR).initialize(
|
||||
L2_CUSTOM_ERC20_GATEWAY_PROXY_ADDR,
|
||||
L1_GATEWAY_ROUTER_PROXY_ADDR,
|
||||
L1_SCROLL_MESSENGER_PROXY_ADDR
|
||||
);
|
||||
|
||||
// initialize L1ERC1155Gateway
|
||||
proxyAdmin.upgrade(
|
||||
ITransparentUpgradeableProxy(L1_ERC1155_GATEWAY_PROXY_ADDR),
|
||||
L1_ERC1155_GATEWAY_IMPLEMENTATION_ADDR
|
||||
);
|
||||
|
||||
L1ERC1155Gateway(L1_ERC1155_GATEWAY_PROXY_ADDR).initialize(
|
||||
L2_ERC1155_GATEWAY_PROXY_ADDR,
|
||||
L1_SCROLL_MESSENGER_PROXY_ADDR
|
||||
);
|
||||
|
||||
// initialize L1ERC721Gateway
|
||||
proxyAdmin.upgrade(
|
||||
ITransparentUpgradeableProxy(L1_ERC721_GATEWAY_PROXY_ADDR),
|
||||
L1_ERC721_GATEWAY_IMPLEMENTATION_ADDR
|
||||
);
|
||||
|
||||
L1ERC721Gateway(L1_ERC721_GATEWAY_PROXY_ADDR).initialize(
|
||||
L2_ERC721_GATEWAY_PROXY_ADDR,
|
||||
L1_SCROLL_MESSENGER_PROXY_ADDR
|
||||
);
|
||||
|
||||
// initialize L1ETHGateway
|
||||
proxyAdmin.upgrade(ITransparentUpgradeableProxy(L1_ETH_GATEWAY_PROXY_ADDR), L1_ETH_GATEWAY_IMPLEMENTATION_ADDR);
|
||||
|
||||
L1ETHGateway(L1_ETH_GATEWAY_PROXY_ADDR).initialize(
|
||||
L2_ETH_GATEWAY_PROXY_ADDR,
|
||||
L1_GATEWAY_ROUTER_PROXY_ADDR,
|
||||
L1_SCROLL_MESSENGER_PROXY_ADDR
|
||||
);
|
||||
|
||||
// initialize L1StandardERC20Gateway
|
||||
proxyAdmin.upgrade(
|
||||
ITransparentUpgradeableProxy(L1_STANDARD_ERC20_GATEWAY_PROXY_ADDR),
|
||||
L1_STANDARD_ERC20_GATEWAY_IMPLEMENTATION_ADDR
|
||||
);
|
||||
|
||||
L1StandardERC20Gateway(L1_STANDARD_ERC20_GATEWAY_PROXY_ADDR).initialize(
|
||||
L2_STANDARD_ERC20_GATEWAY_PROXY_ADDR,
|
||||
L1_GATEWAY_ROUTER_PROXY_ADDR,
|
||||
L1_SCROLL_MESSENGER_PROXY_ADDR,
|
||||
L2_SCROLL_STANDARD_ERC20_ADDR,
|
||||
L2_SCROLL_STANDARD_ERC20_FACTORY_ADDR
|
||||
);
|
||||
|
||||
// initialize L1WETHGateway
|
||||
proxyAdmin.upgrade(
|
||||
ITransparentUpgradeableProxy(L1_WETH_GATEWAY_PROXY_ADDR),
|
||||
L1_WETH_GATEWAY_IMPLEMENTATION_ADDR
|
||||
);
|
||||
|
||||
L1WETHGateway(payable(L1_WETH_GATEWAY_PROXY_ADDR)).initialize(
|
||||
L2_WETH_GATEWAY_PROXY_ADDR,
|
||||
L1_GATEWAY_ROUTER_PROXY_ADDR,
|
||||
L1_SCROLL_MESSENGER_PROXY_ADDR
|
||||
);
|
||||
|
||||
// set WETH gateway in router
|
||||
{
|
||||
address[] memory _tokens = new address[](1);
|
||||
_tokens[0] = L1_WETH_ADDR;
|
||||
address[] memory _gateways = new address[](1);
|
||||
_gateways[0] = L1_WETH_GATEWAY_PROXY_ADDR;
|
||||
L1GatewayRouter(L1_GATEWAY_ROUTER_PROXY_ADDR).setERC20Gateway(_tokens, _gateways);
|
||||
}
|
||||
|
||||
vm.stopBroadcast();
|
||||
}
|
||||
}
|
||||
275
contracts/scripts/foundry/InitializeL1ScrollOwner.s.sol
Normal file
275
contracts/scripts/foundry/InitializeL1ScrollOwner.s.sol
Normal file
@@ -0,0 +1,275 @@
|
||||
// SPDX-License-Identifier: UNLICENSED
|
||||
pragma solidity =0.8.24;
|
||||
|
||||
import {Script} from "forge-std/Script.sol";
|
||||
|
||||
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
|
||||
import {ProxyAdmin} from "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol";
|
||||
|
||||
import {L1ScrollMessenger} from "../../src/L1/L1ScrollMessenger.sol";
|
||||
import {L1USDCGateway} from "../../src/L1/gateways/usdc/L1USDCGateway.sol";
|
||||
import {EnforcedTxGateway} from "../../src/L1/gateways/EnforcedTxGateway.sol";
|
||||
import {L1CustomERC20Gateway} from "../../src/L1/gateways/L1CustomERC20Gateway.sol";
|
||||
import {L1ERC1155Gateway} from "../../src/L1/gateways/L1ERC1155Gateway.sol";
|
||||
import {L1ERC721Gateway} from "../../src/L1/gateways/L1ERC721Gateway.sol";
|
||||
import {L1GatewayRouter} from "../../src/L1/gateways/L1GatewayRouter.sol";
|
||||
import {L1MessageQueue} from "../../src/L1/rollup/L1MessageQueue.sol";
|
||||
import {ScrollMessengerBase} from "../../src/libraries/ScrollMessengerBase.sol";
|
||||
import {L2GasPriceOracle} from "../../src/L1/rollup/L2GasPriceOracle.sol";
|
||||
import {MultipleVersionRollupVerifier} from "../../src/L1/rollup/MultipleVersionRollupVerifier.sol";
|
||||
import {ScrollChain} from "../../src/L1/rollup/ScrollChain.sol";
|
||||
import {ScrollOwner} from "../../src/misc/ScrollOwner.sol";
|
||||
import {Whitelist} from "../../src/L2/predeploys/Whitelist.sol";
|
||||
|
||||
// solhint-disable max-states-count
|
||||
// solhint-disable state-visibility
|
||||
// solhint-disable var-name-mixedcase
|
||||
|
||||
contract InitializeL1ScrollOwner is Script {
|
||||
uint256 L1_DEPLOYER_PRIVATE_KEY = vm.envUint("L1_DEPLOYER_PRIVATE_KEY");
|
||||
|
||||
bytes32 constant SECURITY_COUNCIL_NO_DELAY_ROLE = keccak256("SECURITY_COUNCIL_NO_DELAY_ROLE");
|
||||
bytes32 constant SCROLL_MULTISIG_NO_DELAY_ROLE = keccak256("SCROLL_MULTISIG_NO_DELAY_ROLE");
|
||||
bytes32 constant EMERGENCY_MULTISIG_NO_DELAY_ROLE = keccak256("EMERGENCY_MULTISIG_NO_DELAY_ROLE");
|
||||
|
||||
bytes32 constant TIMELOCK_1DAY_DELAY_ROLE = keccak256("TIMELOCK_1DAY_DELAY_ROLE");
|
||||
bytes32 constant TIMELOCK_7DAY_DELAY_ROLE = keccak256("TIMELOCK_7DAY_DELAY_ROLE");
|
||||
|
||||
address SCROLL_MULTISIG_ADDR = vm.envAddress("L1_SCROLL_MULTISIG_ADDR");
|
||||
address SECURITY_COUNCIL_ADDR = vm.envAddress("L1_SECURITY_COUNCIL_ADDR");
|
||||
address EMERGENCY_MULTISIG_ADDR = vm.envAddress("L1_EMERGENCY_MULTISIG_ADDR");
|
||||
|
||||
address L1_SCROLL_OWNER_ADDR = vm.envAddress("L1_SCROLL_OWNER_ADDR");
|
||||
address L1_1D_TIMELOCK_ADDR = vm.envAddress("L1_1D_TIMELOCK_ADDR");
|
||||
address L1_7D_TIMELOCK_ADDR = vm.envAddress("L1_7D_TIMELOCK_ADDR");
|
||||
address L1_14D_TIMELOCK_ADDR = vm.envAddress("L1_14D_TIMELOCK_ADDR");
|
||||
|
||||
address L1_PROXY_ADMIN_ADDR = vm.envAddress("L1_PROXY_ADMIN_ADDR");
|
||||
address L1_SCROLL_CHAIN_PROXY_ADDR = vm.envAddress("L1_SCROLL_CHAIN_PROXY_ADDR");
|
||||
address L1_MESSAGE_QUEUE_PROXY_ADDR = vm.envAddress("L1_MESSAGE_QUEUE_PROXY_ADDR");
|
||||
address L2_GAS_PRICE_ORACLE_PROXY_ADDR = vm.envAddress("L2_GAS_PRICE_ORACLE_PROXY_ADDR");
|
||||
address L1_SCROLL_MESSENGER_PROXY_ADDR = vm.envAddress("L1_SCROLL_MESSENGER_PROXY_ADDR");
|
||||
address L1_GATEWAY_ROUTER_PROXY_ADDR = vm.envAddress("L1_GATEWAY_ROUTER_PROXY_ADDR");
|
||||
address L1_CUSTOM_ERC20_GATEWAY_PROXY_ADDR = vm.envAddress("L1_CUSTOM_ERC20_GATEWAY_PROXY_ADDR");
|
||||
address L1_DAI_GATEWAY_PROXY_ADDR = vm.envAddress("L1_DAI_GATEWAY_PROXY_ADDR");
|
||||
address L1_LIDO_GATEWAY_PROXY_ADDR = vm.envAddress("L1_LIDO_GATEWAY_PROXY_ADDR");
|
||||
address L1_ETH_GATEWAY_PROXY_ADDR = vm.envAddress("L1_ETH_GATEWAY_PROXY_ADDR");
|
||||
address L1_STANDARD_ERC20_GATEWAY_PROXY_ADDR = vm.envAddress("L1_STANDARD_ERC20_GATEWAY_PROXY_ADDR");
|
||||
address L1_USDC_GATEWAY_PROXY_ADDR = vm.envAddress("L1_USDC_GATEWAY_PROXY_ADDR");
|
||||
address L1_WETH_GATEWAY_PROXY_ADDR = vm.envAddress("L1_WETH_GATEWAY_PROXY_ADDR");
|
||||
address L1_ERC721_GATEWAY_PROXY_ADDR = vm.envAddress("L1_ERC721_GATEWAY_PROXY_ADDR");
|
||||
address L1_ERC1155_GATEWAY_PROXY_ADDR = vm.envAddress("L1_ERC1155_GATEWAY_PROXY_ADDR");
|
||||
address L1_MULTIPLE_VERSION_ROLLUP_VERIFIER_ADDR = vm.envAddress("L1_MULTIPLE_VERSION_ROLLUP_VERIFIER_ADDR");
|
||||
address L1_ENFORCED_TX_GATEWAY_PROXY_ADDR = vm.envAddress("L1_ENFORCED_TX_GATEWAY_PROXY_ADDR");
|
||||
address L1_WHITELIST_ADDR = vm.envAddress("L1_WHITELIST_ADDR");
|
||||
|
||||
ScrollOwner owner;
|
||||
|
||||
function run() external {
|
||||
vm.startBroadcast(L1_DEPLOYER_PRIVATE_KEY);
|
||||
|
||||
owner = ScrollOwner(payable(L1_SCROLL_OWNER_ADDR));
|
||||
|
||||
// @note we don't config 14D access, since the default admin is a 14D timelock which can access all methods.
|
||||
configProxyAdmin();
|
||||
configScrollChain();
|
||||
configL1MessageQueue();
|
||||
configL1ScrollMessenger();
|
||||
configL2GasPriceOracle();
|
||||
configL1Whitelist();
|
||||
configMultipleVersionRollupVerifier();
|
||||
configL1GatewayRouter();
|
||||
configL1CustomERC20Gateway();
|
||||
configL1ERC721Gateway();
|
||||
configL1ERC1155Gateway();
|
||||
|
||||
configL1USDCGateway();
|
||||
configEnforcedTxGateway();
|
||||
|
||||
grantRoles();
|
||||
transferOwnership();
|
||||
|
||||
vm.stopBroadcast();
|
||||
}
|
||||
|
||||
function transferOwnership() internal {
|
||||
Ownable(L1_PROXY_ADMIN_ADDR).transferOwnership(address(owner));
|
||||
Ownable(L1_SCROLL_CHAIN_PROXY_ADDR).transferOwnership(address(owner));
|
||||
Ownable(L1_MESSAGE_QUEUE_PROXY_ADDR).transferOwnership(address(owner));
|
||||
Ownable(L1_SCROLL_MESSENGER_PROXY_ADDR).transferOwnership(address(owner));
|
||||
Ownable(L1_ENFORCED_TX_GATEWAY_PROXY_ADDR).transferOwnership(address(owner));
|
||||
Ownable(L2_GAS_PRICE_ORACLE_PROXY_ADDR).transferOwnership(address(owner));
|
||||
Ownable(L1_WHITELIST_ADDR).transferOwnership(address(owner));
|
||||
Ownable(L1_MULTIPLE_VERSION_ROLLUP_VERIFIER_ADDR).transferOwnership(address(owner));
|
||||
Ownable(L1_GATEWAY_ROUTER_PROXY_ADDR).transferOwnership(address(owner));
|
||||
Ownable(L1_CUSTOM_ERC20_GATEWAY_PROXY_ADDR).transferOwnership(address(owner));
|
||||
Ownable(L1_DAI_GATEWAY_PROXY_ADDR).transferOwnership(address(owner));
|
||||
Ownable(L1_LIDO_GATEWAY_PROXY_ADDR).transferOwnership(address(owner));
|
||||
Ownable(L1_ETH_GATEWAY_PROXY_ADDR).transferOwnership(address(owner));
|
||||
Ownable(L1_STANDARD_ERC20_GATEWAY_PROXY_ADDR).transferOwnership(address(owner));
|
||||
Ownable(L1_USDC_GATEWAY_PROXY_ADDR).transferOwnership(address(owner));
|
||||
Ownable(L1_WETH_GATEWAY_PROXY_ADDR).transferOwnership(address(owner));
|
||||
Ownable(L1_ERC721_GATEWAY_PROXY_ADDR).transferOwnership(address(owner));
|
||||
Ownable(L1_ERC1155_GATEWAY_PROXY_ADDR).transferOwnership(address(owner));
|
||||
}
|
||||
|
||||
function grantRoles() internal {
|
||||
owner.grantRole(SECURITY_COUNCIL_NO_DELAY_ROLE, SECURITY_COUNCIL_ADDR);
|
||||
owner.grantRole(SCROLL_MULTISIG_NO_DELAY_ROLE, SCROLL_MULTISIG_ADDR);
|
||||
owner.grantRole(EMERGENCY_MULTISIG_NO_DELAY_ROLE, EMERGENCY_MULTISIG_ADDR);
|
||||
owner.grantRole(TIMELOCK_1DAY_DELAY_ROLE, L1_1D_TIMELOCK_ADDR);
|
||||
owner.grantRole(TIMELOCK_7DAY_DELAY_ROLE, L1_7D_TIMELOCK_ADDR);
|
||||
|
||||
owner.grantRole(owner.DEFAULT_ADMIN_ROLE(), L1_14D_TIMELOCK_ADDR);
|
||||
owner.revokeRole(owner.DEFAULT_ADMIN_ROLE(), vm.addr(L1_DEPLOYER_PRIVATE_KEY));
|
||||
}
|
||||
|
||||
function configProxyAdmin() internal {
|
||||
bytes4[] memory _selectors;
|
||||
|
||||
// no delay, security council
|
||||
_selectors = new bytes4[](2);
|
||||
_selectors[0] = ProxyAdmin.upgrade.selector;
|
||||
_selectors[1] = ProxyAdmin.upgradeAndCall.selector;
|
||||
owner.updateAccess(L1_PROXY_ADMIN_ADDR, _selectors, SECURITY_COUNCIL_NO_DELAY_ROLE, true);
|
||||
}
|
||||
|
||||
function configScrollChain() internal {
|
||||
bytes4[] memory _selectors;
|
||||
|
||||
// no delay, scroll multisig and emergency multisig
|
||||
_selectors = new bytes4[](4);
|
||||
_selectors[0] = ScrollChain.revertBatch.selector;
|
||||
_selectors[1] = ScrollChain.removeSequencer.selector;
|
||||
_selectors[2] = ScrollChain.removeProver.selector;
|
||||
_selectors[3] = ScrollChain.setPause.selector;
|
||||
owner.updateAccess(L1_SCROLL_CHAIN_PROXY_ADDR, _selectors, SCROLL_MULTISIG_NO_DELAY_ROLE, true);
|
||||
owner.updateAccess(L1_SCROLL_CHAIN_PROXY_ADDR, _selectors, EMERGENCY_MULTISIG_NO_DELAY_ROLE, true);
|
||||
|
||||
// delay 1 day, scroll multisig
|
||||
_selectors = new bytes4[](2);
|
||||
_selectors[0] = ScrollChain.addSequencer.selector;
|
||||
_selectors[1] = ScrollChain.addProver.selector;
|
||||
owner.updateAccess(L1_SCROLL_CHAIN_PROXY_ADDR, _selectors, TIMELOCK_1DAY_DELAY_ROLE, true);
|
||||
|
||||
// delay 7 day, scroll multisig
|
||||
_selectors = new bytes4[](1);
|
||||
_selectors[0] = ScrollChain.updateMaxNumTxInChunk.selector;
|
||||
owner.updateAccess(L1_SCROLL_CHAIN_PROXY_ADDR, _selectors, TIMELOCK_7DAY_DELAY_ROLE, true);
|
||||
}
|
||||
|
||||
function configL1MessageQueue() internal {
|
||||
bytes4[] memory _selectors;
|
||||
|
||||
// delay 1 day, scroll multisig
|
||||
_selectors = new bytes4[](2);
|
||||
_selectors[0] = L1MessageQueue.updateGasOracle.selector;
|
||||
_selectors[1] = L1MessageQueue.updateMaxGasLimit.selector;
|
||||
owner.updateAccess(L1_MESSAGE_QUEUE_PROXY_ADDR, _selectors, TIMELOCK_1DAY_DELAY_ROLE, true);
|
||||
}
|
||||
|
||||
function configL1ScrollMessenger() internal {
|
||||
bytes4[] memory _selectors;
|
||||
|
||||
// no delay, scroll multisig and emergency multisig
|
||||
_selectors = new bytes4[](1);
|
||||
_selectors[0] = ScrollMessengerBase.setPause.selector;
|
||||
owner.updateAccess(L1_SCROLL_MESSENGER_PROXY_ADDR, _selectors, SCROLL_MULTISIG_NO_DELAY_ROLE, true);
|
||||
owner.updateAccess(L1_SCROLL_MESSENGER_PROXY_ADDR, _selectors, EMERGENCY_MULTISIG_NO_DELAY_ROLE, true);
|
||||
|
||||
// delay 1 day, scroll multisig
|
||||
_selectors = new bytes4[](1);
|
||||
_selectors[0] = L1ScrollMessenger.updateMaxReplayTimes.selector;
|
||||
owner.updateAccess(L1_SCROLL_MESSENGER_PROXY_ADDR, _selectors, TIMELOCK_1DAY_DELAY_ROLE, true);
|
||||
}
|
||||
|
||||
function configL2GasPriceOracle() internal {
|
||||
bytes4[] memory _selectors;
|
||||
|
||||
// no delay, scroll multisig and emergency multisig
|
||||
_selectors = new bytes4[](1);
|
||||
_selectors[0] = L2GasPriceOracle.setIntrinsicParams.selector;
|
||||
owner.updateAccess(L2_GAS_PRICE_ORACLE_PROXY_ADDR, _selectors, SCROLL_MULTISIG_NO_DELAY_ROLE, true);
|
||||
owner.updateAccess(L2_GAS_PRICE_ORACLE_PROXY_ADDR, _selectors, EMERGENCY_MULTISIG_NO_DELAY_ROLE, true);
|
||||
}
|
||||
|
||||
function configL1Whitelist() internal {
|
||||
bytes4[] memory _selectors;
|
||||
|
||||
// delay 1 day, scroll multisig
|
||||
_selectors = new bytes4[](1);
|
||||
_selectors[0] = Whitelist.updateWhitelistStatus.selector;
|
||||
owner.updateAccess(L1_WHITELIST_ADDR, _selectors, TIMELOCK_1DAY_DELAY_ROLE, true);
|
||||
}
|
||||
|
||||
function configMultipleVersionRollupVerifier() internal {
|
||||
bytes4[] memory _selectors;
|
||||
|
||||
// no delay, security council
|
||||
_selectors = new bytes4[](1);
|
||||
_selectors[0] = MultipleVersionRollupVerifier.updateVerifier.selector;
|
||||
owner.updateAccess(L1_MULTIPLE_VERSION_ROLLUP_VERIFIER_ADDR, _selectors, SECURITY_COUNCIL_NO_DELAY_ROLE, true);
|
||||
|
||||
// delay 7 day, scroll multisig
|
||||
_selectors = new bytes4[](1);
|
||||
_selectors[0] = MultipleVersionRollupVerifier.updateVerifier.selector;
|
||||
owner.updateAccess(L1_MULTIPLE_VERSION_ROLLUP_VERIFIER_ADDR, _selectors, TIMELOCK_7DAY_DELAY_ROLE, true);
|
||||
}
|
||||
|
||||
function configL1GatewayRouter() internal {
|
||||
bytes4[] memory _selectors;
|
||||
|
||||
// delay 1 day, scroll multisig
|
||||
_selectors = new bytes4[](1);
|
||||
_selectors[0] = L1GatewayRouter.setERC20Gateway.selector;
|
||||
owner.updateAccess(L1_GATEWAY_ROUTER_PROXY_ADDR, _selectors, TIMELOCK_1DAY_DELAY_ROLE, true);
|
||||
}
|
||||
|
||||
function configL1CustomERC20Gateway() internal {
|
||||
bytes4[] memory _selectors;
|
||||
|
||||
// delay 1 day, scroll multisig
|
||||
_selectors = new bytes4[](1);
|
||||
_selectors[0] = L1CustomERC20Gateway.updateTokenMapping.selector;
|
||||
owner.updateAccess(L1_CUSTOM_ERC20_GATEWAY_PROXY_ADDR, _selectors, TIMELOCK_1DAY_DELAY_ROLE, true);
|
||||
}
|
||||
|
||||
function configL1ERC721Gateway() internal {
|
||||
bytes4[] memory _selectors;
|
||||
|
||||
// delay 1 day, scroll multisig
|
||||
_selectors = new bytes4[](1);
|
||||
_selectors[0] = L1ERC721Gateway.updateTokenMapping.selector;
|
||||
owner.updateAccess(L1_ERC721_GATEWAY_PROXY_ADDR, _selectors, TIMELOCK_1DAY_DELAY_ROLE, true);
|
||||
}
|
||||
|
||||
function configL1ERC1155Gateway() internal {
|
||||
bytes4[] memory _selectors;
|
||||
|
||||
// delay 1 day, scroll multisig
|
||||
_selectors = new bytes4[](1);
|
||||
_selectors[0] = L1ERC1155Gateway.updateTokenMapping.selector;
|
||||
owner.updateAccess(L1_ERC1155_GATEWAY_PROXY_ADDR, _selectors, TIMELOCK_1DAY_DELAY_ROLE, true);
|
||||
}
|
||||
|
||||
function configL1USDCGateway() internal {
|
||||
bytes4[] memory _selectors;
|
||||
|
||||
// delay 7 day, scroll multisig
|
||||
_selectors = new bytes4[](3);
|
||||
_selectors[0] = L1USDCGateway.updateCircleCaller.selector;
|
||||
_selectors[1] = L1USDCGateway.pauseDeposit.selector;
|
||||
_selectors[2] = L1USDCGateway.pauseWithdraw.selector;
|
||||
owner.updateAccess(L1_USDC_GATEWAY_PROXY_ADDR, _selectors, TIMELOCK_7DAY_DELAY_ROLE, true);
|
||||
}
|
||||
|
||||
function configEnforcedTxGateway() internal {
|
||||
bytes4[] memory _selectors;
|
||||
|
||||
// no delay, scroll multisig and emergency multisig
|
||||
_selectors = new bytes4[](1);
|
||||
_selectors[0] = EnforcedTxGateway.setPause.selector;
|
||||
owner.updateAccess(L1_ENFORCED_TX_GATEWAY_PROXY_ADDR, _selectors, SCROLL_MULTISIG_NO_DELAY_ROLE, true);
|
||||
owner.updateAccess(L1_ENFORCED_TX_GATEWAY_PROXY_ADDR, _selectors, EMERGENCY_MULTISIG_NO_DELAY_ROLE, true);
|
||||
}
|
||||
}
|
||||
180
contracts/scripts/foundry/InitializeL2BridgeContracts.s.sol
Normal file
180
contracts/scripts/foundry/InitializeL2BridgeContracts.s.sol
Normal file
@@ -0,0 +1,180 @@
|
||||
// SPDX-License-Identifier: UNLICENSED
|
||||
pragma solidity =0.8.24;
|
||||
|
||||
import {Script} from "forge-std/Script.sol";
|
||||
|
||||
import {ProxyAdmin} from "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol";
|
||||
import {ITransparentUpgradeableProxy} from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol";
|
||||
|
||||
import {L2ScrollMessenger} from "../../src/L2/L2ScrollMessenger.sol";
|
||||
import {L2CustomERC20Gateway} from "../../src/L2/gateways/L2CustomERC20Gateway.sol";
|
||||
import {L2ERC1155Gateway} from "../../src/L2/gateways/L2ERC1155Gateway.sol";
|
||||
import {L2ERC721Gateway} from "../../src/L2/gateways/L2ERC721Gateway.sol";
|
||||
import {L2ETHGateway} from "../../src/L2/gateways/L2ETHGateway.sol";
|
||||
import {L2GatewayRouter} from "../../src/L2/gateways/L2GatewayRouter.sol";
|
||||
import {L2StandardERC20Gateway} from "../../src/L2/gateways/L2StandardERC20Gateway.sol";
|
||||
import {L2WETHGateway} from "../../src/L2/gateways/L2WETHGateway.sol";
|
||||
import {L2MessageQueue} from "../../src/L2/predeploys/L2MessageQueue.sol";
|
||||
import {L2TxFeeVault} from "../../src/L2/predeploys/L2TxFeeVault.sol";
|
||||
import {L1GasPriceOracle} from "../../src/L2/predeploys/L1GasPriceOracle.sol";
|
||||
import {Whitelist} from "../../src/L2/predeploys/Whitelist.sol";
|
||||
import {ScrollStandardERC20Factory} from "../../src/libraries/token/ScrollStandardERC20Factory.sol";
|
||||
|
||||
// solhint-disable max-states-count
|
||||
// solhint-disable state-visibility
|
||||
// solhint-disable var-name-mixedcase
|
||||
|
||||
contract InitializeL2BridgeContracts is Script {
|
||||
uint256 deployerPrivateKey = vm.envUint("L2_DEPLOYER_PRIVATE_KEY");
|
||||
|
||||
address L2_WETH_ADDR = vm.envAddress("L2_WETH_ADDR");
|
||||
address L2_PROXY_ADMIN_ADDR = vm.envAddress("L2_PROXY_ADMIN_ADDR");
|
||||
|
||||
address L1_SCROLL_MESSENGER_PROXY_ADDR = vm.envAddress("L1_SCROLL_MESSENGER_PROXY_ADDR");
|
||||
address L1_GATEWAY_ROUTER_PROXY_ADDR = vm.envAddress("L1_GATEWAY_ROUTER_PROXY_ADDR");
|
||||
address L1_CUSTOM_ERC20_GATEWAY_PROXY_ADDR = vm.envAddress("L1_CUSTOM_ERC20_GATEWAY_PROXY_ADDR");
|
||||
address L1_ERC721_GATEWAY_PROXY_ADDR = vm.envAddress("L1_ERC721_GATEWAY_PROXY_ADDR");
|
||||
address L1_ERC1155_GATEWAY_PROXY_ADDR = vm.envAddress("L1_ERC1155_GATEWAY_PROXY_ADDR");
|
||||
address L1_ETH_GATEWAY_PROXY_ADDR = vm.envAddress("L1_ETH_GATEWAY_PROXY_ADDR");
|
||||
address L1_STANDARD_ERC20_GATEWAY_PROXY_ADDR = vm.envAddress("L1_STANDARD_ERC20_GATEWAY_PROXY_ADDR");
|
||||
address L1_WETH_GATEWAY_PROXY_ADDR = vm.envAddress("L1_WETH_GATEWAY_PROXY_ADDR");
|
||||
|
||||
address L2_TX_FEE_VAULT_ADDR = vm.envAddress("L2_TX_FEE_VAULT_ADDR");
|
||||
address L1_GAS_PRICE_ORACLE_ADDR = vm.envAddress("L1_GAS_PRICE_ORACLE_ADDR");
|
||||
address L2_WHITELIST_ADDR = vm.envAddress("L2_WHITELIST_ADDR");
|
||||
address L2_MESSAGE_QUEUE_ADDR = vm.envAddress("L2_MESSAGE_QUEUE_ADDR");
|
||||
|
||||
address L2_SCROLL_MESSENGER_PROXY_ADDR = vm.envAddress("L2_SCROLL_MESSENGER_PROXY_ADDR");
|
||||
address L2_SCROLL_MESSENGER_IMPLEMENTATION_ADDR = vm.envAddress("L2_SCROLL_MESSENGER_IMPLEMENTATION_ADDR");
|
||||
address L2_GATEWAY_ROUTER_PROXY_ADDR = vm.envAddress("L2_GATEWAY_ROUTER_PROXY_ADDR");
|
||||
address L2_CUSTOM_ERC20_GATEWAY_PROXY_ADDR = vm.envAddress("L2_CUSTOM_ERC20_GATEWAY_PROXY_ADDR");
|
||||
address L2_CUSTOM_ERC20_GATEWAY_IMPLEMENTATION_ADDR = vm.envAddress("L2_CUSTOM_ERC20_GATEWAY_IMPLEMENTATION_ADDR");
|
||||
address L2_ERC721_GATEWAY_PROXY_ADDR = vm.envAddress("L2_ERC721_GATEWAY_PROXY_ADDR");
|
||||
address L2_ERC721_GATEWAY_IMPLEMENTATION_ADDR = vm.envAddress("L2_ERC721_GATEWAY_IMPLEMENTATION_ADDR");
|
||||
address L2_ERC1155_GATEWAY_PROXY_ADDR = vm.envAddress("L2_ERC1155_GATEWAY_PROXY_ADDR");
|
||||
address L2_ERC1155_GATEWAY_IMPLEMENTATION_ADDR = vm.envAddress("L2_ERC1155_GATEWAY_IMPLEMENTATION_ADDR");
|
||||
address L2_ETH_GATEWAY_PROXY_ADDR = vm.envAddress("L2_ETH_GATEWAY_PROXY_ADDR");
|
||||
address L2_ETH_GATEWAY_IMPLEMENTATION_ADDR = vm.envAddress("L2_ETH_GATEWAY_IMPLEMENTATION_ADDR");
|
||||
address L2_STANDARD_ERC20_GATEWAY_PROXY_ADDR = vm.envAddress("L2_STANDARD_ERC20_GATEWAY_PROXY_ADDR");
|
||||
address L2_STANDARD_ERC20_GATEWAY_IMPLEMENTATION_ADDR =
|
||||
vm.envAddress("L2_STANDARD_ERC20_GATEWAY_IMPLEMENTATION_ADDR");
|
||||
address L2_WETH_GATEWAY_PROXY_ADDR = vm.envAddress("L2_WETH_GATEWAY_PROXY_ADDR");
|
||||
address L2_WETH_GATEWAY_IMPLEMENTATION_ADDR = vm.envAddress("L2_WETH_GATEWAY_IMPLEMENTATION_ADDR");
|
||||
address L2_SCROLL_STANDARD_ERC20_FACTORY_ADDR = vm.envAddress("L2_SCROLL_STANDARD_ERC20_FACTORY_ADDR");
|
||||
|
||||
function run() external {
|
||||
ProxyAdmin proxyAdmin = ProxyAdmin(L2_PROXY_ADMIN_ADDR);
|
||||
|
||||
vm.startBroadcast(deployerPrivateKey);
|
||||
|
||||
// note: we use call upgrade(...) and initialize(...) instead of upgradeAndCall(...),
|
||||
// otherwise the contract owner would become ProxyAdmin.
|
||||
|
||||
// initialize L2MessageQueue
|
||||
L2MessageQueue(L2_MESSAGE_QUEUE_ADDR).initialize(L2_SCROLL_MESSENGER_PROXY_ADDR);
|
||||
|
||||
// initialize L2TxFeeVault
|
||||
L2TxFeeVault(payable(L2_TX_FEE_VAULT_ADDR)).updateMessenger(L2_SCROLL_MESSENGER_PROXY_ADDR);
|
||||
|
||||
// initialize L1GasPriceOracle
|
||||
L1GasPriceOracle(L1_GAS_PRICE_ORACLE_ADDR).updateWhitelist(L2_WHITELIST_ADDR);
|
||||
|
||||
// initialize L2ScrollMessenger
|
||||
proxyAdmin.upgrade(
|
||||
ITransparentUpgradeableProxy(L2_SCROLL_MESSENGER_PROXY_ADDR),
|
||||
L2_SCROLL_MESSENGER_IMPLEMENTATION_ADDR
|
||||
);
|
||||
|
||||
L2ScrollMessenger(payable(L2_SCROLL_MESSENGER_PROXY_ADDR)).initialize(L1_SCROLL_MESSENGER_PROXY_ADDR);
|
||||
|
||||
// initialize L2GatewayRouter
|
||||
L2GatewayRouter(L2_GATEWAY_ROUTER_PROXY_ADDR).initialize(
|
||||
L2_ETH_GATEWAY_PROXY_ADDR,
|
||||
L2_STANDARD_ERC20_GATEWAY_PROXY_ADDR
|
||||
);
|
||||
|
||||
// initialize L2CustomERC20Gateway
|
||||
proxyAdmin.upgrade(
|
||||
ITransparentUpgradeableProxy(L2_CUSTOM_ERC20_GATEWAY_PROXY_ADDR),
|
||||
L2_CUSTOM_ERC20_GATEWAY_IMPLEMENTATION_ADDR
|
||||
);
|
||||
|
||||
L2CustomERC20Gateway(L2_CUSTOM_ERC20_GATEWAY_PROXY_ADDR).initialize(
|
||||
L1_CUSTOM_ERC20_GATEWAY_PROXY_ADDR,
|
||||
L2_GATEWAY_ROUTER_PROXY_ADDR,
|
||||
L2_SCROLL_MESSENGER_PROXY_ADDR
|
||||
);
|
||||
|
||||
// initialize L2ERC1155Gateway
|
||||
proxyAdmin.upgrade(
|
||||
ITransparentUpgradeableProxy(L2_ERC1155_GATEWAY_PROXY_ADDR),
|
||||
L2_ERC1155_GATEWAY_IMPLEMENTATION_ADDR
|
||||
);
|
||||
|
||||
L2ERC1155Gateway(L2_ERC1155_GATEWAY_PROXY_ADDR).initialize(
|
||||
L1_ERC1155_GATEWAY_PROXY_ADDR,
|
||||
L2_SCROLL_MESSENGER_PROXY_ADDR
|
||||
);
|
||||
|
||||
// initialize L2ERC721Gateway
|
||||
proxyAdmin.upgrade(
|
||||
ITransparentUpgradeableProxy(L2_ERC721_GATEWAY_PROXY_ADDR),
|
||||
L2_ERC721_GATEWAY_IMPLEMENTATION_ADDR
|
||||
);
|
||||
|
||||
L2ERC721Gateway(L2_ERC721_GATEWAY_PROXY_ADDR).initialize(
|
||||
L1_ERC721_GATEWAY_PROXY_ADDR,
|
||||
L2_SCROLL_MESSENGER_PROXY_ADDR
|
||||
);
|
||||
|
||||
// initialize L2ETHGateway
|
||||
proxyAdmin.upgrade(ITransparentUpgradeableProxy(L2_ETH_GATEWAY_PROXY_ADDR), L2_ETH_GATEWAY_IMPLEMENTATION_ADDR);
|
||||
|
||||
L2ETHGateway(L2_ETH_GATEWAY_PROXY_ADDR).initialize(
|
||||
L1_ETH_GATEWAY_PROXY_ADDR,
|
||||
L2_GATEWAY_ROUTER_PROXY_ADDR,
|
||||
L2_SCROLL_MESSENGER_PROXY_ADDR
|
||||
);
|
||||
|
||||
// initialize L2StandardERC20Gateway
|
||||
proxyAdmin.upgrade(
|
||||
ITransparentUpgradeableProxy(L2_STANDARD_ERC20_GATEWAY_PROXY_ADDR),
|
||||
L2_STANDARD_ERC20_GATEWAY_IMPLEMENTATION_ADDR
|
||||
);
|
||||
|
||||
L2StandardERC20Gateway(L2_STANDARD_ERC20_GATEWAY_PROXY_ADDR).initialize(
|
||||
L1_STANDARD_ERC20_GATEWAY_PROXY_ADDR,
|
||||
L2_GATEWAY_ROUTER_PROXY_ADDR,
|
||||
L2_SCROLL_MESSENGER_PROXY_ADDR,
|
||||
L2_SCROLL_STANDARD_ERC20_FACTORY_ADDR
|
||||
);
|
||||
|
||||
// initialize L2WETHGateway
|
||||
proxyAdmin.upgrade(
|
||||
ITransparentUpgradeableProxy(L2_WETH_GATEWAY_PROXY_ADDR),
|
||||
L2_WETH_GATEWAY_IMPLEMENTATION_ADDR
|
||||
);
|
||||
|
||||
L2WETHGateway(payable(L2_WETH_GATEWAY_PROXY_ADDR)).initialize(
|
||||
L1_WETH_GATEWAY_PROXY_ADDR,
|
||||
L2_GATEWAY_ROUTER_PROXY_ADDR,
|
||||
L2_SCROLL_MESSENGER_PROXY_ADDR
|
||||
);
|
||||
|
||||
// set WETH gateway in router
|
||||
{
|
||||
address[] memory _tokens = new address[](1);
|
||||
_tokens[0] = L2_WETH_ADDR;
|
||||
address[] memory _gateways = new address[](1);
|
||||
_gateways[0] = L2_WETH_GATEWAY_PROXY_ADDR;
|
||||
L2GatewayRouter(L2_GATEWAY_ROUTER_PROXY_ADDR).setERC20Gateway(_tokens, _gateways);
|
||||
}
|
||||
|
||||
// initialize ScrollStandardERC20Factory
|
||||
ScrollStandardERC20Factory(L2_SCROLL_STANDARD_ERC20_FACTORY_ADDR).transferOwnership(
|
||||
L2_STANDARD_ERC20_GATEWAY_PROXY_ADDR
|
||||
);
|
||||
|
||||
vm.stopBroadcast();
|
||||
}
|
||||
}
|
||||
228
contracts/scripts/foundry/InitializeL2ScrollOwner.s.sol
Normal file
228
contracts/scripts/foundry/InitializeL2ScrollOwner.s.sol
Normal file
@@ -0,0 +1,228 @@
|
||||
// SPDX-License-Identifier: UNLICENSED
|
||||
pragma solidity =0.8.24;
|
||||
|
||||
import {Script} from "forge-std/Script.sol";
|
||||
|
||||
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
|
||||
import {AccessControl} from "@openzeppelin/contracts/access/AccessControl.sol";
|
||||
import {AccessControlEnumerable} from "@openzeppelin/contracts/access/AccessControlEnumerable.sol";
|
||||
import {ProxyAdmin} from "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol";
|
||||
|
||||
import {L2USDCGateway} from "../../src/L2/gateways/usdc/L2USDCGateway.sol";
|
||||
import {L2CustomERC20Gateway} from "../../src/L2/gateways/L2CustomERC20Gateway.sol";
|
||||
import {L2CustomERC20Gateway} from "../../src/L2/gateways/L2CustomERC20Gateway.sol";
|
||||
import {L2ERC1155Gateway} from "../../src/L2/gateways/L2ERC1155Gateway.sol";
|
||||
import {L2ERC721Gateway} from "../../src/L2/gateways/L2ERC721Gateway.sol";
|
||||
import {L2GatewayRouter} from "../../src/L2/gateways/L2GatewayRouter.sol";
|
||||
import {ScrollMessengerBase} from "../../src/libraries/ScrollMessengerBase.sol";
|
||||
import {L1GasPriceOracle} from "../../src/L2/predeploys/L1GasPriceOracle.sol";
|
||||
import {L2TxFeeVault} from "../../src/L2/predeploys/L2TxFeeVault.sol";
|
||||
import {Whitelist} from "../../src/L2/predeploys/Whitelist.sol";
|
||||
import {ScrollOwner} from "../../src/misc/ScrollOwner.sol";
|
||||
|
||||
// solhint-disable max-states-count
|
||||
// solhint-disable state-visibility
|
||||
// solhint-disable var-name-mixedcase
|
||||
|
||||
contract InitializeL2ScrollOwner is Script {
|
||||
uint256 L2_DEPLOYER_PRIVATE_KEY = vm.envUint("L2_DEPLOYER_PRIVATE_KEY");
|
||||
|
||||
bytes32 constant SECURITY_COUNCIL_NO_DELAY_ROLE = keccak256("SECURITY_COUNCIL_NO_DELAY_ROLE");
|
||||
bytes32 constant SCROLL_MULTISIG_NO_DELAY_ROLE = keccak256("SCROLL_MULTISIG_NO_DELAY_ROLE");
|
||||
bytes32 constant EMERGENCY_MULTISIG_NO_DELAY_ROLE = keccak256("EMERGENCY_MULTISIG_NO_DELAY_ROLE");
|
||||
|
||||
bytes32 constant TIMELOCK_1DAY_DELAY_ROLE = keccak256("TIMELOCK_1DAY_DELAY_ROLE");
|
||||
bytes32 constant TIMELOCK_7DAY_DELAY_ROLE = keccak256("TIMELOCK_7DAY_DELAY_ROLE");
|
||||
|
||||
address SCROLL_MULTISIG_ADDR = vm.envAddress("L2_SCROLL_MULTISIG_ADDR");
|
||||
address SECURITY_COUNCIL_ADDR = vm.envAddress("L2_SECURITY_COUNCIL_ADDR");
|
||||
address EMERGENCY_MULTISIG_ADDR = vm.envAddress("L2_EMERGENCY_MULTISIG_ADDR");
|
||||
|
||||
address L2_SCROLL_OWNER_ADDR = vm.envAddress("L2_SCROLL_OWNER_ADDR");
|
||||
address L2_1D_TIMELOCK_ADDR = vm.envAddress("L2_1D_TIMELOCK_ADDR");
|
||||
address L2_7D_TIMELOCK_ADDR = vm.envAddress("L2_7D_TIMELOCK_ADDR");
|
||||
address L2_14D_TIMELOCK_ADDR = vm.envAddress("L2_14D_TIMELOCK_ADDR");
|
||||
|
||||
address L2_PROXY_ADMIN_ADDR = vm.envAddress("L2_PROXY_ADMIN_ADDR");
|
||||
address L2_TX_FEE_VAULT_ADDR = vm.envAddress("L2_TX_FEE_VAULT_ADDR");
|
||||
address L1_GAS_PRICE_ORACLE_ADDR = vm.envAddress("L1_GAS_PRICE_ORACLE_ADDR");
|
||||
address L2_WHITELIST_ADDR = vm.envAddress("L2_WHITELIST_ADDR");
|
||||
address L2_MESSAGE_QUEUE_ADDR = vm.envAddress("L2_MESSAGE_QUEUE_ADDR");
|
||||
|
||||
address L2_SCROLL_MESSENGER_PROXY_ADDR = vm.envAddress("L2_SCROLL_MESSENGER_PROXY_ADDR");
|
||||
address L2_GATEWAY_ROUTER_PROXY_ADDR = vm.envAddress("L2_GATEWAY_ROUTER_PROXY_ADDR");
|
||||
address L2_CUSTOM_ERC20_GATEWAY_PROXY_ADDR = vm.envAddress("L2_CUSTOM_ERC20_GATEWAY_PROXY_ADDR");
|
||||
address L2_DAI_GATEWAY_PROXY_ADDR = vm.envAddress("L2_DAI_GATEWAY_PROXY_ADDR");
|
||||
address L2_LIDO_GATEWAY_PROXY_ADDR = vm.envAddress("L2_LIDO_GATEWAY_PROXY_ADDR");
|
||||
address L2_ETH_GATEWAY_PROXY_ADDR = vm.envAddress("L2_ETH_GATEWAY_PROXY_ADDR");
|
||||
address L2_STANDARD_ERC20_GATEWAY_PROXY_ADDR = vm.envAddress("L2_STANDARD_ERC20_GATEWAY_PROXY_ADDR");
|
||||
address L2_USDC_GATEWAY_PROXY_ADDR = vm.envAddress("L2_USDC_GATEWAY_PROXY_ADDR");
|
||||
address L2_WETH_GATEWAY_PROXY_ADDR = vm.envAddress("L2_WETH_GATEWAY_PROXY_ADDR");
|
||||
address L2_ERC721_GATEWAY_PROXY_ADDR = vm.envAddress("L2_ERC721_GATEWAY_PROXY_ADDR");
|
||||
address L2_ERC1155_GATEWAY_PROXY_ADDR = vm.envAddress("L2_ERC1155_GATEWAY_PROXY_ADDR");
|
||||
|
||||
address L2_USDC_PROXY_ADDR = vm.envAddress("L2_USDC_PROXY_ADDR");
|
||||
address L2_USDC_MASTER_MINTER_ADDR = vm.envAddress("L2_USDC_MASTER_MINTER_ADDR");
|
||||
|
||||
ScrollOwner owner;
|
||||
|
||||
function run() external {
|
||||
vm.startBroadcast(L2_DEPLOYER_PRIVATE_KEY);
|
||||
|
||||
owner = ScrollOwner(payable(L2_SCROLL_OWNER_ADDR));
|
||||
|
||||
// @note we don't config 14D access, since the default admin is a 14D timelock which can access all methods.
|
||||
configProxyAdmin();
|
||||
configL1GasPriceOracle();
|
||||
configL2TxFeeVault();
|
||||
configL2Whitelist();
|
||||
configL2ScrollMessenger();
|
||||
configL2GatewayRouter();
|
||||
configL2CustomERC20Gateway();
|
||||
configL2ERC721Gateway();
|
||||
configL2ERC1155Gateway();
|
||||
|
||||
configL2USDCGateway();
|
||||
|
||||
grantRoles();
|
||||
transferOwnership();
|
||||
|
||||
vm.stopBroadcast();
|
||||
}
|
||||
|
||||
function transferOwnership() internal {
|
||||
Ownable(L2_PROXY_ADMIN_ADDR).transferOwnership(address(owner));
|
||||
Ownable(L2_MESSAGE_QUEUE_ADDR).transferOwnership(address(owner));
|
||||
Ownable(L1_GAS_PRICE_ORACLE_ADDR).transferOwnership(address(owner));
|
||||
Ownable(L2_TX_FEE_VAULT_ADDR).transferOwnership(address(owner));
|
||||
Ownable(L2_WHITELIST_ADDR).transferOwnership(address(owner));
|
||||
Ownable(L2_SCROLL_MESSENGER_PROXY_ADDR).transferOwnership(address(owner));
|
||||
Ownable(L2_GATEWAY_ROUTER_PROXY_ADDR).transferOwnership(address(owner));
|
||||
Ownable(L2_CUSTOM_ERC20_GATEWAY_PROXY_ADDR).transferOwnership(address(owner));
|
||||
Ownable(L2_DAI_GATEWAY_PROXY_ADDR).transferOwnership(address(owner));
|
||||
Ownable(L2_LIDO_GATEWAY_PROXY_ADDR).transferOwnership(address(owner));
|
||||
Ownable(L2_ETH_GATEWAY_PROXY_ADDR).transferOwnership(address(owner));
|
||||
Ownable(L2_STANDARD_ERC20_GATEWAY_PROXY_ADDR).transferOwnership(address(owner));
|
||||
Ownable(L2_WETH_GATEWAY_PROXY_ADDR).transferOwnership(address(owner));
|
||||
Ownable(L2_ERC721_GATEWAY_PROXY_ADDR).transferOwnership(address(owner));
|
||||
Ownable(L2_ERC1155_GATEWAY_PROXY_ADDR).transferOwnership(address(owner));
|
||||
|
||||
Ownable(L2_USDC_GATEWAY_PROXY_ADDR).transferOwnership(address(owner));
|
||||
Ownable(L2_USDC_PROXY_ADDR).transferOwnership(address(owner));
|
||||
Ownable(L2_USDC_MASTER_MINTER_ADDR).transferOwnership(address(owner));
|
||||
}
|
||||
|
||||
function grantRoles() internal {
|
||||
owner.grantRole(SECURITY_COUNCIL_NO_DELAY_ROLE, SECURITY_COUNCIL_ADDR);
|
||||
owner.grantRole(SCROLL_MULTISIG_NO_DELAY_ROLE, SCROLL_MULTISIG_ADDR);
|
||||
owner.grantRole(EMERGENCY_MULTISIG_NO_DELAY_ROLE, EMERGENCY_MULTISIG_ADDR);
|
||||
owner.grantRole(TIMELOCK_1DAY_DELAY_ROLE, L2_1D_TIMELOCK_ADDR);
|
||||
owner.grantRole(TIMELOCK_7DAY_DELAY_ROLE, L2_7D_TIMELOCK_ADDR);
|
||||
|
||||
owner.grantRole(owner.DEFAULT_ADMIN_ROLE(), L2_14D_TIMELOCK_ADDR);
|
||||
owner.revokeRole(owner.DEFAULT_ADMIN_ROLE(), vm.addr(L2_DEPLOYER_PRIVATE_KEY));
|
||||
}
|
||||
|
||||
function configProxyAdmin() internal {
|
||||
bytes4[] memory _selectors;
|
||||
|
||||
// no delay, security council
|
||||
_selectors = new bytes4[](2);
|
||||
_selectors[0] = ProxyAdmin.upgrade.selector;
|
||||
_selectors[1] = ProxyAdmin.upgradeAndCall.selector;
|
||||
owner.updateAccess(L2_PROXY_ADMIN_ADDR, _selectors, SECURITY_COUNCIL_NO_DELAY_ROLE, true);
|
||||
}
|
||||
|
||||
function configL1GasPriceOracle() internal {
|
||||
bytes4[] memory _selectors;
|
||||
|
||||
// no delay, scroll multisig and emergency multisig
|
||||
_selectors = new bytes4[](2);
|
||||
_selectors[0] = L1GasPriceOracle.setOverhead.selector;
|
||||
_selectors[1] = L1GasPriceOracle.setScalar.selector;
|
||||
owner.updateAccess(L1_GAS_PRICE_ORACLE_ADDR, _selectors, SCROLL_MULTISIG_NO_DELAY_ROLE, true);
|
||||
owner.updateAccess(L1_GAS_PRICE_ORACLE_ADDR, _selectors, EMERGENCY_MULTISIG_NO_DELAY_ROLE, true);
|
||||
}
|
||||
|
||||
function configL2TxFeeVault() internal {
|
||||
bytes4[] memory _selectors;
|
||||
|
||||
// no delay, scroll multisig and emergency multisig
|
||||
_selectors = new bytes4[](1);
|
||||
_selectors[0] = L2TxFeeVault.updateMinWithdrawAmount.selector;
|
||||
owner.updateAccess(L2_TX_FEE_VAULT_ADDR, _selectors, SCROLL_MULTISIG_NO_DELAY_ROLE, true);
|
||||
owner.updateAccess(L2_TX_FEE_VAULT_ADDR, _selectors, EMERGENCY_MULTISIG_NO_DELAY_ROLE, true);
|
||||
}
|
||||
|
||||
function configL2Whitelist() internal {
|
||||
bytes4[] memory _selectors;
|
||||
|
||||
// delay 1 day, scroll multisig
|
||||
_selectors = new bytes4[](1);
|
||||
_selectors[0] = Whitelist.updateWhitelistStatus.selector;
|
||||
owner.updateAccess(L2_WHITELIST_ADDR, _selectors, TIMELOCK_1DAY_DELAY_ROLE, true);
|
||||
}
|
||||
|
||||
function configL2ScrollMessenger() internal {
|
||||
bytes4[] memory _selectors;
|
||||
|
||||
// no delay, scroll multisig and emergency multisig
|
||||
_selectors = new bytes4[](1);
|
||||
_selectors[0] = ScrollMessengerBase.setPause.selector;
|
||||
owner.updateAccess(L2_SCROLL_MESSENGER_PROXY_ADDR, _selectors, SCROLL_MULTISIG_NO_DELAY_ROLE, true);
|
||||
owner.updateAccess(L2_SCROLL_MESSENGER_PROXY_ADDR, _selectors, EMERGENCY_MULTISIG_NO_DELAY_ROLE, true);
|
||||
}
|
||||
|
||||
function configL2GatewayRouter() internal {
|
||||
bytes4[] memory _selectors;
|
||||
|
||||
// delay 1 day, scroll multisig
|
||||
_selectors = new bytes4[](1);
|
||||
_selectors[0] = L2GatewayRouter.setERC20Gateway.selector;
|
||||
owner.updateAccess(L2_GATEWAY_ROUTER_PROXY_ADDR, _selectors, TIMELOCK_1DAY_DELAY_ROLE, true);
|
||||
}
|
||||
|
||||
function configL2CustomERC20Gateway() internal {
|
||||
bytes4[] memory _selectors;
|
||||
|
||||
// delay 1 day, scroll multisig
|
||||
_selectors = new bytes4[](1);
|
||||
_selectors[0] = L2CustomERC20Gateway.updateTokenMapping.selector;
|
||||
owner.updateAccess(L2_CUSTOM_ERC20_GATEWAY_PROXY_ADDR, _selectors, TIMELOCK_1DAY_DELAY_ROLE, true);
|
||||
}
|
||||
|
||||
function configL2ERC721Gateway() internal {
|
||||
bytes4[] memory _selectors;
|
||||
|
||||
// delay 1 day, scroll multisig
|
||||
_selectors = new bytes4[](1);
|
||||
_selectors[0] = L2ERC721Gateway.updateTokenMapping.selector;
|
||||
owner.updateAccess(L2_ERC721_GATEWAY_PROXY_ADDR, _selectors, TIMELOCK_1DAY_DELAY_ROLE, true);
|
||||
}
|
||||
|
||||
function configL2ERC1155Gateway() internal {
|
||||
bytes4[] memory _selectors;
|
||||
|
||||
// delay 1 day, scroll multisig
|
||||
_selectors = new bytes4[](1);
|
||||
_selectors[0] = L2ERC1155Gateway.updateTokenMapping.selector;
|
||||
owner.updateAccess(L2_ERC1155_GATEWAY_PROXY_ADDR, _selectors, TIMELOCK_1DAY_DELAY_ROLE, true);
|
||||
}
|
||||
|
||||
function configL2USDCGateway() internal {
|
||||
bytes4[] memory _selectors;
|
||||
|
||||
// delay 7 day, scroll multisig
|
||||
_selectors = new bytes4[](3);
|
||||
_selectors[0] = L2USDCGateway.updateCircleCaller.selector;
|
||||
_selectors[1] = L2USDCGateway.pauseDeposit.selector;
|
||||
_selectors[2] = L2USDCGateway.pauseWithdraw.selector;
|
||||
owner.updateAccess(L2_USDC_GATEWAY_PROXY_ADDR, _selectors, TIMELOCK_7DAY_DELAY_ROLE, true);
|
||||
|
||||
// delay 7 day, scroll multisig
|
||||
_selectors = new bytes4[](1);
|
||||
_selectors[0] = Ownable.transferOwnership.selector;
|
||||
owner.updateAccess(L2_USDC_PROXY_ADDR, _selectors, TIMELOCK_7DAY_DELAY_ROLE, true);
|
||||
owner.updateAccess(L2_USDC_MASTER_MINTER_ADDR, _selectors, TIMELOCK_7DAY_DELAY_ROLE, true);
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user