Compare commits

..

56 Commits

Author SHA1 Message Date
zimpha
782078834d xxx 2023-08-10 22:00:44 +08:00
zimpha
e8eb1e7264 fix version 2023-08-10 21:40:50 +08:00
zimpha
5b6cd3fdfb merge with develop branch 2023-08-10 21:20:35 +08:00
Steven
e8f5251ae2 fix: upgrade libzkp to use scroll-prover v0.5.12 (#769)
Co-authored-by: HAOYUatHZ <37070449+HAOYUatHZ@users.noreply.github.com>
2023-08-10 20:10:30 +08:00
HAOYUatHZ
d10438ae0f ci(github): temp fix gacts/install-geth-tools (#770) 2023-08-10 19:28:31 +08:00
maskpp
a7ce900aa7 ci(github): add prover_stats_api docker build action (#768)
Co-authored-by: HAOYUatHZ <37070449+HAOYUatHZ@users.noreply.github.com>
2023-08-10 17:21:27 +08:00
maskpp
49ec0b8fa8 fix(integration test): fix TestCoordinatorProverInteraction (#765)
Co-authored-by: HAOYUatHZ <37070449+HAOYUatHZ@users.noreply.github.com>
Co-authored-by: Péter Garamvölgyi <peter@scroll.io>
2023-08-10 17:20:25 +08:00
georgehao
244e5e915a fix(coordinator): fix update proving_status bug (#759)
Co-authored-by: HAOYUatHZ <37070449+HAOYUatHZ@users.noreply.github.com>
2023-08-10 17:02:53 +08:00
HAOYUatHZ
dc53d6d022 ci(github): speed up docker builds (#766) 2023-08-10 14:59:51 +08:00
HAOYUatHZ
6dc89a9c0b fix coordinator version in docker (#764) 2023-08-10 00:24:54 +08:00
Steven
9e450a7b0f fix: upgrade libzkp to use scroll-prover v0.5.11 (#761) 2023-08-09 22:48:18 +08:00
HAOYUatHZ
af76593c1d feat(coordinator): reject old-version prover (#757) 2023-08-09 21:25:46 +08:00
colin
a2ae697f79 fix(relayer): increase ProcessCommittedBatches loop time (#762) 2023-08-09 19:59:13 +08:00
colin
41b07bd05a feat(rollup-relayer): add calldata log in commitBatch failed tx (#760) 2023-08-09 17:28:07 +08:00
maskpp
90dc0911d3 feat: add prover-stats-api docker file (#758) 2023-08-09 17:10:38 +08:00
HAOYUatHZ
3f775ae7bc feat(coordinator): add ProverVersion to ProverTask (#756) 2023-08-09 15:43:29 +08:00
Steven
674b801005 fix: upgrade libzkp to use scroll-prover v0.5.10 (#754) 2023-08-08 21:08:32 +08:00
georgehao
c5b80937ce fix(coordinator): fix get task exceed the attempt times (#753)
Co-authored-by: HAOYUatHZ <37070449+HAOYUatHZ@users.noreply.github.com>
2023-08-08 12:50:27 +08:00
Xi Lin
ea3e08ab2a fix(contracts): initialize maxGasLimit by vm.env (#752) 2023-08-08 11:53:30 +08:00
Steven
0360f44ff6 fix: upgrade libzkp to use scroll-prover v0.5.8 (#750) 2023-08-07 23:17:19 +08:00
Xinran
1b57982368 fix(prover): fix ZK_VERSION in Makefile (#751) 2023-08-07 22:51:25 +08:00
Steven
b09c2bbecb fix: upgrade to use scroll-prover v0.5.7 (#749) 2023-08-07 20:51:24 +08:00
HAOYUatHZ
7d2a516be1 bump version (#747) 2023-08-07 16:30:56 +08:00
Péter Garamvölgyi
ee55fe3d51 fix: do not update batch rollup_status to FinalizationFailed on tx error (#745) 2023-08-07 16:18:57 +08:00
Steven
09d7764dcb fix: upgrade libzkp to use scroll-prover v0.5.6 (#744) 2023-08-07 12:26:19 +08:00
Xi Lin
4cd199b3b3 test(contracts): add unit tests when num txs < num L1 msgs (#742)
Co-authored-by: Péter Garamvölgyi <peter@scroll.io>
2023-08-07 05:13:04 +02:00
Péter Garamvölgyi
ced64e8563 refactor: remove debug log (#743) 2023-08-06 21:56:43 +02:00
Péter Garamvölgyi
336d76e0dc fix: Consider skipped messages in block.numTransaction encoding (#741) 2023-08-06 21:45:58 +02:00
Péter Garamvölgyi
a0ca0e6295 feat: commit batch extra logs (#740) 2023-08-06 21:06:35 +02:00
HAOYUatHZ
9f73554b31 fix(libzkp): pin ethers-core version (#739)
Co-authored-by: Your Name <you@example.com>
2023-08-07 01:03:27 +08:00
Péter Garamvölgyi
44c7d75544 refactor: make failed batch proof log more explicit (#738)
Co-authored-by: georgehao <haohongfan@gmail.com>
2023-08-06 18:09:05 +02:00
Xi Lin
f1073e7d13 refactor(contracts): OZ-L1-N03 Events Should Emit Old and New Value (#673)
Co-authored-by: Péter Garamvölgyi <peter@scroll.io>
2023-08-06 14:18:13 +02:00
georgehao
816a3b4a15 fix(coordinator&prover): jwt token expired bug (#736)
Co-authored-by: colinlyguo <colinlyguo@scroll.io>
2023-08-06 19:56:16 +08:00
HAOYUatHZ
11fac0330f feat(coordinator): add log to valid proof result (#734) 2023-08-06 17:36:02 +08:00
Xi Lin
e2185ffe20 refactor(contracts): OZ-L1-L03 Code Redundancy, OZ-L1-N15 Unused Imports and OZ-L2-N02 Unused Imports (#698)
Co-authored-by: Péter Garamvölgyi <peter@scroll.io>
2023-08-06 10:21:18 +02:00
ChuhanJin
b0628b67ee fix(bridge-history-api): fix txhashes api error (#732)
Co-authored-by: Péter Garamvölgyi <peter@scroll.io>
2023-08-06 09:51:37 +02:00
Xi Lin
bb0a0d0d09 feat(contracts): better access control of the ScrollChain (#700)
Co-authored-by: Péter Garamvölgyi <peter@scroll.io>
2023-08-06 09:43:39 +02:00
Péter Garamvölgyi
b977e5a62f fix: handle importGenesisBatch in bridge-history calldata decoder (#731) 2023-08-06 07:41:29 +02:00
Péter Garamvölgyi
1b77f9044a fix(bridge-history): do not fail if all proofs in DB are empty (#730) 2023-08-06 06:48:22 +02:00
Péter Garamvölgyi
46adbc7c0c fix: update ScrollChain ABI (#729) 2023-08-06 05:39:36 +02:00
HAOYUatHZ
9ee65119d8 feat(prover): make l2gethClient optional for batch_prover (#724)
Co-authored-by: colinlyguo <colinlyguo@scroll.io>
Co-authored-by: colin <102356659+colinlyguo@users.noreply.github.com>
Co-authored-by: Péter Garamvölgyi <peter@scroll.io>
2023-08-06 04:26:27 +02:00
colin
fb1c800532 fix(coordinator & prover): bug fixes (#727)
Co-authored-by: georgehao <haohongfan@gmail.com>
2023-08-06 04:11:47 +02:00
Steven
2baad2ecad fix: upgrade libzkp with scroll-prover v0.5.3 (#728) 2023-08-06 06:14:59 +08:00
ChuhanJin
bdf2968771 fix(bridge-history-api): Fix cors (#726) 2023-08-05 13:55:30 +02:00
Steven
4d09e13b0c feat: upgrade libzkp to v0.5.2 (#725) 2023-08-05 19:29:26 +08:00
georgehao
a98a2ff4b5 feat(coordinator): fix login replay attack (#723)
Co-authored-by: Péter Garamvölgyi <peter@scroll.io>
Co-authored-by: colinlyguo <colinlyguo@scroll.io>
2023-08-05 10:58:59 +02:00
colin
2a0c7ae6b5 refactor(coordinator & prover): RESTful API (#696)
Co-authored-by: georgehao <haohongfan@gmail.com>
Co-authored-by: HAOYUatHZ <37070449+HAOYUatHZ@users.noreply.github.com>
2023-08-05 08:27:07 +02:00
HAOYUatHZ
b0b6a3db5e test(prover): add tests for TracesToChunkInfo (#719)
Co-authored-by: Steven Gu <asongala@163.com>
2023-08-05 10:21:14 +08:00
zimpha
4e76fb0976 fix failed unit tests 2023-05-11 03:51:18 +08:00
zimpha
b457094247 Merge remote-tracking branch 'origin/develop' into feat/usdc_gateway 2023-05-11 03:41:34 +08:00
zimpha
33f572deb3 add calldata forward in L1/L2 USDC gateway 2023-05-09 14:17:10 +08:00
zimpha
8ccf3b16dd Merge branch 'develop' into feat/usdc_gateway 2023-05-09 14:14:19 +08:00
zimpha
ae694267fc check nonce in _cctpMessage 2023-05-09 14:13:24 +08:00
zimpha
1f383ca2f5 add USDC Gateway with CCTP 2023-04-19 01:10:00 +08:00
zimpha
2bf31f046e add unit tests for L2USDCGateway 2023-04-17 13:17:52 +08:00
zimpha
5b5b45bebb add usdc gateway 2023-04-17 12:29:54 +08:00
143 changed files with 2840 additions and 1121 deletions

View File

@@ -43,6 +43,8 @@ jobs:
version: '0.8.16'
- name: Install Geth Tools
uses: gacts/install-geth-tools@v1
with:
version: 1.10.19
- name: Lint
working-directory: 'bridge'
run: |
@@ -92,6 +94,8 @@ jobs:
version: '0.8.16'
- name: Install Geth Tools
uses: gacts/install-geth-tools@v1
with:
version: 1.10.19
- name: Build prerequisites
run: |
make dev_docker

View File

@@ -88,6 +88,8 @@ jobs:
version: '0.8.16'
- name: Install Geth Tools
uses: gacts/install-geth-tools@v1
with:
version: 1.10.19
- name: Build prerequisites
run: |
make dev_docker

View File

@@ -104,6 +104,8 @@ jobs:
version: '0.8.16'
- name: Install Geth Tools
uses: gacts/install-geth-tools@v1
with:
version: 1.10.19
- name: Build prerequisites
run: |
make dev_docker

View File

@@ -81,6 +81,8 @@ jobs:
version: '0.8.16'
- name: Install Geth Tools
uses: gacts/install-geth-tools@v1
with:
version: 1.10.19
- name: Build prerequisites
run: |
make dev_docker

View File

@@ -6,7 +6,7 @@ on:
- v**
jobs:
build-and-push:
event_watcher:
runs-on: ubuntu-latest
steps:
- name: Checkout code
@@ -27,6 +27,18 @@ jobs:
tags: scrolltech/event-watcher:${{github.ref_name}}
# cache-from: type=gha,scope=${{ github.workflow }}
# cache-to: type=gha,scope=${{ github.workflow }}
gas_oracle:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@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: Build and push gas_oracle docker
uses: docker/build-push-action@v2
with:
@@ -36,6 +48,18 @@ jobs:
tags: scrolltech/gas-oracle:${{github.ref_name}}
# cache-from: type=gha,scope=${{ github.workflow }}
# cache-to: type=gha,scope=${{ github.workflow }}
msg_relayer:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@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: Build and push msg_relayer docker
uses: docker/build-push-action@v2
with:
@@ -45,6 +69,18 @@ jobs:
tags: scrolltech/msg-relayer:${{github.ref_name}}
# cache-from: type=gha,scope=${{ github.workflow }}
# cache-to: type=gha,scope=${{ github.workflow }}
rollup_relayer:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@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: Build and push rollup_relayer docker
uses: docker/build-push-action@v2
with:
@@ -54,6 +90,18 @@ jobs:
tags: scrolltech/rollup-relayer:${{github.ref_name}}
# cache-from: type=gha,scope=${{ github.workflow }}
# cache-to: type=gha,scope=${{ github.workflow }}
bridgehistoryapi-cross-msg-fetcher:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@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: Build and push bridgehistoryapi-cross-msg-fetcher docker
uses: docker/build-push-action@v2
with:
@@ -63,6 +111,18 @@ jobs:
tags: scrolltech/bridgehistoryapi-cross-msg-fetcher:${{github.ref_name}}
# cache-from: type=gha,scope=${{ github.workflow }}
# cache-to: type=gha,scope=${{ github.workflow }}
bridgehistoryapi-server:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@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: Build and push bridgehistoryapi-server docker
uses: docker/build-push-action@v2
with:
@@ -72,6 +132,18 @@ jobs:
tags: scrolltech/bridgehistoryapi-server:${{github.ref_name}}
# cache-from: type=gha,scope=${{ github.workflow }}
# cache-to: type=gha,scope=${{ github.workflow }}
coordinator:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@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: Build and push coordinator docker
uses: docker/build-push-action@v2
with:
@@ -81,3 +153,24 @@ jobs:
tags: scrolltech/coordinator:${{github.ref_name}}
# cache-from: type=gha,scope=${{ github.workflow }}
# cache-to: type=gha,scope=${{ github.workflow }}
prover-stats-api:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@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: Build and push prover-stats-api docker
uses: docker/build-push-action@v2
with:
context: .
file: ./build/dockerfiles/prover-stats-api.Dockerfile
push: true
tags: scrolltech/prover-stats-api:${{github.ref_name}}
# cache-from: type=gha,scope=${{ github.workflow }}
# cache-to: type=gha,scope=${{ github.workflow }}

View File

@@ -33,6 +33,8 @@ jobs:
version: '0.8.16'
- name: Install Geth Tools
uses: gacts/install-geth-tools@v1
with:
version: 1.10.19
- name: Build prerequisites
run: |
make dev_docker

File diff suppressed because one or more lines are too long

View File

@@ -53,11 +53,11 @@ func (m *MsgProofUpdater) Start() {
continue
}
latestBatchIndexWithProof, err := m.l2SentMsgOrm.GetLatestL2SentMsgBatchIndex(m.ctx)
log.Info("latest batc with proof", "batch_index", latestBatchIndexWithProof)
if err != nil {
log.Error("MsgProofUpdater: Can not get latest L2SentMsgBatchIndex: ", "err", err)
continue
}
log.Info("latest batch with proof", "batch_index", latestBatchIndexWithProof)
var start uint64
if latestBatchIndexWithProof < 0 {
start = 1

View File

@@ -15,6 +15,7 @@ func Route(router *gin.Engine, conf *config.Config) {
router.Use(cors.New(cors.Config{
AllowOrigins: []string{"*"},
AllowMethods: []string{"GET", "POST", "PUT", "DELETE"},
AllowHeaders: []string{"Origin", "Content-Type", "Authorization"},
AllowCredentials: true,
MaxAge: 12 * time.Hour,
}))

View File

@@ -204,7 +204,7 @@ func (c *CrossMsg) DeleteL1CrossMsgAfterHeight(ctx context.Context, height uint6
// GetL2CrossMsgByHash returns layer2 cross message by given hash
func (c *CrossMsg) GetL2CrossMsgByHash(ctx context.Context, l2Hash common.Hash) (*CrossMsg, error) {
var result CrossMsg
err := c.db.WithContext(ctx).Model(&CrossMsg{}).Where("layer2_hash = ? AND msg_type = ?", l2Hash.String(), Layer1Msg).First(&result).Error
err := c.db.WithContext(ctx).Model(&CrossMsg{}).Where("layer2_hash = ? AND msg_type = ?", l2Hash.String(), Layer2Msg).First(&result).Error
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, nil

View File

@@ -2,6 +2,7 @@ package orm
import (
"context"
"errors"
"fmt"
"time"
@@ -102,6 +103,9 @@ func (l *L2SentMsg) GetLatestL2SentMsgBatchIndex(ctx context.Context) (int64, er
Select("batch_index").
First(&result).
Error
if err != nil && errors.Is(err, gorm.ErrRecordNotFound) {
return -1, nil
}
if err != nil {
return -1, fmt.Errorf("L2SentMsg.GetLatestL2SentMsgBatchIndex error: %w", err)
}

View File

@@ -1,7 +1,6 @@
package utils
import (
"bytes"
"context"
"encoding/binary"
"errors"
@@ -76,6 +75,14 @@ func GetBatchRangeFromCalldataV2(calldata []byte) (uint64, uint64, uint64, error
method := backendabi.ScrollChainV2ABI.Methods["commitBatch"]
values, err := method.Inputs.Unpack(calldata[4:])
if err != nil {
// special case: import genesis batch
method = backendabi.ScrollChainV2ABI.Methods["importGenesisBatch"]
_, err2 := method.Inputs.Unpack(calldata[4:])
if err2 == nil {
// genesis batch
return 0, 0, 0, nil
}
// none of "commitBatch" and "importGenesisBatch" match, give up
return 0, 0, 0, err
}
args := commitBatchArgs{}
@@ -110,48 +117,3 @@ func GetBatchRangeFromCalldataV2(calldata []byte) (uint64, uint64, uint64, error
return batchIndex, startBlock, finishBlock, err
}
// GetBatchRangeFromCalldataV1 find the block range from calldata, both inclusive.
func GetBatchRangeFromCalldataV1(calldata []byte) ([]uint64, []uint64, []uint64, error) {
var batchIndices []uint64
var startBlocks []uint64
var finishBlocks []uint64
if bytes.Equal(calldata[0:4], common.Hex2Bytes("cb905499")) {
// commitBatches
method := backendabi.ScrollChainABI.Methods["commitBatches"]
values, err := method.Inputs.Unpack(calldata[4:])
if err != nil {
return batchIndices, startBlocks, finishBlocks, err
}
args := make([]backendabi.IScrollChainBatch, len(values))
err = method.Inputs.Copy(&args, values)
if err != nil {
return batchIndices, startBlocks, finishBlocks, err
}
for i := 0; i < len(args); i++ {
batchIndices = append(batchIndices, args[i].BatchIndex)
startBlocks = append(startBlocks, args[i].Blocks[0].BlockNumber)
finishBlocks = append(finishBlocks, args[i].Blocks[len(args[i].Blocks)-1].BlockNumber)
}
} else if bytes.Equal(calldata[0:4], common.Hex2Bytes("8c73235d")) {
// commitBatch
method := backendabi.ScrollChainABI.Methods["commitBatch"]
values, err := method.Inputs.Unpack(calldata[4:])
if err != nil {
return batchIndices, startBlocks, finishBlocks, err
}
args := backendabi.IScrollChainBatch{}
err = method.Inputs.Copy(&args, values)
if err != nil {
return batchIndices, startBlocks, finishBlocks, err
}
batchIndices = append(batchIndices, args.BatchIndex)
startBlocks = append(startBlocks, args.Blocks[0].BlockNumber)
finishBlocks = append(finishBlocks, args.Blocks[len(args.Blocks)-1].BlockNumber)
} else {
return batchIndices, startBlocks, finishBlocks, errors.New("invalid selector")
}
return batchIndices, startBlocks, finishBlocks, nil
}

View File

@@ -1,7 +1,6 @@
package utils_test
import (
"os"
"testing"
"github.com/ethereum/go-ethereum/common"
@@ -34,31 +33,11 @@ func TestGetBatchRangeFromCalldataV2(t *testing.T) {
assert.Equal(t, start, uint64(10))
assert.Equal(t, finish, uint64(20))
assert.Equal(t, batchIndex, uint64(2))
}
func TestGetBatchRangeFromCalldataV1(t *testing.T) {
calldata, err := os.ReadFile("../testdata/commit-batches-0x3095e91db7ba4a6fbf4654d607db322e58ff5579c502219c8024acaea74cf311.txt")
// genesis batch
batchIndex, start, finish, err = utils.GetBatchRangeFromCalldataV2(common.Hex2Bytes("3fdeecb200000000000000000000000000000000000000000000000000000000000000402dcb5308098d24a37fc1487a229fcedb09fa4343ede39cbad365bc925535bb09000000000000000000000000000000000000000000000000000000000000005900000000000000000000000000000000000000000000000000c252bc9780c4d83cf11f14b8cd03c92c4d18ce07710ba836d31d12da216c8330000000000000000000000000000000000000000000000000000000000000000000000000000000"))
assert.NoError(t, err)
// multiple batches
batchIndices, startBlocks, finishBlocks, err := utils.GetBatchRangeFromCalldataV1(common.Hex2Bytes(string(calldata[:])))
assert.NoError(t, err)
assert.Equal(t, len(batchIndices), 5)
assert.Equal(t, len(startBlocks), 5)
assert.Equal(t, len(finishBlocks), 5)
assert.Equal(t, batchIndices[0], uint64(1))
assert.Equal(t, batchIndices[1], uint64(2))
assert.Equal(t, batchIndices[2], uint64(3))
assert.Equal(t, batchIndices[3], uint64(4))
assert.Equal(t, batchIndices[4], uint64(5))
assert.Equal(t, startBlocks[0], uint64(1))
assert.Equal(t, startBlocks[1], uint64(6))
assert.Equal(t, startBlocks[2], uint64(7))
assert.Equal(t, startBlocks[3], uint64(19))
assert.Equal(t, startBlocks[4], uint64(20))
assert.Equal(t, finishBlocks[0], uint64(5))
assert.Equal(t, finishBlocks[1], uint64(6))
assert.Equal(t, finishBlocks[2], uint64(18))
assert.Equal(t, finishBlocks[3], uint64(19))
assert.Equal(t, finishBlocks[4], uint64(20))
assert.Equal(t, start, uint64(0))
assert.Equal(t, finish, uint64(0))
assert.Equal(t, batchIndex, uint64(0))
}

File diff suppressed because one or more lines are too long

View File

@@ -15,8 +15,8 @@ func TestEventSignature(t *testing.T) {
assert.Equal(L1RelayedMessageEventSignature, common.HexToHash("4641df4a962071e12719d8c8c8e5ac7fc4d97b927346a3d7a335b1f7517e133c"))
assert.Equal(L1FailedRelayedMessageEventSignature, common.HexToHash("99d0e048484baa1b1540b1367cb128acd7ab2946d1ed91ec10e3c85e4bf51b8f"))
assert.Equal(L1CommitBatchEventSignature, common.HexToHash("2cdc615c74452778c0fb6184735e014c13aad2b62774fe0b09bd1dcc2cc14a62"))
assert.Equal(L1FinalizeBatchEventSignature, common.HexToHash("9d3058a3cb9739a2527f22dd9a4138065844037d3004254952e2458d808cc364"))
assert.Equal(L1CommitBatchEventSignature, common.HexToHash("2c32d4ae151744d0bf0b9464a3e897a1d17ed2f1af71f7c9a75f12ce0d28238f"))
assert.Equal(L1FinalizeBatchEventSignature, common.HexToHash("26ba82f907317eedc97d0cbef23de76a43dd6edb563bdb6e9407645b950a7a2d"))
assert.Equal(L1QueueTransactionEventSignature, common.HexToHash("69cfcb8e6d4192b8aba9902243912587f37e550d75c1fa801491fce26717f37e"))

View File

@@ -110,7 +110,7 @@ func action(ctx *cli.Context) error {
go utils.Loop(subCtx, 2*time.Second, l2relayer.ProcessPendingBatches)
go utils.Loop(subCtx, 2*time.Second, l2relayer.ProcessCommittedBatches)
go utils.Loop(subCtx, 60*time.Second, l2relayer.ProcessCommittedBatches)
// Finish start all rollup relayer functions.
log.Info("Start rollup-relayer successfully")

View File

@@ -376,9 +376,14 @@ func (r *Layer2Relayer) ProcessPendingBatches() {
txID := batch.Hash + "-commit"
txHash, err := r.rollupSender.SendTransaction(txID, &r.cfg.RollupContractAddress, big.NewInt(0), calldata, 0)
if err != nil {
if !errors.Is(err, sender.ErrNoAvailableAccount) && !errors.Is(err, sender.ErrFullPending) {
log.Error("Failed to send commitBatch tx to layer1 ", "err", err)
}
log.Error(
"Failed to send commitBatch tx to layer1",
"index", batch.Index,
"hash", batch.Hash,
"RollupContractAddress", r.cfg.RollupContractAddress,
"calldata", common.Bytes2Hex(calldata),
"err", err,
)
return
}
@@ -424,7 +429,6 @@ func (r *Layer2Relayer) ProcessCommittedBatches() {
return
case types.ProvingTaskVerified:
log.Info("Start to roll up zk proof", "hash", hash)
success := false
var parentBatchStateRoot string
if batch.Index > 0 {
@@ -438,24 +442,14 @@ func (r *Layer2Relayer) ProcessCommittedBatches() {
parentBatchStateRoot = parentBatch.StateRoot
}
defer func() {
// TODO: need to revisit this and have a more fine-grained error handling
if !success {
log.Info("Failed to upload the proof, change rollup status to RollupFinalizeFailed", "hash", hash)
if err = r.batchOrm.UpdateRollupStatus(r.ctx, hash, types.RollupFinalizeFailed); err != nil {
log.Warn("UpdateRollupStatus failed", "hash", hash, "err", err)
}
}
}()
aggProof, err := r.batchOrm.GetVerifiedProofByHash(r.ctx, hash)
if err != nil {
log.Warn("get verified proof by hash failed", "hash", hash, "err", err)
log.Error("get verified proof by hash failed", "hash", hash, "err", err)
return
}
if err = aggProof.SanityCheck(); err != nil {
log.Warn("agg_proof sanity check fails", "hash", hash, "error", err)
log.Error("agg_proof sanity check fails", "hash", hash, "error", err)
return
}
@@ -478,8 +472,18 @@ func (r *Layer2Relayer) ProcessCommittedBatches() {
finalizeTxHash := &txHash
if err != nil {
if !errors.Is(err, sender.ErrNoAvailableAccount) && !errors.Is(err, sender.ErrFullPending) {
log.Error("finalizeBatchWithProof in layer1 failed",
"index", batch.Index, "hash", batch.Hash, "err", err)
// This can happen normally if we try to finalize 2 or more
// batches around the same time. The 2nd tx might fail since
// the client does not see the 1st tx's updates at this point.
// TODO: add more fine-grained error handling
log.Error(
"finalizeBatchWithProof in layer1 failed",
"index", batch.Index,
"hash", batch.Hash,
"RollupContractAddress", r.cfg.RollupContractAddress,
"calldata", common.Bytes2Hex(data),
"err", err,
)
}
return
}
@@ -489,13 +493,31 @@ func (r *Layer2Relayer) ProcessCommittedBatches() {
// record and sync with db, @todo handle db error
err = r.batchOrm.UpdateFinalizeTxHashAndRollupStatus(r.ctx, hash, finalizeTxHash.String(), types.RollupFinalizing)
if err != nil {
log.Warn("UpdateFinalizeTxHashAndRollupStatus failed",
log.Error("UpdateFinalizeTxHashAndRollupStatus failed",
"index", batch.Index, "batch hash", batch.Hash,
"tx hash", finalizeTxHash.String(), "err", err)
}
success = true
r.processingFinalization.Store(txID, hash)
case types.ProvingTaskFailed:
// We were unable to prove this batch. There are two possibilities:
// (a) Prover bug. In this case, we should fix and redeploy the prover.
// In the meantime, we continue to commit batches to L1 as well as
// proposing and proving chunks and batches.
// (b) Unprovable batch, e.g. proof overflow. In this case we need to
// stop the ledger, fix the limit, revert all the violating blocks,
// chunks and batches and all subsequent ones, and resume, i.e. this
// case requires manual resolution.
log.Error(
"batch proving failed",
"Index", batch.Index,
"Hash", batch.Hash,
"ProverAssignedAt", batch.ProverAssignedAt,
"ProvedAt", batch.ProvedAt,
"ProofTimeSec", batch.ProofTimeSec,
)
return
default:
log.Error("encounter unreachable case in ProcessCommittedBatches", "proving status", status)
}

View File

@@ -90,10 +90,9 @@ func testL2RelayerProcessCommittedBatches(t *testing.T) {
statuses, err := batchOrm.GetRollupStatusByHashList(context.Background(), []string{batch.Hash})
assert.NoError(t, err)
assert.Equal(t, 1, len(statuses))
assert.Equal(t, types.RollupFinalizeFailed, statuses[0])
// no valid proof, rollup status remains the same
assert.Equal(t, types.RollupCommitted, statuses[0])
err = batchOrm.UpdateRollupStatus(context.Background(), batch.Hash, types.RollupCommitted)
assert.NoError(t, err)
proof := &message.BatchProof{
Proof: []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31},
}

View File

@@ -56,13 +56,13 @@ contract MockBridgeL1 {
/// @notice Emitted when a new batch is committed.
/// @param batchHash The hash of the batch.
event CommitBatch(bytes32 indexed batchHash);
event CommitBatch(uint256 indexed batchIndex, bytes32 indexed batchHash);
/// @notice Emitted when a batch is finalized.
/// @param batchHash The hash of the batch
/// @param stateRoot The state root on layer 2 after this batch.
/// @param withdrawRoot The merkle root on layer2 after this batch.
event FinalizeBatch(bytes32 indexed batchHash, bytes32 stateRoot, bytes32 withdrawRoot);
event FinalizeBatch(uint256 indexed batchIndex, bytes32 indexed batchHash, bytes32 stateRoot, bytes32 withdrawRoot);
/***********
* Structs *
@@ -130,7 +130,7 @@ contract MockBridgeL1 {
function commitBatch(
uint8 /*version*/,
bytes calldata /*parentBatchHeader*/,
bytes calldata _parentBatchHeader,
bytes[] memory chunks,
bytes calldata /*skippedL1MessageBitmap*/
) external {
@@ -138,6 +138,17 @@ contract MockBridgeL1 {
uint256 _chunksLength = chunks.length;
require(_chunksLength > 0, "batch is empty");
// decode batch index
uint256 headerLength = _parentBatchHeader.length;
uint256 parentBatchPtr;
uint256 parentBatchIndex;
assembly {
parentBatchPtr := mload(0x40)
calldatacopy(parentBatchPtr, _parentBatchHeader.offset, headerLength)
mstore(0x40, add(parentBatchPtr, headerLength))
parentBatchIndex := shr(192, mload(add(parentBatchPtr, 1)))
}
uint256 dataPtr;
assembly {
dataPtr := mload(0x40)
@@ -169,18 +180,29 @@ contract MockBridgeL1 {
}
bytes32 _batchHash = BatchHeaderV0Codec.computeBatchHash(batchPtr, 89);
committedBatches[0] = _batchHash;
emit CommitBatch(_batchHash);
emit CommitBatch(parentBatchIndex + 1, _batchHash);
}
function finalizeBatchWithProof(
bytes calldata /*batchHeader*/,
bytes calldata batchHeader,
bytes32 /*prevStateRoot*/,
bytes32 postStateRoot,
bytes32 withdrawRoot,
bytes calldata /*aggrProof*/
) external {
// decode batch index
uint256 headerLength = batchHeader.length;
uint256 batchPtr;
uint256 batchIndex;
assembly {
batchPtr := mload(0x40)
calldatacopy(batchPtr, batchHeader.offset, headerLength)
mstore(0x40, add(batchPtr, headerLength))
batchIndex := shr(192, mload(add(batchPtr, 1)))
}
bytes32 _batchHash = committedBatches[0];
emit FinalizeBatch(_batchHash, postStateRoot, withdrawRoot);
emit FinalizeBatch(batchIndex, _batchHash, postStateRoot, withdrawRoot);
}
/**********************

View File

@@ -37,7 +37,7 @@ 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/
COPY --from=zkp-builder /app/target/release/libzktrie.so ./coordinator/internal/logic/verifier/lib/
RUN cd ./coordinator && go build -v -p 4 -o /bin/coordinator ./cmd && mv internal/logic/verifier/lib /bin/
RUN cd ./coordinator && make coordinator_skip_libzkp && mv ./build/bin/coordinator /bin/coordinator && mv internal/logic/verifier/lib /bin/
# Pull coordinator into a second stage deploy alpine container
FROM ubuntu:20.04
@@ -46,6 +46,6 @@ ENV LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/src/coordinator/internal/logic/verifier/li
RUN mkdir -p /src/coordinator/internal/logic/verifier/lib
COPY --from=builder /bin/lib /src/coordinator/internal/logic/verifier/lib
COPY --from=builder /bin/coordinator /bin/
RUN /bin/coordinator --version
ENTRYPOINT ["/bin/coordinator"]

View File

@@ -0,0 +1,31 @@
# Download Go dependencies
FROM scrolltech/go-alpine-builder:1.19 as base
WORKDIR /src
COPY go.work* ./
COPY ./bridge/go.* ./bridge/
COPY ./common/go.* ./common/
COPY ./coordinator/go.* ./coordinator/
COPY ./database/go.* ./database/
COPY ./prover-stats-api/go.* ./prover-stats-api/
COPY ./prover/go.* ./prover/
COPY ./tests/integration-test/go.* ./tests/integration-test/
COPY ./bridge-history-api/go.* ./bridge-history-api/
# Support mainland environment.
#ENV GOPROXY="https://goproxy.cn,direct"
RUN go mod download -x
# Build prover-stats-api
FROM base as builder
RUN --mount=target=. \
--mount=type=cache,target=/root/.cache/go-build \
cd /src/prover-stats-api/cmd/ && go build -v -p 4 -o /bin/prover-stats-api
# Pull prover-stats-api into a second stage deploy alpine container \
FROM alpine:latest
COPY --from=builder /bin/prover-stats-api /bin/
ENTRYPOINT ["prover-stats-api"]

View File

@@ -83,7 +83,9 @@ func (c *Cmd) Write(data []byte) (int, error) {
out := string(data)
if verbose || c.openLog {
fmt.Printf("%s:\n\t%v", c.name, out)
} else if strings.Contains(strings.ToLower(out), "error") || strings.Contains(strings.ToLower(out), "warning") || strings.Contains(strings.ToLower(out), "info") {
} else if strings.Contains(strings.ToLower(out), "error") ||
strings.Contains(strings.ToLower(out), "warning") ||
strings.Contains(strings.ToLower(out), "info") {
fmt.Printf("%s:\n\t%v", c.name, out)
}
go c.checkFuncs.IterCb(func(_ string, value interface{}) {

View File

@@ -32,7 +32,7 @@ dependencies = [
[[package]]
name = "aggregator"
version = "0.1.0"
source = "git+https://github.com/scroll-tech/zkevm-circuits.git?branch=develop#2855c13b5d3e6ec4056f823f56a33bf25d0080bb"
source = "git+https://github.com/scroll-tech/zkevm-circuits.git?tag=v0.5.12#554bdcf00334bab45670b8daa72d687a7ff2b919"
dependencies = [
"ark-std",
"env_logger 0.10.0",
@@ -432,7 +432,7 @@ checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1"
[[package]]
name = "bus-mapping"
version = "0.1.0"
source = "git+https://github.com/scroll-tech/zkevm-circuits.git?branch=develop#2855c13b5d3e6ec4056f823f56a33bf25d0080bb"
source = "git+https://github.com/scroll-tech/zkevm-circuits.git?tag=v0.5.12#554bdcf00334bab45670b8daa72d687a7ff2b919"
dependencies = [
"eth-types",
"ethers-core",
@@ -630,9 +630,12 @@ checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e"
[[package]]
name = "convert_case"
version = "0.5.0"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fb4a24b1aaf0fd0ce8b45161144d6f42cd91677fd5940fd431183eb023b3a2b8"
checksum = "ec182b0ca2f35d8fc196cf3404988fd8b8c739a4d270ff118a398feb0cbec1ca"
dependencies = [
"unicode-segmentation",
]
[[package]]
name = "core-foundation-sys"
@@ -1045,7 +1048,7 @@ dependencies = [
[[package]]
name = "eth-types"
version = "0.1.0"
source = "git+https://github.com/scroll-tech/zkevm-circuits.git?branch=develop#2855c13b5d3e6ec4056f823f56a33bf25d0080bb"
source = "git+https://github.com/scroll-tech/zkevm-circuits.git?tag=v0.5.12#554bdcf00334bab45670b8daa72d687a7ff2b919"
dependencies = [
"ethers-core",
"ethers-signers",
@@ -1138,13 +1141,12 @@ dependencies = [
[[package]]
name = "ethers-core"
version = "0.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ebdd63c828f58aa067f40f9adcbea5e114fb1f90144b3a1e2858e0c9b1ff4e8"
source = "git+https://github.com/scroll-tech/ethers-rs.git?branch=v0.17.0#739ec9a0df8daf536937739c87e85612bd73212f"
dependencies = [
"arrayvec",
"bytes",
"chrono",
"convert_case 0.5.0",
"convert_case 0.6.0",
"elliptic-curve",
"ethabi",
"fastrlp",
@@ -1223,7 +1225,7 @@ dependencies = [
[[package]]
name = "external-tracer"
version = "0.1.0"
source = "git+https://github.com/scroll-tech/zkevm-circuits.git?branch=develop#2855c13b5d3e6ec4056f823f56a33bf25d0080bb"
source = "git+https://github.com/scroll-tech/zkevm-circuits.git?tag=v0.5.12#554bdcf00334bab45670b8daa72d687a7ff2b919"
dependencies = [
"eth-types",
"geth-utils",
@@ -1436,7 +1438,7 @@ dependencies = [
[[package]]
name = "gadgets"
version = "0.1.0"
source = "git+https://github.com/scroll-tech/zkevm-circuits.git?branch=develop#2855c13b5d3e6ec4056f823f56a33bf25d0080bb"
source = "git+https://github.com/scroll-tech/zkevm-circuits.git?tag=v0.5.12#554bdcf00334bab45670b8daa72d687a7ff2b919"
dependencies = [
"digest 0.7.6",
"eth-types",
@@ -1476,7 +1478,7 @@ dependencies = [
[[package]]
name = "geth-utils"
version = "0.1.0"
source = "git+https://github.com/scroll-tech/zkevm-circuits.git?branch=develop#2855c13b5d3e6ec4056f823f56a33bf25d0080bb"
source = "git+https://github.com/scroll-tech/zkevm-circuits.git?tag=v0.5.12#554bdcf00334bab45670b8daa72d687a7ff2b919"
dependencies = [
"env_logger 0.9.3",
"gobuild 0.1.0-alpha.2 (git+https://github.com/scroll-tech/gobuild.git)",
@@ -2074,7 +2076,7 @@ dependencies = [
[[package]]
name = "keccak256"
version = "0.1.0"
source = "git+https://github.com/scroll-tech/zkevm-circuits.git?branch=develop#2855c13b5d3e6ec4056f823f56a33bf25d0080bb"
source = "git+https://github.com/scroll-tech/zkevm-circuits.git?tag=v0.5.12#554bdcf00334bab45670b8daa72d687a7ff2b919"
dependencies = [
"env_logger 0.9.3",
"eth-types",
@@ -2261,7 +2263,7 @@ dependencies = [
[[package]]
name = "mock"
version = "0.1.0"
source = "git+https://github.com/scroll-tech/zkevm-circuits.git?branch=develop#2855c13b5d3e6ec4056f823f56a33bf25d0080bb"
source = "git+https://github.com/scroll-tech/zkevm-circuits.git?tag=v0.5.12#554bdcf00334bab45670b8daa72d687a7ff2b919"
dependencies = [
"eth-types",
"ethers-core",
@@ -2276,7 +2278,7 @@ dependencies = [
[[package]]
name = "mpt-zktrie"
version = "0.1.0"
source = "git+https://github.com/scroll-tech/zkevm-circuits.git?branch=develop#2855c13b5d3e6ec4056f823f56a33bf25d0080bb"
source = "git+https://github.com/scroll-tech/zkevm-circuits.git?tag=v0.5.12#554bdcf00334bab45670b8daa72d687a7ff2b919"
dependencies = [
"bus-mapping",
"eth-types",
@@ -2752,7 +2754,7 @@ dependencies = [
[[package]]
name = "prover"
version = "0.4.0"
source = "git+https://github.com/scroll-tech/scroll-prover?tag=v0.5.1#15aac6e1484a42f723098fbc9d8783f374e7e90a"
source = "git+https://github.com/scroll-tech/scroll-prover?tag=v0.5.12#ef945901bee26c4b79be8af60e259443392368fa"
dependencies = [
"aggregator",
"anyhow",
@@ -3621,7 +3623,7 @@ checksum = "62bb4feee49fdd9f707ef802e22365a35de4b7b299de4763d44bfea899442ff9"
[[package]]
name = "snark-verifier"
version = "0.1.0"
source = "git+https://github.com/scroll-tech/snark-verifier?branch=develop#f8bdcbee60348e5c996c04f19ff30522e6b276b0"
source = "git+https://github.com/scroll-tech/snark-verifier?branch=develop#12c306ec57849921e690221b10b8a08189868d4a"
dependencies = [
"bytes",
"ethereum-types 0.14.1",
@@ -3645,7 +3647,7 @@ dependencies = [
[[package]]
name = "snark-verifier-sdk"
version = "0.0.1"
source = "git+https://github.com/scroll-tech/snark-verifier?branch=develop#f8bdcbee60348e5c996c04f19ff30522e6b276b0"
source = "git+https://github.com/scroll-tech/snark-verifier?branch=develop#12c306ec57849921e690221b10b8a08189868d4a"
dependencies = [
"bincode",
"env_logger 0.10.0",
@@ -4037,7 +4039,7 @@ checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba"
[[package]]
name = "types"
version = "0.4.0"
source = "git+https://github.com/scroll-tech/scroll-prover?tag=v0.5.1#15aac6e1484a42f723098fbc9d8783f374e7e90a"
source = "git+https://github.com/scroll-tech/scroll-prover?tag=v0.5.12#ef945901bee26c4b79be8af60e259443392368fa"
dependencies = [
"base64 0.13.1",
"blake2",
@@ -4082,6 +4084,12 @@ dependencies = [
"tinyvec",
]
[[package]]
name = "unicode-segmentation"
version = "1.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36"
[[package]]
name = "unicode-xid"
version = "0.2.4"
@@ -4482,7 +4490,7 @@ checksum = "2a0956f1ba7c7909bfb66c2e9e4124ab6f6482560f6628b5aaeba39207c9aad9"
[[package]]
name = "zkevm-circuits"
version = "0.1.0"
source = "git+https://github.com/scroll-tech/zkevm-circuits.git?branch=develop#2855c13b5d3e6ec4056f823f56a33bf25d0080bb"
source = "git+https://github.com/scroll-tech/zkevm-circuits.git?tag=v0.5.12#554bdcf00334bab45670b8daa72d687a7ff2b919"
dependencies = [
"array-init",
"bus-mapping",

View File

@@ -7,6 +7,8 @@ edition = "2021"
[lib]
crate-type = ["cdylib"]
[patch.crates-io]
ethers-core = { git = "https://github.com/scroll-tech/ethers-rs.git", branch = "v0.17.0" }
[patch."https://github.com/privacy-scaling-explorations/halo2.git"]
halo2_proofs = { git = "https://github.com/scroll-tech/halo2.git", branch = "develop" }
[patch."https://github.com/privacy-scaling-explorations/poseidon.git"]
@@ -18,8 +20,8 @@ maingate = { git = "https://github.com/scroll-tech/halo2wrong", branch = "halo2-
halo2curves = { git = "https://github.com/scroll-tech/halo2curves.git", branch = "0.3.1-derive-serde" }
[dependencies]
prover = { git = "https://github.com/scroll-tech/scroll-prover", tag = "v0.5.1" }
types = { git = "https://github.com/scroll-tech/scroll-prover", tag = "v0.5.1" }
prover = { git = "https://github.com/scroll-tech/scroll-prover", tag = "v0.5.12" }
types = { git = "https://github.com/scroll-tech/scroll-prover", tag = "v0.5.12" }
halo2_proofs = { git = "https://github.com/scroll-tech/halo2.git", branch = "develop" }
log = "0.4"
@@ -33,8 +35,6 @@ once_cell = "1.8.0"
[profile.test]
opt-level = 3
# debug-assertions = true
[profile.release]
opt-level = 3
# debug-assertions = true

View File

@@ -169,7 +169,7 @@ func TestBatchHeaderEncode(t *testing.T) {
assert.NotNil(t, batchHeader)
bytes = batchHeader.Encode()
assert.Equal(t, 121, len(bytes))
assert.Equal(t, "010000000000000001000000000000000b000000000000000b457a9e90e8e51ba2de2f66c6b589540b88cf594dac7fa7d04b99cdcfecf24e384136709aabc8a23aa17fbcc833da2f7857d3c2884feec9aae73429c135f9498500000000000000000000000000000000000000000000000000000000000003ff", common.Bytes2Hex(bytes))
assert.Equal(t, "010000000000000001000000000000000b000000000000000b34f419ce7e882295bdb5aec6cce56ffa788a5fed4744d7fbd77e4acbf409f1ca4136709aabc8a23aa17fbcc833da2f7857d3c2884feec9aae73429c135f9498500000000000000000000000000000000000000000000000000000000000003ff", common.Bytes2Hex(bytes))
}
func TestBatchHeaderHash(t *testing.T) {
@@ -230,7 +230,7 @@ func TestBatchHeaderHash(t *testing.T) {
assert.NoError(t, err)
assert.NotNil(t, batchHeader)
hash = batchHeader.Hash()
assert.Equal(t, "0ec9547c6645d5f0c1254e121f49e93f54525cfda5bfb2236440fb3470f48902", common.Bytes2Hex(hash.Bytes()))
assert.Equal(t, "1c3007880f0eafe74572ede7d164ff1ee5376e9ac9bff6f7fb837b2630cddc9a", common.Bytes2Hex(hash.Bytes()))
}
func TestBatchHeaderDecode(t *testing.T) {

View File

@@ -36,6 +36,17 @@ func (w *WrappedBlock) NumL1Messages(totalL1MessagePoppedBefore uint64) uint64 {
return *lastQueueIndex - totalL1MessagePoppedBefore + 1
}
// NumL2Transactions returns the number of L2 transactions in this block.
func (w *WrappedBlock) NumL2Transactions() uint64 {
var count uint64
for _, txData := range w.Transactions {
if txData.Type != types.L1MessageTxType {
count++
}
}
return count
}
// Encode encodes the WrappedBlock into RollupV2 BlockContext Encoding.
func (w *WrappedBlock) Encode(totalL1MessagePoppedBefore uint64) ([]byte, error) {
bytes := make([]byte, 60)
@@ -43,20 +54,25 @@ func (w *WrappedBlock) Encode(totalL1MessagePoppedBefore uint64) ([]byte, error)
if !w.Header.Number.IsUint64() {
return nil, errors.New("block number is not uint64")
}
if len(w.Transactions) > math.MaxUint16 {
return nil, errors.New("number of transactions exceeds max uint16")
}
// note: numL1Messages includes skipped messages
numL1Messages := w.NumL1Messages(totalL1MessagePoppedBefore)
if numL1Messages > math.MaxUint16 {
return nil, errors.New("number of L1 messages exceeds max uint16")
}
// note: numTransactions includes skipped messages
numL2Transactions := w.NumL2Transactions()
numTransactions := numL1Messages + numL2Transactions
if numTransactions > math.MaxUint16 {
return nil, errors.New("number of transactions exceeds max uint16")
}
binary.BigEndian.PutUint64(bytes[0:], w.Header.Number.Uint64())
binary.BigEndian.PutUint64(bytes[8:], w.Header.Time)
// TODO: [16:47] Currently, baseFee is 0, because we disable EIP-1559.
binary.BigEndian.PutUint64(bytes[48:], w.Header.GasLimit)
binary.BigEndian.PutUint16(bytes[56:], uint16(len(w.Transactions)))
binary.BigEndian.PutUint16(bytes[56:], uint16(numTransactions))
binary.BigEndian.PutUint16(bytes[58:], uint16(numL1Messages))
return bytes, nil

View File

@@ -65,9 +65,10 @@ func TestChunkEncode(t *testing.T) {
hexString = hex.EncodeToString(bytes)
assert.NoError(t, err)
assert.Equal(t, 97, len(bytes))
assert.Equal(t, "01000000000000000d00000000646b6e13000000000000000000000000000000000000000000000000000000000000000000000000007a12000002000b00000020df0b80825dc0941a258d17bf244c4df02d40343a7626a9d321e1058080808080", hexString)
assert.Equal(t, "01000000000000000d00000000646b6e13000000000000000000000000000000000000000000000000000000000000000000000000007a1200000c000b00000020df0b80825dc0941a258d17bf244c4df02d40343a7626a9d321e1058080808080", hexString)
// Test case 5: when the chunk contains two blocks each with 1 L1MsgTx
// TODO: revise this test, we cannot reuse the same L1MsgTx twice
chunk = &Chunk{
Blocks: []*WrappedBlock{
wrappedBlock2,
@@ -78,7 +79,7 @@ func TestChunkEncode(t *testing.T) {
hexString = hex.EncodeToString(bytes)
assert.NoError(t, err)
assert.Equal(t, 193, len(bytes))
assert.Equal(t, "02000000000000000d00000000646b6e13000000000000000000000000000000000000000000000000000000000000000000000000007a12000002000b000000000000000d00000000646b6e13000000000000000000000000000000000000000000000000000000000000000000000000007a12000002000000000020df0b80825dc0941a258d17bf244c4df02d40343a7626a9d321e105808080808000000020df0b80825dc0941a258d17bf244c4df02d40343a7626a9d321e1058080808080", hexString)
assert.Equal(t, "02000000000000000d00000000646b6e13000000000000000000000000000000000000000000000000000000000000000000000000007a1200000c000b000000000000000d00000000646b6e13000000000000000000000000000000000000000000000000000000000000000000000000007a12000001000000000020df0b80825dc0941a258d17bf244c4df02d40343a7626a9d321e105808080808000000020df0b80825dc0941a258d17bf244c4df02d40343a7626a9d321e1058080808080", hexString)
}
func TestChunkHash(t *testing.T) {
@@ -133,5 +134,5 @@ func TestChunkHash(t *testing.T) {
}
hash, err = chunk.Hash(0)
assert.NoError(t, err)
assert.Equal(t, "0x42967825696a129e7a83f082097aca982747480956dcaa448c9296e795c9a91a", hash.Hex())
assert.Equal(t, "0x2eb7dd63bf8fc29a0f8c10d16c2ae6f9da446907c79d50f5c164d30dc8526b60", hash.Hex())
}

View File

@@ -126,7 +126,7 @@ const (
ProvingTaskUnassigned
// ProvingTaskAssigned : proving_task is assigned to be proved
ProvingTaskAssigned
// ProvingTaskProved : proof has been returned by prover
// ProvingTaskProved DEPRECATED: proof has been returned by prover
ProvingTaskProved
// ProvingTaskVerified : proof is valid
ProvingTaskVerified

View File

@@ -33,7 +33,7 @@ func (r ProofType) String() string {
case ProofTypeBatch:
return "proof type batch"
default:
return "illegal proof type"
return fmt.Sprintf("illegal proof type: %d", r)
}
}
@@ -60,6 +60,8 @@ type AuthMsg struct {
type Identity struct {
// ProverName the prover name
ProverName string `json:"prover_name"`
// ProverVersion the prover version
ProverVersion string `json:"prover_version"`
// Challenge unique challenge generated by manager
Challenge string `json:"challenge"`
}

View File

@@ -15,8 +15,9 @@ func TestAuthMessageSignAndVerify(t *testing.T) {
authMsg := &AuthMsg{
Identity: &Identity{
Challenge: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2OTEwMzgxNzUsIm9yaWdfaWF0IjoxNjkxMDM0NTc1fQ.HybBMsEJFhyZqtIa2iVcHUP7CEFttf708jmTMAImAWA",
ProverName: "test",
Challenge: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2OTEwMzgxNzUsIm9yaWdfaWF0IjoxNjkxMDM0NTc1fQ.HybBMsEJFhyZqtIa2iVcHUP7CEFttf708jmTMAImAWA",
ProverName: "test",
ProverVersion: "v1.0.0",
},
}
assert.NoError(t, authMsg.SignWithKey(privkey))
@@ -45,14 +46,15 @@ func TestGenerateToken(t *testing.T) {
func TestIdentityHash(t *testing.T) {
identity := &Identity{
Challenge: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2OTEwMzM0MTksIm9yaWdfaWF0IjoxNjkxMDI5ODE5fQ.EhkLZsj__rNPVC3ZDYBtvdh0nB8mmM_Hl82hObaIWOs",
ProverName: "test",
Challenge: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2OTEwMzM0MTksIm9yaWdfaWF0IjoxNjkxMDI5ODE5fQ.EhkLZsj__rNPVC3ZDYBtvdh0nB8mmM_Hl82hObaIWOs",
ProverName: "test",
ProverVersion: "v1.0.0",
}
hash, err := identity.Hash()
assert.NoError(t, err)
expectedHash := "7373bb57ab7c01307d86fec55e088e00c526d82d9d1303fa4a189ff6ea95fbe2"
expectedHash := "83f5e0ad023e9c1de639ab07b9b4cb972ec9dbbd2524794c533a420a5b137721"
assert.Equal(t, expectedHash, hex.EncodeToString(hash))
}
@@ -116,7 +118,7 @@ func TestProveTypeString(t *testing.T) {
assert.Equal(t, "proof type batch", proofTypeBatch.String())
illegalProof := ProofType(3)
assert.Equal(t, "illegal proof type", illegalProof.String())
assert.Equal(t, "illegal proof type: 3", illegalProof.String())
}
func TestProofMsgPublicKey(t *testing.T) {

View File

@@ -20,12 +20,17 @@ var (
MessageRelayerApp MockAppName = "message-relayer-test"
// RollupRelayerApp the name of mock rollup-relayer app.
RollupRelayerApp MockAppName = "rollup-relayer-test"
// CoordinatorApp the name of mock coordinator app.
CoordinatorApp MockAppName = "coordinator-test"
// DBCliApp the name of mock database app.
DBCliApp MockAppName = "db_cli-test"
// ProverApp the name of mock prover app.
ProverApp MockAppName = "prover-test"
// CoordinatorApp the name of mock coordinator app.
CoordinatorApp MockAppName = "coordinator-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.

View File

@@ -3,9 +3,10 @@ package version
import (
"fmt"
"runtime/debug"
"strings"
)
var tag = "v4.1.1"
var tag = "v4.1.31"
var commit = func() string {
if info, ok := debug.ReadBuildInfo(); ok {
@@ -19,11 +20,29 @@ var commit = func() string {
}
}
}
return ""
// Set default value for integration test.
return "000000"
}()
// ZkVersion is commit-id of common/libzkp/impl/cargo.lock/scroll-prover
var ZkVersion string
// ZkVersion is commit-id of common/libzkp/impl/cargo.lock/scroll-prover and halo2, contacted by a "-"
// The default `000000-000000` is set for integration test, and will be overwritten by coordinator's & prover's actual compilations (see their Makefiles).
var ZkVersion = "000000-000000"
// Version denote the version of scroll protocol, including the l2geth, relayer, coordinator, prover, contracts and etc.
var Version = fmt.Sprintf("%s-%s-%s", tag, commit, ZkVersion)
// CheckScrollProverVersion check the "scroll-prover" version, if it's different from the local one, return false
func CheckScrollProverVersion(proverVersion string) bool {
// note the the version is in fact in the format of "tag-commit-scroll_prover-halo2",
// so split-by-'-' length should be 4
remote := strings.Split(proverVersion, "-")
if len(remote) != 4 {
return false
}
local := strings.Split(Version, "-")
if len(local) != 4 {
return false
}
// compare the `scroll_prover` version
return remote[2] == local[2]
}

View File

@@ -1,16 +1,16 @@
{
"ProxyAdmin": null,
"ProxyAdmin": "0x95ec888F34b23063aeaB47c8E229B3a25DBF8e4F",
"ZKRollup": {
"implementation": null,
"proxy": null
},
"L1ScrollMessenger": {
"implementation": null,
"proxy": null
"implementation": "0xC71532468A74084cfd824c0445E96f9A2dc3Bd7E",
"proxy": "0x50c7d3e7f7c656493D1D76aaa1a836CedfCBB16A"
},
"L1GatewayRouter": {
"implementation": null,
"proxy": null
"implementation": "0x5431937CF9cb638df5e3587Ae0a2F62130CEE27e",
"proxy": "0x13FBE0D0e5552b8c9c4AE9e2435F38f37355998a"
},
"L1StandardERC20Gateway": {
"implementation": null,
@@ -19,5 +19,9 @@
"L1WETHGateway": {
"implementation": null,
"proxy": null
},
"L1USDCGateway": {
"implementation": "0x2Cf090069Bc47CA931f350fe1D0a160dba4c7C53",
"proxy": "0xeED47C513265cefe6846Dd51B624F1102A9a89d3"
}
}

View File

@@ -1,13 +1,16 @@
{
"ProxyAdmin": null,
"ProxyAdmin": "0x95ec888F34b23063aeaB47c8E229B3a25DBF8e4F",
"WETH": null,
"Whitelist": null,
"ScrollStandardERC20": null,
"ScrollStandardERC20Factory": null,
"L2ScrollMessenger": null,
"L2ScrollMessenger": {
"implementation": "0x45BA70424D61e6A0D2A5FF9093927350471A2728",
"proxy": "0xBa50f5340FB9F3Bd074bD638c9BE13eCB36E603d"
},
"L2GatewayRouter": {
"implementation": null,
"proxy": null
"implementation": "0x0378D0F56f13f018b8d4803f09349781e143453e",
"proxy": "0x9aD3c5617eCAa556d6E166787A97081907171230"
},
"L2StandardERC20Gateway": {
"implementation": null,
@@ -16,5 +19,9 @@
"L2WETHGateway": {
"implementation": null,
"proxy": null
},
"L2USDCGateway": {
"implementation": "0xCad8ba59173F3d6b3d15E8eeE2CB5C8b43e50fC0",
"proxy": "0x78a5dacf40E26c21A69fA3D701F9e75f19FD7113"
}
}

View File

@@ -533,7 +533,7 @@ Emitted when some ERC1155 token is refunded.
### UpdateTokenMapping
```solidity
event UpdateTokenMapping(address _l1Token, address _l2Token)
event UpdateTokenMapping(address indexed l1Token, address indexed oldL2Token, address indexed newL2Token)
```
Emitted when token mapping for ERC1155 token is updated.
@@ -544,8 +544,9 @@ Emitted when token mapping for ERC1155 token is updated.
| Name | Type | Description |
|---|---|---|
| _l1Token | address | The address of ERC1155 token on layer 1. |
| _l2Token | address | The address of corresponding ERC1155 token on layer 2. |
| 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. |

View File

@@ -472,7 +472,7 @@ Emitted when some ERC721 token is refunded.
### UpdateTokenMapping
```solidity
event UpdateTokenMapping(address _l1Token, address _l2Token)
event UpdateTokenMapping(address indexed l1Token, address indexed oldL2Token, address indexed newL2Token)
```
Emitted when token mapping for ERC721 token is updated.
@@ -483,8 +483,9 @@ Emitted when token mapping for ERC721 token is updated.
| Name | Type | Description |
|---|---|---|
| _l1Token | address | The address of ERC721 token on layer 1. |
| _l2Token | address | The address of corresponding ERC721 token on layer 2. |
| 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. |

View File

@@ -350,7 +350,7 @@ Request ERC20 token transfer from users to gateways.
### setDefaultERC20Gateway
```solidity
function setDefaultERC20Gateway(address _defaultERC20Gateway) external nonpayable
function setDefaultERC20Gateway(address _newDefaultERC20Gateway) external nonpayable
```
Update the address of default ERC20 gateway contract.
@@ -361,7 +361,7 @@ Update the address of default ERC20 gateway contract.
| Name | Type | Description |
|---|---|---|
| _defaultERC20Gateway | address | The address to update. |
| _newDefaultERC20Gateway | address | undefined |
### setERC20Gateway
@@ -383,7 +383,7 @@ Update the mapping from token address to gateway address.
### setETHGateway
```solidity
function setETHGateway(address _ethGateway) external nonpayable
function setETHGateway(address _newEthGateway) external nonpayable
```
Update the address of ETH gateway contract.
@@ -394,7 +394,7 @@ Update the address of ETH gateway contract.
| Name | Type | Description |
|---|---|---|
| _ethGateway | address | The address to update. |
| _newEthGateway | address | undefined |
### transferOwnership
@@ -567,7 +567,7 @@ Emitted when some ETH is refunded.
### SetDefaultERC20Gateway
```solidity
event SetDefaultERC20Gateway(address indexed defaultERC20Gateway)
event SetDefaultERC20Gateway(address indexed oldDefaultERC20Gateway, address indexed newDefaultERC20Gateway)
```
Emitted when the address of default ERC20 Gateway is updated.
@@ -578,12 +578,13 @@ Emitted when the address of default ERC20 Gateway is updated.
| Name | Type | Description |
|---|---|---|
| defaultERC20Gateway `indexed` | address | undefined |
| oldDefaultERC20Gateway `indexed` | address | undefined |
| newDefaultERC20Gateway `indexed` | address | undefined |
### SetERC20Gateway
```solidity
event SetERC20Gateway(address indexed token, address indexed gateway)
event SetERC20Gateway(address indexed token, address indexed oldGateway, address indexed newGateway)
```
Emitted when the `gateway` for `token` is updated.
@@ -595,12 +596,13 @@ Emitted when the `gateway` for `token` is updated.
| Name | Type | Description |
|---|---|---|
| token `indexed` | address | undefined |
| gateway `indexed` | address | undefined |
| oldGateway `indexed` | address | undefined |
| newGateway `indexed` | address | undefined |
### SetETHGateway
```solidity
event SetETHGateway(address indexed ethGateway)
event SetETHGateway(address indexed oldETHGateway, address indexed newEthGateway)
```
Emitted when the address of ETH Gateway is updated.
@@ -611,7 +613,8 @@ Emitted when the address of ETH Gateway is updated.
| Name | Type | Description |
|---|---|---|
| ethGateway `indexed` | address | undefined |
| oldETHGateway `indexed` | address | undefined |
| newEthGateway `indexed` | address | undefined |

View File

@@ -423,7 +423,7 @@ Update fee vault contract.
### updateMaxReplayTimes
```solidity
function updateMaxReplayTimes(uint256 _maxReplayTimes) external nonpayable
function updateMaxReplayTimes(uint256 _newMaxReplayTimes) external nonpayable
```
Update max replay times.
@@ -434,7 +434,7 @@ Update max replay times.
| Name | Type | Description |
|---|---|---|
| _maxReplayTimes | uint256 | The new max replay times. |
| _newMaxReplayTimes | uint256 | The new max replay times. |
### xDomainMessageSender
@@ -595,7 +595,7 @@ Emitted when owner updates fee vault contract.
### UpdateMaxReplayTimes
```solidity
event UpdateMaxReplayTimes(uint256 maxReplayTimes)
event UpdateMaxReplayTimes(uint256 oldMaxReplayTimes, uint256 newMaxReplayTimes)
```
Emitted when the maximum number of times each message can be replayed is updated.
@@ -606,7 +606,8 @@ Emitted when the maximum number of times each message can be replayed is updated
| Name | Type | Description |
|---|---|---|
| maxReplayTimes | uint256 | undefined |
| oldMaxReplayTimes | uint256 | undefined |
| newMaxReplayTimes | uint256 | undefined |

View File

@@ -214,6 +214,34 @@ function onDropMessage(bytes _message) external payable
|---|---|---|
| _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
@@ -231,6 +259,22 @@ The address of L1GatewayRouter/L2GatewayRouter contract.
|---|---|---|
| _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
@@ -293,6 +337,23 @@ event Initialized(uint8 version)
|---|---|---|
| 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

View File

@@ -212,6 +212,34 @@ function onDropMessage(bytes _message) external payable
|---|---|---|
| _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
@@ -229,6 +257,22 @@ The address of L1GatewayRouter/L2GatewayRouter contract.
|---|---|---|
| _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
@@ -291,6 +335,23 @@ event Initialized(uint8 version)
|---|---|---|
| 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

View File

@@ -458,7 +458,7 @@ event OwnershipTransferred(address indexed previousOwner, address indexed newOwn
### UpdateTokenMapping
```solidity
event UpdateTokenMapping(address _l2Token, address _l1Token)
event UpdateTokenMapping(address indexed l2Token, address indexed oldL1Token, address indexed newL1Token)
```
Emitted when token mapping for ERC1155 token is updated.
@@ -469,8 +469,9 @@ Emitted when token mapping for ERC1155 token is updated.
| Name | Type | Description |
|---|---|---|
| _l2Token | address | The address of corresponding ERC1155 token on layer 2. |
| _l1Token | address | The address of ERC1155 token on layer 1. |
| 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

View File

@@ -400,7 +400,7 @@ event OwnershipTransferred(address indexed previousOwner, address indexed newOwn
### UpdateTokenMapping
```solidity
event UpdateTokenMapping(address _l2Token, address _l1Token)
event UpdateTokenMapping(address indexed l2Token, address indexed oldL1Token, address indexed newL1Token)
```
Emitted when token mapping for ERC721 token is updated.
@@ -411,8 +411,9 @@ Emitted when token mapping for ERC721 token is updated.
| Name | Type | Description |
|---|---|---|
| _l2Token | address | The address of corresponding ERC721 token on layer 2. |
| _l1Token | address | The address of ERC721 token on layer 1. |
| 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

View File

@@ -220,7 +220,7 @@ function renounceOwnership() external nonpayable
### setDefaultERC20Gateway
```solidity
function setDefaultERC20Gateway(address _defaultERC20Gateway) external nonpayable
function setDefaultERC20Gateway(address _newDefaultERC20Gateway) external nonpayable
```
Update the address of default ERC20 gateway contract.
@@ -231,7 +231,7 @@ Update the address of default ERC20 gateway contract.
| Name | Type | Description |
|---|---|---|
| _defaultERC20Gateway | address | The address to update. |
| _newDefaultERC20Gateway | address | The address to update. |
### setERC20Gateway
@@ -253,7 +253,7 @@ Update the mapping from token address to gateway address.
### setETHGateway
```solidity
function setETHGateway(address _ethGateway) external nonpayable
function setETHGateway(address _newEthGateway) external nonpayable
```
Update the address of ETH gateway contract.
@@ -264,7 +264,7 @@ Update the address of ETH gateway contract.
| Name | Type | Description |
|---|---|---|
| _ethGateway | address | The address to update. |
| _newEthGateway | address | The address to update. |
### transferOwnership
@@ -473,7 +473,7 @@ event OwnershipTransferred(address indexed previousOwner, address indexed newOwn
### SetDefaultERC20Gateway
```solidity
event SetDefaultERC20Gateway(address indexed defaultERC20Gateway)
event SetDefaultERC20Gateway(address indexed oldDefaultERC20Gateway, address indexed newDefaultERC20Gateway)
```
Emitted when the address of default ERC20 Gateway is updated.
@@ -484,12 +484,13 @@ Emitted when the address of default ERC20 Gateway is updated.
| Name | Type | Description |
|---|---|---|
| defaultERC20Gateway `indexed` | address | undefined |
| oldDefaultERC20Gateway `indexed` | address | undefined |
| newDefaultERC20Gateway `indexed` | address | undefined |
### SetERC20Gateway
```solidity
event SetERC20Gateway(address indexed token, address indexed gateway)
event SetERC20Gateway(address indexed token, address indexed oldGateway, address indexed newGateway)
```
Emitted when the `gateway` for `token` is updated.
@@ -501,12 +502,13 @@ Emitted when the `gateway` for `token` is updated.
| Name | Type | Description |
|---|---|---|
| token `indexed` | address | undefined |
| gateway `indexed` | address | undefined |
| oldGateway `indexed` | address | undefined |
| newGateway `indexed` | address | undefined |
### SetETHGateway
```solidity
event SetETHGateway(address indexed ethGateway)
event SetETHGateway(address indexed oldETHGateway, address indexed newEthGateway)
```
Emitted when the address of ETH Gateway is updated.
@@ -517,7 +519,8 @@ Emitted when the address of ETH Gateway is updated.
| Name | Type | Description |
|---|---|---|
| ethGateway `indexed` | address | undefined |
| oldETHGateway `indexed` | address | undefined |
| newEthGateway `indexed` | address | undefined |
### WithdrawERC20

View File

@@ -47,7 +47,7 @@ The address of fee vault, collecting cross domain messaging fee.
### initialize
```solidity
function initialize(address _counterpart, address _feeVault) external nonpayable
function initialize(address _counterpart) external nonpayable
```
@@ -59,7 +59,6 @@ function initialize(address _counterpart, address _feeVault) external nonpayable
| Name | Type | Description |
|---|---|---|
| _counterpart | address | undefined |
| _feeVault | address | undefined |
### isL1MessageExecuted
@@ -316,7 +315,7 @@ Update fee vault contract.
### updateMaxFailedExecutionTimes
```solidity
function updateMaxFailedExecutionTimes(uint256 _maxFailedExecutionTimes) external nonpayable
function updateMaxFailedExecutionTimes(uint256 _newMaxFailedExecutionTimes) external nonpayable
```
Update max failed execution times.
@@ -327,7 +326,7 @@ Update max failed execution times.
| Name | Type | Description |
|---|---|---|
| _maxFailedExecutionTimes | uint256 | The new max failed execution times. |
| _newMaxFailedExecutionTimes | uint256 | The new max failed execution times. |
### xDomainMessageSender
@@ -488,7 +487,7 @@ Emitted when owner updates fee vault contract.
### UpdateMaxFailedExecutionTimes
```solidity
event UpdateMaxFailedExecutionTimes(uint256 maxFailedExecutionTimes)
event UpdateMaxFailedExecutionTimes(uint256 oldMaxFailedExecutionTimes, uint256 newMaxFailedExecutionTimes)
```
Emitted when the maximum number of times each message can fail in L2 is updated.
@@ -499,7 +498,8 @@ Emitted when the maximum number of times each message can fail in L2 is updated.
| Name | Type | Description |
|---|---|---|
| maxFailedExecutionTimes | uint256 | The new maximum number of times each message can fail in L2. |
| oldMaxFailedExecutionTimes | uint256 | undefined |
| newMaxFailedExecutionTimes | uint256 | undefined |

View File

@@ -128,6 +128,34 @@ The address of corresponding L1ScrollMessenger/L2ScrollMessenger contract.
|---|---|---|
| _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
@@ -162,6 +190,22 @@ The address of ScrollStandardERC20Factory.
|---|---|---|
| _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
@@ -260,6 +304,23 @@ event Initialized(uint8 version)
|---|---|---|
| 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

View File

@@ -161,6 +161,34 @@ The address of corresponding L1ScrollMessenger/L2ScrollMessenger contract.
|---|---|---|
| _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
@@ -178,6 +206,22 @@ The address of L1GatewayRouter/L2GatewayRouter contract.
|---|---|---|
| _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
@@ -276,6 +320,23 @@ event Initialized(uint8 version)
|---|---|---|
| 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

View File

@@ -60,14 +60,10 @@ const config: HardhatUserConfig = {
},
l1geth: {
url: SCROLL_L1_RPC,
gasPrice: 20000000000,
gasMultiplier: 1.1,
accounts: [L1_DEPLOYER_PRIVATE_KEY],
},
l2geth: {
url: SCROLL_L2_RPC,
gasPrice: 20000000000,
gasMultiplier: 1.1,
accounts: [L2_DEPLOYER_PRIVATE_KEY],
},
},
@@ -83,6 +79,16 @@ const config: HardhatUserConfig = {
},
etherscan: {
apiKey: process.env.ETHERSCAN_API_KEY,
customChains: [
{
network: "l2geth",
chainId: 534351,
urls: {
apiURL: "https://sepolia-blockscout.scroll.io/api",
browserURL: "https://sepolia-blockscout.scroll.io",
},
},
],
},
dodoc: {
runOnCompile: true,

View File

@@ -1,7 +1,6 @@
/* eslint-disable node/no-unpublished-import */
/* eslint-disable node/no-missing-import */
import { constants } from "ethers";
import { concat } from "ethers/lib/utils";
import { ethers } from "hardhat";
import { ScrollChain, L1MessageQueue } from "../typechain";
@@ -28,7 +27,7 @@ describe("ScrollChain", async () => {
await chain.deployed();
await chain.initialize(queue.address, constants.AddressZero, 44);
await chain.updateSequencer(deployer.address, true);
await chain.addSequencer(deployer.address);
await queue.initialize(
constants.AddressZero,
chain.address,

View File

@@ -21,7 +21,7 @@ async function main() {
if (!addressFile.get(`${contractName}.implementation`)) {
console.log(`>> Deploy ${contractName} implementation`);
const ContractImpl = await ethers.getContractFactory(contractName, deployer);
const impl = await ContractImpl.deploy();
const impl = await ContractImpl.deploy(process.env.L1_USDC_ADDR, process.env.L2_USDC_ADDR);
console.log(`>> waiting for transaction: ${impl.deployTransaction.hash}`);
await impl.deployed();
console.log(`${contractName} implementation deployed at ${impl.address}`);

View File

@@ -22,6 +22,7 @@ contract InitializeL1BridgeContracts is Script {
uint256 CHAIN_ID_L2 = vm.envUint("CHAIN_ID_L2");
uint256 MAX_L2_TX_IN_CHUNK = vm.envUint("MAX_L2_TX_IN_CHUNK");
uint256 MAX_L1_MESSAGE_GAS_LIMIT = vm.envUint("MAX_L1_MESSAGE_GAS_LIMIT");
address L1_ROLLUP_OPERATOR_ADDR = vm.envAddress("L1_ROLLUP_OPERATOR_ADDR");
address L1_FEE_VAULT_ADDR = vm.envAddress("L1_FEE_VAULT_ADDR");
address L1_WETH_ADDR = vm.envAddress("L1_WETH_ADDR");
@@ -66,8 +67,8 @@ contract InitializeL1BridgeContracts is Script {
L1_MULTIPLE_VERSION_ROLLUP_VERIFIER_ADDR,
MAX_L2_TX_IN_CHUNK
);
ScrollChain(L1_SCROLL_CHAIN_PROXY_ADDR).updateSequencer(L1_ROLLUP_OPERATOR_ADDR, true);
ScrollChain(L1_SCROLL_CHAIN_PROXY_ADDR).updateProver(L1_ROLLUP_OPERATOR_ADDR, true);
ScrollChain(L1_SCROLL_CHAIN_PROXY_ADDR).addSequencer(L1_ROLLUP_OPERATOR_ADDR);
ScrollChain(L1_SCROLL_CHAIN_PROXY_ADDR).addProver(L1_ROLLUP_OPERATOR_ADDR);
// initialize L2GasPriceOracle
L2GasPriceOracle(L2_GAS_PRICE_ORACLE_PROXY_ADDR).initialize(
@@ -84,7 +85,7 @@ contract InitializeL1BridgeContracts is Script {
L1_SCROLL_CHAIN_PROXY_ADDR,
L1_ENFORCED_TX_GATEWAY_PROXY_ADDR,
L2_GAS_PRICE_ORACLE_PROXY_ADDR,
10000000
MAX_L1_MESSAGE_GAS_LIMIT
);
// initialize L1ScrollMessenger

View File

@@ -65,10 +65,7 @@ contract InitializeL2BridgeContracts is Script {
L1GasPriceOracle(L1_GAS_PRICE_ORACLE_ADDR).updateWhitelist(L2_WHITELIST_ADDR);
// initialize L2ScrollMessenger
L2ScrollMessenger(payable(L2_SCROLL_MESSENGER_PROXY_ADDR)).initialize(
L1_SCROLL_MESSENGER_PROXY_ADDR,
L2_TX_FEE_VAULT_ADDR
);
L2ScrollMessenger(payable(L2_SCROLL_MESSENGER_PROXY_ADDR)).initialize(L1_SCROLL_MESSENGER_PROXY_ADDR);
// initialize L2GatewayRouter
L2GatewayRouter(L2_GATEWAY_ROUTER_PROXY_ADDR).initialize(

View File

@@ -25,18 +25,18 @@ async function main() {
const L2StandardERC20Impl = process.env.L2_SCROLL_STANDARD_ERC20_ADDR!;
const L2StandardERC20FactoryAddress = process.env.L2_SCROLL_STANDARD_ERC20_FACTORY_ADDR!;
// if ((await L1StandardERC20Gateway.counterpart()) === constants.AddressZero) {
const tx = await L1StandardERC20Gateway.initialize(
L2StandardERC20GatewayAddress,
L1GatewayRouterAddress,
L1ScrollMessengerAddress,
L2StandardERC20Impl,
L2StandardERC20FactoryAddress
);
console.log("initialize L1StandardERC20Gateway, hash:", tx.hash);
const receipt = await tx.wait();
console.log(`✅ Done, gas used: ${receipt.gasUsed}`);
// }
if ((await L1StandardERC20Gateway.counterpart()) === constants.AddressZero) {
const tx = await L1StandardERC20Gateway.initialize(
L2StandardERC20GatewayAddress,
L1GatewayRouterAddress,
L1ScrollMessengerAddress,
L2StandardERC20Impl,
L2StandardERC20FactoryAddress
);
console.log("initialize L1StandardERC20Gateway, hash:", tx.hash);
const receipt = await tx.wait();
console.log(`✅ Done, gas used: ${receipt.gasUsed}`);
}
}
// We recommend this pattern to be able to use async/await everywhere

View File

@@ -23,16 +23,16 @@ async function main() {
const L1ScrollMessengerAddress = addressFile.get("L1ScrollMessenger.proxy");
const L2GatewayRouterAddress = process.env.L2_GATEWAY_ROUTER_PROXY_ADDR!;
// if ((await L1GatewayRouter.counterpart()) === constants.AddressZero) {
const tx = await L1GatewayRouter.initialize(
L1StandardERC20GatewayAddress,
L2GatewayRouterAddress,
L1ScrollMessengerAddress
);
console.log("initialize L1StandardERC20Gateway, hash:", tx.hash);
const receipt = await tx.wait();
console.log(`✅ Done, gas used: ${receipt.gasUsed}`);
// }
if ((await L1GatewayRouter.counterpart()) === constants.AddressZero) {
const tx = await L1GatewayRouter.initialize(
L1StandardERC20GatewayAddress,
L2GatewayRouterAddress,
L1ScrollMessengerAddress
);
console.log("initialize L1StandardERC20Gateway, hash:", tx.hash);
const receipt = await tx.wait();
console.log(`✅ Done, gas used: ${receipt.gasUsed}`);
}
}
// We recommend this pattern to be able to use async/await everywhere

View File

@@ -21,12 +21,12 @@ async function main() {
const ZKRollupAddress = addressFile.get("ZKRollup.proxy");
// if ((await L1ScrollMessenger.rollup()) === constants.AddressZero) {
const tx = await L1ScrollMessenger.initialize(ZKRollupAddress);
console.log("initialize L1StandardERC20Gateway, hash:", tx.hash);
const receipt = await tx.wait();
console.log(`✅ Done, gas used: ${receipt.gasUsed}`);
// }
if ((await L1ScrollMessenger.rollup()) === constants.AddressZero) {
const tx = await L1ScrollMessenger.initialize(ZKRollupAddress);
console.log("initialize L1StandardERC20Gateway, hash:", tx.hash);
const receipt = await tx.wait();
console.log(`✅ Done, gas used: ${receipt.gasUsed}`);
}
}
// We recommend this pattern to be able to use async/await everywhere

View File

@@ -0,0 +1,35 @@
/* eslint-disable node/no-missing-import */
import * as dotenv from "dotenv";
import { constants } from "ethers";
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();
const L1USDCGateway = await ethers.getContractAt("L1USDCGateway", addressFile.get("L1USDCGateway.proxy"), deployer);
const L1GatewayRouterAddress = addressFile.get("L1GatewayRouter.proxy");
const L1ScrollMessengerAddress = addressFile.get("L1ScrollMessenger.proxy");
const L2USDCGatewayAddress = process.env.L2_USDC_GATEWAY_PROXY_ADDR!;
if ((await L1USDCGateway.counterpart()) === constants.AddressZero) {
const tx = await L1USDCGateway.initialize(L2USDCGatewayAddress, L1GatewayRouterAddress, L1ScrollMessengerAddress);
console.log("initialize L1USDCGateway, hash:", tx.hash);
const receipt = await tx.wait();
console.log(`✅ Done, 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;
});

View File

@@ -24,17 +24,17 @@ async function main() {
const L2StandardERC20FactoryAddress = addressFile.get("ScrollStandardERC20Factory");
const L1StandardERC20GatewayAddress = process.env.L1_STANDARD_ERC20_GATEWAY_PROXY_ADDR!;
// if ((await L2StandardERC20Gateway.counterpart()) === constants.AddressZero) {
const tx = await L2StandardERC20Gateway.initialize(
L1StandardERC20GatewayAddress,
L2GatewayRouterAddress,
L2ScrollMessengerAddress,
L2StandardERC20FactoryAddress
);
console.log("initialize L2StandardERC20Gateway, hash:", tx.hash);
const receipt = await tx.wait();
console.log(`✅ Done, gas used: ${receipt.gasUsed}`);
// }
if ((await L2StandardERC20Gateway.counterpart()) === constants.AddressZero) {
const tx = await L2StandardERC20Gateway.initialize(
L1StandardERC20GatewayAddress,
L2GatewayRouterAddress,
L2ScrollMessengerAddress,
L2StandardERC20FactoryAddress
);
console.log("initialize L2StandardERC20Gateway, hash:", tx.hash);
const receipt = await tx.wait();
console.log(`✅ Done, gas used: ${receipt.gasUsed}`);
}
}
// We recommend this pattern to be able to use async/await everywhere

View File

@@ -23,16 +23,16 @@ async function main() {
const L2ScrollMessengerAddress = addressFile.get("L2ScrollMessenger");
const L1GatewayRouterAddress = process.env.L1_GATEWAY_ROUTER_PROXY_ADDR!;
// if ((await L2GatewayRouter.counterpart()) === constants.AddressZero) {
const tx = await L2GatewayRouter.initialize(
L2StandardERC20GatewayAddress,
L1GatewayRouterAddress,
L2ScrollMessengerAddress
);
console.log("initialize L1StandardERC20Gateway, hash:", tx.hash);
const receipt = await tx.wait();
console.log(`✅ Done, gas used: ${receipt.gasUsed}`);
// }
if ((await L2GatewayRouter.counterpart()) === constants.AddressZero) {
const tx = await L2GatewayRouter.initialize(
L2StandardERC20GatewayAddress,
L1GatewayRouterAddress,
L2ScrollMessengerAddress
);
console.log("initialize L1StandardERC20Gateway, hash:", tx.hash);
const receipt = await tx.wait();
console.log(`✅ Done, gas used: ${receipt.gasUsed}`);
}
}
// We recommend this pattern to be able to use async/await everywhere

View File

@@ -0,0 +1,35 @@
/* eslint-disable node/no-missing-import */
import * as dotenv from "dotenv";
import { constants } from "ethers";
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();
const L2USDCGateway = await ethers.getContractAt("L2USDCGateway", addressFile.get("L2USDCGateway.proxy"), deployer);
const L2GatewayRouterAddress = addressFile.get("L2GatewayRouter.proxy");
const L2ScrollMessengerAddress = addressFile.get("L2ScrollMessenger.proxy");
const L1USDCGatewayAddress = process.env.L1_USDC_GATEWAY_PROXY_ADDR!;
if ((await L2USDCGateway.counterpart()) === constants.AddressZero) {
const tx = await L2USDCGateway.initialize(L1USDCGatewayAddress, L2GatewayRouterAddress, L2ScrollMessengerAddress);
console.log("initialize L2USDCGateway, hash:", tx.hash);
const receipt = await tx.wait();
console.log(`✅ Done, 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;
});

View File

@@ -10,8 +10,9 @@ interface IL1ScrollMessenger is IScrollMessenger {
**********/
/// @notice Emitted when the maximum number of times each message can be replayed is updated.
/// @param maxReplayTimes The new maximum number of times each message can be replayed.
event UpdateMaxReplayTimes(uint256 maxReplayTimes);
/// @param oldMaxReplayTimes The old maximum number of times each message can be replayed.
/// @param newMaxReplayTimes The new maximum number of times each message can be replayed.
event UpdateMaxReplayTimes(uint256 oldMaxReplayTimes, uint256 newMaxReplayTimes);
/***********
* Structs *

View File

@@ -2,15 +2,12 @@
pragma solidity =0.8.16;
import {PausableUpgradeable} from "@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol";
import {IScrollChain} from "./rollup/IScrollChain.sol";
import {IL1MessageQueue} from "./rollup/IL1MessageQueue.sol";
import {IL1ScrollMessenger} from "./IL1ScrollMessenger.sol";
import {ScrollConstants} from "../libraries/constants/ScrollConstants.sol";
import {IScrollMessenger} from "../libraries/IScrollMessenger.sol";
import {ScrollMessengerBase} from "../libraries/ScrollMessengerBase.sol";
import {AddressAliasHelper} from "../libraries/common/AddressAliasHelper.sol";
import {WithdrawTrieVerifier} from "../libraries/verifier/WithdrawTrieVerifier.sol";
import {IMessageDropCallback} from "../libraries/callbacks/IMessageDropCallback.sol";
@@ -28,7 +25,7 @@ import {IMessageDropCallback} from "../libraries/callbacks/IMessageDropCallback.
///
/// @dev All deposited Ether (including `WETH` deposited throng `L1WETHGateway`) will locked in
/// this contract.
contract L1ScrollMessenger is PausableUpgradeable, ScrollMessengerBase, IL1ScrollMessenger {
contract L1ScrollMessenger is ScrollMessengerBase, IL1ScrollMessenger {
/***********
* Structs *
***********/
@@ -97,8 +94,7 @@ contract L1ScrollMessenger is PausableUpgradeable, ScrollMessengerBase, IL1Scrol
address _rollup,
address _messageQueue
) public initializer {
PausableUpgradeable.__Pausable_init();
ScrollMessengerBase._initialize(_counterpart, _feeVault);
ScrollMessengerBase.__ScrollMessengerBase_init(_counterpart, _feeVault);
rollup = _rollup;
messageQueue = _messageQueue;
@@ -295,24 +291,14 @@ contract L1ScrollMessenger is PausableUpgradeable, ScrollMessengerBase, IL1Scrol
* Restricted Functions *
************************/
/// @notice Pause the contract
/// @dev This function can only called by contract owner.
/// @param _status The pause status to update.
function setPause(bool _status) external onlyOwner {
if (_status) {
_pause();
} else {
_unpause();
}
}
/// @notice Update max replay times.
/// @dev This function can only called by contract owner.
/// @param _maxReplayTimes The new max replay times.
function updateMaxReplayTimes(uint256 _maxReplayTimes) external onlyOwner {
maxReplayTimes = _maxReplayTimes;
/// @param _newMaxReplayTimes The new max replay times.
function updateMaxReplayTimes(uint256 _newMaxReplayTimes) external onlyOwner {
uint256 _oldMaxReplayTimes = maxReplayTimes;
maxReplayTimes = _newMaxReplayTimes;
emit UpdateMaxReplayTimes(_maxReplayTimes);
emit UpdateMaxReplayTimes(_oldMaxReplayTimes, _newMaxReplayTimes);
}
/**********************

View File

@@ -11,17 +11,20 @@ interface IL1GatewayRouter is IL1ETHGateway, IL1ERC20Gateway {
**********/
/// @notice Emitted when the address of ETH Gateway is updated.
/// @param ethGateway The address of new ETH Gateway.
event SetETHGateway(address indexed ethGateway);
/// @param oldETHGateway The address of the old ETH Gateway.
/// @param newEthGateway The address of the new ETH Gateway.
event SetETHGateway(address indexed oldETHGateway, address indexed newEthGateway);
/// @notice Emitted when the address of default ERC20 Gateway is updated.
/// @param defaultERC20Gateway The address of new default ERC20 Gateway.
event SetDefaultERC20Gateway(address indexed defaultERC20Gateway);
/// @param oldDefaultERC20Gateway The address of the old default ERC20 Gateway.
/// @param newDefaultERC20Gateway The address of the new default ERC20 Gateway.
event SetDefaultERC20Gateway(address indexed oldDefaultERC20Gateway, address indexed newDefaultERC20Gateway);
/// @notice Emitted when the `gateway` for `token` is updated.
/// @param token The address of token updated.
/// @param gateway The corresponding address of gateway updated.
event SetERC20Gateway(address indexed token, address indexed gateway);
/// @param oldGateway The corresponding address of the old gateway.
/// @param newGateway The corresponding address of the new gateway.
event SetERC20Gateway(address indexed token, address indexed oldGateway, address indexed newGateway);
/*************************
* Public View Functions *

View File

@@ -2,7 +2,6 @@
pragma solidity =0.8.16;
import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import {IERC20Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol";
import {SafeERC20Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol";
@@ -18,7 +17,7 @@ import {L1ERC20Gateway} from "./L1ERC20Gateway.sol";
/// finalize withdraw the tokens from layer 2.
/// @dev The deposited tokens are held in this gateway. On finalizing withdraw, the corresponding
/// tokens will be transfer to the recipient directly.
contract L1CustomERC20Gateway is OwnableUpgradeable, ScrollGatewayBase, L1ERC20Gateway {
contract L1CustomERC20Gateway is L1ERC20Gateway {
using SafeERC20Upgradeable for IERC20Upgradeable;
/**********
@@ -26,9 +25,10 @@ contract L1CustomERC20Gateway is OwnableUpgradeable, ScrollGatewayBase, L1ERC20G
**********/
/// @notice Emitted when token mapping for ERC20 token is updated.
/// @param _l1Token The address of ERC20 token on layer 1.
/// @param _l2Token The address of corresponding ERC20 token on layer 2.
event UpdateTokenMapping(address _l1Token, address _l2Token);
/// @param l1Token The address of ERC20 token in layer 1.
/// @param oldL2Token The address of the old corresponding ERC20 token in layer 2.
/// @param newL2Token The address of the new corresponding ERC20 token in layer 2.
event UpdateTokenMapping(address indexed l1Token, address indexed oldL2Token, address indexed newL2Token);
/*************
* Variables *
@@ -56,7 +56,6 @@ contract L1CustomERC20Gateway is OwnableUpgradeable, ScrollGatewayBase, L1ERC20G
) external initializer {
require(_router != address(0), "zero router address");
OwnableUpgradeable.__Ownable_init();
ScrollGatewayBase._initialize(_counterpart, _router, _messenger);
}
@@ -79,9 +78,10 @@ contract L1CustomERC20Gateway is OwnableUpgradeable, ScrollGatewayBase, L1ERC20G
function updateTokenMapping(address _l1Token, address _l2Token) external onlyOwner {
require(_l2Token != address(0), "token address cannot be 0");
address _oldL2Token = tokenMapping[_l1Token];
tokenMapping[_l1Token] = _l2Token;
emit UpdateTokenMapping(_l1Token, _l2Token);
emit UpdateTokenMapping(_l1Token, _oldL2Token, _l2Token);
}
/**********************

View File

@@ -2,7 +2,6 @@
pragma solidity =0.8.16;
import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import {IERC1155Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC1155/IERC1155Upgradeable.sol";
import {ERC1155HolderUpgradeable, ERC1155ReceiverUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC1155/utils/ERC1155HolderUpgradeable.sol";
@@ -20,21 +19,16 @@ import {ScrollGatewayBase} from "../../libraries/gateway/ScrollGatewayBase.sol";
/// NFT will be transfer to the recipient directly.
///
/// This will be changed if we have more specific scenarios.
contract L1ERC1155Gateway is
OwnableUpgradeable,
ERC1155HolderUpgradeable,
ScrollGatewayBase,
IL1ERC1155Gateway,
IMessageDropCallback
{
contract L1ERC1155Gateway is ERC1155HolderUpgradeable, ScrollGatewayBase, IL1ERC1155Gateway, IMessageDropCallback {
/**********
* Events *
**********/
/// @notice Emitted when token mapping for ERC1155 token is updated.
/// @param _l1Token The address of ERC1155 token on layer 1.
/// @param _l2Token The address of corresponding ERC1155 token on layer 2.
event UpdateTokenMapping(address _l1Token, address _l2Token);
/// @param l1Token The address of ERC1155 token in layer 1.
/// @param oldL2Token The address of the old corresponding ERC1155 token in layer 2.
/// @param newL2Token The address of the new corresponding ERC1155 token in layer 2.
event UpdateTokenMapping(address indexed l1Token, address indexed oldL2Token, address indexed newL2Token);
/*************
* Variables *
@@ -55,7 +49,6 @@ contract L1ERC1155Gateway is
/// @param _counterpart The address of L2ERC1155Gateway in L2.
/// @param _messenger The address of L1ScrollMessenger.
function initialize(address _counterpart, address _messenger) external initializer {
OwnableUpgradeable.__Ownable_init();
ERC1155HolderUpgradeable.__ERC1155Holder_init();
ERC1155ReceiverUpgradeable.__ERC1155Receiver_init();
@@ -177,9 +170,10 @@ contract L1ERC1155Gateway is
function updateTokenMapping(address _l1Token, address _l2Token) external onlyOwner {
require(_l2Token != address(0), "token address cannot be 0");
address _oldL2Token = tokenMapping[_l1Token];
tokenMapping[_l1Token] = _l2Token;
emit UpdateTokenMapping(_l1Token, _l2Token);
emit UpdateTokenMapping(_l1Token, _oldL2Token, _l2Token);
}
/**********************

View File

@@ -2,14 +2,12 @@
pragma solidity ^0.8.16;
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {IERC20Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol";
import {SafeERC20Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol";
import {IL1ERC20Gateway} from "./IL1ERC20Gateway.sol";
import {IL1GatewayRouter} from "./IL1GatewayRouter.sol";
import {ScrollGatewayBase} from "../../libraries/gateway/ScrollGatewayBase.sol";
import {IL2ERC20Gateway} from "../../L2/gateways/IL2ERC20Gateway.sol";
import {IScrollMessenger} from "../../libraries/IScrollMessenger.sol";
import {ScrollConstants} from "../../libraries/constants/ScrollConstants.sol";
@@ -19,7 +17,7 @@ import {IMessageDropCallback} from "../../libraries/callbacks/IMessageDropCallba
// solhint-disable no-empty-blocks
abstract contract L1ERC20Gateway is IL1ERC20Gateway, IMessageDropCallback, ScrollGatewayBase {
using SafeERC20 for IERC20;
using SafeERC20Upgradeable for IERC20Upgradeable;
/*************
* Variables *
@@ -70,12 +68,12 @@ abstract contract L1ERC20Gateway is IL1ERC20Gateway, IMessageDropCallback, Scrol
address _to,
uint256 _amount,
bytes calldata _data
) external payable override onlyCallByCounterpart nonReentrant {
) external payable virtual override onlyCallByCounterpart nonReentrant {
_beforeFinalizeWithdrawERC20(_l1Token, _l2Token, _from, _to, _amount, _data);
// @note can possible trigger reentrant call to this contract or messenger,
// but it seems not a big problem.
IERC20(_l1Token).safeTransfer(_to, _amount);
IERC20Upgradeable(_l1Token).safeTransfer(_to, _amount);
_doCallback(_to, _data);
@@ -96,7 +94,7 @@ abstract contract L1ERC20Gateway is IL1ERC20Gateway, IMessageDropCallback, Scrol
// do dome check for each custom gateway
_beforeDropMessage(_token, _receiver, _amount);
IERC20(_token).safeTransfer(_receiver, _amount);
IERC20Upgradeable(_token).safeTransfer(_receiver, _amount);
emit RefundERC20(_token, _receiver, _amount);
}
@@ -154,9 +152,9 @@ abstract contract L1ERC20Gateway is IL1ERC20Gateway, IMessageDropCallback, Scrol
_amount = IL1GatewayRouter(msg.sender).requestERC20(_from, _token, _amount);
} else {
// common practice to handle fee on transfer token.
uint256 _before = IERC20(_token).balanceOf(address(this));
IERC20(_token).safeTransferFrom(_from, address(this), _amount);
uint256 _after = IERC20(_token).balanceOf(address(this));
uint256 _before = IERC20Upgradeable(_token).balanceOf(address(this));
IERC20Upgradeable(_token).safeTransferFrom(_from, address(this), _amount);
uint256 _after = IERC20Upgradeable(_token).balanceOf(address(this));
// no unchecked here, since some weird token may return arbitrary balance.
_amount = _after - _before;
}

View File

@@ -2,7 +2,6 @@
pragma solidity =0.8.16;
import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import {IERC721Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC721/IERC721Upgradeable.sol";
import {ERC721HolderUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC721/utils/ERC721HolderUpgradeable.sol";
@@ -20,21 +19,16 @@ import {ScrollGatewayBase} from "../../libraries/gateway/ScrollGatewayBase.sol";
/// NFT will be transfer to the recipient directly.
///
/// This will be changed if we have more specific scenarios.
contract L1ERC721Gateway is
OwnableUpgradeable,
ERC721HolderUpgradeable,
ScrollGatewayBase,
IL1ERC721Gateway,
IMessageDropCallback
{
contract L1ERC721Gateway is ERC721HolderUpgradeable, ScrollGatewayBase, IL1ERC721Gateway, IMessageDropCallback {
/**********
* Events *
**********/
/// @notice Emitted when token mapping for ERC721 token is updated.
/// @param _l1Token The address of ERC721 token on layer 1.
/// @param _l2Token The address of corresponding ERC721 token on layer 2.
event UpdateTokenMapping(address _l1Token, address _l2Token);
/// @param l1Token The address of ERC721 token in layer 1.
/// @param oldL2Token The address of the old corresponding ERC721 token in layer 2.
/// @param newL2Token The address of the new corresponding ERC721 token in layer 2.
event UpdateTokenMapping(address indexed l1Token, address indexed oldL2Token, address indexed newL2Token);
/*************
* Variables *
@@ -55,7 +49,6 @@ contract L1ERC721Gateway is
/// @param _counterpart The address of L2ERC721Gateway in L2.
/// @param _messenger The address of L1ScrollMessenger.
function initialize(address _counterpart, address _messenger) external initializer {
OwnableUpgradeable.__Ownable_init();
ERC721HolderUpgradeable.__ERC721Holder_init();
ScrollGatewayBase._initialize(_counterpart, address(0), _messenger);
@@ -173,9 +166,10 @@ contract L1ERC721Gateway is
function updateTokenMapping(address _l1Token, address _l2Token) external onlyOwner {
require(_l2Token != address(0), "token address cannot be 0");
address _oldL2Token = tokenMapping[_l1Token];
tokenMapping[_l1Token] = _l2Token;
emit UpdateTokenMapping(_l1Token, _l2Token);
emit UpdateTokenMapping(_l1Token, _oldL2Token, _l2Token);
}
/**********************

View File

@@ -2,8 +2,6 @@
pragma solidity =0.8.16;
import {Initializable} from "@openzeppelin/contracts/proxy/utils/Initializable.sol";
import {IL2ETHGateway} from "../../L2/gateways/IL2ETHGateway.sol";
import {IL1ScrollMessenger} from "../IL1ScrollMessenger.sol";
import {IL1ETHGateway} from "./IL1ETHGateway.sol";
@@ -18,7 +16,7 @@ import {ScrollGatewayBase} from "../../libraries/gateway/ScrollGatewayBase.sol";
/// finalize withdraw ETH from layer 2.
/// @dev The deposited ETH tokens are held in this gateway. On finalizing withdraw, the corresponding
/// ETH will be transfer to the recipient directly.
contract L1ETHGateway is Initializable, ScrollGatewayBase, IL1ETHGateway, IMessageDropCallback {
contract L1ETHGateway is ScrollGatewayBase, IL1ETHGateway, IMessageDropCallback {
/***************
* Constructor *
***************/

View File

@@ -6,8 +6,6 @@ import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/Own
import {IERC20Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol";
import {SafeERC20Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol";
import {IScrollGateway} from "../../libraries/gateway/IScrollGateway.sol";
import {IL1ScrollMessenger} from "../IL1ScrollMessenger.sol";
import {IL1ETHGateway} from "./IL1ETHGateway.sol";
import {IL1ERC20Gateway} from "./IL1ERC20Gateway.sol";
import {IL1GatewayRouter} from "./IL1GatewayRouter.sol";
@@ -68,13 +66,13 @@ contract L1GatewayRouter is OwnableUpgradeable, IL1GatewayRouter {
// it can be zero during initialization
if (_defaultERC20Gateway != address(0)) {
defaultERC20Gateway = _defaultERC20Gateway;
emit SetDefaultERC20Gateway(_defaultERC20Gateway);
emit SetDefaultERC20Gateway(address(0), _defaultERC20Gateway);
}
// it can be zero during initialization
if (_ethGateway != address(0)) {
ethGateway = _ethGateway;
emit SetETHGateway(_ethGateway);
emit SetETHGateway(address(0), _ethGateway);
}
}
@@ -225,17 +223,19 @@ contract L1GatewayRouter is OwnableUpgradeable, IL1GatewayRouter {
************************/
/// @inheritdoc IL1GatewayRouter
function setETHGateway(address _ethGateway) external onlyOwner {
ethGateway = _ethGateway;
function setETHGateway(address _newEthGateway) external onlyOwner {
address _oldETHGateway = ethGateway;
ethGateway = _newEthGateway;
emit SetETHGateway(_ethGateway);
emit SetETHGateway(_oldETHGateway, _newEthGateway);
}
/// @inheritdoc IL1GatewayRouter
function setDefaultERC20Gateway(address _defaultERC20Gateway) external onlyOwner {
defaultERC20Gateway = _defaultERC20Gateway;
function setDefaultERC20Gateway(address _newDefaultERC20Gateway) external onlyOwner {
address _oldDefaultERC20Gateway = defaultERC20Gateway;
defaultERC20Gateway = _newDefaultERC20Gateway;
emit SetDefaultERC20Gateway(_defaultERC20Gateway);
emit SetDefaultERC20Gateway(_oldDefaultERC20Gateway, _newDefaultERC20Gateway);
}
/// @inheritdoc IL1GatewayRouter
@@ -243,9 +243,10 @@ contract L1GatewayRouter is OwnableUpgradeable, IL1GatewayRouter {
require(_tokens.length == _gateways.length, "length mismatch");
for (uint256 i = 0; i < _tokens.length; i++) {
address _oldGateway = ERC20Gateway[_tokens[i]];
ERC20Gateway[_tokens[i]] = _gateways[i];
emit SetERC20Gateway(_tokens[i], _gateways[i]);
emit SetERC20Gateway(_tokens[i], _oldGateway, _gateways[i]);
}
}
}

View File

@@ -2,12 +2,9 @@
pragma solidity =0.8.16;
import {Initializable} from "@openzeppelin/contracts/proxy/utils/Initializable.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {Clones} from "@openzeppelin/contracts/proxy/Clones.sol";
import {ClonesUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/ClonesUpgradeable.sol";
import {IERC20MetadataUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/IERC20MetadataUpgradeable.sol";
import {IERC20Metadata} from "../../interfaces/IERC20Metadata.sol";
import {IL2ERC20Gateway} from "../../L2/gateways/IL2ERC20Gateway.sol";
import {IL1ScrollMessenger} from "../IL1ScrollMessenger.sol";
import {IL1ERC20Gateway} from "./IL1ERC20Gateway.sol";
@@ -21,9 +18,7 @@ import {L1ERC20Gateway} from "./L1ERC20Gateway.sol";
/// @dev 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.
contract L1StandardERC20Gateway is Initializable, ScrollGatewayBase, L1ERC20Gateway {
using SafeERC20 for IERC20;
contract L1StandardERC20Gateway is L1ERC20Gateway {
/*************
* Variables *
*************/
@@ -81,7 +76,7 @@ contract L1StandardERC20Gateway is Initializable, ScrollGatewayBase, L1ERC20Gate
// we can calculate the l2 address directly.
bytes32 _salt = keccak256(abi.encodePacked(counterpart, keccak256(abi.encodePacked(_l1Token))));
return Clones.predictDeterministicAddress(l2TokenImplementation, _salt, l2TokenFactory);
return ClonesUpgradeable.predictDeterministicAddress(l2TokenImplementation, _salt, l2TokenFactory);
}
/**********************
@@ -143,9 +138,9 @@ contract L1StandardERC20Gateway is Initializable, ScrollGatewayBase, L1ERC20Gate
_l2Token = getL2ERC20Address(_token);
// passing symbol/name/decimal in order to deploy in L2.
string memory _symbol = IERC20Metadata(_token).symbol();
string memory _name = IERC20Metadata(_token).name();
uint8 _decimals = IERC20Metadata(_token).decimals();
string memory _symbol = IERC20MetadataUpgradeable(_token).symbol();
string memory _name = IERC20MetadataUpgradeable(_token).name();
uint8 _decimals = IERC20MetadataUpgradeable(_token).decimals();
_l2Data = abi.encode(true, abi.encode(_data, abi.encode(_symbol, _name, _decimals)));
} else {
_l2Data = abi.encode(false, _data);

View File

@@ -2,10 +2,6 @@
pragma solidity =0.8.16;
import {Initializable} from "@openzeppelin/contracts/proxy/utils/Initializable.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {IWETH} from "../../interfaces/IWETH.sol";
import {IL2ERC20Gateway} from "../../L2/gateways/IL2ERC20Gateway.sol";
import {IL1ScrollMessenger} from "../IL1ScrollMessenger.sol";
@@ -21,9 +17,7 @@ import {L1ERC20Gateway} from "./L1ERC20Gateway.sol";
/// as Ether and then the Ether will be sent to the `L1ScrollMessenger` contract.
/// On finalizing withdraw, the Ether will be transfered from `L1ScrollMessenger`, then
/// wrapped as WETH and finally transfer to recipient.
contract L1WETHGateway is Initializable, ScrollGatewayBase, L1ERC20Gateway {
using SafeERC20 for IERC20;
contract L1WETHGateway is L1ERC20Gateway {
/*************
* Constants *
*************/

View File

@@ -2,10 +2,163 @@
pragma solidity =0.8.16;
import {L1CustomERC20Gateway} from "../L1CustomERC20Gateway.sol";
import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import {IERC20Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol";
import {SafeERC20Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol";
// solhint-disable no-empty-blocks
import {IFiatToken} from "../../../interfaces/IFiatToken.sol";
import {IUSDCBurnableSourceBridge} from "../../../interfaces/IUSDCBurnableSourceBridge.sol";
import {IL2ERC20Gateway} from "../../../L2/gateways/IL2ERC20Gateway.sol";
import {IL1ScrollMessenger} from "../../IL1ScrollMessenger.sol";
import {IL1ERC20Gateway} from "../IL1ERC20Gateway.sol";
contract L1USDCGateway is L1CustomERC20Gateway {
import {ScrollGatewayBase} from "../../../libraries/gateway/ScrollGatewayBase.sol";
import {L1ERC20Gateway} from "../L1ERC20Gateway.sol";
/// @title L1USDCGateway
/// @notice The `L1USDCGateway` contract is used to deposit `USDC` token in layer 1 and
/// finalize withdraw `USDC` from layer 2, before USDC become native in layer 2.
contract L1USDCGateway is L1ERC20Gateway, IUSDCBurnableSourceBridge {
using SafeERC20Upgradeable for IERC20Upgradeable;
/*************
* Constants *
*************/
/// @notice The address of L1 USDC address.
// solhint-disable-next-line var-name-mixedcase
address public immutable l1USDC;
/// @notice The address of L2 USDC address.
address public immutable l2USDC;
/*************
* Variables *
*************/
address public circleCaller;
bool public depositPaused;
bool public withdrawPaused;
/***************
* Constructor *
***************/
constructor(address _l1USDC, address _l2USDC) {
_disableInitializers();
l1USDC = _l1USDC;
l2USDC = _l2USDC;
}
/// @notice Initialize the storage of L1WETHGateway.
/// @param _counterpart The address of L2ETHGateway in L2.
/// @param _router The address of L1GatewayRouter.
/// @param _messenger The address of L1ScrollMessenger.
function initialize(
address _counterpart,
address _router,
address _messenger
) external initializer {
require(_router != address(0), "zero router address");
ScrollGatewayBase._initialize(_counterpart, _router, _messenger);
}
/*************************
* Public View Functions *
*************************/
/// @inheritdoc IL1ERC20Gateway
function getL2ERC20Address(address) public view override returns (address) {
return l2USDC;
}
/*******************************
* Public Restricted Functions *
*******************************/
/// @inheritdoc IUSDCBurnableSourceBridge
function burnAllLockedUSDC() external override {
require(msg.sender == circleCaller, "only circle caller");
uint256 _balance = IERC20Upgradeable(l1USDC).balanceOf(address(this));
require(IFiatToken(l1USDC).burn(_balance), "burn USDC failed");
}
/// @notice Update the Circle EOA address.
/// @param _caller The address to update.
function updateCircleCaller(address _caller) external onlyOwner {
circleCaller = _caller;
}
/// @notice Change the deposit pause status of this contract.
/// @param _paused The new status, `true` means paused and `false` means not paused.
function pauseDeposit(bool _paused) external onlyOwner {
depositPaused = _paused;
}
/// @notice Change the withdraw pause status of this contract.
/// @param _paused The new status, `true` means paused and `false` means not paused.
function pauseWithdraw(bool _paused) external onlyOwner {
withdrawPaused = _paused;
}
/**********************
* Internal Functions *
**********************/
/// @inheritdoc L1ERC20Gateway
function _beforeFinalizeWithdrawERC20(
address _l1Token,
address _l2Token,
address,
address,
uint256,
bytes calldata
) internal virtual override {
require(msg.value == 0, "nonzero msg.value");
require(_l1Token == l1USDC, "l1 token not USDC");
require(_l2Token == l2USDC, "l2 token not USDC");
require(!withdrawPaused, "withdraw paused");
}
/// @inheritdoc L1ERC20Gateway
function _beforeDropMessage(
address,
address,
uint256
) internal virtual override {
require(msg.value == 0, "nonzero msg.value");
}
/// @inheritdoc L1ERC20Gateway
function _deposit(
address _token,
address _to,
uint256 _amount,
bytes memory _data,
uint256 _gasLimit
) internal virtual override nonReentrant {
require(_amount > 0, "deposit zero amount");
require(_token == l1USDC, "only USDC is allowed");
require(!depositPaused, "deposit paused");
// 1. Transfer token into this contract.
address _from;
(_from, _amount, _data) = _transferERC20In(_token, _amount, _data);
require(_data.length == 0, "call is not allowed");
// 2. Generate message passed to L2USDCGateway.
bytes memory _message = abi.encodeCall(
IL2ERC20Gateway.finalizeDepositERC20,
(_token, l2USDC, _from, _to, _amount, _data)
);
// 3. Send message to L1ScrollMessenger.
IL1ScrollMessenger(messenger).sendMessage{value: msg.value}(counterpart, 0, _message, _gasLimit, _from);
emit DepositERC20(_token, l2USDC, _from, _to, _amount, _data);
}
}

View File

@@ -0,0 +1,184 @@
// SPDX-License-Identifier: MIT
pragma solidity =0.8.16;
import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import {IERC20Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol";
import {SafeERC20Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol";
import {ITokenMessenger} from "../../../interfaces/ITokenMessenger.sol";
import {IL2ERC20Gateway} from "../../../L2/gateways/IL2ERC20Gateway.sol";
import {IL1ScrollMessenger} from "../../IL1ScrollMessenger.sol";
import {IL1ERC20Gateway} from "../IL1ERC20Gateway.sol";
import {CCTPGatewayBase} from "../../../libraries/gateway/CCTPGatewayBase.sol";
import {ScrollGatewayBase} from "../../../libraries/gateway/ScrollGatewayBase.sol";
import {L1ERC20Gateway} from "../L1ERC20Gateway.sol";
/// @title L1USDCGatewayCCTP
/// @notice The `L1USDCGateway` contract is used to deposit `USDC` token in layer 1 and
/// finalize withdraw `USDC` from layer 2, after USDC become native in layer 2.
contract L1USDCGatewayCCTP is CCTPGatewayBase, L1ERC20Gateway {
using SafeERC20Upgradeable for IERC20Upgradeable;
/***************
* Constructor *
***************/
constructor(
address _l1USDC,
address _l2USDC,
uint32 _destinationDomain
) CCTPGatewayBase(_l1USDC, _l2USDC, _destinationDomain) {}
/// @notice Initialize the storage of L1USDCGatewayCCTP.
/// @param _counterpart The address of L2USDCGatewayCCTP in L2.
/// @param _router The address of L1GatewayRouter.
/// @param _messenger The address of L1ScrollMessenger.
/// @param _cctpMessenger The address of TokenMessenger in local domain.
/// @param _cctpTransmitter The address of MessageTransmitter in local domain.
function initialize(
address _counterpart,
address _router,
address _messenger,
address _cctpMessenger,
address _cctpTransmitter
) external initializer {
require(_router != address(0), "zero router address");
ScrollGatewayBase._initialize(_counterpart, _router, _messenger);
CCTPGatewayBase._initialize(_cctpMessenger, _cctpTransmitter);
OwnableUpgradeable.__Ownable_init();
}
/*************************
* Public View Functions *
*************************/
/// @inheritdoc IL1ERC20Gateway
function getL2ERC20Address(address) public view override returns (address) {
return l2USDC;
}
/*****************************
* Public Mutating Functions *
*****************************/
/// @notice Relay cross chain message and claim USDC that has been cross chained.
/// @dev The `_scrollMessage` is actually encoded calldata for `L1ScrollMessenger.relayMessageWithProof`.
///
/// @dev This helper function is aimed to claim USDC in single transaction.
/// Normally, an user should call `L1ScrollMessenger.relayMessageWithProof` first,
/// then `L1USDCGatewayCCTP.claimUSDC`.
///
/// @param _nonce The nonce of the message from CCTP.
/// @param _cctpMessage The message passed to MessageTransmitter contract in CCTP.
/// @param _cctpSignature The message passed to MessageTransmitter contract in CCTP.
/// @param _scrollMessage The message passed to L1ScrollMessenger contract.
function relayAndClaimUSDC(
uint256 _nonce,
bytes calldata _cctpMessage,
bytes calldata _cctpSignature,
bytes calldata _scrollMessage
) external {
require(status[_nonce] == CCTPMessageStatus.None, "message relayed");
// call messenger to set `status[_nonce]` to `CCTPMessageStatus.Pending`.
(bool _success, ) = messenger.call(_scrollMessage);
require(_success, "call messenger failed");
claimUSDC(_nonce, _cctpMessage, _cctpSignature);
}
/// @inheritdoc IL1ERC20Gateway
/// @dev The function will not mint the USDC, users need to call `claimUSDC` after this function is done.
function finalizeWithdrawERC20(
address _l1Token,
address _l2Token,
address _from,
address _to,
uint256 _amount,
bytes memory _data
) external payable override onlyCallByCounterpart {
require(msg.value == 0, "nonzero msg.value");
require(_l1Token == l1USDC, "l1 token not USDC");
require(_l2Token == l2USDC, "l2 token not USDC");
uint256 _nonce;
(_nonce, _data) = abi.decode(_data, (uint256, bytes));
require(status[_nonce] == CCTPMessageStatus.None, "message relayed");
status[_nonce] = CCTPMessageStatus.Pending;
emit FinalizeWithdrawERC20(_l1Token, _l2Token, _from, _to, _amount, _data);
}
/*******************************
* Public Restricted Functions *
*******************************/
/// @notice Update the CCTP contract addresses.
/// @param _messenger The address of TokenMessenger in local domain.
/// @param _transmitter The address of MessageTransmitter in local domain.
function updateCCTPContracts(address _messenger, address _transmitter) external onlyOwner {
cctpMessenger = _messenger;
cctpTransmitter = _transmitter;
}
/**********************
* Internal Functions *
**********************/
/// @inheritdoc L1ERC20Gateway
function _beforeFinalizeWithdrawERC20(
address,
address,
address,
address,
uint256,
bytes calldata
) internal virtual override {}
/// @inheritdoc L1ERC20Gateway
function _beforeDropMessage(
address,
address,
uint256
) internal virtual override {
require(msg.value == 0, "nonzero msg.value");
}
/// @inheritdoc L1ERC20Gateway
function _deposit(
address _token,
address _to,
uint256 _amount,
bytes memory _data,
uint256 _gasLimit
) internal virtual override nonReentrant {
require(_amount > 0, "deposit zero amount");
require(_token == l1USDC, "only USDC is allowed");
// 1. Extract real sender if this call is from L1GatewayRouter.
address _from;
(_from, _amount, _data) = _transferERC20In(_token, _amount, _data);
// 2. Burn token through CCTP TokenMessenger
uint256 _nonce = ITokenMessenger(cctpMessenger).depositForBurnWithCaller(
_amount,
destinationDomain,
bytes32(uint256(uint160(_to))),
address(this),
bytes32(uint256(uint160(counterpart)))
);
// 3. Generate message passed to L2USDCGatewayCCTP.
bytes memory _message = abi.encodeCall(
IL2ERC20Gateway.finalizeDepositERC20,
(_token, l2USDC, _from, _to, _amount, abi.encode(_nonce, _data))
);
// 4. Send message to L1ScrollMessenger.
IL1ScrollMessenger(messenger).sendMessage{value: msg.value}(counterpart, 0, _message, _gasLimit);
emit DepositERC20(_token, l2USDC, _from, _to, _amount, _data);
}
}

View File

@@ -24,12 +24,12 @@ contract L1MessageQueue is OwnableUpgradeable, IL1MessageQueue {
/// @notice Emitted when owner updates gas oracle contract.
/// @param _oldGasOracle The address of old gas oracle contract.
/// @param _newGasOracle The address of new gas oracle contract.
event UpdateGasOracle(address _oldGasOracle, address _newGasOracle);
event UpdateGasOracle(address indexed _oldGasOracle, address indexed _newGasOracle);
/// @notice Emitted when owner updates EnforcedTxGateway contract.
/// @param _oldGateway The address of old EnforcedTxGateway contract.
/// @param _newGateway The address of new EnforcedTxGateway contract.
event UpdateEnforcedTxGateway(address _oldGateway, address _newGateway);
event UpdateEnforcedTxGateway(address indexed _oldGateway, address indexed _newGateway);
/// @notice Emitted when owner updates max gas limit.
/// @param _oldMaxGasLimit The old max gas limit.

View File

@@ -19,8 +19,9 @@ contract L2GasPriceOracle is OwnableUpgradeable, IL2GasPriceOracle {
event UpdateWhitelist(address _oldWhitelist, address _newWhitelist);
/// @notice Emitted when current l2 base fee is updated.
/// @param l2BaseFee The current l2 base fee updated.
event L2BaseFeeUpdated(uint256 l2BaseFee);
/// @param oldL2BaseFee The original l2 base fee before update.
/// @param newL2BaseFee The current l2 base fee updated.
event L2BaseFeeUpdated(uint256 oldL2BaseFee, uint256 newL2BaseFee);
/// @notice Emitted when intrinsic params are updated.
/// @param txGas The intrinsic gas for transaction.
@@ -130,13 +131,14 @@ contract L2GasPriceOracle is OwnableUpgradeable, IL2GasPriceOracle {
}
/// @notice Allows the owner to modify the l2 base fee.
/// @param _l2BaseFee The new l2 base fee.
function setL2BaseFee(uint256 _l2BaseFee) external {
/// @param _newL2BaseFee The new l2 base fee.
function setL2BaseFee(uint256 _newL2BaseFee) external {
require(whitelist.isSenderAllowed(msg.sender), "Not whitelisted sender");
l2BaseFee = _l2BaseFee;
uint256 _oldL2BaseFee = l2BaseFee;
l2BaseFee = _newL2BaseFee;
emit L2BaseFeeUpdated(_l2BaseFee);
emit L2BaseFeeUpdated(_oldL2BaseFee, _newL2BaseFee);
}
/************************

View File

@@ -3,6 +3,7 @@
pragma solidity =0.8.16;
import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import {PausableUpgradeable} from "@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol";
import {IL1MessageQueue} from "./IL1MessageQueue.sol";
import {IScrollChain} from "./IScrollChain.sol";
@@ -15,7 +16,7 @@ import {IRollupVerifier} from "../../libraries/verifier/IRollupVerifier.sol";
/// @title ScrollChain
/// @notice This contract maintains data for the Scroll rollup.
contract ScrollChain is OwnableUpgradeable, IScrollChain {
contract ScrollChain is OwnableUpgradeable, PausableUpgradeable, IScrollChain {
/**********
* Events *
**********/
@@ -33,7 +34,7 @@ contract ScrollChain is OwnableUpgradeable, IScrollChain {
/// @notice Emitted when the address of rollup verifier is updated.
/// @param oldVerifier The address of old rollup verifier.
/// @param newVerifier The address of new rollup verifier.
event UpdateVerifier(address oldVerifier, address newVerifier);
event UpdateVerifier(address indexed oldVerifier, address indexed newVerifier);
/// @notice Emitted when the value of `maxNumL2TxInChunk` is updated.
/// @param oldMaxNumL2TxInChunk The old value of `maxNumL2TxInChunk`.
@@ -165,7 +166,7 @@ contract ScrollChain is OwnableUpgradeable, IScrollChain {
bytes calldata _parentBatchHeader,
bytes[] memory _chunks,
bytes calldata _skippedL1MessageBitmap
) external override OnlySequencer {
) external override OnlySequencer whenNotPaused {
require(_version == 0, "invalid version");
// check whether the batch is empty
@@ -291,7 +292,7 @@ contract ScrollChain is OwnableUpgradeable, IScrollChain {
bytes32 _postStateRoot,
bytes32 _withdrawRoot,
bytes calldata _aggrProof
) external override OnlyProver {
) external override OnlyProver whenNotPaused {
require(_prevStateRoot != bytes32(0), "previous state root is zero");
require(_postStateRoot != bytes32(0), "new state root is zero");
@@ -355,24 +356,36 @@ contract ScrollChain is OwnableUpgradeable, IScrollChain {
* Restricted Functions *
************************/
/// @notice Update the status of sequencer.
/// @dev This function can only called by contract owner.
/// @param _account The address of account to update.
/// @param _status The status of the account to update.
function updateSequencer(address _account, bool _status) external onlyOwner {
isSequencer[_account] = _status;
/// @notice Add an account to the sequencer list.
/// @param _account The address of account to add.
function addSequencer(address _account) external onlyOwner {
isSequencer[_account] = true;
emit UpdateSequencer(_account, _status);
emit UpdateSequencer(_account, true);
}
/// @notice Update the status of prover.
/// @dev This function can only called by contract owner.
/// @param _account The address of account to update.
/// @param _status The status of the account to update.
function updateProver(address _account, bool _status) external onlyOwner {
isProver[_account] = _status;
/// @notice Remove an account from the sequencer list.
/// @param _account The address of account to remove.
function removeSequencer(address _account) external onlyOwner {
isSequencer[_account] = false;
emit UpdateProver(_account, _status);
emit UpdateSequencer(_account, false);
}
/// @notice Add an account to the prover list.
/// @param _account The address of account to add.
function addProver(address _account) external onlyOwner {
isProver[_account] = true;
emit UpdateProver(_account, true);
}
/// @notice Add an account from the prover list.
/// @param _account The address of account to remove.
function removeProver(address _account) external onlyOwner {
isProver[_account] = false;
emit UpdateProver(_account, false);
}
/// @notice Update the address verifier contract.
@@ -393,6 +406,16 @@ contract ScrollChain is OwnableUpgradeable, IScrollChain {
emit UpdateMaxNumL2TxInChunk(_oldMaxNumL2TxInChunk, _maxNumL2TxInChunk);
}
/// @notice Pause the contract
/// @param _status The pause status to update.
function setPause(bool _status) external onlyOwner {
if (_status) {
_pause();
} else {
_unpause();
}
}
/**********************
* Internal Functions *
**********************/
@@ -469,6 +492,7 @@ contract ScrollChain is OwnableUpgradeable, IScrollChain {
// concatenate l2 transaction hashes
uint256 _numTransactionsInBlock = ChunkCodec.numTransactions(blockPtr);
require(_numTransactionsInBlock >= _numL1MessagesInBlock, "num txs less than num L1 msgs");
for (uint256 j = _numL1MessagesInBlock; j < _numTransactionsInBlock; j++) {
bytes32 txHash;
(txHash, l2TxPtr) = ChunkCodec.loadL2TxHash(l2TxPtr);

View File

@@ -5,6 +5,15 @@ pragma solidity ^0.8.16;
import {IScrollMessenger} from "../libraries/IScrollMessenger.sol";
interface IL2ScrollMessenger is IScrollMessenger {
/**********
* Events *
**********/
/// @notice Emitted when the maximum number of times each message can fail in L2 is updated.
/// @param oldMaxFailedExecutionTimes The old maximum number of times each message can fail in L2.
/// @param newMaxFailedExecutionTimes The new maximum number of times each message can fail in L2.
event UpdateMaxFailedExecutionTimes(uint256 oldMaxFailedExecutionTimes, uint256 newMaxFailedExecutionTimes);
/*****************************
* Public Mutating Functions *
*****************************/

View File

@@ -2,12 +2,8 @@
pragma solidity =0.8.16;
import {PausableUpgradeable} from "@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol";
import {IL2ScrollMessenger} from "./IL2ScrollMessenger.sol";
import {L2MessageQueue} from "./predeploys/L2MessageQueue.sol";
import {IL1BlockContainer} from "./predeploys/IL1BlockContainer.sol";
import {IL1GasPriceOracle} from "./predeploys/IL1GasPriceOracle.sol";
import {PatriciaMerkleTrieVerifier} from "../libraries/verifier/PatriciaMerkleTrieVerifier.sol";
import {ScrollConstants} from "../libraries/constants/ScrollConstants.sol";
@@ -26,15 +22,7 @@ import {ScrollMessengerBase} from "../libraries/ScrollMessengerBase.sol";
///
/// @dev 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.
contract L2ScrollMessenger is ScrollMessengerBase, PausableUpgradeable, IL2ScrollMessenger {
/**********
* Events *
**********/
/// @notice Emitted when the maximum number of times each message can fail in L2 is updated.
/// @param maxFailedExecutionTimes The new maximum number of times each message can fail in L2.
event UpdateMaxFailedExecutionTimes(uint256 maxFailedExecutionTimes);
contract L2ScrollMessenger is ScrollMessengerBase, IL2ScrollMessenger {
/*************
* Constants *
*************/
@@ -68,9 +56,8 @@ contract L2ScrollMessenger is ScrollMessengerBase, PausableUpgradeable, IL2Scrol
messageQueue = _messageQueue;
}
function initialize(address _counterpart, address _feeVault) external initializer {
PausableUpgradeable.__Pausable_init();
ScrollMessengerBase._initialize(_counterpart, _feeVault);
function initialize(address _counterpart) external initializer {
ScrollMessengerBase.__ScrollMessengerBase_init(_counterpart, address(0));
maxFailedExecutionTimes = 3;
}
@@ -122,26 +109,16 @@ contract L2ScrollMessenger is ScrollMessengerBase, PausableUpgradeable, IL2Scrol
* Restricted Functions *
************************/
/// @notice Pause the contract
/// @dev This function can only called by contract owner.
/// @param _status The pause status to update.
function setPause(bool _status) external onlyOwner {
if (_status) {
_pause();
} else {
_unpause();
}
}
/// @notice Update max failed execution times.
/// @dev This function can only called by contract owner.
/// @param _maxFailedExecutionTimes The new max failed execution times.
function updateMaxFailedExecutionTimes(uint256 _maxFailedExecutionTimes) external onlyOwner {
require(_maxFailedExecutionTimes > 0, "maxFailedExecutionTimes cannot be zero");
/// @param _newMaxFailedExecutionTimes The new max failed execution times.
function updateMaxFailedExecutionTimes(uint256 _newMaxFailedExecutionTimes) external onlyOwner {
require(_newMaxFailedExecutionTimes > 0, "maxFailedExecutionTimes cannot be zero");
maxFailedExecutionTimes = _maxFailedExecutionTimes;
uint256 _oldMaxFailedExecutionTimes = maxFailedExecutionTimes;
maxFailedExecutionTimes = _newMaxFailedExecutionTimes;
emit UpdateMaxFailedExecutionTimes(_maxFailedExecutionTimes);
emit UpdateMaxFailedExecutionTimes(_oldMaxFailedExecutionTimes, _newMaxFailedExecutionTimes);
}
/**********************

View File

@@ -11,15 +11,18 @@ interface IL2GatewayRouter is IL2ETHGateway, IL2ERC20Gateway {
**********/
/// @notice Emitted when the address of ETH Gateway is updated.
/// @param ethGateway The address of new ETH Gateway.
event SetETHGateway(address indexed ethGateway);
/// @param oldETHGateway The address of the old ETH Gateway.
/// @param newEthGateway The address of the new ETH Gateway.
event SetETHGateway(address indexed oldETHGateway, address indexed newEthGateway);
/// @notice Emitted when the address of default ERC20 Gateway is updated.
/// @param defaultERC20Gateway The address of new default ERC20 Gateway.
event SetDefaultERC20Gateway(address indexed defaultERC20Gateway);
/// @param oldDefaultERC20Gateway The address of the old default ERC20 Gateway.
/// @param newDefaultERC20Gateway The address of the new default ERC20 Gateway.
event SetDefaultERC20Gateway(address indexed oldDefaultERC20Gateway, address indexed newDefaultERC20Gateway);
/// @notice Emitted when the `gateway` for `token` is updated.
/// @param token The address of token updated.
/// @param gateway The corresponding address of gateway updated.
event SetERC20Gateway(address indexed token, address indexed gateway);
/// @param oldGateway The corresponding address of the old gateway.
/// @param newGateway The corresponding address of the new gateway.
event SetERC20Gateway(address indexed token, address indexed oldGateway, address indexed newGateway);
}

View File

@@ -2,29 +2,27 @@
pragma solidity =0.8.16;
import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import {IERC20Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol";
import {IL2ERC20Gateway, L2ERC20Gateway} from "./L2ERC20Gateway.sol";
import {IL2ScrollMessenger} from "../IL2ScrollMessenger.sol";
import {IL1ERC20Gateway} from "../../L1/gateways/IL1ERC20Gateway.sol";
import {ScrollGatewayBase, IScrollGateway} from "../../libraries/gateway/ScrollGatewayBase.sol";
import {IScrollERC20} from "../../libraries/token/IScrollERC20.sol";
import {ScrollGatewayBase} from "../../libraries/gateway/ScrollGatewayBase.sol";
import {IScrollERC20Upgradeable} from "../../libraries/token/IScrollERC20Upgradeable.sol";
/// @title L2ERC20Gateway
/// @notice The `L2ERC20Gateway` is used to withdraw custom ERC20 compatible tokens on layer 2 and
/// finalize deposit the tokens from layer 1.
/// @dev The withdrawn tokens tokens will be burned directly. On finalizing deposit, the corresponding
/// tokens will be minted and transfered to the recipient.
contract L2CustomERC20Gateway is OwnableUpgradeable, ScrollGatewayBase, L2ERC20Gateway {
contract L2CustomERC20Gateway is L2ERC20Gateway {
/**********
* Events *
**********/
/// @notice Emitted when token mapping for ERC20 token is updated.
/// @param _l2Token The address of corresponding ERC20 token on layer 2.
/// @param _l1Token The address of ERC20 token on layer 1.
event UpdateTokenMapping(address _l2Token, address _l1Token);
/// @param l2Token The address of corresponding ERC20 token in layer 2.
/// @param oldL1Token The address of the old corresponding ERC20 token in layer 1.
/// @param newL1Token The address of the new corresponding ERC20 token in layer 1.
event UpdateTokenMapping(address indexed l2Token, address indexed oldL1Token, address indexed newL1Token);
/*************
* Variables *
@@ -47,7 +45,6 @@ contract L2CustomERC20Gateway is OwnableUpgradeable, ScrollGatewayBase, L2ERC20G
address _messenger
) external initializer {
require(_router != address(0), "zero router address");
OwnableUpgradeable.__Ownable_init();
ScrollGatewayBase._initialize(_counterpart, _router, _messenger);
}
@@ -83,7 +80,7 @@ contract L2CustomERC20Gateway is OwnableUpgradeable, ScrollGatewayBase, L2ERC20G
require(_l1Token != address(0), "token address cannot be 0");
require(_l1Token == tokenMapping[_l2Token], "l1 token mismatch");
IScrollERC20(_l2Token).mint(_to, _amount);
IScrollERC20Upgradeable(_l2Token).mint(_to, _amount);
_doCallback(_to, _data);
@@ -100,9 +97,10 @@ contract L2CustomERC20Gateway is OwnableUpgradeable, ScrollGatewayBase, L2ERC20G
function updateTokenMapping(address _l2Token, address _l1Token) external onlyOwner {
require(_l1Token != address(0), "token address cannot be 0");
address _oldL1Token = tokenMapping[_l2Token];
tokenMapping[_l2Token] = _l1Token;
emit UpdateTokenMapping(_l2Token, _l1Token);
emit UpdateTokenMapping(_l2Token, _oldL1Token, _l1Token);
}
/**********************
@@ -129,7 +127,7 @@ contract L2CustomERC20Gateway is OwnableUpgradeable, ScrollGatewayBase, L2ERC20G
}
// 2. Burn token.
IScrollERC20(_token).burn(_from, _amount);
IScrollERC20Upgradeable(_token).burn(_from, _amount);
// 3. Generate message passed to L1StandardERC20Gateway.
bytes memory _message = abi.encodeCall(

View File

@@ -2,14 +2,12 @@
pragma solidity =0.8.16;
import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import {IERC1155Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC1155/IERC1155Upgradeable.sol";
import {ERC1155HolderUpgradeable, ERC1155ReceiverUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC1155/utils/ERC1155HolderUpgradeable.sol";
import {IL2ERC1155Gateway} from "./IL2ERC1155Gateway.sol";
import {IL2ScrollMessenger} from "../IL2ScrollMessenger.sol";
import {IL1ERC1155Gateway} from "../../L1/gateways/IL1ERC1155Gateway.sol";
import {ScrollGatewayBase, IScrollGateway} from "../../libraries/gateway/ScrollGatewayBase.sol";
import {ScrollGatewayBase} from "../../libraries/gateway/ScrollGatewayBase.sol";
import {IScrollERC1155} from "../../libraries/token/IScrollERC1155.sol";
/// @title L2ERC1155Gateway
@@ -19,15 +17,16 @@ import {IScrollERC1155} from "../../libraries/token/IScrollERC1155.sol";
/// NFT will be minted and transfered to the recipient.
///
/// This will be changed if we have more specific scenarios.
contract L2ERC1155Gateway is OwnableUpgradeable, ERC1155HolderUpgradeable, ScrollGatewayBase, IL2ERC1155Gateway {
contract L2ERC1155Gateway is ERC1155HolderUpgradeable, ScrollGatewayBase, IL2ERC1155Gateway {
/**********
* Events *
**********/
/// @notice Emitted when token mapping for ERC1155 token is updated.
/// @param _l2Token The address of corresponding ERC1155 token on layer 2.
/// @param _l1Token The address of ERC1155 token on layer 1.
event UpdateTokenMapping(address _l2Token, address _l1Token);
/// @param l2Token The address of corresponding ERC1155 token in layer 2.
/// @param oldL1Token The address of the old corresponding ERC1155 token in layer 1.
/// @param newL1Token The address of the new corresponding ERC1155 token in layer 1.
event UpdateTokenMapping(address indexed l2Token, address indexed oldL1Token, address indexed newL1Token);
/*************
* Variables *
@@ -45,7 +44,6 @@ contract L2ERC1155Gateway is OwnableUpgradeable, ERC1155HolderUpgradeable, Scrol
}
function initialize(address _counterpart, address _messenger) external initializer {
OwnableUpgradeable.__Ownable_init();
ERC1155HolderUpgradeable.__ERC1155Holder_init();
ERC1155ReceiverUpgradeable.__ERC1155Receiver_init();
@@ -142,9 +140,10 @@ contract L2ERC1155Gateway is OwnableUpgradeable, ERC1155HolderUpgradeable, Scrol
function updateTokenMapping(address _l2Token, address _l1Token) external onlyOwner {
require(_l1Token != address(0), "token address cannot be 0");
address _oldL1Token = tokenMapping[_l2Token];
tokenMapping[_l2Token] = _l1Token;
emit UpdateTokenMapping(_l2Token, _l1Token);
emit UpdateTokenMapping(_l2Token, _oldL1Token, _l1Token);
}
/**********************

View File

@@ -4,9 +4,11 @@ pragma solidity ^0.8.16;
import {IL2ERC20Gateway} from "./IL2ERC20Gateway.sol";
import {ScrollGatewayBase} from "../../libraries/gateway/ScrollGatewayBase.sol";
// solhint-disable no-empty-blocks
abstract contract L2ERC20Gateway is IL2ERC20Gateway {
abstract contract L2ERC20Gateway is ScrollGatewayBase, IL2ERC20Gateway {
/*************
* Variables *
*************/

View File

@@ -2,14 +2,12 @@
pragma solidity =0.8.16;
import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import {IERC721Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC721/IERC721Upgradeable.sol";
import {ERC721HolderUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC721/utils/ERC721HolderUpgradeable.sol";
import {IL2ERC721Gateway} from "./IL2ERC721Gateway.sol";
import {IL2ScrollMessenger} from "../IL2ScrollMessenger.sol";
import {IL1ERC721Gateway} from "../../L1/gateways/IL1ERC721Gateway.sol";
import {ScrollGatewayBase, IScrollGateway} from "../../libraries/gateway/ScrollGatewayBase.sol";
import {ScrollGatewayBase} from "../../libraries/gateway/ScrollGatewayBase.sol";
import {IScrollERC721} from "../../libraries/token/IScrollERC721.sol";
/// @title L2ERC721Gateway
@@ -19,15 +17,16 @@ import {IScrollERC721} from "../../libraries/token/IScrollERC721.sol";
/// NFT will be minted and transfered to the recipient.
///
/// This will be changed if we have more specific scenarios.
contract L2ERC721Gateway is OwnableUpgradeable, ERC721HolderUpgradeable, ScrollGatewayBase, IL2ERC721Gateway {
contract L2ERC721Gateway is ERC721HolderUpgradeable, ScrollGatewayBase, IL2ERC721Gateway {
/**********
* Events *
**********/
/// @notice Emitted when token mapping for ERC721 token is updated.
/// @param _l2Token The address of corresponding ERC721 token on layer 2.
/// @param _l1Token The address of ERC721 token on layer 1.
event UpdateTokenMapping(address _l2Token, address _l1Token);
/// @param l2Token The address of corresponding ERC721 token in layer 2.
/// @param oldL1Token The address of the old corresponding ERC721 token in layer 1.
/// @param newL1Token The address of the new corresponding ERC721 token in layer 1.
event UpdateTokenMapping(address indexed l2Token, address indexed oldL1Token, address indexed newL1Token);
/*************
* Variables *
@@ -45,7 +44,6 @@ contract L2ERC721Gateway is OwnableUpgradeable, ERC721HolderUpgradeable, ScrollG
}
function initialize(address _counterpart, address _messenger) external initializer {
OwnableUpgradeable.__Ownable_init();
ERC721HolderUpgradeable.__ERC721Holder_init();
ScrollGatewayBase._initialize(_counterpart, address(0), _messenger);
@@ -137,9 +135,10 @@ contract L2ERC721Gateway is OwnableUpgradeable, ERC721HolderUpgradeable, ScrollG
function updateTokenMapping(address _l2Token, address _l1Token) external onlyOwner {
require(_l1Token != address(0), "token address cannot be 0");
address _oldL1Token = tokenMapping[_l2Token];
tokenMapping[_l2Token] = _l1Token;
emit UpdateTokenMapping(_l2Token, _l1Token);
emit UpdateTokenMapping(_l2Token, _oldL1Token, _l1Token);
}
/**********************

View File

@@ -2,8 +2,6 @@
pragma solidity =0.8.16;
import {Initializable} from "@openzeppelin/contracts/proxy/utils/Initializable.sol";
import {IL1ETHGateway} from "../../L1/gateways/IL1ETHGateway.sol";
import {IL2ScrollMessenger} from "../IL2ScrollMessenger.sol";
import {IL2ETHGateway} from "./IL2ETHGateway.sol";
@@ -15,7 +13,7 @@ import {ScrollGatewayBase} from "../../libraries/gateway/ScrollGatewayBase.sol";
/// finalize deposit ETH from layer 1.
/// @dev The ETH are not held in the gateway. The ETH will be sent to the `L2ScrollMessenger` contract.
/// On finalizing deposit, the Ether will be transfered from `L2ScrollMessenger`, then transfer to recipient.
contract L2ETHGateway is Initializable, ScrollGatewayBase, IL2ETHGateway {
contract L2ETHGateway is ScrollGatewayBase, IL2ETHGateway {
/***************
* Constructor *
***************/

View File

@@ -7,9 +7,6 @@ import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/Own
import {IL2GatewayRouter} from "./IL2GatewayRouter.sol";
import {IL2ETHGateway} from "./IL2ETHGateway.sol";
import {IL2ERC20Gateway} from "./IL2ERC20Gateway.sol";
import {IL2ScrollMessenger} from "../IL2ScrollMessenger.sol";
import {IL1ETHGateway} from "../../L1/gateways/IL1ETHGateway.sol";
import {IScrollGateway} from "../../libraries/gateway/IScrollGateway.sol";
/// @title L2GatewayRouter
/// @notice The `L2GatewayRouter` is the main entry for withdrawing Ether and ERC20 tokens.
@@ -45,13 +42,13 @@ contract L2GatewayRouter is OwnableUpgradeable, IL2GatewayRouter {
// it can be zero during initialization
if (_defaultERC20Gateway != address(0)) {
defaultERC20Gateway = _defaultERC20Gateway;
emit SetDefaultERC20Gateway(_defaultERC20Gateway);
emit SetDefaultERC20Gateway(address(0), _defaultERC20Gateway);
}
// it can be zero during initialization
if (_ethGateway != address(0)) {
ethGateway = _ethGateway;
emit SetETHGateway(_ethGateway);
emit SetETHGateway(address(0), _ethGateway);
}
}
@@ -182,20 +179,22 @@ contract L2GatewayRouter is OwnableUpgradeable, IL2GatewayRouter {
/// @notice Update the address of ETH gateway contract.
/// @dev This function should only be called by contract owner.
/// @param _ethGateway The address to update.
function setETHGateway(address _ethGateway) external onlyOwner {
ethGateway = _ethGateway;
/// @param _newEthGateway The address to update.
function setETHGateway(address _newEthGateway) external onlyOwner {
address _oldEthGateway = ethGateway;
ethGateway = _newEthGateway;
emit SetETHGateway(_ethGateway);
emit SetETHGateway(_oldEthGateway, _newEthGateway);
}
/// @notice Update the address of default ERC20 gateway contract.
/// @dev This function should only be called by contract owner.
/// @param _defaultERC20Gateway The address to update.
function setDefaultERC20Gateway(address _defaultERC20Gateway) external onlyOwner {
defaultERC20Gateway = _defaultERC20Gateway;
/// @param _newDefaultERC20Gateway The address to update.
function setDefaultERC20Gateway(address _newDefaultERC20Gateway) external onlyOwner {
address _oldDefaultERC20Gateway = defaultERC20Gateway;
defaultERC20Gateway = _newDefaultERC20Gateway;
emit SetDefaultERC20Gateway(_defaultERC20Gateway);
emit SetDefaultERC20Gateway(_oldDefaultERC20Gateway, _newDefaultERC20Gateway);
}
/// @notice Update the mapping from token address to gateway address.
@@ -206,9 +205,10 @@ contract L2GatewayRouter is OwnableUpgradeable, IL2GatewayRouter {
require(_tokens.length == _gateways.length, "length mismatch");
for (uint256 i = 0; i < _tokens.length; i++) {
address _oldGateway = ERC20Gateway[_tokens[i]];
ERC20Gateway[_tokens[i]] = _gateways[i];
emit SetERC20Gateway(_tokens[i], _gateways[i]);
emit SetERC20Gateway(_tokens[i], _oldGateway, _gateways[i]);
}
}
}

View File

@@ -2,18 +2,15 @@
pragma solidity =0.8.16;
import {Initializable} from "@openzeppelin/contracts/proxy/utils/Initializable.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {Address} from "@openzeppelin/contracts/utils/Address.sol";
import {AddressUpgradeable} from "@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol";
import {IL2ERC20Gateway, L2ERC20Gateway} from "./L2ERC20Gateway.sol";
import {IL2ScrollMessenger} from "../IL2ScrollMessenger.sol";
import {IL1ERC20Gateway} from "../../L1/gateways/IL1ERC20Gateway.sol";
import {IScrollERC20} from "../../libraries/token/IScrollERC20.sol";
import {IScrollERC20Upgradeable} from "../../libraries/token/IScrollERC20Upgradeable.sol";
import {ScrollStandardERC20} from "../../libraries/token/ScrollStandardERC20.sol";
import {IScrollStandardERC20Factory} from "../../libraries/token/IScrollStandardERC20Factory.sol";
import {ScrollGatewayBase, IScrollGateway} from "../../libraries/gateway/ScrollGatewayBase.sol";
import {ScrollGatewayBase} from "../../libraries/gateway/ScrollGatewayBase.sol";
/// @title L2StandardERC20Gateway
/// @notice The `L2StandardERC20Gateway` is used to withdraw standard ERC20 tokens on layer 2 and
@@ -21,9 +18,8 @@ import {ScrollGatewayBase, IScrollGateway} from "../../libraries/gateway/ScrollG
/// @dev The withdrawn ERC20 tokens will be burned directly. On finalizing deposit, the corresponding
/// token will be minted and transfered to the recipient. Any ERC20 that requires non-standard functionality
/// should use a separate gateway.
contract L2StandardERC20Gateway is Initializable, ScrollGatewayBase, L2ERC20Gateway {
using SafeERC20 for IERC20;
using Address for address;
contract L2StandardERC20Gateway is L2ERC20Gateway {
using AddressUpgradeable for address;
/*************
* Variables *
@@ -114,7 +110,7 @@ contract L2StandardERC20Gateway is Initializable, ScrollGatewayBase, L2ERC20Gate
_deployL2Token(_deployData, _l1Token);
}
IScrollERC20(_l2Token).mint(_to, _amount);
IScrollERC20Upgradeable(_l2Token).mint(_to, _amount);
_doCallback(_to, _callData);
@@ -145,7 +141,7 @@ contract L2StandardERC20Gateway is Initializable, ScrollGatewayBase, L2ERC20Gate
require(_l1Token != address(0), "no corresponding l1 token");
// 2. Burn token.
IScrollERC20(_token).burn(_from, _amount);
IScrollERC20Upgradeable(_token).burn(_from, _amount);
// 3. Generate message passed to L1StandardERC20Gateway.
bytes memory _message = abi.encodeCall(

View File

@@ -2,15 +2,14 @@
pragma solidity =0.8.16;
import {Initializable} from "@openzeppelin/contracts/proxy/utils/Initializable.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {IERC20Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol";
import {SafeERC20Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol";
import {IL2ERC20Gateway, L2ERC20Gateway} from "./L2ERC20Gateway.sol";
import {IL2ScrollMessenger} from "../IL2ScrollMessenger.sol";
import {IWETH} from "../../interfaces/IWETH.sol";
import {IL1ERC20Gateway} from "../../L1/gateways/IL1ERC20Gateway.sol";
import {ScrollGatewayBase, IScrollGateway} from "../../libraries/gateway/ScrollGatewayBase.sol";
import {ScrollGatewayBase} from "../../libraries/gateway/ScrollGatewayBase.sol";
/// @title L2WETHGateway
/// @notice The `L2WETHGateway` contract is used to withdraw `WETH` token on layer 2 and
@@ -19,8 +18,8 @@ import {ScrollGatewayBase, IScrollGateway} from "../../libraries/gateway/ScrollG
/// then the Ether will be sent to the `L2ScrollMessenger` contract.
/// On finalizing deposit, the Ether will be transfered from `L2ScrollMessenger`, then
/// wrapped as WETH and finally transfer to recipient.
contract L2WETHGateway is Initializable, ScrollGatewayBase, L2ERC20Gateway {
using SafeERC20 for IERC20;
contract L2WETHGateway is L2ERC20Gateway {
using SafeERC20Upgradeable for IERC20Upgradeable;
/*************
* Constants *
@@ -89,7 +88,7 @@ contract L2WETHGateway is Initializable, ScrollGatewayBase, L2ERC20Gateway {
require(_amount == msg.value, "msg.value mismatch");
IWETH(_l2Token).deposit{value: _amount}();
IERC20(_l2Token).safeTransfer(_to, _amount);
IERC20Upgradeable(_l2Token).safeTransfer(_to, _amount);
_doCallback(_to, _data);
@@ -118,7 +117,7 @@ contract L2WETHGateway is Initializable, ScrollGatewayBase, L2ERC20Gateway {
}
// 2. Transfer token into this contract.
IERC20(_token).safeTransferFrom(_from, address(this), _amount);
IERC20Upgradeable(_token).safeTransferFrom(_from, address(this), _amount);
IWETH(_token).withdraw(_amount);
// 3. Generate message passed to L2StandardERC20Gateway.

View File

@@ -2,11 +2,11 @@
pragma solidity =0.8.16;
import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import {IERC20Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol";
import {SafeERC20Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol";
import {IFiatToken} from "../../../interfaces/IFiatToken.sol";
import {IUSDCDestinationBridge} from "../../../interfaces/IUSDCDestinationBridge.sol";
import {IL1ERC20Gateway} from "../../../L1/gateways/IL1ERC20Gateway.sol";
import {IL2ScrollMessenger} from "../../IL2ScrollMessenger.sol";
import {IL2ERC20Gateway} from "../IL2ERC20Gateway.sol";
@@ -17,7 +17,7 @@ import {L2ERC20Gateway} from "../L2ERC20Gateway.sol";
/// @title L2USDCGateway
/// @notice The `L2USDCGateway` contract is used to withdraw `USDC` token on layer 2 and
/// finalize deposit `USDC` from layer 1.
contract L2USDCGateway is OwnableUpgradeable, ScrollGatewayBase, L2ERC20Gateway {
contract L2USDCGateway is L2ERC20Gateway, IUSDCDestinationBridge {
using SafeERC20Upgradeable for IERC20Upgradeable;
/*************
@@ -34,6 +34,8 @@ contract L2USDCGateway is OwnableUpgradeable, ScrollGatewayBase, L2ERC20Gateway
* Variables *
*************/
address public circleCaller;
bool public depositPaused;
bool public withdrawPaused;
@@ -56,8 +58,6 @@ contract L2USDCGateway is OwnableUpgradeable, ScrollGatewayBase, L2ERC20Gateway
) external initializer {
require(_router != address(0), "zero router address");
ScrollGatewayBase._initialize(_counterpart, _router, _messenger);
OwnableUpgradeable.__Ownable_init();
}
/*************************
@@ -94,7 +94,8 @@ contract L2USDCGateway is OwnableUpgradeable, ScrollGatewayBase, L2ERC20Gateway
require(IFiatToken(_l2Token).mint(_to, _amount), "mint USDC failed");
_doCallback(_to, _data);
// disable call for USDC
// _doCallback(_to, _data);
emit FinalizeDepositERC20(_l1Token, _l2Token, _from, _to, _amount, _data);
}
@@ -103,6 +104,19 @@ contract L2USDCGateway is OwnableUpgradeable, ScrollGatewayBase, L2ERC20Gateway
* Public Restricted Functions *
*******************************/
/// @inheritdoc IUSDCDestinationBridge
function transferUSDCRoles(address _owner) external {
require(msg.sender == circleCaller, "only circle caller");
_transferOwnership(_owner);
}
/// @notice Update the Circle EOA address.
/// @param _caller The address to update.
function updateCircleCaller(address _caller) external onlyOwner {
circleCaller = _caller;
}
/// @notice Change the deposit pause status of this contract.
/// @param _paused The new status, `true` means paused and `false` means not paused.
function pauseDeposit(bool _paused) external onlyOwner {
@@ -136,6 +150,7 @@ contract L2USDCGateway is OwnableUpgradeable, ScrollGatewayBase, L2ERC20Gateway
if (router == msg.sender) {
(_from, _data) = abi.decode(_data, (address, bytes));
}
require(_data.length == 0, "call is not allowed");
// 2. Transfer token into this contract.
IERC20Upgradeable(_token).safeTransferFrom(_from, address(this), _amount);

View File

@@ -0,0 +1,156 @@
// SPDX-License-Identifier: MIT
pragma solidity =0.8.16;
import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import {IERC20Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol";
import {SafeERC20Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol";
import {ITokenMessenger} from "../../../interfaces/ITokenMessenger.sol";
import {IL1ERC20Gateway} from "../../../L1/gateways/IL1ERC20Gateway.sol";
import {IL2ScrollMessenger} from "../../IL2ScrollMessenger.sol";
import {IL2ERC20Gateway} from "../IL2ERC20Gateway.sol";
import {CCTPGatewayBase} from "../../../libraries/gateway/CCTPGatewayBase.sol";
import {ScrollGatewayBase} from "../../../libraries/gateway/ScrollGatewayBase.sol";
import {L2ERC20Gateway} from "../L2ERC20Gateway.sol";
/// @title L2USDCGatewayCCTP
/// @notice The `L2USDCGatewayCCTP` contract is used to withdraw `USDC` token in layer 2 and
/// finalize deposit `USDC` from layer 1.
contract L2USDCGatewayCCTP is CCTPGatewayBase, L2ERC20Gateway {
using SafeERC20Upgradeable for IERC20Upgradeable;
/***************
* Constructor *
***************/
constructor(
address _l1USDC,
address _l2USDC,
uint32 _destinationDomain
) CCTPGatewayBase(_l1USDC, _l2USDC, _destinationDomain) {}
/// @notice Initialize the storage of L2USDCGatewayCCTP.
/// @param _counterpart The address of L1USDCGatewayCCTP in L1.
/// @param _router The address of L2GatewayRouter.
/// @param _messenger The address of L2ScrollMessenger.
/// @param _cctpMessenger The address of TokenMessenger in local domain.
/// @param _cctpTransmitter The address of MessageTransmitter in local domain.
function initialize(
address _counterpart,
address _router,
address _messenger,
address _cctpMessenger,
address _cctpTransmitter
) external initializer {
require(_router != address(0), "zero router address");
ScrollGatewayBase._initialize(_counterpart, _router, _messenger);
CCTPGatewayBase._initialize(_cctpMessenger, _cctpTransmitter);
OwnableUpgradeable.__Ownable_init();
}
/*************************
* Public View Functions *
*************************/
/// @inheritdoc IL2ERC20Gateway
function getL1ERC20Address(address) external view override returns (address) {
return l1USDC;
}
/// @inheritdoc IL2ERC20Gateway
function getL2ERC20Address(address) public view override returns (address) {
return l2USDC;
}
/*****************************
* Public Mutating Functions *
*****************************/
/// @inheritdoc IL2ERC20Gateway
/// @dev The function will not mint the USDC, users need to call `claimUSDC` after this function is done.
function finalizeDepositERC20(
address _l1Token,
address _l2Token,
address _from,
address _to,
uint256 _amount,
bytes memory _data
) external payable override onlyCallByCounterpart {
require(msg.value == 0, "nonzero msg.value");
require(_l1Token == l1USDC, "l1 token not USDC");
require(_l2Token == l2USDC, "l2 token not USDC");
uint256 _nonce;
(_nonce, _data) = abi.decode(_data, (uint256, bytes));
require(status[_nonce] == CCTPMessageStatus.None, "message relayed");
status[_nonce] = CCTPMessageStatus.Pending;
emit FinalizeDepositERC20(_l1Token, _l2Token, _from, _to, _amount, _data);
}
/*******************************
* Public Restricted Functions *
*******************************/
/// @notice Update the CCTP contract addresses.
/// @param _messenger The address of TokenMessenger in local domain.
/// @param _transmitter The address of MessageTransmitter in local domain.
function updateCCTPContracts(address _messenger, address _transmitter) external onlyOwner {
cctpMessenger = _messenger;
cctpTransmitter = _transmitter;
}
/**********************
* Internal Functions *
**********************/
/// @inheritdoc L2ERC20Gateway
function _withdraw(
address _token,
address _to,
uint256 _amount,
bytes memory _data,
uint256 _gasLimit
) internal virtual override {
require(_amount > 0, "withdraw zero amount");
require(_token == l2USDC, "only USDC is allowed");
// 1. Extract real sender if this call is from L1GatewayRouter.
address _from = msg.sender;
if (router == msg.sender) {
(_from, _data) = abi.decode(_data, (address, bytes));
}
// 2. Transfer token into this contract.
IERC20Upgradeable(_token).safeTransferFrom(_from, address(this), _amount);
// 3. Burn token through CCTP TokenMessenger
uint256 _nonce = ITokenMessenger(cctpMessenger).depositForBurnWithCaller(
_amount,
destinationDomain,
bytes32(uint256(uint160(_to))),
address(this),
bytes32(uint256(uint160(counterpart)))
);
// 4. Generate message passed to L1USDCGateway.
address _l1USDC = l1USDC;
bytes memory _message = abi.encodeWithSelector(
IL1ERC20Gateway.finalizeWithdrawERC20.selector,
_l1USDC,
_token,
_from,
_to,
_amount,
abi.encode(_nonce, _data)
);
// 4. Send message to L1ScrollMessenger.
IL2ScrollMessenger(messenger).sendMessage{value: msg.value}(counterpart, 0, _message, _gasLimit);
emit WithdrawERC20(_l1USDC, _token, _from, _to, _amount, _data);
}
}

View File

@@ -5,7 +5,6 @@ pragma solidity =0.8.16;
import {OwnableBase} from "../../libraries/common/OwnableBase.sol";
import {IWhitelist} from "../../libraries/common/IWhitelist.sol";
import {IL1BlockContainer} from "./IL1BlockContainer.sol";
import {IL1GasPriceOracle} from "./IL1GasPriceOracle.sol";
contract L1GasPriceOracle is OwnableBase, IL1GasPriceOracle {

View File

@@ -1,6 +1,6 @@
A library for interacting with Scroll contracts.
This library includes contracts and interfaces needed to interact with the Scroll Smart Contracts deployed on both Layer 1 and Layer 2. This includes deposting and withdrawing ETH, ERC20 tokens and NFTs or sending arbitrary messages.
This library includes contracts and interfaces needed to interact with the Scroll Smart Contracts deployed on both Layer 1 and Layer 2. This includes deposting and withdrawing ETH, ERC20 tokens and NFTs or sending arbitrary messages.
# Overview
@@ -21,10 +21,11 @@ pragma solidity 0.8.20;
import "@scroll-tech/contracts/L1/gateways/IL1ETHGateway.sol";
contract MyContract {
function bridgeETH(address scrollBridge, uint gasLimit) public payable {
IL1ETHGateway(scrollBridge).depositETH(msg.sender, msg.value, gasLimit);
}
function bridgeETH(address scrollBridge, uint256 gasLimit) public payable {
IL1ETHGateway(scrollBridge).depositETH(msg.sender, msg.value, gasLimit);
}
}
```
Visit the Bridge Documentation for API reference, architecture overview and guides with code examples.

View File

@@ -1,11 +0,0 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.16;
interface IERC20Metadata {
function symbol() external view returns (string memory);
function name() external view returns (string memory);
function decimals() external view returns (uint8);
}

View File

@@ -0,0 +1,16 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.16;
interface IMessageTransmitter {
function usedNonces(bytes32 _sourceAndNonce) external view returns (uint256);
/**
* @notice Receives an incoming message, validating the header and passing
* the body to application-specific handler.
* @param message The message raw bytes
* @param signature The message signature
* @return success bool, true if successful
*/
function receiveMessage(bytes calldata message, bytes calldata signature) external returns (bool success);
}

View File

@@ -0,0 +1,63 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.16;
interface ITokenMessenger {
/**
* @notice Deposits and burns tokens from sender to be minted on destination domain. The mint
* on the destination domain must be called by `destinationCaller`.
* WARNING: if the `destinationCaller` does not represent a valid address as bytes32, then it will not be possible
* to broadcast the message on the destination domain. This is an advanced feature, and the standard
* depositForBurn() should be preferred for use cases where a specific destination caller is not required.
* Emits a `DepositForBurn` event.
* @dev reverts if:
* - given destinationCaller is zero address
* - given burnToken is not supported
* - given destinationDomain has no TokenMessenger registered
* - transferFrom() reverts. For example, if sender's burnToken balance or approved allowance
* to this contract is less than `amount`.
* - burn() reverts. For example, if `amount` is 0.
* - MessageTransmitter returns false or reverts.
* @param amount amount of tokens to burn
* @param destinationDomain destination domain
* @param mintRecipient address of mint recipient on destination domain
* @param burnToken address of contract to burn deposited tokens, on local domain
* @param destinationCaller caller on the destination domain, as bytes32
* @return nonce unique nonce reserved by message
*/
function depositForBurnWithCaller(
uint256 amount,
uint32 destinationDomain,
bytes32 mintRecipient,
address burnToken,
bytes32 destinationCaller
) external returns (uint64 nonce);
/**
* @notice Replace a BurnMessage to change the mint recipient and/or
* destination caller. Allows the sender of a previous BurnMessage
* (created by depositForBurn or depositForBurnWithCaller)
* to send a new BurnMessage to replace the original.
* The new BurnMessage will reuse the amount and burn token of the original,
* without requiring a new deposit.
* @dev The new message will reuse the original message's nonce. For a
* given nonce, all replacement message(s) and the original message are
* valid to broadcast on the destination domain, until the first message
* at the nonce confirms, at which point all others are invalidated.
* Note: The msg.sender of the replaced message must be the same as the
* msg.sender of the original message.
* @param originalMessage original message bytes (to replace)
* @param originalAttestation original attestation bytes
* @param newDestinationCaller the new destination caller, which may be the
* same as the original destination caller, a new destination caller, or an empty
* destination caller (bytes32(0), indicating that any destination caller is valid.)
* @param newMintRecipient the new mint recipient, which may be the same as the
* original mint recipient, or different.
*/
function replaceDepositForBurn(
bytes calldata originalMessage,
bytes calldata originalAttestation,
bytes32 newDestinationCaller,
bytes32 newMintRecipient
) external;
}

View File

@@ -0,0 +1,12 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.16;
// Implement this on the source chain (Ethereum).
interface IUSDCBurnableSourceBridge {
/**
* @notice Called by Circle, this executes a burn on the source
* chain.
*/
function burnAllLockedUSDC() external;
}

View File

@@ -0,0 +1,11 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.16;
// Implement this on the destination chain (Scroll).
interface IUSDCDestinationBridge {
/**
* @notice Called by Circle, this transfers FiatToken roles to the designated owner.
*/
function transferUSDCRoles(address owner) external;
}

View File

@@ -3,13 +3,20 @@
pragma solidity ^0.8.16;
import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import {PausableUpgradeable} from "@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol";
import {ReentrancyGuardUpgradeable} from "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol";
import {ScrollConstants} from "./constants/ScrollConstants.sol";
import {IScrollMessenger} from "./IScrollMessenger.sol";
// solhint-disable var-name-mixedcase
abstract contract ScrollMessengerBase is OwnableUpgradeable, IScrollMessenger {
abstract contract ScrollMessengerBase is
OwnableUpgradeable,
PausableUpgradeable,
ReentrancyGuardUpgradeable,
IScrollMessenger
{
/**********
* Events *
**********/
@@ -19,14 +26,6 @@ abstract contract ScrollMessengerBase is OwnableUpgradeable, IScrollMessenger {
/// @param _newFeeVault The address of new fee vault contract.
event UpdateFeeVault(address _oldFeeVault, address _newFeeVault);
/*************
* Constants *
*************/
// https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.5.0/contracts/security/ReentrancyGuard.sol
uint256 internal constant _NOT_ENTERED = 1;
uint256 internal constant _ENTERED = 2;
/*************
* Variables *
*************/
@@ -40,31 +39,13 @@ abstract contract ScrollMessengerBase is OwnableUpgradeable, IScrollMessenger {
/// @notice The address of fee vault, collecting cross domain messaging fee.
address public feeVault;
// @note move to ScrollMessengerBase in next big refactor
/// @dev The status of for non-reentrant check.
uint256 private _lock_status;
/// @dev The storage slots for future usage.
uint256[46] private __gap;
uint256[47] private __gap;
/**********************
* Function Modifiers *
**********************/
modifier nonReentrant() {
// On the first call to nonReentrant, _notEntered will be true
require(_lock_status != _ENTERED, "ReentrancyGuard: reentrant call");
// Any calls to nonReentrant after this point will fail
_lock_status = _ENTERED;
_;
// By storing the original value once again, a refund is triggered (see
// https://eips.ethereum.org/EIPS/eip-2200)
_lock_status = _NOT_ENTERED;
}
modifier notInExecution() {
require(
xDomainMessageSender == ScrollConstants.DEFAULT_XDOMAIN_MESSAGE_SENDER,
@@ -77,14 +58,18 @@ abstract contract ScrollMessengerBase is OwnableUpgradeable, IScrollMessenger {
* Constructor *
***************/
function _initialize(address _counterpart, address _feeVault) internal {
function __ScrollMessengerBase_init(address _counterpart, address _feeVault) internal onlyInitializing {
OwnableUpgradeable.__Ownable_init();
PausableUpgradeable.__Pausable_init();
ReentrancyGuardUpgradeable.__ReentrancyGuard_init();
// initialize to a nonzero value
xDomainMessageSender = ScrollConstants.DEFAULT_XDOMAIN_MESSAGE_SENDER;
counterpart = _counterpart;
feeVault = _feeVault;
if (_feeVault != address(0)) {
feeVault = _feeVault;
}
}
// make sure only owner can send ether to messenger to avoid possible user fund loss.
@@ -104,6 +89,17 @@ abstract contract ScrollMessengerBase is OwnableUpgradeable, IScrollMessenger {
emit UpdateFeeVault(_oldFeeVault, _newFeeVault);
}
/// @notice Pause the contract
/// @dev This function can only called by contract owner.
/// @param _status The pause status to update.
function setPause(bool _status) external onlyOwner {
if (_status) {
_pause();
} else {
_unpause();
}
}
/**********************
* Internal Functions *
**********************/

View File

@@ -0,0 +1,95 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import {IMessageTransmitter} from "../../interfaces/IMessageTransmitter.sol";
import {ScrollGatewayBase} from "./ScrollGatewayBase.sol";
abstract contract CCTPGatewayBase is ScrollGatewayBase {
/*********
* Enums *
*********/
enum CCTPMessageStatus {
None,
Pending,
Relayed
}
/*************
* Constants *
*************/
/// @notice The address of L1 USDC address.
address public immutable l1USDC;
/// @notice The address of L2 USDC address.
address public immutable l2USDC;
/// @notice The destination domain for layer2.
uint32 public immutable destinationDomain;
/*************
* Variables *
*************/
/// @notice The address of TokenMessenger in local domain.
address public cctpMessenger;
/// @notice The address of MessageTransmitter in local domain.
address public cctpTransmitter;
/// @notice Mapping from destination domain CCTP nonce to status.
mapping(uint256 => CCTPMessageStatus) public status;
/***************
* Constructor *
***************/
constructor(
address _l1USDC,
address _l2USDC,
uint32 _destinationDomain
) {
l1USDC = _l1USDC;
l2USDC = _l2USDC;
destinationDomain = _destinationDomain;
}
function _initialize(address _cctpMessenger, address _cctpTransmitter) internal {
cctpMessenger = _cctpMessenger;
cctpTransmitter = _cctpTransmitter;
}
/*****************************
* Public Mutating Functions *
*****************************/
/// @notice Claim USDC that has been cross chained.
/// @param _nonce The nonce of the message from CCTP.
/// @param _cctpMessage The message passed to MessageTransmitter contract in CCTP.
/// @param _cctpSignature The message passed to MessageTransmitter contract in CCTP.
function claimUSDC(
uint256 _nonce,
bytes calldata _cctpMessage,
bytes calldata _cctpSignature
) public {
// Check `_nonce` match with `_cctpMessage`.
// According to the encoding of `_cctpMessage`, the nonce is in bytes 12 to 16.
// See here: https://github.com/circlefin/evm-cctp-contracts/blob/master/src/messages/Message.sol#L29
uint256 _expectedMessageNonce;
assembly {
_expectedMessageNonce := and(shr(96, calldataload(_cctpMessage.offset)), 0xffffffffffffffff)
}
require(_expectedMessageNonce == _nonce, "nonce mismatch");
require(status[_nonce] == CCTPMessageStatus.Pending, "message not relayed");
// call transmitter to mint USDC
bool _success = IMessageTransmitter(cctpTransmitter).receiveMessage(_cctpMessage, _cctpSignature);
require(_success, "call transmitter failed");
status[_nonce] = CCTPMessageStatus.Relayed;
}
}

View File

@@ -2,20 +2,15 @@
pragma solidity ^0.8.16;
import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import {ReentrancyGuardUpgradeable} from "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol";
import {IScrollGateway} from "./IScrollGateway.sol";
import {IScrollMessenger} from "../IScrollMessenger.sol";
import {IScrollGatewayCallback} from "../callbacks/IScrollGatewayCallback.sol";
import {ScrollConstants} from "../constants/ScrollConstants.sol";
abstract contract ScrollGatewayBase is IScrollGateway {
/*************
* Constants *
*************/
// https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.5.0/contracts/security/ReentrancyGuard.sol
uint256 private constant _NOT_ENTERED = 1;
uint256 private constant _ENTERED = 2;
abstract contract ScrollGatewayBase is ReentrancyGuardUpgradeable, OwnableUpgradeable, IScrollGateway {
/*************
* Variables *
*************/
@@ -29,35 +24,13 @@ abstract contract ScrollGatewayBase is IScrollGateway {
/// @inheritdoc IScrollGateway
address public override messenger;
/// @dev The status of for non-reentrant check.
uint256 private _status;
/// @dev The storage slots for future usage.
uint256[46] private __gap;
uint256[47] private __gap;
/**********************
* Function Modifiers *
**********************/
modifier nonReentrant() {
// On the first call to nonReentrant, _notEntered will be true
require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
// Any calls to nonReentrant after this point will fail
_status = _ENTERED;
_;
// By storing the original value once again, a refund is triggered (see
// https://eips.ethereum.org/EIPS/eip-2200)
_status = _NOT_ENTERED;
}
modifier onlyMessenger() {
require(msg.sender == messenger, "only messenger can call");
_;
}
modifier onlyCallByCounterpart() {
address _messenger = messenger; // gas saving
require(msg.sender == _messenger, "only messenger can call");
@@ -87,6 +60,9 @@ abstract contract ScrollGatewayBase is IScrollGateway {
require(_counterpart != address(0), "zero counterpart address");
require(_messenger != address(0), "zero messenger address");
ReentrancyGuardUpgradeable.__ReentrancyGuard_init();
OwnableUpgradeable.__Ownable_init();
counterpart = _counterpart;
messenger = _messenger;
@@ -94,9 +70,6 @@ abstract contract ScrollGatewayBase is IScrollGateway {
if (_router != address(0)) {
router = _router;
}
// for reentrancy guard
_status = _NOT_ENTERED;
}
/**********************

View File

@@ -76,12 +76,7 @@ contract ScrollStandardERC20 is ERC20PermitUpgradeable, IScrollERC20Upgradeable
}
function isContract(address _addr) private view returns (bool hasCode) {
uint256 length;
// solhint-disable-next-line no-inline-assembly
assembly {
length := extcodesize(_addr)
}
return length > 0;
hasCode = _addr.code.length > 0;
}
/// @inheritdoc IScrollERC20Upgradeable

View File

@@ -20,9 +20,9 @@ import {TransferReentrantToken} from "./mocks/tokens/TransferReentrantToken.sol"
contract L1GatewayRouterTest is L1GatewayTestBase {
// from L1GatewayRouter
event SetETHGateway(address indexed ethGateway);
event SetDefaultERC20Gateway(address indexed defaultERC20Gateway);
event SetERC20Gateway(address indexed token, address indexed gateway);
event SetETHGateway(address indexed oldETHGateway, address indexed newEthGateway);
event SetDefaultERC20Gateway(address indexed oldDefaultERC20Gateway, address indexed newDefaultERC20Gateway);
event SetERC20Gateway(address indexed token, address indexed oldGateway, address indexed newGateway);
ScrollStandardERC20 private template;
ScrollStandardERC20Factory private factory;
@@ -94,8 +94,8 @@ contract L1GatewayRouterTest is L1GatewayTestBase {
hevm.stopPrank();
// set by owner, should succeed
hevm.expectEmit(true, false, false, true);
emit SetDefaultERC20Gateway(address(l1StandardERC20Gateway));
hevm.expectEmit(true, true, false, true);
emit SetDefaultERC20Gateway(address(0), address(l1StandardERC20Gateway));
assertEq(address(0), router.getERC20Gateway(address(l1Token)));
assertEq(address(0), router.defaultERC20Gateway());
@@ -121,8 +121,8 @@ contract L1GatewayRouterTest is L1GatewayTestBase {
_tokens[0] = address(l1Token);
_gateways[0] = address(l1StandardERC20Gateway);
hevm.expectEmit(true, true, false, true);
emit SetERC20Gateway(address(l1Token), address(l1StandardERC20Gateway));
hevm.expectEmit(true, true, true, true);
emit SetERC20Gateway(address(l1Token), address(0), address(l1StandardERC20Gateway));
assertEq(address(0), router.getERC20Gateway(address(l1Token)));
router.setERC20Gateway(_tokens, _gateways);

View File

@@ -101,8 +101,8 @@ abstract contract L1GatewayTestBase is DSTestPlus {
}
function prepareL2MessageRoot(bytes32 messageHash) internal {
rollup.updateSequencer(address(this), true);
rollup.updateProver(address(this), true);
rollup.addSequencer(address(this));
rollup.addProver(address(this));
// import genesis batch
bytes memory batchHeader0 = new bytes(89);

Some files were not shown because too many files have changed in this diff Show More