diff --git a/yarn-project/.gitignore b/yarn-project/.gitignore index 0ef0316a3f12..399ef4765c67 100644 --- a/yarn-project/.gitignore +++ b/yarn-project/.gitignore @@ -14,7 +14,6 @@ **/*.result accounts/artifacts aztec.js/src/contract/protocol_contracts -aztec-faucet/data* aztec-node/data* aztec/log stdlib/fixtures/*.json diff --git a/yarn-project/aztec-faucet/README.md b/yarn-project/aztec-faucet/README.md deleted file mode 100644 index 44427ad4f0c2..000000000000 --- a/yarn-project/aztec-faucet/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# Aztec Faucet - -This application allows someone to obtain a small amount of eth via a http endpoint. diff --git a/yarn-project/aztec-faucet/eslint.config.js b/yarn-project/aztec-faucet/eslint.config.js deleted file mode 100644 index 0331d0552f62..000000000000 --- a/yarn-project/aztec-faucet/eslint.config.js +++ /dev/null @@ -1,3 +0,0 @@ -import config from '@aztec/foundation/eslint'; - -export default config; diff --git a/yarn-project/aztec-faucet/package.json b/yarn-project/aztec-faucet/package.json deleted file mode 100644 index 9365d15752ed..000000000000 --- a/yarn-project/aztec-faucet/package.json +++ /dev/null @@ -1,94 +0,0 @@ -{ - "name": "@aztec/aztec-faucet", - "version": "0.1.0", - "main": "dest/bin/index.js", - "type": "module", - "exports": { - ".": "./dest/index.js", - "./config": "./dest/config.js" - }, - "typedocOptions": { - "entryPoints": [ - "./src/bin/index.ts" - ], - "name": "Aztec Faucet", - "tsconfig": "./tsconfig.json" - }, - "scripts": { - "start": "node --no-warnings ./dest/bin", - "build": "yarn clean && ../scripts/tsc.sh", - "build:dev": "../scripts/tsc.sh --watch", - "clean": "rm -rf ./dest .tsbuildinfo", - "test": "NODE_NO_WARNINGS=1 node --experimental-vm-modules ../node_modules/.bin/jest --passWithNoTests --maxWorkers=${JEST_MAX_WORKERS:-8}" - }, - "inherits": [ - "../package.common.json" - ], - "jest": { - "moduleNameMapper": { - "^(\\.{1,2}/.*)\\.[cm]?js$": "$1" - }, - "testRegex": "./src/.*\\.test\\.(js|mjs|ts)$", - "rootDir": "./src", - "transform": { - "^.+\\.tsx?$": [ - "@swc/jest", - { - "jsc": { - "parser": { - "syntax": "typescript", - "decorators": true - }, - "transform": { - "decoratorVersion": "2022-03" - } - } - } - ] - }, - "extensionsToTreatAsEsm": [ - ".ts" - ], - "reporters": [ - "default" - ], - "testTimeout": 120000, - "setupFiles": [ - "../../foundation/src/jest/setup.mjs" - ], - "testEnvironment": "../../foundation/src/jest/env.mjs", - "setupFilesAfterEnv": [ - "../../foundation/src/jest/setupAfterEnv.mjs" - ] - }, - "dependencies": { - "@aztec/ethereum": "workspace:^", - "@aztec/foundation": "workspace:^", - "@aztec/l1-artifacts": "workspace:^", - "@koa/cors": "^5.0.0", - "koa": "^2.16.1", - "koa-bodyparser": "^4.4.1", - "koa-router": "^13.1.1", - "viem": "npm:@aztec/viem@2.38.2", - "zod": "^3.23.8" - }, - "devDependencies": { - "@jest/globals": "^30.0.0", - "@types/jest": "^30.0.0", - "@types/koa-bodyparser": "^4.3.12", - "@types/node": "^22.15.17", - "@typescript/native-preview": "7.0.0-dev.20260113.1", - "jest": "^30.0.0", - "ts-node": "^10.9.1", - "typescript": "^5.3.3" - }, - "files": [ - "dest", - "src", - "!*.test.*" - ], - "types": "./dest/index.d.ts", - "engines": { - "node": ">=20.10" - } -} diff --git a/yarn-project/aztec-faucet/src/bin/index.ts b/yarn-project/aztec-faucet/src/bin/index.ts deleted file mode 100644 index 3adaa2a413ec..000000000000 --- a/yarn-project/aztec-faucet/src/bin/index.ts +++ /dev/null @@ -1,26 +0,0 @@ -#!/usr/bin/env -S node --no-warnings -import { createLogger } from '@aztec/foundation/log'; - -import { getFaucetConfigFromEnv } from '../config.js'; -import { Faucet } from '../faucet.js'; -import { createFaucetHttpServer } from '../http.js'; - -const logger = createLogger('aztec:faucet:http'); - -/** - * Create and start a new Aztec Node HTTP Server - */ -async function main() { - const config = getFaucetConfigFromEnv(); - const faucet = await Faucet.create(config); - const httpServer = createFaucetHttpServer(faucet, '/', logger); - const port = parseInt(process.env?.AZTEC_PORT ?? '', 10) || 8080; - httpServer.listen(port); - logger.info(`Aztec Faucet listening on port ${port}`); - await Promise.resolve(); -} - -main().catch(err => { - logger.error(err); - process.exit(1); -}); diff --git a/yarn-project/aztec-faucet/src/config.ts b/yarn-project/aztec-faucet/src/config.ts deleted file mode 100644 index c2e6eff75687..000000000000 --- a/yarn-project/aztec-faucet/src/config.ts +++ /dev/null @@ -1,65 +0,0 @@ -import { type L1ReaderConfig, l1ReaderConfigMappings } from '@aztec/ethereum/l1-reader'; -import { - type ConfigMappingsType, - SecretValue, - getConfigFromMappings, - numberConfigHelper, - secretStringConfigHelper, -} from '@aztec/foundation/config'; -import { EthAddress } from '@aztec/foundation/eth-address'; - -export type L1AssetConfig = { - address: EthAddress; - amount: bigint; -}; - -export type FaucetConfig = L1ReaderConfig & { - l1Mnemonic?: SecretValue; - mnemonicAddressIndex: number; - interval: number; - ethAmount: string; - l1Assets: L1AssetConfig[]; -}; - -export const faucetConfigMapping: ConfigMappingsType = { - ...l1ReaderConfigMappings, - l1Mnemonic: { - env: 'MNEMONIC', - description: 'The mnemonic for the faucet account', - ...secretStringConfigHelper(), - }, - mnemonicAddressIndex: { - env: 'FAUCET_MNEMONIC_ADDRESS_INDEX', - description: 'The address to use', - ...numberConfigHelper(0), - }, - interval: { - env: 'FAUCET_INTERVAL_MS', - description: 'How often the faucet can be dripped', - ...numberConfigHelper(1 * 60 * 60 * 1000), // 1 hour - }, - ethAmount: { - env: 'FAUCET_ETH_AMOUNT', - description: 'How much eth the faucet should drip per call', - defaultValue: '1.0', - }, - l1Assets: { - env: 'FAUCET_L1_ASSETS', - description: 'Which other L1 assets the faucet is able to drip', - defaultValue: '', - parseEnv(val): L1AssetConfig[] { - const assetConfigs = val.split(','); - return assetConfigs.flatMap(assetConfig => { - if (!assetConfig) { - return []; - } - const [address, amount = '1e9'] = assetConfig.split(':'); - return [{ address: EthAddress.fromString(address), amount: BigInt(amount) }]; - }); - }, - }, -}; - -export function getFaucetConfigFromEnv(): FaucetConfig { - return getConfigFromMappings(faucetConfigMapping); -} diff --git a/yarn-project/aztec-faucet/src/faucet.ts b/yarn-project/aztec-faucet/src/faucet.ts deleted file mode 100644 index b4fc31686f57..000000000000 --- a/yarn-project/aztec-faucet/src/faucet.ts +++ /dev/null @@ -1,156 +0,0 @@ -import { createEthereumChain } from '@aztec/ethereum/chain'; -import { createExtendedL1Client } from '@aztec/ethereum/client'; -import type { ExtendedViemWalletClient } from '@aztec/ethereum/types'; -import type { EthAddress } from '@aztec/foundation/eth-address'; -import { createLogger } from '@aztec/foundation/log'; -import { TestERC20Abi } from '@aztec/l1-artifacts'; - -import { - type Account, - type Chain, - type GetContractReturnType, - type HttpTransport, - type LocalAccount, - type WalletClient, - getContract, - parseEther, -} from 'viem'; -import { mnemonicToAccount } from 'viem/accounts'; - -import type { FaucetConfig, L1AssetConfig } from './config.js'; - -type L1Asset = { - contract: GetContractReturnType>; - amount: bigint; -}; - -export class Faucet { - private l1Client: ExtendedViemWalletClient; - - private dripHistory = new Map>(); - private l1Assets = new Map(); - - constructor( - private config: FaucetConfig, - private account: LocalAccount, - private timeFn: () => number = Date.now, - private log = createLogger('aztec:faucet'), - ) { - const chain = createEthereumChain(config.l1RpcUrls, config.l1ChainId); - - this.l1Client = createExtendedL1Client(config.l1RpcUrls, this.account, chain.chainInfo); - } - - public static async create(config: FaucetConfig): Promise { - if (!config.l1Mnemonic || !config.l1Mnemonic.getValue()) { - throw new Error('Missing faucet mnemonic'); - } - - const account = mnemonicToAccount(config.l1Mnemonic.getValue(), { addressIndex: config.mnemonicAddressIndex }); - const faucet = new Faucet(config, account); - - for (const asset of config.l1Assets) { - await faucet.addL1Asset(asset); - } - - return faucet; - } - - public send(to: EthAddress, assetName: string): Promise { - if (assetName.toUpperCase() === 'ETH') { - return this.sendEth(to); - } else { - return this.sendERC20(to, assetName); - } - } - - public async sendEth(to: EthAddress): Promise { - this.checkThrottle(to, 'ETH'); - - const hash = await this.l1Client.sendTransaction({ - account: this.account, - to: to.toString(), - value: parseEther(this.config.ethAmount), - }); - await this.l1Client.waitForTransactionReceipt({ hash }); - - this.updateThrottle(to, 'ETH'); - this.log.info(`Sent ETH ${this.config.ethAmount} to ${to} in tx ${hash}`); - } - - public async sendERC20(to: EthAddress, assetName: string): Promise { - const asset = this.l1Assets.get(assetName); - if (!asset) { - throw new UnknownAsset(assetName); - } - - this.checkThrottle(to, assetName); - - const hash = await asset.contract.write.mint([to.toString(), asset.amount]); - await this.l1Client.waitForTransactionReceipt({ hash }); - - this.updateThrottle(to, assetName); - - this.log.info(`Sent ${assetName} ${asset.amount} to ${to} in tx ${hash}`); - } - - public async addL1Asset(l1AssetConfig: L1AssetConfig): Promise { - const contract = getContract({ - abi: TestERC20Abi, - address: l1AssetConfig.address.toString(), - client: this.l1Client, - }); - - const [name, owner] = await Promise.all([contract.read.name(), contract.read.owner()]); - - if (owner !== this.account.address) { - throw new Error( - `Owner mismatch. Expected contract ${name} to be owned by ${this.account.address}, received ${owner}`, - ); - } - - if ( - this.l1Assets.has(name) && - this.l1Assets.get(name)!.contract.address.toLowerCase() !== l1AssetConfig.address.toString().toLowerCase() - ) { - this.log.warn(`Updating asset ${name} to address=${contract.address}`); - } - - this.l1Assets.set(name, { contract, amount: l1AssetConfig.amount }); - } - - private checkThrottle(address: EthAddress, asset = 'ETH') { - const addressHistory = this.dripHistory.get(address.toString()); - if (!addressHistory) { - return; - } - - const now = this.timeFn(); - const last = addressHistory.get(asset); - if (typeof last === 'number' && last + this.config.interval > now) { - throw new ThrottleError(address.toString(), asset); - } - } - - private updateThrottle(address: EthAddress, asset = 'ETH') { - const addressStr = address.toString(); - if (!this.dripHistory.has(addressStr)) { - this.dripHistory.set(addressStr, new Map()); - } - - const addressHistory = this.dripHistory.get(addressStr)!; - addressHistory.set(asset, this.timeFn()); - } -} - -export class ThrottleError extends Error { - constructor(address: string, asset: string) { - super(`Not funding ${asset}: throttled ${address}`); - } -} - -export class UnknownAsset extends Error { - constructor(asset: string) { - super(`Unknown asset: ${asset}`); - } -} diff --git a/yarn-project/aztec-faucet/src/http.ts b/yarn-project/aztec-faucet/src/http.ts deleted file mode 100644 index fad380ddbf55..000000000000 --- a/yarn-project/aztec-faucet/src/http.ts +++ /dev/null @@ -1,85 +0,0 @@ -import { EthAddress } from '@aztec/foundation/eth-address'; -import { createLogger } from '@aztec/foundation/log'; -import { type ApiSchemaFor, schemas } from '@aztec/foundation/schemas'; - -import cors from '@koa/cors'; -import { createServer } from 'http'; -import Koa from 'koa'; -import bodyParser from 'koa-bodyparser'; -import Router from 'koa-router'; -import { z } from 'zod'; - -import { type Faucet, ThrottleError } from './faucet.js'; - -export function createFaucetHttpServer(faucet: Faucet, apiPrefix = '', logger = createLogger('aztec:faucet:http')) { - const router = new Router({ prefix: `${apiPrefix}` }); - router.get('/drip/:address', async ctx => { - const { address } = ctx.params; - const { asset } = ctx.query; - - if (typeof asset !== 'string') { - throw new Error(`Bad asset: [${asset}]`); - } - - await faucet.send(EthAddress.fromString(address), asset); - - ctx.status = 200; - }); - - const L1AssetRequestSchema = z.object({ - address: z.string().transform(str => EthAddress.fromString(str)), - amount: z.string().transform(str => BigInt(str)), - }); - - router.post('/l1-asset', async ctx => { - if (!ctx.request.body) { - throw new Error('Invalid request body'); - } - - const result = L1AssetRequestSchema.safeParse(ctx.request.body); - - if (!result.success) { - throw new Error(`Invalid request: ${result.error.message}`); - } - - const { address, amount } = result.data; - - await faucet.addL1Asset({ address, amount }); - - ctx.status = 200; - }); - - const app = new Koa(); - - app.on('error', error => { - logger.error(`Error on API handler: ${error}`); - }); - - app.use(async (ctx, next) => { - try { - await next(); - } catch (err: any) { - logger.error(err); - ctx.status = err instanceof ThrottleError ? 429 : 400; - ctx.body = { error: err.message }; - } - }); - - app.use(cors()); - app.use(bodyParser()); - app.use(router.routes()); - app.use(router.allowedMethods()); - - // eslint-disable-next-line @typescript-eslint/no-misused-promises - return createServer(app.callback()); -} - -export const FaucetSchema: ApiSchemaFor = { - send: z.function().args(schemas.EthAddress, z.string()).returns(z.void()), - sendERC20: z.function().args(schemas.EthAddress, z.string()).returns(z.void()), - sendEth: z.function().args(schemas.EthAddress).returns(z.void()), - addL1Asset: z - .function() - .args(z.object({ address: schemas.EthAddress, amount: z.bigint() })) - .returns(z.void()), -}; diff --git a/yarn-project/aztec-faucet/src/index.ts b/yarn-project/aztec-faucet/src/index.ts deleted file mode 100644 index e4e8281d7f0a..000000000000 --- a/yarn-project/aztec-faucet/src/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -export * from './faucet.js'; -export * from './http.js'; -export * from './config.js'; diff --git a/yarn-project/aztec-faucet/terraform/main.tf b/yarn-project/aztec-faucet/terraform/main.tf deleted file mode 100644 index 4f8aad1e05c5..000000000000 --- a/yarn-project/aztec-faucet/terraform/main.tf +++ /dev/null @@ -1,236 +0,0 @@ -terraform { - backend "s3" { - bucket = "aztec-terraform" - region = "eu-west-2" - } - required_providers { - aws = { - source = "hashicorp/aws" - version = "3.74.2" - } - } -} - -# Define provider and region -provider "aws" { - region = "eu-west-2" -} - -data "terraform_remote_state" "setup_iac" { - backend = "s3" - config = { - bucket = "aztec-terraform" - key = "setup/setup-iac" - region = "eu-west-2" - } -} - -data "terraform_remote_state" "aztec2_iac" { - backend = "s3" - config = { - bucket = "aztec-terraform" - key = "aztec2/iac" - region = "eu-west-2" - } -} - -locals { - api_prefix = "/${var.DEPLOY_TAG}/aztec-faucet/${var.API_KEY}" - rpc_url = "https://${var.DEPLOY_TAG}-mainnet-fork.aztec.network:8545/${var.API_KEY}" -} - - -resource "aws_cloudwatch_log_group" "aztec-faucet" { - name = "/fargate/service/${var.DEPLOY_TAG}/aztec-faucet" - retention_in_days = 14 -} - -resource "aws_service_discovery_service" "aztec-faucet" { - name = "${var.DEPLOY_TAG}-faucet" - - health_check_custom_config { - failure_threshold = 1 - } - - dns_config { - namespace_id = data.terraform_remote_state.setup_iac.outputs.local_service_discovery_id - - dns_records { - ttl = 60 - type = "A" - } - - dns_records { - ttl = 60 - type = "SRV" - } - - routing_policy = "MULTIVALUE" - } - - # Terraform just fails if this resource changes and you have registered instances. - provisioner "local-exec" { - when = destroy - command = "${path.module}/servicediscovery-drain.sh ${self.id}" - } -} - -# Define task definition and service. -resource "aws_ecs_task_definition" "aztec-faucet" { - family = "${var.DEPLOY_TAG}-aztec-faucet" - requires_compatibilities = ["FARGATE"] - network_mode = "awsvpc" - cpu = "2048" - memory = "4096" - execution_role_arn = data.terraform_remote_state.setup_iac.outputs.ecs_task_execution_role_arn - task_role_arn = data.terraform_remote_state.aztec2_iac.outputs.cloudwatch_logging_ecs_role_arn - - container_definitions = jsonencode([ - { - name = "${var.DEPLOY_TAG}-aztec-faucet" - image = "${var.DOCKERHUB_ACCOUNT}/aztec-faucet:${var.IMAGE_TAG}" - essential = true - memoryReservation = 3376 - portMappings = [ - { - containerPort = 80 - hostPort = 80 - } - ] - environment = [ - { - name = "NODE_ENV", - value = "production" - }, - { - name = "FAUCET_PORT", - value = "80" - }, - { - name = "LOG_LEVEL", - value = "verbose" - }, - { - name = "RPC_URL", - value = local.rpc_url - }, - { - name = "API_PREFIX", - value = local.api_prefix - }, - { - name = "L1_CHAIN_ID", - value = var.L1_CHAIN_ID - }, - { - name = "PRIVATE_KEY", - value = var.FAUCET_PRIVATE_KEY - }, - { - name = "INTERVAL", - value = "86400" - }, - { - name = "ETH_AMOUNT", - value = "1.0" - }, - { - name = "FAUCET_ACCOUNT_INDEX", - value = tostring(var.FAUCET_ACCOUNT_INDEX) - }, - { - name = "FORK_MNEMONIC", - value = var.FORK_MNEMONIC - }, - { - name = "EXTRA_ASSETS", - value = "fee_juice:${var.FEE_JUICE_CONTRACT_ADDRESS},dev_coin:${var.DEV_COIN_CONTRACT_ADDRESS}" - }, - { - name = "EXTRA_ASSET_AMOUNT", - value = "1000000000000000000000" - } - ] - logConfiguration = { - logDriver = "awslogs" - options = { - "awslogs-group" = aws_cloudwatch_log_group.aztec-faucet.name - "awslogs-region" = "eu-west-2" - "awslogs-stream-prefix" = "ecs" - } - } - } - ]) -} - -resource "aws_ecs_service" "aztec-faucet" { - name = "${var.DEPLOY_TAG}-aztec-faucet" - cluster = data.terraform_remote_state.setup_iac.outputs.ecs_cluster_id - launch_type = "FARGATE" - desired_count = 1 - deployment_maximum_percent = 100 - deployment_minimum_healthy_percent = 0 - platform_version = "1.4.0" - enable_execute_command = true - - network_configuration { - subnets = [ - data.terraform_remote_state.setup_iac.outputs.subnet_az1_private_id, - data.terraform_remote_state.setup_iac.outputs.subnet_az2_private_id - ] - security_groups = [data.terraform_remote_state.setup_iac.outputs.security_group_private_id] - } - - load_balancer { - target_group_arn = aws_alb_target_group.aztec-faucet.arn - container_name = "${var.DEPLOY_TAG}-aztec-faucet" - container_port = 80 - } - - service_registries { - registry_arn = aws_service_discovery_service.aztec-faucet.arn - container_name = "${var.DEPLOY_TAG}-aztec-faucet" - container_port = 80 - } - - task_definition = aws_ecs_task_definition.aztec-faucet.family -} - -# Configure ALB to route /aztec-faucet to server. -resource "aws_alb_target_group" "aztec-faucet" { - name = "${var.DEPLOY_TAG}-faucet" - port = 80 - protocol = "HTTP" - target_type = "ip" - vpc_id = data.terraform_remote_state.setup_iac.outputs.vpc_id - deregistration_delay = 5 - - health_check { - path = "${local.api_prefix}/status" - matcher = "200" - interval = 10 - healthy_threshold = 2 - unhealthy_threshold = 5 - timeout = 5 - } - - tags = { - name = "${var.DEPLOY_TAG}-faucet" - } -} - -resource "aws_lb_listener_rule" "api-1" { - listener_arn = data.terraform_remote_state.aztec2_iac.outputs.alb_listener_arn - priority = var.FAUCET_LB_RULE_PRIORITY - - action { - type = "forward" - target_group_arn = aws_alb_target_group.aztec-faucet.arn - } - - condition { - path_pattern { - values = ["/${var.DEPLOY_TAG}/aztec-faucet*"] - } - } -} diff --git a/yarn-project/aztec-faucet/terraform/servicediscovery-drain.sh b/yarn-project/aztec-faucet/terraform/servicediscovery-drain.sh deleted file mode 100755 index b8d6c3015196..000000000000 --- a/yarn-project/aztec-faucet/terraform/servicediscovery-drain.sh +++ /dev/null @@ -1,20 +0,0 @@ -#!/usr/bin/env bash - -[ $# -ne 1 ] && echo "Usage: $0 " && exit 1 - -serviceId="--service-id=$1" - -echo "Draining servicediscovery instances from $1 ..." -ids="$(aws servicediscovery list-instances $serviceId --query 'Instances[].Id' --output text | tr '\t' ' ')" - -found= -for id in $ids; do - if [ -n "$id" ]; then - echo "Deregistering $1 / $id ..." - aws servicediscovery deregister-instance $serviceId --instance-id "$id" - found=1 - fi -done - -# Yes, I'm being lazy here... -[ -n "$found" ] && sleep 5 || true \ No newline at end of file diff --git a/yarn-project/aztec-faucet/terraform/variables.tf b/yarn-project/aztec-faucet/terraform/variables.tf deleted file mode 100644 index 992719e667d0..000000000000 --- a/yarn-project/aztec-faucet/terraform/variables.tf +++ /dev/null @@ -1,49 +0,0 @@ -variable "DEPLOY_TAG" { - type = string -} - -variable "IMAGE_TAG" { - type = string -} - -variable "API_KEY" { - type = string -} - -variable "L1_CHAIN_ID" { - type = string -} - -variable "FAUCET_PRIVATE_KEY" { - type = string - default = "" -} - -variable "DOCKERHUB_ACCOUNT" { - type = string -} - -variable "FORK_MNEMONIC" { - type = string -} - -variable "FAUCET_ACCOUNT_INDEX" { - type = string -} - -variable "FEE_JUICE_CONTRACT_ADDRESS" { - type = string -} - -variable "STAKING_ASSET_CONTRACT_ADDRESS" { - type = string -} - -variable "DEV_COIN_CONTRACT_ADDRESS" { - type = string -} - -variable "FAUCET_LB_RULE_PRIORITY" { - type = number - default = 600 -} diff --git a/yarn-project/aztec-faucet/tsconfig.json b/yarn-project/aztec-faucet/tsconfig.json deleted file mode 100644 index 29a3691c1d6b..000000000000 --- a/yarn-project/aztec-faucet/tsconfig.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "extends": "..", - "compilerOptions": { - "outDir": "dest", - "rootDir": "src", - "tsBuildInfoFile": ".tsbuildinfo" - }, - "references": [ - { - "path": "../ethereum" - }, - { - "path": "../foundation" - }, - { - "path": "../l1-artifacts" - } - ], - "include": ["src"] -} diff --git a/yarn-project/aztec/package.json b/yarn-project/aztec/package.json index df0af1e38d73..108e35adf1d8 100644 --- a/yarn-project/aztec/package.json +++ b/yarn-project/aztec/package.json @@ -30,7 +30,6 @@ "dependencies": { "@aztec/accounts": "workspace:^", "@aztec/archiver": "workspace:^", - "@aztec/aztec-faucet": "workspace:^", "@aztec/aztec-node": "workspace:^", "@aztec/aztec.js": "workspace:^", "@aztec/bb-prover": "workspace:^", diff --git a/yarn-project/aztec/tsconfig.json b/yarn-project/aztec/tsconfig.json index 35c68da09741..aef1ccaa1c21 100644 --- a/yarn-project/aztec/tsconfig.json +++ b/yarn-project/aztec/tsconfig.json @@ -12,9 +12,6 @@ { "path": "../archiver" }, - { - "path": "../aztec-faucet" - }, { "path": "../aztec-node" }, diff --git a/yarn-project/end-to-end/src/devnet/e2e_smoke.test.ts b/yarn-project/end-to-end/src/devnet/e2e_smoke.test.ts deleted file mode 100644 index 6b985b3a0242..000000000000 --- a/yarn-project/end-to-end/src/devnet/e2e_smoke.test.ts +++ /dev/null @@ -1,269 +0,0 @@ -import { AztecAddress } from '@aztec/aztec.js/addresses'; -import type { EthAddress } from '@aztec/aztec.js/addresses'; -import type { WaitOpts } from '@aztec/aztec.js/contracts'; -import { FeeJuicePaymentMethodWithClaim } from '@aztec/aztec.js/fee'; -import { Fr } from '@aztec/aztec.js/fields'; -import { createAztecNodeClient } from '@aztec/aztec.js/node'; -import type { Logger } from '@aztec/foundation/log'; -import { promiseWithResolvers } from '@aztec/foundation/promise'; -import { retryUntil } from '@aztec/foundation/retry'; -import { FeeJuiceContract } from '@aztec/noir-contracts.js/FeeJuice'; -import { TestContract } from '@aztec/noir-test-contracts.js/Test'; -import type { AztecNode } from '@aztec/stdlib/interfaces/client'; -import { deriveSigningKey } from '@aztec/stdlib/keys'; -import { registerInitialLocalNetworkAccountsInWallet } from '@aztec/wallets/testing'; - -import { exec } from 'node:child_process'; -import { lookup } from 'node:dns/promises'; -import { tmpdir } from 'node:os'; -import { resolve } from 'node:path'; -import { fileURLToPath } from 'url'; - -import { getACVMConfig } from '../fixtures/get_acvm_config.js'; -import { getBBConfig } from '../fixtures/get_bb_config.js'; -import { getLogger, setupPXEAndGetWallet } from '../fixtures/utils.js'; -import { TestWallet } from '../test-wallet/test_wallet.js'; - -const { - AZTEC_NODE_URL, - FAUCET_URL, - AZTEC_CLI = `node ${resolve(fileURLToPath(import.meta.url), '../../../../aztec/dest/bin/index.js')}`, - ETHEREUM_HOSTS, - PXE_PROVER_ENABLED = '0', - USE_EMPTY_BLOCKS = '0', -} = process.env; - -const waitOpts: WaitOpts = { timeout: 3600, interval: 1 }; - -const MIN_BLOCKS_FOR_BRIDGING = 2; - -/** - * If we can successfully resolve 'host.docker.internal', then we are running in a container, and we should treat - * localhost as being host.docker.internal. - */ -export const getLocalhost = () => - lookup('host.docker.internal') - .then(() => 'host.docker.internal') - .catch(() => 'localhost'); - -describe('End-to-end tests for devnet', () => { - let node: AztecNode; - let wallet: TestWallet; - let logger: Logger; - let l1ChainId: number; - let feeJuiceL1: EthAddress; - let teardown: () => void | Promise; - - beforeAll(async () => { - logger = getLogger(); - - if (!ETHEREUM_HOSTS) { - throw new Error('ETHEREUM_HOSTS must be set'); - } - - if (!AZTEC_CLI) { - throw new Error('AZTEC_CLI must be set'); - } - - if (!FAUCET_URL) { - throw new Error('FAUCET_URL must be set'); - } - - if (!AZTEC_NODE_URL) { - throw new Error('AZTEC_NODE_URL must be set'); - } - - logger.info(`Using AZTEC_CLI: ${AZTEC_CLI}`); - - logger.info(`Using AZTEC_NODE_URL: ${AZTEC_NODE_URL}`); - node = createAztecNodeClient(AZTEC_NODE_URL); - const bbConfig = await getBBConfig(logger); - const acvmConfig = await getACVMConfig(logger); - const svc = await setupPXEAndGetWallet(node, { - ...bbConfig, - ...acvmConfig, - proverEnabled: ['1', 'true'].includes(PXE_PROVER_ENABLED!), - }); - wallet = svc.wallet; - - teardown = async () => { - await svc.teardown(); - await bbConfig?.cleanup(); - await acvmConfig?.cleanup(); - }; - - ({ - l1ChainId, - l1ContractAddresses: { feeJuiceAddress: feeJuiceL1 }, - } = await node.getNodeInfo()); - logger.info(`PXE instance started`); - }); - - afterAll(async () => { - await teardown(); - }); - - it('deploys an account while paying with FeeJuice', async () => { - const privateKey = Fr.random(); - const l1Account = await cli<{ privateKey: string; address: string }>('create-l1-account'); - const l2AccountManager = await wallet.createSchnorrAccount(privateKey, Fr.ZERO, deriveSigningKey(privateKey)); - const l2AccountAddress = l2AccountManager.address; - - await expect(getL1Balance(l1Account.address)).resolves.toEqual(0n); - await expect(getL1Balance(l1Account.address, feeJuiceL1)).resolves.toEqual(0n); - - await cli('drip-faucet', { 'faucet-url': FAUCET_URL!, token: 'eth', address: l1Account.address }); - await expect(getL1Balance(l1Account.address)).resolves.toBeGreaterThan(0n); - - await cli('drip-faucet', { 'faucet-url': FAUCET_URL!, token: 'fee_juice', address: l1Account.address }); - await expect(getL1Balance(l1Account.address, feeJuiceL1)).resolves.toBeGreaterThan(0n); - - const amount = 1_000_000_000_000n; - const { claimAmount, claimSecret, messageLeafIndex } = await cli<{ - claimAmount: string; - claimSecret: { value: string }; - messageLeafIndex: string; - }>('bridge-fee-juice', [amount, l2AccountManager.address], { - 'l1-rpc-urls': ETHEREUM_HOSTS!, - 'l1-chain-id': l1ChainId.toString(), - 'l1-private-key': l1Account.privateKey, - mint: true, - }); - - if (['1', 'true', 'yes'].includes(USE_EMPTY_BLOCKS)) { - await advanceChainWithEmptyBlocks(wallet); - } else { - await waitForL1MessageToArrive(); - } - - const l2AccountDeployMethod = await l2AccountManager.getDeployMethod(); - - const { receipt: txReceipt } = await l2AccountDeployMethod.send({ - from: AztecAddress.ZERO, - fee: { - paymentMethod: new FeeJuicePaymentMethodWithClaim(l2AccountAddress, { - claimAmount: Fr.fromHexString(claimAmount).toBigInt(), - claimSecret: Fr.fromHexString(claimSecret.value), - messageLeafIndex: BigInt(messageLeafIndex), - }), - }, - wait: { ...waitOpts, returnReceipt: true }, - }); - - // disabled because the CLI process doesn't exit - // const { txHash, address } = await cli<{ txHash: string; address: { value: string } }>('create-account', { - // 'private-key': privateKey, - // payment: `method=fee_juice,claimSecret=${claimSecret.value},claimAmount=${claimAmount}`, - // wait: false, - // }); - // expect(address).toEqual(l2Account.address.toString()); - // const txReceipt = await retryUntil( - // async () => { - // const receipt = await pxe.getTxReceipt(txHash); - // if (receipt.status === TxStatus.PENDING) { - // return undefined; - // } - // return receipt; - // }, - // 'wait_for_l2_account', - // waitOpts.timeout, - // waitOpts.interval, - // ); - - expect(txReceipt.isMined() && txReceipt.hasExecutionSucceeded()).toBe(true); - const feeJuice = FeeJuiceContract.at((await node.getNodeInfo()).protocolContractAddresses.feeJuice, wallet); - const { result: balance } = await feeJuice.methods - .balance_of_public(l2AccountAddress) - .simulate({ from: l2AccountAddress }); - expect(balance).toEqual(amount - txReceipt.transactionFee!); - }); - - type OptionValue = null | undefined | boolean | { toString(): string }; - type ArgumentValue = { toString(): string }; - - function cli(cliCommand: string): Promise; - function cli(cliCommand: string, args: ArgumentValue[]): Promise; - function cli(cliCommand: string, opts: Record): Promise; - function cli(cliCommand: string, args: ArgumentValue[], opts: Record): Promise; - function cli( - cliCommand: string, - _args?: ArgumentValue[] | Record, - _opts?: Record, - ): Promise { - const { promise, resolve, reject } = promiseWithResolvers(); - const args = Array.isArray(_args) ? _args : []; - const opts = _args && !Array.isArray(_args) ? _args : typeof _opts !== 'undefined' ? _opts : {}; - - const cmdArguments = args.map(x => x.toString()); - - opts.json = true; - const cmdOptions = Object.entries(opts) - .filter((entry): entry is [string, { toString(): string }] => entry[1] !== undefined && entry[1] !== null) - .map(([key, value]) => - typeof value === 'boolean' ? (value ? `--${key}` : `--no-${key}`) : `--${key} ${value.toString()}`, - ); - - const cmd = `${AZTEC_CLI} ${cliCommand} ${cmdArguments.join(' ')} ${cmdOptions.join(' ')}`; - logger.info(`Running aztec-cli: ${cmd}`); - const child = exec(cmd, { - cwd: tmpdir(), - env: { - NODE_OPTIONS: '--no-warnings', - }, - }); - - let err = ''; - child.stderr?.on('data', data => { - logger.error(data.toString()); - err += data.toString(); - }); - - let out = ''; - child.stdout?.on('data', data => { - out += data.toString(); - }); - - child.on('error', reject); - child.on('close', (code, signal) => { - if (code === 0) { - const res = JSON.parse(out); - logger.info(`aztec-cli JSON output: ${JSON.stringify(res)}`); - resolve(res); - } else { - reject(new Error(`aztec-cli ${cliCommand} non-zero exit: code=${code} signal=${signal} ${err}`)); - } - }); - - return promise; - } - - async function getL1Balance(address: string, token?: EthAddress): Promise { - const { balance } = await cli<{ balance: string }>('get-l1-balance', [address], { - 'l1-rpc-urls': ETHEREUM_HOSTS!, - 'l1-chain-id': l1ChainId.toString(), - token, - }); - - return BigInt(balance); - } - - async function waitForL1MessageToArrive() { - const targetBlockNumber = (await node.getBlockNumber()) + MIN_BLOCKS_FOR_BRIDGING; - await retryUntil(async () => (await node.getBlockNumber()) >= targetBlockNumber, 'wait_for_l1_message', 0, 10); - } - - async function advanceChainWithEmptyBlocks(wallet: TestWallet) { - const [fundedAccountAddress] = await registerInitialLocalNetworkAccountsInWallet(wallet); - - const { contract: test } = await TestContract.deploy(wallet).send({ - from: fundedAccountAddress, - universalDeploy: true, - skipClassPublication: true, - }); - - // start at 1 because deploying the contract has already mined a block - for (let i = 1; i < MIN_BLOCKS_FOR_BRIDGING; i++) { - await test.methods.get_this_address().send({ from: fundedAccountAddress, wait: waitOpts }); - } - } -}); diff --git a/yarn-project/package.json b/yarn-project/package.json index 6524ec3ba123..4db7e7de405d 100644 --- a/yarn-project/package.json +++ b/yarn-project/package.json @@ -18,7 +18,6 @@ "workspaces": [ "accounts", "archiver", - "aztec-faucet", "aztec-node", "aztec.js", "aztec", diff --git a/yarn-project/tsconfig.json b/yarn-project/tsconfig.json index ff81b33d59d8..ea810712f5f9 100644 --- a/yarn-project/tsconfig.json +++ b/yarn-project/tsconfig.json @@ -25,7 +25,6 @@ { "path": "accounts/tsconfig.json" }, { "path": "simulator/tsconfig.json" }, { "path": "archiver/tsconfig.json" }, - { "path": "aztec-faucet/tsconfig.json" }, { "path": "aztec.js/tsconfig.json" }, { "path": "aztec-node/tsconfig.json" }, { "path": "validator-client/tsconfig.json" }, diff --git a/yarn-project/yarn.lock b/yarn-project/yarn.lock index 596bfd2ffe72..e16902cd019e 100644 --- a/yarn-project/yarn.lock +++ b/yarn-project/yarn.lock @@ -748,30 +748,6 @@ __metadata: languageName: unknown linkType: soft -"@aztec/aztec-faucet@workspace:^, @aztec/aztec-faucet@workspace:aztec-faucet": - version: 0.0.0-use.local - resolution: "@aztec/aztec-faucet@workspace:aztec-faucet" - dependencies: - "@aztec/ethereum": "workspace:^" - "@aztec/foundation": "workspace:^" - "@aztec/l1-artifacts": "workspace:^" - "@jest/globals": "npm:^30.0.0" - "@koa/cors": "npm:^5.0.0" - "@types/jest": "npm:^30.0.0" - "@types/koa-bodyparser": "npm:^4.3.12" - "@types/node": "npm:^22.15.17" - "@typescript/native-preview": "npm:7.0.0-dev.20260113.1" - jest: "npm:^30.0.0" - koa: "npm:^2.16.1" - koa-bodyparser: "npm:^4.4.1" - koa-router: "npm:^13.1.1" - ts-node: "npm:^10.9.1" - typescript: "npm:^5.3.3" - viem: "npm:@aztec/viem@2.38.2" - zod: "npm:^3.23.8" - languageName: unknown - linkType: soft - "@aztec/aztec-node@workspace:^, @aztec/aztec-node@workspace:aztec-node": version: 0.0.0-use.local resolution: "@aztec/aztec-node@workspace:aztec-node" @@ -879,7 +855,6 @@ __metadata: dependencies: "@aztec/accounts": "workspace:^" "@aztec/archiver": "workspace:^" - "@aztec/aztec-faucet": "workspace:^" "@aztec/aztec-node": "workspace:^" "@aztec/aztec.js": "workspace:^" "@aztec/bb-prover": "workspace:^" @@ -7687,7 +7662,7 @@ __metadata: languageName: node linkType: hard -"@types/koa-bodyparser@npm:^4.3.10, @types/koa-bodyparser@npm:^4.3.12": +"@types/koa-bodyparser@npm:^4.3.10": version: 4.3.12 resolution: "@types/koa-bodyparser@npm:4.3.12" dependencies: @@ -16104,7 +16079,7 @@ __metadata: languageName: node linkType: hard -"koa-bodyparser@npm:^4.4.0, koa-bodyparser@npm:^4.4.1": +"koa-bodyparser@npm:^4.4.0": version: 4.4.1 resolution: "koa-bodyparser@npm:4.4.1" dependencies: