diff --git a/.circleci/config.yml b/.circleci/config.yml index 31170a65531c..0deb777b5ee0 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -956,6 +956,14 @@ jobs: description: The make target to use to test the devnet type: string default: devnet-test + devnet-up-2: + description: A make target to start an optional second devnet + type: string + default: "" + devnet-test-2: + description: A make target to test the optional second devnet + type: string + default: "" steps: - checkout - check-changed: @@ -1011,9 +1019,21 @@ jobs: - run: name: Bring up the stack command: make <> + - when: + condition: <> + steps: + - run: + name: Bring up the second stack + command: make <> - run: name: Test the stack command: make <> + - when: + condition: <> + steps: + - run: + name: Test the second stack + command: make <> - run: name: Dump op-node logs command: | @@ -1216,6 +1236,8 @@ workflows: name: devnet-espresso devnet-up: devnet-up-espresso devnet-test: devnet-test-espresso + devnet-up-2: devnet-up-espresso2 + devnet-test-2: devnet-test-espresso2 requires: - pnpm-monorepo - go-lint-test-build: diff --git a/Makefile b/Makefile index 2e20a5bfaa82..04f3840346d3 100644 --- a/Makefile +++ b/Makefile @@ -2,8 +2,8 @@ COMPOSEFLAGS=-d ITESTS_L2_HOST=http://localhost:9545 BEDROCK_TAGS_REMOTE?=origin DEVNET_ESPRESSO_FLAGS=--espresso --deploy-config="devnetL1-espresso.json" --deploy-config-template="devnetL1-espresso-template.json" --deployment="devnetL1-espresso" --devnet-dir=".devnet-espresso" --l2-provider-url="http://localhost:19090" -DEVNET_ESPRESSO_OP2_FLAGS=--espresso --deploy-config="devnetL1-espresso2.json" --deploy-config-template="devnetL1-espresso2-template.json" --deployment="devnetL1-espresso2" --devnet-dir=".devnet-espresso2" --l2-provider-url="http://localhost:29090" --l2="op2" -DEVNET_ESPRESSO_DEMO_FLAGS=--espresso --deploy-config="espresso-demo.json" --deploy-config-template="espresso-demo-template.json" --deployment="espresso-demo" --devnet-dir=".espresso-demo" --l2-provider-url="http://localhost:19090" --l2="op" --compose-file "demo-docker-compose.yml" +DEVNET_ESPRESSO_OP2_FLAGS=--espresso --deploy-config="devnetL1-espresso2.json" --deploy-config-template="devnetL1-espresso2-template.json" --deployment="devnetL1-espresso2" --devnet-dir=".devnet-espresso2" --l2-provider-url="http://localhost:29090" --faucet-url="http://localhost:28111" --l2="op2" +DEVNET_ESPRESSO_DEMO_FLAGS=--espresso --deploy-config="espresso-demo.json" --deploy-config-template="espresso-demo-template.json" --deployment="espresso-demo" --devnet-dir=".espresso-demo" --l2-provider-url="http://localhost:19090" --l2="op" --compose-file "demo-docker-compose.yml" --faucet-url="http://localhost:28111" monorepo-base := $(realpath .) build: build-go build-ts diff --git a/bedrock-devnet/devnet/__init__.py b/bedrock-devnet/devnet/__init__.py index 04d1e5cb2b1e..231d7a728168 100644 --- a/bedrock-devnet/devnet/__init__.py +++ b/bedrock-devnet/devnet/__init__.py @@ -21,6 +21,7 @@ parser.add_argument('--test', help='Tests the deployment, must already be deployed', type=bool, action=argparse.BooleanOptionalAction) parser.add_argument('--l2', help='Which L2 to run', type=str, default='op1') parser.add_argument('--l2-provider-url', help='URL for the L2 RPC node', type=str, default='http://localhost:19545') +parser.add_argument('--faucet-url', help='URL for the L2 faucet', type=str, default='http://localhost:18111') parser.add_argument('--deploy-l2', help='Deploy the L2 onto a running L1 and sequencer network', type=bool, action=argparse.BooleanOptionalAction) parser.add_argument('--deploy-config', help='Deployment config, relative to packages/contracts-bedrock/deploy-config', default='devnetL1.json') parser.add_argument('--deploy-config-template', help='Deployment config template, relative to packages/contracts-bedrock/deploy-config', default='devnetL1-template.json') @@ -94,7 +95,7 @@ def main(): if args.test: log.info('Testing deployed devnet') - devnet_test(paths, args.l2_provider_url) + devnet_test(paths, args.l2_provider_url, args.faucet_url) return os.makedirs(devnet_dir, exist_ok=True) @@ -304,7 +305,7 @@ def devnet_deploy(paths, args): # If we are deploying onto an existing L1, don't restart the services that are already # running. command.append('--no-recreate') - services = [f'{l2}-node', f'{l2}-proposer', f'{l2}-batcher'] + services = [f'{l2}-node', f'{l2}-proposer', f'{l2}-batcher', f'{l2}-faucet'] run_command(command + services, cwd=paths.ops_bedrock_dir, env={ 'PWD': paths.ops_bedrock_dir, 'L2OO_ADDRESS': l2_output_oracle, @@ -369,7 +370,7 @@ def deploy_erc20(paths, l2_provider_url): timeout=60, ) -def devnet_test(paths, l2_provider_url): +def devnet_test(paths, l2_provider_url, faucet_url): # Check the L2 config run_command( ['go', 'run', 'cmd/check-l2/main.go', '--l2-rpc-url', l2_provider_url, '--l1-rpc-url', 'http://localhost:8545'], @@ -388,6 +389,12 @@ def devnet_test(paths, l2_provider_url): timeout=8*60, ) + run_command( + ['npx', 'hardhat', 'faucet-request', '--network', 'devnetL1', '--l2-provider-url', l2_provider_url, '--faucet-url', faucet_url], + cwd=paths.sdk_dir, + timeout=8*60, + ) + def run_command(args, check=True, shell=False, cwd=None, env=None, timeout=None, capture_output=False): env = env if env else {} return subprocess.run( diff --git a/ops-bedrock/.env b/ops-bedrock/.env index f11a1a336dde..eeb15c95cddd 100644 --- a/ops-bedrock/.env +++ b/ops-bedrock/.env @@ -20,6 +20,7 @@ OP1_BATCHER_DEBUG_PORT=16061 OP1_BATCHER_METRICS_PORT=17301 OP1_BATCHER_RPC_PORT=16545 OP1_GETH_PROXY_PORT=19090 +OP1_FAUCET_PORT=18111 ### Rollup 901 block explorer OP1_BLOCKSCOUT_PORT=14000 @@ -41,6 +42,7 @@ OP2_BATCHER_DEBUG_PORT=26061 OP2_BATCHER_METRICS_PORT=27301 OP2_BATCHER_RPC_PORT=26545 OP2_GETH_PROXY_PORT=29090 +OP2_FAUCET_PORT=28111 ### Rollup 902 block explorer OP2_BLOCKSCOUT_PORT=24000 diff --git a/ops-bedrock/demo-docker-compose.yml b/ops-bedrock/demo-docker-compose.yml index 9d9c051016d7..4ed83d66de7e 100644 --- a/ops-bedrock/demo-docker-compose.yml +++ b/ops-bedrock/demo-docker-compose.yml @@ -156,6 +156,23 @@ services: networks: - espresso-sequencer + op-faucet: + image: ghcr.io/espressosystems/discord-faucet:main + ports: + - "$OP1_FAUCET_PORT:8111" + environment: + - ESPRESSO_DISCORD_FAUCET_NUM_CLIENTS=1 + - ESPRESSO_DISCORD_FAUCET_MNEMONIC=test test test test test test test test test test test junk + - ESPRESSO_DISCORD_FAUCET_FIRST_ACCOUNT_INDEX=5 + - ESPRESSO_DISCORD_FAUCET_GRANT_AMOUNT_ETHERS=0.1 + - ESPRESSO_DISCORD_FAUCET_WEB3_PROVIDER_URL_HTTP=http://op-geth-proxy:9090 + - ESPRESSO_DISCORD_FAUCET_POLL_INTERVAL=2s + - RUST_LOG + depends_on: + - op-geth-proxy + networks: + - espresso-sequencer + artifact-server: image: nginx:1.25-alpine ports: diff --git a/ops-bedrock/docker-compose.yml b/ops-bedrock/docker-compose.yml index 7b9d3f0946e0..9c5e731e017b 100644 --- a/ops-bedrock/docker-compose.yml +++ b/ops-bedrock/docker-compose.yml @@ -172,6 +172,21 @@ services: extra_hosts: - "host.docker.internal:host-gateway" + op1-faucet: + image: ghcr.io/espressosystems/discord-faucet:main + ports: + - "$OP1_FAUCET_PORT:8111" + environment: + - ESPRESSO_DISCORD_FAUCET_NUM_CLIENTS=1 + - ESPRESSO_DISCORD_FAUCET_MNEMONIC=test test test test test test test test test test test junk + - ESPRESSO_DISCORD_FAUCET_FIRST_ACCOUNT_INDEX=5 + - ESPRESSO_DISCORD_FAUCET_GRANT_AMOUNT_ETHERS=0.1 + - ESPRESSO_DISCORD_FAUCET_WEB3_PROVIDER_URL_HTTP=http://op1-geth-proxy:9090 + - ESPRESSO_DISCORD_FAUCET_POLL_INTERVAL=2s + - RUST_LOG + depends_on: + - op1-geth-proxy + artifact-server: depends_on: - l1 @@ -420,6 +435,21 @@ services: extra_hosts: - "host.docker.internal:host-gateway" + op2-faucet: + image: ghcr.io/espressosystems/discord-faucet:main + ports: + - "$OP2_FAUCET_PORT:8111" + environment: + - ESPRESSO_DISCORD_FAUCET_NUM_CLIENTS=1 + - ESPRESSO_DISCORD_FAUCET_MNEMONIC=test test test test test test test test test test test junk + - ESPRESSO_DISCORD_FAUCET_FIRST_ACCOUNT_INDEX=5 + - ESPRESSO_DISCORD_FAUCET_GRANT_AMOUNT_ETHERS=0.1 + - ESPRESSO_DISCORD_FAUCET_WEB3_PROVIDER_URL_HTTP=http://op2-geth-proxy:9090 + - ESPRESSO_DISCORD_FAUCET_POLL_INTERVAL=2s + - RUST_LOG + depends_on: + - op2-geth-proxy + ################################################################################################## # OP stack 902 block explorer # diff --git a/packages/sdk/package.json b/packages/sdk/package.json index 3607d4a19f52..2664d1e3606e 100644 --- a/packages/sdk/package.json +++ b/packages/sdk/package.json @@ -52,6 +52,7 @@ "hardhat-deploy": "^0.11.4", "isomorphic-fetch": "^3.0.0", "mocha": "^10.2.0", + "node-fetch": "^2.6.7", "nyc": "^15.1.0", "ts-node": "^10.9.1", "typedoc": "^0.25.1", diff --git a/packages/sdk/tasks/faucet-request.ts b/packages/sdk/tasks/faucet-request.ts new file mode 100644 index 000000000000..180e8a66b12c --- /dev/null +++ b/packages/sdk/tasks/faucet-request.ts @@ -0,0 +1,55 @@ +import { task, types } from 'hardhat/config' +import { providers, utils } from 'ethers' +import fetch from 'node-fetch' + +const GRANT_AMOUNT = utils.parseEther('0.1') + +task('faucet-request', 'Deposits WETH9 onto L2.') + .addParam( + 'l2ProviderUrl', + 'L2 provider URL.', + 'http://localhost:9545', + types.string + ) + .addParam( + 'faucetUrl', + 'L2 faucet URL', + 'http://localhost:18111', + types.string + ) + .setAction(async (args, hre) => { + const signers = await hre.ethers.getSigners() + if (signers.length === 0) { + throw new Error('No configured signers') + } + // Use the last configured signer so we don't conflict with some other task + const provider = new providers.StaticJsonRpcProvider(args.l2ProviderUrl) + const signer = new hre.ethers.Wallet( + hre.network.config.accounts[0], + provider + ) + const address = await signer.getAddress() + console.log(`Using signer ${address}`) + + // Check the signer's balance before we do anything + const initialBalance = await signer.getBalance() + console.log(`Signer initial balance is ${initialBalance}`) + + // Request from the faucet + const res = await fetch(`${args.faucetUrl}/faucet/request/${address}`, { + method: 'POST', + }) + if (res.status !== 200) { + throw new Error(`Request failed with status ${res.status}`) + } + + // Wait for our balance to increase. + for (;;) { + const balance = await signer.getBalance() + console.log(`Signer balance is ${balance}`) + if (balance >= initialBalance + GRANT_AMOUNT) { + break + } + await new Promise((resolve) => setTimeout(resolve, 1000)) + } + }) diff --git a/packages/sdk/tasks/index.ts b/packages/sdk/tasks/index.ts index c45b3ad6881c..52961b8f4d16 100644 --- a/packages/sdk/tasks/index.ts +++ b/packages/sdk/tasks/index.ts @@ -1,4 +1,5 @@ import './deploy-erc20' import './deposit-eth' import './deposit-erc20' +import './faucet-request' import './finalize-withdrawal' diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 0ed8b2ba9f17..fd7fbc1241c6 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -501,6 +501,9 @@ importers: mocha: specifier: ^10.2.0 version: 10.2.0 + node-fetch: + specifier: ^2.6.7 + version: 2.6.12 nyc: specifier: ^15.1.0 version: 15.1.0 @@ -2773,7 +2776,7 @@ packages: hardhat: ^2.0.0 dependencies: ethers: 5.7.2 - hardhat: 2.17.2(ts-node@10.9.1)(typescript@5.2.2) + hardhat: 2.17.2(ts-node@10.9.1)(typescript@5.1.6) dev: true /@nomiclabs/hardhat-waffle@2.0.1(@nomiclabs/hardhat-ethers@2.2.3)(ethereum-waffle@4.0.10)(ethers@5.7.2)(hardhat@2.17.2):