diff --git a/.github/workflows/sparta.yml b/.github/workflows/sparta.yml index 1a1833e..b82e267 100644 --- a/.github/workflows/sparta.yml +++ b/.github/workflows/sparta.yml @@ -7,6 +7,11 @@ permissions: contents: read pull-requests: write +env: + TF_LOG: DEBUG + AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + jobs: terraform-sparta: name: Terraform Sparta Bot @@ -15,29 +20,61 @@ jobs: run: working-directory: tooling/sparta/terraform - env: - AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} - AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} - TF_VAR_bot_token: ${{ secrets.BOT_TOKEN }} - TF_VAR_passport_api_key: ${{ secrets.PASSPORT_API_KEY }} - TF_VAR_ethereum_host: ${{ secrets.ETHEREUM_HOST }} - TF_VAR_backend_api_key: ${{ secrets.BACKEND_API_KEY }} - TF_VAR_aws_region: "eu-west-2" - TF_VAR_environment: "production" - TF_VAR_bot_client_id: "1329079356785688616" - TF_VAR_guild_id: "1144692727120937080" - TF_VAR_passport_verified_role_id: "1364982673604345886" - TF_VAR_minimum_score: "10" - TF_VAR_passport_scorer_id: "11493" - TF_VAR_vite_reown_project_id: "d037e9da5c5c9b24cfcd94c509d88dce" - TF_VAR_staking_asset_handler_address: "0xF739D03e98e23A7B65940848aBA8921fF3bAc4b2" - TF_VAR_l1_chain_id: "11155111" - TF_VAR_local_dynamo_db: "false" - TF_VAR_dynamodb_local_endpoint: "http://localhost:8000" - TF_VAR_log_level: "info" - TF_VAR_log_pretty_print: "false" - TF_VAR_api_port: "3000" steps: - name: Checkout uses: actions/checkout@v4 + + - name: Setup Terraform + uses: hashicorp/setup-terraform@v3 + with: + terraform_version: 1.5.7 + + - name: Terraform Init + run: terraform init + + - name: Terraform Format + run: terraform fmt -check + continue-on-error: true + + - name: Terraform Validate + run: terraform validate + + - name: Generate terraform.production.tfvars + run: | + cat > terraform.production.tfvars << EOF + # ============================================================================= + # AWS Configuration + # ============================================================================= + aws_region = "eu-west-2" + environment = "production" + + # ============================================================================= + # Application Secrets & Configuration + # ============================================================================= + + # --- Discord --- + bot_token = "${{ secrets.BOT_TOKEN }}" + bot_client_id = "1329079356785688616" + guild_id = "1144692727120937080" + + # --- Ethereum --- + ethereum_host = "${{ secrets.ETHEREUM_HOST }}" + staking_asset_handler_address = "0xF739D03e98e23A7B65940848aBA8921fF3bAc4b2" + l1_chain_id = "11155111" + + # --- DynamoDB --- + local_dynamo_db = false + dynamodb_endpoint = "http://localhost:8000" + + # --- Logging --- + log_level = "debug" + log_pretty_print = false + + # --- API Configuration --- + api_port = 3000 + backend_api_key = "${{ secrets.BACKEND_API_KEY }}" + EOF + + - name: Terraform Apply + run: terraform apply -var-file="terraform.production.tfvars" -auto-approve -input=false diff --git a/.gitignore b/.gitignore index 19dfa3f..cd7260e 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ proofs debug_*.json crs yarn-error.log +.env* \ No newline at end of file diff --git a/tooling/sparta/.dockerignore b/tooling/sparta/.dockerignore deleted file mode 100644 index 64d19ff..0000000 --- a/tooling/sparta/.dockerignore +++ /dev/null @@ -1,3 +0,0 @@ -.env -.env* -dist diff --git a/tooling/sparta/.gitignore b/tooling/sparta/.gitignore deleted file mode 100644 index 2e9690e..0000000 --- a/tooling/sparta/.gitignore +++ /dev/null @@ -1,40 +0,0 @@ -# Node.js -node_modules/ -dist/ -*.log -.env -.env.* -!.env.example - -# Terraform -*.tfstate -*.tfstate.* -.terraform/ -terraform.tfvars -.terraform.lock.hcl -*.tfvars -!terraform.tfvars.example - -# Build artifacts -*.zip -deployment-*.zip - -# IDE -.vscode/ -.idea/ -*.swp -*.swo - -# OS -.DS_Store -Thumbs.db - -# Elastic Beanstalk Files -.elasticbeanstalk/* -!.elasticbeanstalk/*.cfg.yml -!.elasticbeanstalk/*.global.yml - -# Package managers -bun.lockb -yarn.lock -package-lock.json diff --git a/tooling/sparta/Dockerfile b/tooling/sparta/Dockerfile deleted file mode 100644 index 4ccbf1d..0000000 --- a/tooling/sparta/Dockerfile +++ /dev/null @@ -1,39 +0,0 @@ -# Sparta Discord Bot Dockerfile -# This Dockerfile builds the Sparta Discord bot for deployment - -# Start with the official Bun image -FROM oven/bun:latest - -# Add Foundry to PATH for Ethereum development tools -ENV PATH="/root/.foundry/bin:${PATH}" - -# Install required dependencies -# - curl: For downloading tools -# - apt-utils: For better apt functionality -RUN apt update && apt install -y curl apt-utils - -# Install Docker within the container for potential nested container operations -RUN curl -fsSL https://get.docker.com | bash - -# Install Foundry toolkit for Ethereum development (cast, anvil, forge) -RUN curl -L https://foundry.paradigm.xyz | bash -RUN foundryup - -# Verify Foundry installation by checking cast version -RUN cast --version - -# Set the working directory -WORKDIR /app - -# Copy package files first to leverage Docker layer caching -# This way, dependencies are only re-installed when package files change -COPY src/package.json src/bun.lockb ./ -RUN bun install - -# Then copy the rest of the source code -# This step is separate to avoid reinstalling dependencies when only code changes -COPY src ./ - -# Start the bot -# Uses the production start command from package.json -CMD ["bun", "run", "start"] diff --git a/tooling/sparta/README.md b/tooling/sparta/README.md deleted file mode 100644 index 82e491a..0000000 --- a/tooling/sparta/README.md +++ /dev/null @@ -1,272 +0,0 @@ -# Sparta Discord Bot - -A Discord bot for managing Aztec validators and community roles, built with Bun/TypeScript and deployed on AWS Elastic Beanstalk. - -## Overview - -Sparta is a Discord bot designed to manage and monitor Aztec validators and community roles within the Discord server. It provides: - -- **Role Management**: Automatically assigns roles based on user scores from Google Sheets -- **Validator Management**: Commands to add, remove, and check validators -- **Chain Information**: Retrieves blockchain data like pending blocks, proven blocks, epochs, slots -- **Discord Integration**: Full integration with Discord slash commands - -## Prerequisites - -- [Bun](https://bun.sh) v1.0 or higher (used as runtime and package manager) -- Node.js v18 or higher (for development tools) -- AWS CLI configured with appropriate credentials -- Terraform v1.0 or higher -- Discord Bot Token and Application ID from [Discord Developer Portal](https://discord.com/developers/applications) -- Ethereum node access (local or remote) -- Google Sheets API access (for role management) - -## Security Notice - -⚠️ **Important**: This project uses sensitive credentials that should never be committed to version control: -- Discord bot tokens -- Ethereum private keys -- AWS credentials -- Google Sheets API credentials -- Environment variables - -Always use: -- `.env` files for local development (never commit these) -- AWS Secrets Manager for production secrets -- `terraform.tfvars` for Terraform variables (never commit this) -- Ensure `.gitignore` includes all sensitive files -- Use environment-specific configuration files - -## Project Structure - -``` -sparta/ -├── src/ # Source code -│ ├── clients/ # External API clients (Discord, Ethereum, Google) -│ ├── roles/ # Role-specific Discord commands -│ │ ├── nodeOperators/ # Commands for Node Operator role -│ │ └── admins/ # Admin-only commands -│ ├── services/ # Business logic services -│ │ ├── chaininfo-service.ts # Chain information retrieval -│ │ ├── discord-service.ts # Discord role management -│ │ ├── googlesheet-service.ts # Google Sheets integration -│ │ ├── validator-service.ts # Validator management -│ │ └── index.ts # Service exports -│ └── utils/ # Utility functions -├── terraform/ # Infrastructure as Code -└── Dockerfile # Docker configuration -``` - -## Local Development - -1. Clone the repository: -```bash -git clone -cd sparta -``` - -2. Install dependencies using Bun: -```bash -cd src -bun install -``` - -3. Create a `.env` file in the `src` directory using `.env.example` as a template: -```bash -cp .env.example .env -``` - -4. Fill in the required environment variables in `.env`. Required variables include: -``` -# Discord Bot Configuration -BOT_TOKEN=your_bot_token -BOT_CLIENT_ID=your_client_id -GUILD_ID=your_guild_id - -# Ethereum Configuration -ETHEREUM_HOST=http://localhost:8545 -MINTER_PRIVATE_KEY=your_private_key -ETHEREUM_REGISTRY_ADDRESS=your_registry_address -WITHDRAWER_ADDRESS=address_to_withdraw_funds_to -ETHEREUM_CHAIN_ID=1337 -ETHEREUM_VALUE=20ether -MINIMUM_STAKE=100000000000000000000 -APPROVAL_AMOUNT=10000000000000000000000 - -# Google Sheets Configuration -GOOGLE_API_KEY=your_api_key -SPREADSHEET_ID=your_spreadsheet_id -``` - -5. Start the bot in development mode with hot reloading: -```bash -bun run dev -``` - -6. For building a production version: -```bash -bun run build -``` - -7. To start the production version: -```bash -bun run start -``` - -## Building with Docker - -1. Build the Docker image: -```bash -docker build -t sparta-bot . -``` - -2. Run the container: -```bash -docker run -d --name sparta-bot --env-file ./src/.env sparta-bot -``` - -## Deployment with Terraform - -The bot is deployed using Terraform to AWS Elastic Container Service (ECS). Follow these steps: - -1. Navigate to the terraform directory: -```bash -cd terraform -``` - -2. Create `terraform.tfvars` using the example file: -```bash -cp terraform.tfvars.example terraform.tfvars -``` - -3. Fill in the required variables in `terraform.tfvars`. - -4. Initialize Terraform: -```bash -terraform init -``` - -5. Deploy: -```bash -terraform apply -``` - -## Bot Functionality - -### Role Management -- Monitors Google Sheets for user scores -- Assigns Discord roles based on score thresholds: - - Node Operator (base role): Default role - - Defender (middle role): Score > 5 - - Sentinel (highest role): Score > 10 - -### Validator Management -- Add validators to the blockchain -- Remove validators from the blockchain -- Check validator status and information - -### Chain Information -- Get pending block number -- Get proven block number -- Check current epoch and slot -- View committee members - -## Available Commands - -### Node Operator Commands -- `/get-info`: Get chain information including pending block, proven block, current epoch, current slot, and proposer -- `/validator check`: Check if an address is a validator -- `/validator register`: Register a validator address -- `/validator help`: Get help for validator commands - -### Admin Commands -(More details in the admin command section) - -## Environment Variables - -### Development -- Uses `.env` file for local configuration -- Supports hot reloading through `bun run dev` -- Environment-specific configurations (.env.local, .env.staging) - -### Production -- Uses AWS Secrets Manager for secure configuration -- Automatically loads secrets in production environment -- Supports staging and production environments - -## Security Best Practices - -1. **Environment Variables** - - Never commit .env files - - Use different env files for different environments - - Rotate secrets regularly - -2. **AWS Security** - - Use IAM roles with least privilege - - Enable CloudWatch logging - - Use security groups to restrict access - -3. **Discord Security** - - Implement command permissions - - Use ephemeral messages for sensitive info - - Validate user inputs - -4. **Ethereum Security** - - Never expose private keys - - Use secure RPC endpoints - - Implement transaction signing safeguards - -## Monitoring and Logging - -- AWS CloudWatch for container logs -- Discord command execution logging -- Error tracking and reporting -- Performance monitoring - -## Logging - -The application uses Pino for structured logging with the following features: - -- **Multiple log levels**: trace, debug, info, warn, error, fatal -- **Colorful output**: Different colors for different log levels when pretty printing is enabled -- **Timestamps**: Each log includes an ISO timestamp -- **Request logging**: HTTP requests can be logged at the debug level -- **Structured logging**: Logs are output in JSON format for easy parsing - -### Configuration - -Logging can be configured through environment variables: - -- `LOG_LEVEL`: Set the minimum log level (trace, debug, info, warn, error, fatal) -- `LOG_PRETTY_PRINT`: Enable/disable colorful, human-readable logs (true/false) - -#### Example - -```sh -# Set log level to debug and enable pretty printing -export LOG_LEVEL=debug -export LOG_PRETTY_PRINT=true -npm run dev -``` - -### Terraform Configuration - -Logging can also be configured through Terraform variables: - -```hcl -module "sparta" { - # ... - log_level = "debug" - log_pretty_print = true -} -``` - -## Contributing - -1. Create a feature branch -2. Make your changes -3. Submit a pull request - -## Support - -For support, please open an issue in the repository or contact the maintainers. diff --git a/tooling/sparta/src/.env.example b/tooling/sparta/src/.env.example deleted file mode 100644 index a2837e7..0000000 --- a/tooling/sparta/src/.env.example +++ /dev/null @@ -1,25 +0,0 @@ -# Discord Bot Configuration -BOT_TOKEN=your_bot_token_here -BOT_CLIENT_ID=your_client_id_here -GUILD_ID=your_guild_id_here - -# Ethereum Configuration -ETHEREUM_HOST=http://localhost:8545 -MINTER_PRIVATE_KEY=your_minter_private_key_here -ETHEREUM_REGISTRY_ADDRESS=your_registry_address_here -WITHDRAWER_ADDRESS=your_withdrawer_address_here -ETHEREUM_CHAIN_ID=1337 -ETHEREUM_VALUE=20ether - -MINIMUM_STAKE=100000000000000000000 -APPROVAL_AMOUNT=10000000000000000000000 - -# Google Sheets Configuration -GOOGLE_API_KEY=your_google_api_key_here -SPREADSHEET_ID=your_spreadsheet_id_here - -# Logging Configuration -# Available levels: trace, debug, info, warn, error, fatal -LOG_LEVEL=info -# Enable/disable pretty printing with colors (true/false) -LOG_PRETTY_PRINT=true diff --git a/tooling/sparta/src/.gitignore b/tooling/sparta/src/.gitignore deleted file mode 100644 index 212eb5c..0000000 --- a/tooling/sparta/src/.gitignore +++ /dev/null @@ -1,176 +0,0 @@ -# Based on https://raw.githubusercontent.com/github/gitignore/main/Node.gitignore - -# Logs - -logs -_.log -npm-debug.log_ -yarn-debug.log* -yarn-error.log* -lerna-debug.log* -.pnpm-debug.log* - -# Caches - -.cache - -# Diagnostic reports (https://nodejs.org/api/report.html) - -report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json - -# Runtime data - -pids -_.pid -_.seed -*.pid.lock - -# Directory for instrumented libs generated by jscoverage/JSCover - -lib-cov - -# Coverage directory used by tools like istanbul - -coverage -*.lcov - -# nyc test coverage - -.nyc_output - -# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) - -.grunt - -# Bower dependency directory (https://bower.io/) - -bower_components - -# node-waf configuration - -.lock-wscript - -# Compiled binary addons (https://nodejs.org/api/addons.html) - -build/Release - -# Dependency directories - -node_modules/ -jspm_packages/ - -# Snowpack dependency directory (https://snowpack.dev/) - -web_modules/ - -# TypeScript cache - -*.tsbuildinfo - -# Optional npm cache directory - -.npm - -# Optional eslint cache - -.eslintcache - -# Optional stylelint cache - -.stylelintcache - -# Microbundle cache - -.rpt2_cache/ -.rts2_cache_cjs/ -.rts2_cache_es/ -.rts2_cache_umd/ - -# Optional REPL history - -.node_repl_history - -# Output of 'npm pack' - -*.tgz - -# Yarn Integrity file - -.yarn-integrity - -# dotenv environment variable files - -.env -.env.development.local -.env.test.local -.env.production.local -.env.local - -# parcel-bundler cache (https://parceljs.org/) - -.parcel-cache - -# Next.js build output - -.next -out - -# Nuxt.js build / generate output - -.nuxt -dist - -# Gatsby files - -# Comment in the public line in if your project uses Gatsby and not Next.js - -# https://nextjs.org/blog/next-9-1#public-directory-support - -# public - -# vuepress build output - -.vuepress/dist - -# vuepress v2.x temp and cache directory - -.temp - -# Docusaurus cache and generated files - -.docusaurus - -# Serverless directories - -.serverless/ - -# FuseBox cache - -.fusebox/ - -# DynamoDB Local files - -.dynamodb/ - -# TernJS port file - -.tern-port - -# Stores VSCode versions used for testing VSCode extensions - -.vscode-test - -# yarn v2 - -.yarn/cache -.yarn/unplugged -.yarn/build-state.yml -.yarn/install-state.gz -.pnp.* - -# IntelliJ based IDEs -.idea - -# Finder (MacOS) folder config -.DS_Store -dist diff --git a/tooling/sparta/src/README.md b/tooling/sparta/src/README.md deleted file mode 100644 index 3dcb973..0000000 --- a/tooling/sparta/src/README.md +++ /dev/null @@ -1,160 +0,0 @@ -# Sparta Discord Bot - Source Code - -This directory contains the source code for the Sparta Discord bot, which manages Aztec validators and Discord roles. - -## Project Structure - -The project is organized into several directories: - -- **clients/**: API client interfaces for external services (Discord, Ethereum, Google Sheets) -- **roles/**: Command implementations for different Discord roles -- **services/**: Core business logic services -- **utils/**: Utility functions and helpers - -## Key Components - -### Clients - -The `clients/` directory contains interfaces to external services: - -- **discord.ts**: Discord.js client setup and configuration -- **ethereum.ts**: Ethereum blockchain interaction via viem -- **google.ts**: Google Sheets API integration - -### Services - -The `services/` directory contains the core business logic: - -- **chaininfo-service.ts**: Retrieves blockchain state information -- **discord-service.ts**: Manages Discord roles and user identification -- **googlesheet-service.ts**: Monitors Google Sheets for user scores and triggers role assignments -- **validator-service.ts**: Manages validator registration and funding - -### Roles - -The `roles/` directory contains command definitions for different user roles: - -- **nodeOperators/**: Commands available to users with the Node Operator role - - **validator.ts**: Commands for validator registration and checking - - **getChainInfo.ts**: Commands for retrieving chain information -- **admins/**: Commands available only to administrators - -## Key Functionality - -### Role Management - -The bot automatically assigns hierarchical Discord roles based on user scores from Google Sheets: - -1. **Guardian**: Base role (default, requires minimum score of 0) -2. **Defender**: Middle role (requires score > 5) -3. **Sentinel**: Highest role (set manually, but can be removed by this service) - -```typescript -// Example from googlesheet-service.ts -if (score > 10) { - roleName = NodeOperatorRoles.Sentinel; // Highest role -} else if (score > 5) { - roleName = NodeOperatorRoles.Defender; // Middle role -} else { - roleName = NodeOperatorRoles.Guardian; // Default/lowest role -} -``` - -### Validator Management - -The bot provides commands to manage validators on the Ethereum network: - -- Add validators -- Remove validators -- Check validator status -- Fund validators - -```typescript -// Example validator registration -await ValidatorService.addValidator("0x123..."); -``` - -### Chain Information - -The bot provides commands to retrieve blockchain information: - -- Current epoch and slot -- Pending and proven block numbers -- Committee members -- Current proposer - -```typescript -// Example chain info retrieval -const chainInfo = await ChainInfoService.getInfo(); -console.log(`Current epoch: ${chainInfo.currentEpoch}`); -``` - -## Environment Configuration - -The application requires several environment variables to function correctly. Create a `.env` file based on the `.env.example` template with the following variables: - -``` -# Discord Bot Configuration -BOT_TOKEN=your_bot_token -BOT_CLIENT_ID=your_client_id -GUILD_ID=your_guild_id - -# Ethereum Configuration -ETHEREUM_HOST=http://localhost:8545 -MINTER_PRIVATE_KEY=your_private_key -ETHEREUM_REGISTRY_ADDRESS=your_registry_address -WITHDRAWER_ADDRESS=address_to_withdraw_funds_to -ETHEREUM_CHAIN_ID=1337 -ETHEREUM_VALUE=20ether -MINIMUM_STAKE=100000000000000000000 -APPROVAL_AMOUNT=10000000000000000000000 - -# Google Sheets Configuration -GOOGLE_API_KEY=your_api_key -SPREADSHEET_ID=your_spreadsheet_id -``` - -## Development - -### Building and Running - -The project uses Bun for package management and running: - -```bash -# Install dependencies -bun install - -# Run in development mode with hot reloading -bun run dev - -# Build for production -bun run build - -# Run in production mode -bun run start -``` - -### Adding New Commands - -To add a new command: - -1. Create a new command file in the appropriate role directory -2. Define the command using Discord.js slash command builders -3. Export the command and add it to the role's index.ts file - -Example command structure: - -```typescript -import { SlashCommandBuilder } from "discord.js"; - -export default { - data: new SlashCommandBuilder() - .setName("command-name") - .setDescription("Command description"), - - execute: async (interaction) => { - // Command implementation - await interaction.reply("Response message"); - } -}; -``` diff --git a/tooling/sparta/src/clients/README.md b/tooling/sparta/src/clients/README.md deleted file mode 100644 index 2d91ce7..0000000 --- a/tooling/sparta/src/clients/README.md +++ /dev/null @@ -1,8 +0,0 @@ -# Clients - -This directory contains client adapters for external services and APIs. - -- `discord.ts` - Discord client for bot interactions -- `google.ts` - Google Sheets client for spreadsheet operations -- `ethereum.ts` - Ethereum blockchain client for interacting with smart contracts -- `aztec.ts` - Aztec client for interacting with Aztec protocol diff --git a/tooling/sparta/src/clients/aztec.ts b/tooling/sparta/src/clients/aztec.ts deleted file mode 100644 index 925a04f..0000000 --- a/tooling/sparta/src/clients/aztec.ts +++ /dev/null @@ -1,73 +0,0 @@ -/** - * @fileoverview Aztec client and utilities - * @description Provides Aztec node interaction methods via JSON-RPC - * @module sparta/utils/aztec - */ -import { logger } from "../utils/logger.js"; - -export class Aztec { - private readonly rpcUrl: string; - - constructor(rpcUrl: string) { - this.rpcUrl = rpcUrl; - } - - static new = async () => { - try { - logger.info("Initializing Aztec client"); - const rpcUrl = process.env.AZTEC_NODE_URL; - - if (!rpcUrl) { - throw new Error("AZTEC_NODE_URL is not set"); - } - - return new Aztec(rpcUrl); - } catch (error) { - logger.error({ error }, "Error initializing Aztec client"); - throw error; - } - }; - - private async sendJsonRpcRequest( - method: string, - params: any[] = [] - ): Promise { - const response = await fetch(this.rpcUrl, { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify({ - jsonrpc: "2.0", - method, - params, - id: 67, - }), - }); - - if (!response.ok) { - throw new Error(`HTTP error! status: ${response.status}`); - } - - const data = await response.json(); - if (data.error) { - throw new Error(`RPC error: ${JSON.stringify(data.error)}`); - } - - return data.result; - } - - getL2Tips = async (): Promise => { - const result = await this.sendJsonRpcRequest("node_getL2Tips"); - return result.proven.number as string; - }; - - getArchiveSiblingPath = async (blockNumber: string): Promise => { - return await this.sendJsonRpcRequest("node_getArchiveSiblingPath", [ - blockNumber, - blockNumber, - ]); - }; -} - -export const aztec = await Aztec.new(); diff --git a/tooling/sparta/src/clients/discord.ts b/tooling/sparta/src/clients/discord.ts deleted file mode 100644 index b300042..0000000 --- a/tooling/sparta/src/clients/discord.ts +++ /dev/null @@ -1,191 +0,0 @@ -/** - * @fileoverview Discord client and utilities - * @description Provides Discord client configuration and event handling - * @module sparta/utils/discord - */ - -import { - Client, - GatewayIntentBits, - Collection, - Interaction, - MessageFlags, - TextChannel, - REST, - Routes, -} from "discord.js"; -import nodeOperatorCommands from "../roles/nodeOperators/index.js"; -import adminsCommands from "../roles/admins/index.js"; -import { logger } from "../utils/logger.js"; -import { subscribe } from "diagnostics_channel"; - -// Extended Discord client interface with commands collection -export interface ExtendedClient extends Client { - commands: Collection; -} - -export class Discord { - private client: ExtendedClient; - - constructor(client: ExtendedClient) { - this.client = client; - } - - /** - * Creates a new Discord instance with initialized client - */ - static new = async () => { - try { - logger.info("Initializing Discord client"); - - // Initialize Discord client with required intents - const client = new Client({ - intents: [ - GatewayIntentBits.Guilds, - GatewayIntentBits.GuildMessages, - ], - }) as ExtendedClient; - - // Initialize commands collection - client.commands = new Collection(); - - // Set up event handlers - Discord.setupEventHandlers(client); - - // Log in to Discord - await client.login(process.env.BOT_TOKEN); - - return new Discord(client); - } catch (error) { - logger.error({ error }, "Error initializing Discord client"); - throw error; - } - }; - - /** - * Sets up the event handlers for the Discord client - * @param client The Discord client - */ - private static setupEventHandlers(client: ExtendedClient): void { - /** - * Error event handler - */ - client.once("error", (error) => { - logger.error({ error }, "Discord client error"); - }); - - /** - * Ready event handler - called when bot is initialized - */ - client.once("ready", async () => { - logger.info("Sparta bot is ready!"); - logger.info( - { clientId: process.env.BOT_CLIENT_ID }, - "Bot connected with Client ID" - ); - Discord.deployCommands(client); - }); - - /** - * Interaction event handler - processes all slash commands - * @param {Interaction} interaction - The interaction object from Discord - */ - client.on("interactionCreate", async (interaction: Interaction) => { - if (!interaction.isChatInputCommand()) return; - - const command = client.commands.get(interaction.commandName); - if (!command) return; - - logger.debug( - { - command: interaction.commandName, - subcommand: interaction.options.getSubcommand(), - }, - "Command" - ); - try { - const channel = interaction.channel as TextChannel; - - logger.debug( - { - channel: channel.name, - user: interaction.user.username, - date: interaction.createdAt, - }, - "Command info" - ); - const reply = await command.execute(interaction); - logger.debug( - { - reply, - }, - "Command reply" - ); - } catch (error) { - logger.error({ error }, "Error executing command"); - await interaction.reply({ - content: "There was an error executing this command!", - flags: MessageFlags.Ephemeral, - }); - } - }); - } - - /** - * Deploys all slash commands to the Discord server - * @param client The Discord client - */ - private static async deployCommands(client: ExtendedClient): Promise { - const rest = new REST({ version: "10" }).setToken( - process.env.BOT_TOKEN as string - ); - - try { - logger.info("Started refreshing application (/) commands"); - - const commandsData = Object.values({ - ...nodeOperatorCommands, - ...adminsCommands, - }).map((command) => command.data.toJSON()); - - await rest.put( - Routes.applicationGuildCommands( - process.env.BOT_CLIENT_ID as string, - process.env.GUILD_ID as string - ), - { - body: commandsData, - } - ); - - for (const command of Object.values({ - ...nodeOperatorCommands, - ...adminsCommands, - })) { - client.commands.set(command.data.name, command); - logger.debug(`Registered command: ${command.data.name}`); - } - - logger.info("Successfully reloaded application (/) commands"); - } catch (error) { - logger.error({ error }, "Error deploying commands"); - } - } - - /** - * Gets the Discord client - */ - getClient = () => { - return this.client; - }; - - /** - * Finds a guild by ID - */ - getGuild = async (guildId: string) => { - return await this.client.guilds.fetch(guildId); - }; -} - -// Create and export a shared Discord instance -export const discord = await Discord.new(); diff --git a/tooling/sparta/src/clients/ethereum.ts b/tooling/sparta/src/clients/ethereum.ts deleted file mode 100644 index 2a842b6..0000000 --- a/tooling/sparta/src/clients/ethereum.ts +++ /dev/null @@ -1,211 +0,0 @@ -/** - * @fileoverview Ethereum client and utilities - * @description Provides Ethereum client configuration and interaction methods - * @module sparta/utils/ethereum - */ - -import { - createPublicClient, - createWalletClient, - encodeDeployData, - getContract, - getCreate2Address, - http, - padHex, - toHex, - TransactionReceipt, - WalletClient, -} from "viem"; - -import { RollupAbi } from "../utils/abis/rollup.js"; -import { TestERC20Abi } from "../utils/abis/testERC20Abi.js"; -import { RegistryAbi } from "../utils/abis/registryAbi.js"; -import { privateKeyToAccount } from "viem/accounts"; -import type { Hex } from "viem"; -import { ForwarderBytecode, ForwarderAbi } from "../utils/abis/forwarder.js"; -import { logger } from "../utils/logger.js"; - -export const DEPLOYER_ADDRESS: Hex = - "0x4e59b44847b379578588920cA78FbF26c0B4956C"; - -/** - * Ethereum chain configuration - * @const {Object} ethereumChain - */ -const ethereumChain = { - id: parseInt(process.env.L1_CHAIN_ID as string), - name: "Sepolia", - network: "sepolia", - nativeCurrency: { - decimals: 18, - name: "Ethereum", - symbol: "ETH", - }, - rpcUrls: { - default: { - http: [process.env.ETHEREUM_HOST as string], - }, - public: { - http: [process.env.ETHEREUM_HOST as string], - }, - }, -} as const; - -export function getExpectedAddress(args: [`0x${string}`], salt: Hex) { - const paddedSalt = padHex(salt, { size: 32 }); - const calldata = encodeDeployData({ - abi: ForwarderAbi, - bytecode: ForwarderBytecode, - args, - }); - const address = getCreate2Address({ - from: DEPLOYER_ADDRESS, - salt: paddedSalt, - bytecode: calldata, - }); - return { - address, - paddedSalt, - calldata, - }; -} - -export class Ethereum { - constructor( - private publicClient: ReturnType, - private walletClient: ReturnType, - private rollup: any, - private stakingAsset: any - ) {} - - static new = async () => { - try { - logger.info("Initializing Ethereum client"); - const rpcUrl = process.env.ETHEREUM_HOST as string; - const privateKey = process.env.MINTER_PRIVATE_KEY as `0x${string}`; - - const publicClient = createPublicClient({ - chain: ethereumChain, - transport: http(rpcUrl), - }); - - const walletClient = createWalletClient({ - account: privateKeyToAccount(privateKey), - chain: ethereumChain, - transport: http(rpcUrl), - }); - - const registry = getContract({ - address: process.env.ETHEREUM_REGISTRY_ADDRESS as `0x${string}`, - abi: RegistryAbi, - client: walletClient, - }); - - const rollupAddress = await registry.read.getRollup(); - - const rollup = getContract({ - address: rollupAddress as `0x${string}`, - abi: RollupAbi, - client: walletClient, - }); - - const stakingAsset = getContract({ - address: (await rollup.read.getStakingAsset()) as `0x${string}`, - abi: TestERC20Abi, - client: walletClient, - }); - - return new Ethereum( - publicClient, - walletClient, - rollup, - stakingAsset - ); - } catch (error) { - logger.error({ error }, "Error initializing Ethereum client"); - throw error; - } - }; - - getPublicClient = () => { - return this.publicClient; - }; - - getWalletClient = () => { - return this.walletClient; - }; - - getRollup = () => { - return this.rollup; - }; - - // TODO: For now, the withdrawer address is managed by the bot - stakingAssetFaucet = async (address: string) => { - const txHash = await this.stakingAsset.write.mint([ - this.walletClient.account?.address as `0x${string}`, - process.env.MINIMUM_STAKE as unknown as string, - ]); - - const receipt = await this.publicClient.waitForTransactionReceipt({ - hash: txHash, - }); - - return receipt; - }; - - addValidator = async (address: string): Promise => { - const expectedAddress = getExpectedAddress( - [address as `0x${string}`], - address as `0x${string}` - ); - const hashes = await Promise.all( - [ - await this.stakingAsset.write.approve([ - this.rollup.address, - process.env.APPROVAL_AMOUNT as unknown as string, - ]), - await this.rollup.write.deposit([ - address, - expectedAddress.address, - process.env.WITHDRAWER_ADDRESS as `0x${string}`, - process.env.MINIMUM_STAKE as unknown as string, - ]), - ].map((txHash) => - this.publicClient.waitForTransactionReceipt({ - hash: txHash, - }) - ) - ); - - return hashes; - }; - - removeValidator = async (address: string): Promise => { - const withdrawerWalletClient = createWalletClient({ - account: privateKeyToAccount( - process.env.WITHDRAWER_PRIVATE_KEY as `0x${string}` - ), - chain: ethereumChain, - transport: http(process.env.ETHEREUM_HOST as string), - }); - - const rollupWithdrawerScoped = getContract({ - address: this.rollup.address as `0x${string}`, - abi: RollupAbi, - client: withdrawerWalletClient, - }); - - const txHash = await rollupWithdrawerScoped.write.initiateWithdraw([ - address as `0x${string}`, - process.env.WITHDRAWER_ADDRESS as `0x${string}`, - ]); - - const receipt = await this.publicClient.waitForTransactionReceipt({ - hash: txHash, - }); - - return receipt; - }; -} - -export const ethereum = await Ethereum.new(); diff --git a/tooling/sparta/src/clients/google.ts b/tooling/sparta/src/clients/google.ts deleted file mode 100644 index f4d3dd1..0000000 --- a/tooling/sparta/src/clients/google.ts +++ /dev/null @@ -1,292 +0,0 @@ -import { sheets, sheets_v4 } from "@googleapis/sheets"; -import { logger } from "../utils/logger.js"; - -export class GoogleSheet { - private sheets: sheets_v4.Sheets; - private watchInterval: NodeJS.Timer | null = null; - private lastValues: Record = {}; - private spreadsheetId: string; - - /** - * Create a new GoogleSheetService - * @param apiKey Google API key - */ - constructor(spreadsheetId: string) { - logger.info("Initializing GoogleSheetService"); - this.spreadsheetId = spreadsheetId; - if (!process.env.GOOGLE_API_KEY) { - logger.error("GOOGLE_API_KEY environment variable is required"); - process.exit(1); - } - this.sheets = sheets({ - version: "v4", - auth: process.env.GOOGLE_API_KEY, - }); - } - - /** - * Start watching a specific sheet for changes - * @param spreadsheetId The ID of the spreadsheet - * @param sheetRange The A1 notation of the range to watch - * @param columnIndex The index of the column to watch for changes (0-based) - * @param callback Function to call when changes are detected - * @param intervalMs How often to check for changes (in milliseconds) - */ - public watchColumn( - sheetRange: string, - columnIndex: number, - callback: ( - newValue: any, - oldValue: any, - row: number, - rowData: any[] - ) => void, - intervalMs: number = 10000 - ): void { - logger.info( - { columnIndex, sheetRange, intervalMs }, - "Watching column for changes" - ); - // Initial fetch to establish baseline - this.fetchData(this.spreadsheetId, sheetRange) - .then((data) => { - // Store initial values - data.forEach((row, rowIndex) => { - if (row && row[columnIndex] !== undefined) { - const key = `${rowIndex}-${columnIndex}`; - this.lastValues[key] = row[columnIndex]; - } - }); - - // Start watching for changes - this.watchInterval = setInterval(async () => { - try { - const newData = await this.fetchData( - this.spreadsheetId, - sheetRange - ); - - // Check for changes - newData.forEach((row, rowIndex) => { - if (row && row[columnIndex] !== undefined) { - const key = `${rowIndex}-${columnIndex}`; - const newValue = row[columnIndex]; - const oldValue = this.lastValues[key]; - - // If value has changed, trigger callback - if (newValue !== oldValue) { - callback(newValue, oldValue, rowIndex, row); - this.lastValues[key] = newValue; - } - } - }); - } catch (error) { - logger.error({ error }, "Error checking for updates"); - } - }, intervalMs); - }) - .catch((error) => { - logger.error({ error }, "Error initializing sheet watcher"); - }); - } - - /** - * Watch multiple columns for changes and execute callback when changes are detected in any watched column - * @param sheetRange The A1 notation of the range to watch - * @param columnIndexes Array of column indexes to watch (0-based) - * @param callback Function to call when changes are detected - * @param intervalMs How often to check for changes (in milliseconds) - */ - public watchColumns( - sheetRange: string, - columnIndexes: number[], - callback: ( - changedColumnIndex: number, - newValue: any, - oldValue: any, - row: number, - rowData: any[] - ) => void, - intervalMs: number = 10000 - ): void { - logger.info( - { columnIndexes, sheetRange, intervalMs }, - "Watching multiple columns for changes" - ); - - // Initial fetch to establish baseline - this.fetchData(this.spreadsheetId, sheetRange) - .then((data) => { - // Store initial values for all specified columns - data.forEach((row, rowIndex) => { - if (row) { - columnIndexes.forEach((colIndex) => { - if (row[colIndex] !== undefined) { - const key = `${rowIndex}-${colIndex}`; - this.lastValues[key] = row[colIndex]; - } - }); - } - }); - - // Start watching for changes - this.watchInterval = setInterval(async () => { - try { - const newData = await this.fetchData( - this.spreadsheetId, - sheetRange - ); - - // Check for changes in any of the watched columns - newData.forEach((row, rowIndex) => { - if (row) { - columnIndexes.forEach((colIndex) => { - if (row[colIndex] !== undefined) { - const key = `${rowIndex}-${colIndex}`; - const newValue = row[colIndex]; - const oldValue = this.lastValues[key]; - - // If value has changed, trigger callback - if (newValue !== oldValue) { - callback( - colIndex, - newValue, - oldValue, - rowIndex, - row - ); - this.lastValues[key] = newValue; - } - } - }); - } - }); - } catch (error) { - logger.error({ error }, "Error checking for updates"); - } - }, intervalMs); - }) - .catch((error) => { - logger.error({ error }, "Error initializing sheet watcher"); - }); - } - - /** - * Stop watching the spreadsheet - */ - public stopWatching(): void { - if (this.watchInterval) { - clearInterval(this.watchInterval); - this.watchInterval = null; - logger.info("Stopped watching spreadsheet"); - } - } - - /** - * Fetch data from the spreadsheet - * @param spreadsheetId The ID of the spreadsheet - * @param range The A1 notation of the range to fetch - */ - private async fetchData( - spreadsheetId: string, - range: string - ): Promise { - try { - const response = await this.sheets.spreadsheets.values.get({ - spreadsheetId, - range, - }); - - return response.data.values || []; - } catch (error) { - logger.error( - { error, spreadsheetId, range }, - "Error fetching sheet data" - ); - throw error; - } - } - - /** - * Fetch a specific cell value from the spreadsheet - * @param spreadsheetId The ID of the spreadsheet - * @param cellRange The A1 notation of the cell to fetch (e.g., "Sheet1!B2") - * @returns The value of the specified cell - */ - public async fetchCellValue( - spreadsheetId: string, - cellRange: string - ): Promise { - try { - logger.debug({ spreadsheetId, cellRange }, "Fetching cell value"); - const response = await this.sheets.spreadsheets.values.get({ - spreadsheetId, - range: cellRange, - }); - - const values = response.data.values; - if (!values || values.length === 0) { - logger.debug({ cellRange }, "Cell value is null"); - return null; - } - - // When fetching a single cell, sheets API returns a 2D array with just that cell - // Get the value directly - return values[0][0]; - } catch (error) { - logger.error( - { error, spreadsheetId, cellRange }, - "Error fetching cell" - ); - throw error; - } - } - - /** - * Convert a column letter (A, B, C, ..., Z, AA, AB, ...) to a zero-based column index - * @param column The column letter(s) - * @returns The zero-based index - */ - private columnLetterToIndex(column: string): number { - let index = 0; - for (let i = 0; i < column.length; i++) { - index = index * 26 + column.charCodeAt(i) - 64; // 'A' is ASCII 65 - } - return index - 1; // Convert to 0-based index - } - - /** - * Update data in the spreadsheet - * @param spreadsheetId The ID of the spreadsheet - * @param range The A1 notation of the range to update - * @param values The values to write - */ - public async updateValues( - spreadsheetId: string, - range: string, - values: any[][] - ): Promise { - try { - logger.debug({ spreadsheetId, range }, "Updating sheet data"); - await this.sheets.spreadsheets.values.update({ - spreadsheetId, - range, - valueInputOption: "USER_ENTERED", - requestBody: { - values, - }, - }); - logger.info({ range }, "Successfully updated sheet data"); - } catch (error) { - logger.error( - { error, spreadsheetId, range }, - "Error updating sheet data" - ); - throw error; - } - } -} - -export const googleSheet = new GoogleSheet( - process.env.SPREADSHEET_ID as string -); diff --git a/tooling/sparta/src/const.ts b/tooling/sparta/src/const.ts deleted file mode 100644 index c4699d3..0000000 --- a/tooling/sparta/src/const.ts +++ /dev/null @@ -1,35 +0,0 @@ -export const ADDRESSES_PER_PAGE = 20; - -export enum AdminSubcommandGroups { - Admin = "admin", -} - -export enum AdminSubcommands { - Get = "get", - Committee = "committee", - Validators = "validators", - Remove = "remove", - Fund = "fund", -} - -export enum NodeOperatorSubcommandGroups { - Operator = "operator", -} - -export enum NodeOperatorSubcommands { - ChainInfo = "chain-info", -} - -export enum ValidatorSubcommandGroups { - Validator = "validator", -} - -export enum ValidatorSubcommands { - Check = "check", -} - -export enum NodeOperatorRoles { - Guardian = "Guardian", // lowest level, requires minimum score of 0 - Defender = "Defender", // mid level, requires over 5 - Sentinel = "Sentinel", // set manually, but can be removed by this service -} diff --git a/tooling/sparta/src/index.ts b/tooling/sparta/src/index.ts deleted file mode 100644 index 6cd45ff..0000000 --- a/tooling/sparta/src/index.ts +++ /dev/null @@ -1,36 +0,0 @@ -/** - * @fileoverview Main entry point for the Sparta Discord bot - * @description Initializes the Ethereum client and Discord bot services - * @module sparta/index - */ - -import { - ChainInfoService, - ValidatorService, - GoogleSheetService, -} from "./services/index.js"; -import "./clients/discord.js"; // Import to ensure Discord client is initialized -import { logger } from "./utils/logger.js"; - -// Log application startup -logger.info("Sparta bot starting up"); - -// Initialize services -logger.debug("Initializing services"); -export const chainInfoService = new ChainInfoService(); -export const validatorService = new ValidatorService(); -export const googleSheetService = new GoogleSheetService(); - -// Start services -logger.info("Starting services..."); -googleSheetService.watchColumn("Sheet1", "A:B"); - -// Log configuration -logger.debug( - { - logLevel: process.env.LOG_LEVEL || "info", - prettyPrint: process.env.LOG_PRETTY_PRINT !== "false", - environment: process.env.NODE_ENV || "development", - }, - "Current configuration" -); diff --git a/tooling/sparta/src/package.json b/tooling/sparta/src/package.json deleted file mode 100644 index 0bd3f34..0000000 --- a/tooling/sparta/src/package.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "name": "sparta-bot", - "version": "1.0.0", - "type": "module", - "scripts": { - "build": "FOUNDRY_DISABLE_NIGHTLY_WARNING=true bun build index.ts --target bun --minify --outdir=dist", - "dev": "LOG_LEVEL=debug FOUNDRY_DISABLE_NIGHTLY_WARNING=true bun run --watch index.ts", - "start": "FOUNDRY_DISABLE_NIGHTLY_WARNING=true bun run index.ts", - "watch": "FOUNDRY_DISABLE_NIGHTLY_WARNING=true tsc -w", - "lint": "eslint . --ext .ts", - "format": "prettier --write \"src/**/*.ts\"" - }, - "dependencies": { - "@googleapis/sheets": "^9.6.0", - "discord.js": "^14.14.1", - "dotenv": "^16.4.7", - "pino": "^9.6.0", - "pino-pretty": "^13.0.0", - "viem": "^2.22.15" - }, - "devDependencies": { - "@types/bun": "latest", - "@types/node": "^20.10.5", - "typescript": "^5.3.3" - }, - "module": "index.ts", - "packageManager": "yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e" -} diff --git a/tooling/sparta/src/roles/admins/README.md b/tooling/sparta/src/roles/admins/README.md deleted file mode 100644 index 6936c27..0000000 --- a/tooling/sparta/src/roles/admins/README.md +++ /dev/null @@ -1,97 +0,0 @@ -# Admin Role Commands - -The Admin role provides advanced management capabilities for users with administrator permissions in the Sparta Discord bot system. This role is designed for system administrators who need to manage validators and view detailed system information. - -## Available Commands - -| Command | Subcommand | Arguments | Description | -| -------- | ---------------- | --------- | ---------------------------------------------------------- | -| `/admin` | `get validators` | | Get a list of all validators and their forwarder addresses | -| | `get committee` | | Get the current committee members and their forwarders | -| | `remove` | `address` | Remove a validator from the system | -| | `fund` | `address` | Fund a validator with Sepolia ETH | - -## Command Details - -### `/admin get validators` - -Retrieves a list of all validators in the system and their corresponding forwarder addresses. - -**Usage**: `/admin get validators` - -**Returns**: -- Paginated list of validator addresses and their associated forwarder addresses - -**Example Response**: -``` -Validators (Forwarders): -0x1234...5678 -> 0xabcd...efgh -0x5678...1234 -> 0xefgh...abcd -... -``` - -### `/admin get committee` - -Retrieves the current committee members and their forwarder addresses. - -**Usage**: `/admin get committee` - -**Returns**: -- Paginated list of committee member addresses and their associated forwarder addresses - -**Example Response**: -``` -Committee (Forwarders): -0x1234...5678 -> 0xabcd...efgh -0x5678...1234 -> 0xefgh...abcd -... -``` - -### `/admin remove` - -Removes a validator from the system. - -**Usage**: `/admin remove address:0x1234...5678` - -**Arguments**: -- `address`: The Ethereum address of the validator to remove - -**Returns**: -- Confirmation message indicating successful removal or error message - -**Example Response**: -``` -Removed validator 0x1234...5678 -``` - -### `/admin fund` - -Funds a validator with Sepolia ETH. - -**Usage**: `/admin fund address:0x1234...5678` - -**Arguments**: -- `address`: The Ethereum address of the validator to fund - -**Returns**: -- Confirmation message indicating successful funding or error message - -**Example Response**: -``` -Successfully funded validator 0x1234...5678 -``` - -## Permission Requirements - -- Only users with Discord Administrator permissions can access these commands -- These commands are intended for system administrators responsible for maintaining the validator network - -## Technical Implementation - -These commands are implemented in: -- `getValidators.ts`: Handles retrieving the list of validators -- `getCommittee.ts`: Handles retrieving the committee members -- `remove.ts`: Handles removing validators -- `fund.ts`: Handles funding validators - -The commands interact with the Ethereum blockchain using the ChainInfoService and ValidatorService. diff --git a/tooling/sparta/src/roles/admins/index.ts b/tooling/sparta/src/roles/admins/index.ts deleted file mode 100644 index 22efeb4..0000000 --- a/tooling/sparta/src/roles/admins/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -import manageValidators from "./manageValidators/index.js"; - -export default { manageValidators }; diff --git a/tooling/sparta/src/roles/admins/manageValidators/fund.ts b/tooling/sparta/src/roles/admins/manageValidators/fund.ts deleted file mode 100644 index 238ef7f..0000000 --- a/tooling/sparta/src/roles/admins/manageValidators/fund.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { ChatInputCommandInteraction } from "discord.js"; -import { ValidatorService } from "../../../services/validator-service.js"; -import { validateAddress } from "../../../utils/inputValidator.js"; - -export const fund = async (interaction: ChatInputCommandInteraction) => { - const address = validateAddress(interaction); - if (typeof address !== "string") { - return `Invalid address`; - } - await ValidatorService.fundValidator(address); - await interaction.editReply({ - content: `Successfully funded validator ${address}`, - }); - return "Funded validator"; -}; diff --git a/tooling/sparta/src/roles/admins/manageValidators/getCommittee.ts b/tooling/sparta/src/roles/admins/manageValidators/getCommittee.ts deleted file mode 100644 index b108052..0000000 --- a/tooling/sparta/src/roles/admins/manageValidators/getCommittee.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { ChatInputCommandInteraction } from "discord.js"; -import { paginate } from "../../../utils/pagination.js"; -import { ChainInfoService } from "../../../services/chaininfo-service.js"; -import { ADDRESSES_PER_PAGE } from "../../../const.js"; - -export const getCommittee = async ( - interaction: ChatInputCommandInteraction -) => { - const { committee, forwardedCommittee } = await ChainInfoService.getInfo(); - - await paginate( - committee.map((c, i) => `${c} -> ${forwardedCommittee[i]}`) as string[], - committee.length, - ADDRESSES_PER_PAGE, - interaction, - "Committee (Forwarders)" - ); - return "Checked committee"; -}; diff --git a/tooling/sparta/src/roles/admins/manageValidators/getValidators.ts b/tooling/sparta/src/roles/admins/manageValidators/getValidators.ts deleted file mode 100644 index b069b47..0000000 --- a/tooling/sparta/src/roles/admins/manageValidators/getValidators.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { ChatInputCommandInteraction } from "discord.js"; -import { paginate } from "../../../utils/pagination.js"; -import { ADDRESSES_PER_PAGE } from "../../../const.js"; -import { ChainInfoService } from "../../../services/chaininfo-service.js"; - -export const getValidators = async ( - interaction: ChatInputCommandInteraction -) => { - const { validators, forwardedValidators } = - await ChainInfoService.getInfo(); - await paginate( - validators.map( - (v, i) => `${v} -> ${forwardedValidators[i]}` - ) as string[], - validators.length, - ADDRESSES_PER_PAGE, - interaction, - "Validators (Forwarders)" - ); - return "Checked validators"; -}; diff --git a/tooling/sparta/src/roles/admins/manageValidators/index.ts b/tooling/sparta/src/roles/admins/manageValidators/index.ts deleted file mode 100644 index 9a97860..0000000 --- a/tooling/sparta/src/roles/admins/manageValidators/index.ts +++ /dev/null @@ -1,90 +0,0 @@ -import { - SlashCommandBuilder, - ChatInputCommandInteraction, - MessageFlags, - PermissionFlagsBits, -} from "discord.js"; -import { getCommittee } from "./getCommittee.js"; -import { getValidators } from "./getValidators.js"; -import { fund } from "./fund.js"; -import { remove } from "./remove.js"; -import { AdminSubcommands } from "../../../const.js"; - -export default { - data: new SlashCommandBuilder() - .setName("admin") - .setDescription("Admin commands") - .setDefaultMemberPermissions(PermissionFlagsBits.Administrator) - .addSubcommandGroup((group) => - group - .setName(AdminSubcommands.Get) - .setDescription("Get info about validators") - .addSubcommand((subcommand) => - subcommand - .setName(AdminSubcommands.Validators) - .setDescription("Get validators") - ) - .addSubcommand((subcommand) => - subcommand - .setName(AdminSubcommands.Committee) - .setDescription("Get committee") - ) - ) - .addSubcommand((subcommand) => - subcommand - .setName(AdminSubcommands.Remove) - .setDescription("Remove a validator") - .addStringOption((option) => - option - .setName("address") - .setDescription("The validator to remove") - .setRequired(true) - ) - ) - .addSubcommand((subcommand) => - subcommand - .setName(AdminSubcommands.Fund) - .setDescription("Fund a validator with Sepolia ETH") - .addStringOption((option) => - option - .setName("address") - .setDescription("The validator to fund") - .setRequired(true) - ) - ), - execute: async (interaction: ChatInputCommandInteraction) => { - await interaction.deferReply({ - flags: MessageFlags.Ephemeral, - }); - - try { - const subcommand = interaction.options.getSubcommand(); - switch (subcommand) { - case AdminSubcommands.Committee: - await getCommittee(interaction); - break; - case AdminSubcommands.Validators: - await getValidators(interaction); - break; - case AdminSubcommands.Remove: - await remove(interaction); - break; - case AdminSubcommands.Fund: - await fund(interaction); - break; - default: - await interaction.editReply({ - content: `Invalid subcommand: ${subcommand}`, - }); - return; - } - } catch (error) { - await interaction.editReply({ - content: `Failed with error: ${error}`, - }); - return `Failed with error: ${ - error instanceof Error && error.message - }`; - } - }, -}; diff --git a/tooling/sparta/src/roles/admins/manageValidators/remove.ts b/tooling/sparta/src/roles/admins/manageValidators/remove.ts deleted file mode 100644 index 683d944..0000000 --- a/tooling/sparta/src/roles/admins/manageValidators/remove.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { ChatInputCommandInteraction } from "discord.js"; -import { ValidatorService } from "../../../services/validator-service.js"; - -export const remove = async (interaction: ChatInputCommandInteraction) => { - const address = interaction.options.getString("address"); - if (!address) { - await interaction.editReply({ - content: "Please provide an address to remove", - }); - return `Failed`; - } - await ValidatorService.removeValidator(address); - await interaction.editReply({ - content: `Removed validator ${address}`, - }); - return "Removed validator"; -}; diff --git a/tooling/sparta/src/roles/nodeOperators/README.md b/tooling/sparta/src/roles/nodeOperators/README.md deleted file mode 100644 index 28113dd..0000000 --- a/tooling/sparta/src/roles/nodeOperators/README.md +++ /dev/null @@ -1,120 +0,0 @@ -# Node Operator Role Commands - -The Node Operator role is the base role for users in the Sparta Discord bot system. Users who have successfully verified in Discord receive this role and can access the following commands. - -## Available Commands - -| Command | Subcommand | Arguments | Description | -| ------------ | ---------- | ----------------------------------------- | ------------------------------------------------------------------------------------------------------ | -| `/get-info` | | | Get chain information including pending block, proven block, current epoch, current slot, and proposer | -| `/validator` | `check` | `address` | Check if an address is a validator | -| | `register` | `address`, `block-number`, `merkle-proof` | Register a validator address | -| | `help` | `subcommand` | Get help for a specific validator subcommand | - -## Command Details - -### `/get-info` - -Retrieves current blockchain state information. - -**Usage**: `/get-info` - -**Returns**: -- Pending block number: The latest block being processed -- Proven block number: The latest block that has been cryptographically proven -- Current epoch: The current epoch number -- Current slot: The current slot number -- Current proposer: The address of the current block proposer -- Validators: List of current validators -- Committee members: Current committee members for the epoch - -**Example Response**: -``` -Chain Information: -Pending Block: 1234 -Proven Block: 1230 -Current Epoch: 45 -Current Slot: 3 -Current Proposer: 0x1234...5678 -``` - -### `/validator check` - -Checks if a given Ethereum address is a registered validator. - -**Usage**: `/validator check address:0x1234...5678` - -**Arguments**: -- `address`: The Ethereum address to check - -**Returns**: -- Validation status (is/is not a validator) -- If a validator, additional information such as: - - Date registered - - Stake amount - - Current status - -**Example Response**: -``` -Address 0x1234...5678 is a registered validator. -Registered since: Jan 15, 2023 -Stake: 100 ETH -Status: Active -``` - -### `/validator register` - -Registers a new validator address on the blockchain. - -**Usage**: `/validator register address:0x1234...5678 block-number:123456 merkle-proof:0xabcd...1234` - -**Arguments**: -- `address`: The Ethereum address to register as a validator -- `block-number`: The block number for the merkle proof -- `merkle-proof`: Cryptographic proof of eligibility - -**Returns**: -- Registration status (success/failure) -- Transaction hash if successful -- Error message if failed - -**Example Response**: -``` -Successfully registered validator 0x1234...5678. -Transaction: 0xabcd...1234 -Block: 7654321 -``` - -### `/validator help` - -Provides help information for validator commands. - -**Usage**: `/validator help subcommand:check` - -**Arguments**: -- `subcommand`: The validator subcommand to get help for (`check`, `register`) - -**Returns**: -- Detailed help information for the specified subcommand - -**Example Response**: -``` -Validator Check Command Help: -The check command verifies if an address is a registered validator. -Usage: /validator check address:0x1234...5678 -The address should be a valid Ethereum address. -``` - -## Permission Requirements - -- All users with the Node Operator role can access these commands -- The `/validator register` command requires additional verification that the user controls the address being registered - -## Technical Implementation - -These commands are implemented in: -- `getChainInfo.ts`: Handles the `/get-info` command -- `validator.ts`: Handles all validator-related commands - -The commands interact with the Ethereum blockchain using the ChainInfoService and ValidatorService. - diff --git a/tooling/sparta/src/roles/nodeOperators/chainInfo/get.ts b/tooling/sparta/src/roles/nodeOperators/chainInfo/get.ts deleted file mode 100644 index f23aef5..0000000 --- a/tooling/sparta/src/roles/nodeOperators/chainInfo/get.ts +++ /dev/null @@ -1,63 +0,0 @@ -import { - ChatInputCommandInteraction, - DiscordAPIError, - MessageFlags, - TextChannel, -} from "discord.js"; -import { ChainInfoService } from "../../../services/chaininfo-service.js"; -export const get = async ( - interaction: ChatInputCommandInteraction -): Promise => { - const { - pendingBlockNum, - provenBlockNum, - currentEpoch, - currentSlot, - proposerNow, - } = await ChainInfoService.getInfo(); - const channel = interaction.channel as TextChannel; - const messages = await channel.messages.fetch({ - limit: 15, - }); - - // Filter for bot messages that look like chain info responses - // and aren't the current interaction's response - const botMessages = messages.filter( - (m) => - m.author.id === interaction.client.user?.id && - m.content.includes("Pending block:") && - m.content.includes("Proven block:") && - m.content.includes("Current epoch:") && - !m.flags.has(MessageFlags.Ephemeral) && - // Ensure we don't delete the message we're about to send - m.id !== interaction.id - ); - - if (botMessages.size > 0) { - try { - // Try bulk delete first (only works for messages less than 14 days old) - await channel.bulkDelete(botMessages); - } catch (error) { - // If bulk delete fails (e.g., messages are too old), delete individually - if (error instanceof DiscordAPIError && error.code === 50034) { - for (const message of botMessages.values()) { - try { - await message.delete(); - } catch (deleteError) { - console.error( - "Error deleting individual message:", - deleteError - ); - } - } - } else { - throw error; - } - } - } - - await interaction.reply({ - content: `Pending block: ${pendingBlockNum}\nProven block: ${provenBlockNum}\nCurrent epoch: ${currentEpoch}\nCurrent slot: ${currentSlot}\nProposer now: ${proposerNow}`, - }); - return `Pending block: ${pendingBlockNum}\nProven block: ${provenBlockNum}\nCurrent epoch: ${currentEpoch}\nCurrent slot: ${currentSlot}\nProposer now: ${proposerNow}`; -}; diff --git a/tooling/sparta/src/roles/nodeOperators/chainInfo/index.ts b/tooling/sparta/src/roles/nodeOperators/chainInfo/index.ts deleted file mode 100644 index da34ea2..0000000 --- a/tooling/sparta/src/roles/nodeOperators/chainInfo/index.ts +++ /dev/null @@ -1,43 +0,0 @@ -import { - SlashCommandBuilder, - ChatInputCommandInteraction, - MessageFlags, -} from "discord.js"; -import { - NodeOperatorSubcommandGroups, - NodeOperatorSubcommands, -} from "../../../const.js"; -import { get } from "./get.js"; - -export default { - data: new SlashCommandBuilder() - .setName(NodeOperatorSubcommandGroups.Operator) - .setDescription("Node operator commands") - .addSubcommand((subcommand) => - subcommand - .setName(NodeOperatorSubcommands.ChainInfo) - .setDescription("Get chain information") - ), - execute: async (interaction: ChatInputCommandInteraction) => { - try { - const subcommand = interaction.options.getSubcommand(); - switch (subcommand) { - case NodeOperatorSubcommands.ChainInfo: - await get(interaction); - break; - default: - await interaction.editReply({ - content: `Invalid subcommand: ${subcommand}`, - }); - return; - } - } catch (error) { - await interaction.editReply({ - content: `Failed with error: ${error}`, - }); - return `Failed with error: ${ - error instanceof Error && error.message - }`; - } - }, -}; diff --git a/tooling/sparta/src/roles/nodeOperators/index.ts b/tooling/sparta/src/roles/nodeOperators/index.ts deleted file mode 100644 index 5e38841..0000000 --- a/tooling/sparta/src/roles/nodeOperators/index.ts +++ /dev/null @@ -1,4 +0,0 @@ -import validator from "./validator/index.js"; -import chainInfo from "./chainInfo/index.js"; - -export default { validator, chainInfo }; diff --git a/tooling/sparta/src/roles/nodeOperators/validator/check.ts b/tooling/sparta/src/roles/nodeOperators/validator/check.ts deleted file mode 100644 index b277851..0000000 --- a/tooling/sparta/src/roles/nodeOperators/validator/check.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { ChatInputCommandInteraction, MessageFlags } from "discord.js"; -import { validateAddress } from "../../../utils/inputValidator.js"; -import { ChainInfoService } from "../../../services/chaininfo-service.js"; -import { getExpectedAddress } from "../../../clients/ethereum.js"; - -export const check = async ( - interaction: ChatInputCommandInteraction -): Promise => { - const address = validateAddress(interaction); - if (typeof address !== "string") { - await interaction.editReply({ - content: "Please provide a valid address", - }); - return; - } - - const forwarder = getExpectedAddress( - [address as `0x${string}`], - address as `0x${string}` - ).address; - - const info = await ChainInfoService.getInfo(); - const { validators, committee } = info; - - let reply = "Your forwarder contract is: " + forwarder + "\n"; - reply += `It is ${!validators.includes(address) && "not"} a validator\n`; - reply += `It is ${ - !committee.includes(address) && "not" - } a committee member\n`; - - await interaction.editReply({ - content: reply, - }); -}; diff --git a/tooling/sparta/src/roles/nodeOperators/validator/index.ts b/tooling/sparta/src/roles/nodeOperators/validator/index.ts deleted file mode 100644 index 8d20be4..0000000 --- a/tooling/sparta/src/roles/nodeOperators/validator/index.ts +++ /dev/null @@ -1,55 +0,0 @@ -import { - SlashCommandBuilder, - ChatInputCommandInteraction, - MessageFlags, -} from "discord.js"; -import { - ValidatorSubcommandGroups, - ValidatorSubcommands, -} from "../../../const.js"; -import { check } from "./check.js"; - -export default { - data: new SlashCommandBuilder() - .setName(ValidatorSubcommandGroups.Validator) - .setDescription("Validator commands for Node Operator users") - .addSubcommand((subcommand) => - subcommand - .setName(ValidatorSubcommands.Check) - .setDescription("Check if you are a validator") - .addStringOption((option) => - option - .setName("address") - .setDescription("The validator address to check") - .setRequired(true) - ) - ), - execute: async ( - interaction: ChatInputCommandInteraction - ): Promise => { - try { - await interaction.deferReply({ flags: MessageFlags.Ephemeral }); - - const subcommand = interaction.options.getSubcommand(); - switch (subcommand) { - case ValidatorSubcommands.Check: - await check(interaction); - return `Checked validator`; - default: - await interaction.editReply({ - content: `Unknown subcommand: ${subcommand}`, - }); - return `Unknown subcommand`; - } - } catch (error) { - await interaction.editReply({ - content: `Failed with error: ${ - error instanceof Error ? error.message : "Unknown error" - }`, - }); - return `Failed with error: ${ - error instanceof Error ? error.message : "Unknown error" - }`; - } - }, -}; diff --git a/tooling/sparta/src/services/chaininfo-service.ts b/tooling/sparta/src/services/chaininfo-service.ts deleted file mode 100644 index d02f04e..0000000 --- a/tooling/sparta/src/services/chaininfo-service.ts +++ /dev/null @@ -1,120 +0,0 @@ -/** - * @fileoverview Chain Information service for Ethereum blockchain data - * @description Provides methods for retrieving blockchain state and validator information - * @module sparta/services/chaininfo-service - */ - -import { ethereum } from "../clients/ethereum.js"; -import { getExpectedAddress } from "../clients/ethereum.js"; -import { logger } from "../utils/logger.js"; - -/** - * Interface for blockchain information data - * - * @property {string} pendingBlockNum - The current pending block number - * @property {string} provenBlockNum - The current proven block number - * @property {string[]} validators - Array of validator addresses - * @property {string[]} forwardedValidators - Array of forwarded validator addresses - * @property {string[]} committee - Array of committee member addresses - * @property {string[]} forwardedCommittee - Array of forwarded committee addresses - * @property {string[]} archive - Array of archived addresses - * @property {string} currentEpoch - The current epoch number - * @property {string} currentSlot - The current slot number - * @property {string} proposerNow - The current proposer address - */ -type ChainInfo = { - pendingBlockNum: string; - provenBlockNum: string; - validators: string[]; - forwardedValidators: string[]; - committee: string[]; - forwardedCommittee: string[]; - archive: string[]; - currentEpoch: string; - currentSlot: string; - proposerNow: string; -}; - -/** - * Service for retrieving blockchain information and validator data - * - * This service provides methods to: - * - Get current block information (pending, proven) - * - Get validator and committee lists - * - Get epoch and slot information - * - Get current proposer information - */ -export class ChainInfoService { - /** - * Retrieves comprehensive information about the current blockchain state - * - * This method gathers blockchain data from multiple sources and returns - * a consolidated view of the current chain state, including: - * - Block numbers (pending and proven) - * - Validator lists - * - Committee information - * - Epoch and slot data - * - Current proposer - * - * @returns {Promise} A promise that resolves to an object containing chain information - * - * @example - * // Get chain information - * const chainInfo = await ChainInfoService.getInfo(); - * console.log(`Current epoch: ${chainInfo.currentEpoch}`); - * console.log(`Current slot: ${chainInfo.currentSlot}`); - * console.log(`Pending block: ${chainInfo.pendingBlockNum}`); - * - * @throws Will throw an error if retrieving chain information fails - */ - static async getInfo(): Promise { - try { - const rollup = ethereum.getRollup(); - const [ - pendingNum, - provenNum, - validators, - committee, - archive, - epochNum, - slot, - nextBlockTS, - ] = await Promise.all([ - rollup.read.getPendingBlockNumber(), - rollup.read.getProvenBlockNumber(), - rollup.read.getAttesters(), - rollup.read.getCurrentEpochCommittee(), - rollup.read.archive(), - rollup.read.getCurrentEpoch(), - rollup.read.getCurrentSlot(), - rollup.read.getCurrentProposer(), - (async () => { - const block = await ethereum.getPublicClient().getBlock(); - return BigInt(block.timestamp + BigInt(12)); - })(), - ]); - - const proposer = await rollup.read.getProposerAt([nextBlockTS]); - - return { - pendingBlockNum: pendingNum as string, - provenBlockNum: provenNum as string, - validators: validators, - forwardedValidators: validators.map( - (e: `0x${string}`) => getExpectedAddress([e], e).address - ), - committee: committee, - forwardedCommittee: committee.map( - (e: `0x${string}`) => getExpectedAddress([e], e).address - ), - archive: archive as string[], - currentEpoch: epochNum as string, - currentSlot: slot as string, - proposerNow: proposer as string, - }; - } catch (error) { - logger.error({ error }, "Error getting chain info"); - throw error; - } - } -} diff --git a/tooling/sparta/src/services/discord-service.ts b/tooling/sparta/src/services/discord-service.ts deleted file mode 100644 index dd25cd4..0000000 --- a/tooling/sparta/src/services/discord-service.ts +++ /dev/null @@ -1,529 +0,0 @@ -/** - * @fileoverview Discord service for role management - * @description Provides methods for managing Discord roles and finding users - * @module sparta/services/discord-service - */ - -import { discord } from "../clients/discord.js"; -import { logger } from "../utils/logger.js"; -import { NodeOperatorRoles } from "../const.js"; - -/** - * Discord service class for role management and user operations - * - * This service provides methods to: - * - Assign roles to Discord users - * - Find Discord users by username or tag - * - Manage role hierarchies - * - * @example - * // Get the service instance - * const service = DiscordService.getInstance(); - * - * // Assign a role to a user - * await service.assignRole("1234567890", NodeOperatorRoles.Guardian); - * - * // Find a user by username - * const userId = await service.findUserIdByUsername("username"); - */ -export class DiscordService { - private static instance: DiscordService; - - /** - * Gets the singleton instance of DiscordService - * - * @returns {DiscordService} The singleton instance - * - * @example - * const service = DiscordService.getInstance(); - */ - public static getInstance(): DiscordService { - if (!DiscordService.instance) { - DiscordService.instance = new DiscordService(); - } - return DiscordService.instance; - } - - /** - * Assigns a role to a Discord user - * - * This method: - * 1. Finds the guild (Discord server) - * 2. Finds the role by name - * 3. Gets the member by their Discord ID - * 4. Removes any conflicting roles from the hierarchy - * 5. Assigns the new role - * - * @param {string} userId - The Discord user ID to assign the role to - * @param {string} roleName - The name of the role to assign - * @returns {Promise} A promise that resolves to true if the role was assigned, false otherwise - * - * @example - * // Assign the Guardian role to a user - * const success = await discordService.assignRole("1234567890", NodeOperatorRoles.Guardian); - * - * if (success) { - * logger.info("Role assigned successfully"); - * } else { - * logger.error("Failed to assign role"); - * } - */ - public async assignRole( - userId: string, - roleName: string - ): Promise { - try { - // Get the guild (server) - const guildId = process.env.GUILD_ID; - if (!guildId) { - logger.error("GUILD_ID not set in environment variables"); - return false; - } - - const guild = await discord.getGuild(guildId); - if (!guild) { - logger.error({ guildId }, "Guild not found"); - return false; - } - - // Find the role - const role = guild.roles.cache.find((r) => r.name === roleName); - if (!role) { - logger.error( - { roleName, guildName: guild.name }, - "Role not found in guild" - ); - return false; - } - - // Get the member - const member = await guild.members.fetch(userId); - if (!member) { - logger.error( - { userId, guildName: guild.name }, - "Member not found in guild" - ); - return false; - } - - // First check and remove all hierarchy roles (regardless of target role) - const rolesToRemove = member.roles.cache.filter((r) => - Object.values(NodeOperatorRoles).includes( - r.name as NodeOperatorRoles - ) - ); - - if (rolesToRemove.size > 0) { - logger.info( - { - roles: rolesToRemove.map((r) => r.name).join(", "), - username: member.user.username, - }, - "Removing existing roles" - ); - try { - await member.roles.remove(rolesToRemove); - logger.debug( - { - count: rolesToRemove.size, - username: member.user.username, - }, - "Successfully removed roles" - ); - } catch (error: any) { - logger.error( - { error: error.message }, - "Error removing roles" - ); - logger.error( - "Bot might not have sufficient permissions or role hierarchy issue" - ); - } - - // Refresh member data after removing roles - try { - await member.fetch(); - logger.debug( - { - roles: member.roles.cache - .map((r) => r.name) - .join(", "), - username: member.user.username, - }, - "Member data refreshed" - ); - } catch (error: any) { - logger.error( - { error: error.message }, - "Error refreshing member data" - ); - } - } - - // Now add the new role - try { - await member.roles.add(role); - logger.info( - { - roleName, - username: member.user.username, - }, - "Successfully added role" - ); - - // Verify role was added - const updatedMember = await guild.members.fetch(userId); - const hasRole = updatedMember.roles.cache.has(role.id); - await member.fetch(); - - logger.debug( - { - username: member.user.username, - roleName, - hasRole, - }, - "Role verification" - ); - } catch (error: any) { - logger.error({ error: error.message }, "Error adding role"); - logger.error( - "Bot might not have sufficient permissions or role hierarchy issue" - ); - return false; - } - - return true; - } catch (error) { - logger.error({ error }, "Error assigning role"); - return false; - } - } - - /** - * Finds a Discord user by username or username#discriminator - * - * This method attempts to find a user through multiple strategies: - * 1. First checks the cache for the user - * 2. Tries using Discord's search functionality - * 3. Attempts a limited fetch of members - * 4. Tries a direct user lookup if the input looks like an ID - * - * @param {string} usernameOrTag - The Discord username (e.g., "username") or tag (e.g., "username#1234") - * @returns {Promise} A promise that resolves to the user ID if found, null otherwise - * - * @example - * // Find a user by username - * const userId = await discordService.findUserIdByUsername("username"); - * - * // Find a user by tag (legacy format) - * const userId = await discordService.findUserIdByUsername("username#1234"); - * - * if (userId) { - * logger.info(`Found user with ID: ${userId}`); - * } else { - * logger.info("User not found"); - * } - */ - public async findUserIdByUsername( - usernameOrTag: string - ): Promise { - try { - logger.debug({ username: usernameOrTag }, "Starting user lookup"); - - // Get the guild (server) - const guildId = process.env.GUILD_ID; - if (!guildId) { - logger.error("GUILD_ID not set in environment variables"); - return null; - } - - const guild = await discord.getGuild(guildId); - if (!guild) { - logger.error({ guildId }, "Guild not found"); - return null; - } - - logger.debug( - { guildName: guild.name, guildId: guild.id }, - "Guild found" - ); - - // Instead of loading all members at once, which can be slow and cause timeouts, - // we'll use search functionality if available or limit the fetch - - // First try with currently cached members - logger.debug("Checking cached members first"); - const cachedMember = this.findMemberInCache(guild, usernameOrTag); - if (cachedMember) { - logger.info( - { - username: cachedMember.user.username, - userId: cachedMember.id, - }, - "Found user in cache" - ); - return cachedMember.id; - } - - logger.debug("User not found in cache, attempting limited fetch"); - - // Try different strategies to find the user - let userId = null; - - // Strategy 1: Try search if available - userId = await this.trySearchByUsername(guild, usernameOrTag); - if (userId) return userId; - - // Strategy 2: Try limited fetch with timeout - userId = await this.tryLimitedFetch(guild, usernameOrTag); - if (userId) return userId; - - // Strategy 3: Try direct user lookup if it might be an ID already - if (/^\d+$/.test(usernameOrTag)) { - try { - logger.debug( - { username: usernameOrTag }, - "Username looks like an ID, trying direct fetch" - ); - const member = await guild.members - .fetch(usernameOrTag) - .catch(() => null); - if (member) { - logger.info( - { - username: member.user.username, - userId: member.id, - }, - "Found user directly" - ); - return member.id; - } - } catch (error: any) { - logger.debug( - { error: error.message }, - "Direct fetch failed" - ); - } - } - - logger.info( - { username: usernameOrTag }, - "Could not find user with username after trying all strategies" - ); - return null; - } catch (error) { - logger.error({ error }, "Error finding user by username"); - return null; - } - } - - /** - * Attempts to search for a user by username using Discord's search feature - * - * @param {any} guild - The Discord guild object - * @param {string} username - The username to search for - * @returns {Promise} A promise that resolves to the user ID if found, null otherwise - * - * @private - */ - private async trySearchByUsername( - guild: any, - username: string - ): Promise { - if (!guild.members.search) { - logger.debug("Search capability not available"); - return null; - } - - logger.debug({ username }, "Attempting to search for username"); - try { - const searchResults = await guild.members.search({ - query: username, - limit: 5, - }); - - if (searchResults && searchResults.size > 0) { - const member = searchResults.first(); - if (member && member.user) { - logger.info( - { - username: member.user.username, - userId: member.id, - }, - "Found user via search" - ); - return member.id; - } - } - logger.debug("Search returned no results"); - return null; - } catch (searchError) { - logger.error({ searchError }, "Error using member search"); - return null; - } - } - - /** - * Attempts to find a user by fetching a limited number of members - * Uses a timeout to prevent hanging - * - * This method: - * 1. First tries with a small batch (25 members) for speed - * 2. If unsuccessful, tries with a larger batch (100 members) - * 3. Uses an abort controller to prevent hanging - * - * @param {any} guild - The Discord guild object - * @param {string} username - The username to search for - * @returns {Promise} A promise that resolves to the user ID if found, null otherwise - * - * @private - */ - private async tryLimitedFetch( - guild: any, - username: string - ): Promise { - logger.debug("Attempting limited fetch with timeout protection"); - try { - // Create a controller to allow aborting the fetch - const controller = new AbortController(); - const timeoutId = setTimeout(() => { - controller.abort(); - logger.debug("Fetch operation aborted due to timeout"); - }, 5000); - - // Try a smaller batch first (faster) - try { - logger.debug("Trying fetch with limit 25"); - const members = await guild.members.fetch({ - limit: 25, - signal: controller.signal, - }); - - const match = this.findMatchingMember(members, username); - if (match) { - clearTimeout(timeoutId); - return match; - } - } catch (error: any) { - if (error.name === "AbortError") { - logger.debug("First fetch attempt aborted"); - } else { - logger.error( - { error: error.message }, - "Error in first fetch attempt" - ); - } - } - - // Try a larger batch if first attempt failed but not timed out - if (!controller.signal.aborted) { - try { - logger.debug("Trying fetch with limit 100"); - const members = await guild.members.fetch({ - limit: 100, - signal: controller.signal, - }); - - const match = this.findMatchingMember(members, username); - if (match) { - clearTimeout(timeoutId); - return match; - } - } catch (error: any) { - if (error.name === "AbortError") { - logger.debug("Second fetch attempt aborted"); - } else { - logger.error( - { error: error.message }, - "Error in second fetch attempt" - ); - } - } - } - - clearTimeout(timeoutId); - logger.debug( - "Limited fetch attempts completed without finding user" - ); - return null; - } catch (error) { - logger.error({ error }, "Error in limited fetch process"); - return null; - } - } - - /** - * Find a matching member from a collection of Discord members - * - * @param {any} members - Collection of Discord members - * @param {string} username - The username to find - * @returns {string|null} The user ID if found, null otherwise - * - * @private - */ - private findMatchingMember(members: any, username: string): string | null { - if (!members || typeof members.forEach !== "function") { - logger.debug("Invalid members data received"); - return null; - } - - for (const [_, member] of members) { - if (this.isUserMatch(member, username)) { - logger.info( - { - username: member.user.username, - userId: member.id, - }, - "Found user" - ); - return member.id; - } - } - - logger.debug(`No matching user found among ${members.size} members`); - return null; - } - - /** - * Checks if a Discord member matches the given username or tag - * - * Supports both modern username format and legacy username#discriminator format - * - * @param {any} member - The Discord member object - * @param {string} usernameOrTag - The username or tag to check against - * @returns {boolean} True if the member matches, false otherwise - * - * @private - */ - private isUserMatch(member: any, usernameOrTag: string): boolean { - // Check if the input includes a discriminator (#) - const isTag = usernameOrTag.includes("#"); - - if (isTag) { - // For legacy username#discriminator format - const fullTag = `${member.user.username}#${member.user.discriminator}`; - return fullTag === usernameOrTag; - } else { - // For regular username - return member.user.username === usernameOrTag; - } - } - - /** - * Finds a Discord member in the currently cached members - * - * @param {any} guild - The Discord guild object - * @param {string} usernameOrTag - The username or tag to find - * @returns {any} The member object if found, undefined otherwise - * - * @private - */ - private findMemberInCache(guild: any, usernameOrTag: string): any { - return guild.members.cache.find((member: any) => - this.isUserMatch(member, usernameOrTag) - ); - } -} - -// Export a default instance -export const discordService = DiscordService.getInstance(); diff --git a/tooling/sparta/src/services/googlesheet-service.ts b/tooling/sparta/src/services/googlesheet-service.ts deleted file mode 100644 index e314642..0000000 --- a/tooling/sparta/src/services/googlesheet-service.ts +++ /dev/null @@ -1,183 +0,0 @@ -/** - * @fileoverview Google Sheets service for integration with Discord - * @description Provides methods to monitor Google Sheets and assign Discord roles based on sheet data - * @module sparta/services/googlesheet-service - */ - -import { GoogleSheet, googleSheet } from "../clients/google.js"; -import { discordService } from "./discord-service.js"; -import { logger } from "../utils/logger.js"; -import { ADDRESSES_PER_PAGE, NodeOperatorRoles } from "../const.js"; - -/** - * Service for integrating with Google Sheets and assigning Discord roles based on sheet data - * - * This service: - * - Monitors specific columns in Google Sheets - * - Detects changes to user scores - * - Assigns Discord roles based on score thresholds - * - * @example - * // Create an instance and watch a sheet - * const service = new GoogleSheetService(); - * service.watchColumn("Sheet1", "A:B"); - */ -export class GoogleSheetService { - /** - * Watches specified columns in a Google Sheet for changes - * - * This method sets up a watch on column A (scores) and column B (Discord usernames). - * When changes are detected, it triggers the role assignment process if both - * a score and username are present. - * - * @param {string} sheetName - The name of the sheet to watch (e.g., "Sheet1") - * @param {string} range - The range of cells to watch (e.g., "A:B") - * - * @example - * // Watch columns A and B in Sheet1 - * googleSheetService.watchColumn("Sheet1", "A:B"); - */ - watchColumn(sheetName: string, range: string) { - // Watch both columns A and B at the same time - googleSheet.watchColumns( - `${sheetName}!${range}`, - [0, 1], // Watch columns A (index 0) and B (index 1) - (changedColumnIndex, newValue, oldValue, row, rowData) => { - const columnLetter = changedColumnIndex === 0 ? "A" : "B"; - logger.info( - { - cell: `${columnLetter}${row + 2}`, - oldValue, - newValue, - }, - "Cell value changed" - ); - - // Only execute if both columns have values - const scoreValue = rowData[0]; - const discordUsername = rowData[1]; - - if (scoreValue && discordUsername) { - // Handle the promise without blocking - this.assignRoleBasedOnScore( - scoreValue, - discordUsername, - row - ).catch((error) => { - logger.error( - { error, scoreValue, discordUsername, row }, - "Error in role assignment process" - ); - }); - } - } - ); - } - - /** - * Assigns a Discord role based on a user's score - * - * This method: - * 1. Validates and parses the score - * 2. Finds the Discord user ID by username - * 3. Determines the appropriate role based on score thresholds: - * - Score > 10: NodeOperatorRoles.Sentinel (highest role) - * - Score > 5: NodeOperatorRoles.Defender (middle role) - * - Default: NodeOperatorRoles.Guardian (lowest role) - * 4. Assigns the role to the user - * - * @param {string} scoreString - The user's score as a string (will be converted to number) - * @param {string} discordUsername - The Discord username to assign the role to - * @param {number} row - The row number in the spreadsheet (for logging purposes) - * @returns {Promise} A promise that resolves when the role assignment is complete - * - * @private - */ - private async assignRoleBasedOnScore( - scoreString: string, - discordUsername: string, - row: number - ): Promise { - logger.debug(`Processing role assignment for row ${row + 2}`); - logger.debug( - { score: scoreString, username: discordUsername }, - "Processing score for role assignment" - ); - - // Parse score as a number - const score = Number(scoreString); - - // Validate score is a number - if (isNaN(score)) { - logger.error( - { score: scoreString }, - "Invalid score value, expected a number" - ); - return; - } - - logger.debug(`Finding Discord ID for username: ${discordUsername}`); - // Find the Discord ID by username - const discordUserId = await discordService.findUserIdByUsername( - discordUsername - ); - - logger.debug({ userId: discordUserId }, "Discord ID lookup completed"); - - if (!discordUserId) { - logger.error( - { username: discordUsername }, - "Could not find Discord user" - ); - return; - } - - // Determine role based on score threshold using the hierarchy: - // Guardian (lowest) -> Defender -> Sentinel (highest) - let roleName = NodeOperatorRoles.Guardian; // Default/lowest role - - if (score > 10) { - roleName = NodeOperatorRoles.Sentinel; // Highest role - } else if (score > 5) { - roleName = NodeOperatorRoles.Defender; // Middle role - } - - // Assign the appropriate role to the Discord user - try { - const success = await discordService.assignRole( - discordUserId, - roleName - ); - - if (success) { - logger.info( - { - username: discordUsername, - userId: discordUserId, - role: roleName, - }, - "Successfully assigned role" - ); - } else { - logger.error( - { - username: discordUsername, - userId: discordUserId, - role: roleName, - }, - "Failed to assign role" - ); - } - } catch (error) { - logger.error( - { - error, - username: discordUsername, - userId: discordUserId, - role: roleName, - }, - "Error assigning role" - ); - } - } -} diff --git a/tooling/sparta/src/services/index.ts b/tooling/sparta/src/services/index.ts deleted file mode 100644 index 7d69fb6..0000000 --- a/tooling/sparta/src/services/index.ts +++ /dev/null @@ -1,27 +0,0 @@ -/** - * @fileoverview Service module exports - * @description Centralizes exports for all Sparta service modules - * @module sparta/services - */ - -import { GoogleSheetService } from "./googlesheet-service.js"; -import { ChainInfoService } from "./chaininfo-service.js"; -import { ValidatorService } from "./validator-service.js"; -import { DiscordService, discordService } from "./discord-service.js"; - -/** - * Export all service classes and instances - * - * - GoogleSheetService: Monitors Google Sheets and assigns roles based on scores - * - ChainInfoService: Retrieves blockchain state information - * - ValidatorService: Manages Ethereum validators - * - DiscordService: Manages Discord roles and user interactions - * - discordService: Singleton instance of DiscordService - */ -export { - GoogleSheetService, - ChainInfoService, - ValidatorService, - DiscordService, - discordService, -}; diff --git a/tooling/sparta/src/services/validator-service.ts b/tooling/sparta/src/services/validator-service.ts deleted file mode 100644 index 8e9f8de..0000000 --- a/tooling/sparta/src/services/validator-service.ts +++ /dev/null @@ -1,139 +0,0 @@ -/** - * @fileoverview Validator service for Ethereum validator management - * @description Provides methods for managing validators on the Ethereum network - * @module sparta/services/validator-service - */ - -import { exec } from "child_process"; -import { promisify } from "util"; -import { ethereum } from "../clients/ethereum.js"; -import { Transaction, TransactionReceipt } from "viem"; -import { logger } from "../utils/logger.js"; - -const execAsync = promisify(exec); - -/** - * Service for managing Ethereum validators - * - * This service provides methods to: - * - Request tokens from a faucet for validators - * - Add validators to the network - * - Remove validators from the network - * - Fund validators with ETH - */ -export class ValidatorService { - /** - * Requests staking asset tokens from a faucet for a validator address - * - * This method calls the Ethereum client to distribute staking tokens - * to the specified address, which can then be used for staking. - * - * @param {string} address - The Ethereum address to receive staking tokens - * @returns {Promise} A promise that resolves to the transaction receipt - * - * @example - * // Request staking tokens for a validator - * const receipt = await ValidatorService.stakingAssetFaucet("0x123..."); - * logger.info({ transactionHash: receipt.transactionHash }, "Staking asset faucet transaction completed"); - * - * @throws Will throw an error if the faucet transaction fails - */ - static async stakingAssetFaucet( - address: string - ): Promise { - try { - return await ethereum.stakingAssetFaucet(address); - } catch (error) { - logger.error({ error, address }, "Error adding validator"); - throw error; - } - } - - /** - * Adds a new validator to the Ethereum network - * - * This method registers the provided address as a validator - * in the validator registry contract. - * - * @param {string} address - The Ethereum address to add as a validator - * @returns {Promise} A promise that resolves to an array of transaction receipts - * - * @example - * // Add a new validator - * const receipts = await ValidatorService.addValidator("0x123..."); - * logger.info({ transactionCount: receipts.length }, "Added validator"); - * - * @throws Will throw an error if adding the validator fails - */ - static async addValidator(address: string): Promise { - try { - return await ethereum.addValidator(address); - } catch (error) { - logger.error({ error, address }, "Error adding validator"); - throw error; - } - } - - /** - * Removes a validator from the Ethereum network - * - * This method deregisters the provided address from the - * validator registry contract. - * - * @param {string} address - The Ethereum address to remove as a validator - * @returns {Promise} A promise that resolves to the transaction receipt - * - * @example - * // Remove a validator - * const receipt = await ValidatorService.removeValidator("0x123..."); - * logger.info({ transactionHash: receipt.transactionHash }, "Removed validator"); - * - * @throws Will throw an error if removing the validator fails - */ - static async removeValidator(address: string): Promise { - try { - return await ethereum.removeValidator(address); - } catch (error) { - logger.error({ error, address }, "Error removing validator"); - throw error; - } - } - - /** - * Funds a validator address with ETH - * - * This method sends ETH to the specified address using the cast command - * from the Foundry toolkit. The amount sent is specified in the FUNDER_AMOUNT - * environment variable. - * - * @param {string} address - The Ethereum address to fund with ETH - * @returns {Promise} A promise that resolves to the command output - * - * @example - * // Fund a validator with ETH - * const output = await ValidatorService.fundValidator("0x123..."); - * logger.info({ output }, "Funded validator with ETH"); - * - * @throws Will throw an error if funding the validator fails - */ - static async fundValidator(address: string): Promise { - try { - const command = `cast send --value ${process.env.FUNDER_AMOUNT} --rpc-url ${process.env.ETHEREUM_HOST} --chain-id ${process.env.L1_CHAIN_ID} --private-key ${process.env.FUNDER_ADDRESS_PRIVATE_KEY} ${address}`; - - logger.debug( - { address, amount: process.env.FUNDER_AMOUNT }, - "Funding validator" - ); - const { stdout, stderr } = await execAsync(command); - - if (stderr) { - throw new Error(stderr); - } - - return stdout; - } catch (error) { - logger.error({ error, address }, "Error funding validator"); - throw error; - } - } -} diff --git a/tooling/sparta/src/test/README.md b/tooling/sparta/src/test/README.md deleted file mode 100644 index d2dadc3..0000000 --- a/tooling/sparta/src/test/README.md +++ /dev/null @@ -1,5 +0,0 @@ -# Tests - -This directory contains test files for the codebase. - -- `aztec.test.ts` - Tests for Aztec client functionality diff --git a/tooling/sparta/src/test/aztec.test.ts b/tooling/sparta/src/test/aztec.test.ts deleted file mode 100644 index 1a00025..0000000 --- a/tooling/sparta/src/test/aztec.test.ts +++ /dev/null @@ -1,78 +0,0 @@ -import { expect, test, beforeAll, describe } from "bun:test"; -import { Aztec } from "../clients/aztec.js"; -import { config } from "dotenv"; - -config({ path: ".env.local" }); - -// Set the RPC URL for tests -const TEST_RPC_URL = process.env.AZTEC_NODE_URL || "http://localhost:8080"; -let aztec: Aztec; -let isNodeAvailable = false; - -// Verify node is available before tests -beforeAll(async () => { - aztec = new Aztec(TEST_RPC_URL); - - try { - // Try to get L2 tips to check if node is available - await aztec.getL2Tips(); - isNodeAvailable = true; - console.log(`Connected to Aztec node at ${TEST_RPC_URL}`); - } catch (error: any) { - console.warn( - `⚠️ Aztec node at ${TEST_RPC_URL} is not available. Some tests will be skipped.` - ); - console.warn(`Error: ${error.message}`); - throw new Error("Aztec node is not available"); - } -}); - -describe("Aztec Integration Tests", () => { - test("Aztec.new() initializes client with correct URL", async () => { - // This test doesn't need the node to be available - process.env.AZTEC_NODE_URL = TEST_RPC_URL; - const instance = await Aztec.new(); - // @ts-expect-error - accessing private property for test - expect(instance.rpcUrl).toBe(TEST_RPC_URL); - }); - - test("getL2Tips returns the proven block number", async () => { - if (!isNodeAvailable) { - console.log("Skipping test: getL2Tips - node not available"); - return; - } - - const blockNumber = await aztec.getL2Tips(); - console.log(`Current proven block: ${blockNumber}`); - expect(typeof blockNumber).toBe("number"); - expect(blockNumber).toBeGreaterThan(0); - }); - - test("getArchiveSiblingPath returns sibling path data", async () => { - if (!isNodeAvailable) { - console.log( - "Skipping test: getArchiveSiblingPath - node not available" - ); - return; - } - - // Get the current proven block - const provenBlock = await aztec.getL2Tips(); - console.log(`Using proven block: ${provenBlock}`); - - const siblingPath = await aztec.getArchiveSiblingPath(provenBlock); - - // Check if we got a valid response format - expect(siblingPath).toBeDefined(); - - // console.log("Sibling path:", JSON.stringify(siblingPath, null, 2)); - }); - - test("handles RPC errors gracefully", async () => { - // Create an instance with an invalid URL to force an error - const badAztec = new Aztec("http://nonexistent-url:9999"); - - // This should throw an error when trying to connect - await expect(badAztec.getL2Tips()).rejects.toThrow(); - }); -}); diff --git a/tooling/sparta/src/test/discord.test.ts b/tooling/sparta/src/test/discord.test.ts deleted file mode 100644 index 97dbeef..0000000 --- a/tooling/sparta/src/test/discord.test.ts +++ /dev/null @@ -1,133 +0,0 @@ -import { expect, test, beforeAll, describe, mock, Mock } from "bun:test"; -import { Discord } from "../clients/discord.js"; -import { - Client, - Collection, - GatewayIntentBits, - MessageFlags, - REST, - Routes, -} from "discord.js"; -import { config } from "dotenv"; - -config({ path: ".env.local" }); - -// Mock Discord.js components -mock.module("discord.js", () => { - // Create mock client class - const mockClient = { - login: mock(() => Promise.resolve("token")), - once: mock(), - on: mock(), - commands: new Collection(), - guilds: { - fetch: mock(() => Promise.resolve({ id: "mock-guild" })), - }, - }; - - return { - Client: mock(() => mockClient), - Collection, - GatewayIntentBits: { - Guilds: 1, - GuildMessages: 2, - }, - MessageFlags: { - Ephemeral: 64, - }, - REST: mock(() => ({ - setToken: mock().mockReturnThis(), - put: mock(() => Promise.resolve()), - })), - Routes: { - applicationGuildCommands: mock( - (clientId, guildId) => - `/applications/${clientId}/guilds/${guildId}/commands` - ), - }, - }; -}); - -describe("Discord Client Tests", () => { - // Keep reference to any mock clients created during tests - let mockDiscordClient: any; - - test("Discord.new() initializes client with correct configuration", async () => { - // Store original environment variables - const originalToken = process.env.BOT_TOKEN; - const originalClientId = process.env.BOT_CLIENT_ID; - const originalGuildId = process.env.GUILD_ID; - - // Set test environment variables - process.env.BOT_TOKEN = "test-token"; - process.env.BOT_CLIENT_ID = "test-client-id"; - process.env.GUILD_ID = "test-guild-id"; - - try { - const discord = await Discord.new(); - expect(discord).toBeInstanceOf(Discord); - - // Verify the client was initialized - mockDiscordClient = discord.getClient(); - expect(mockDiscordClient).toBeDefined(); - expect(mockDiscordClient.login).toHaveBeenCalledWith("test-token"); - expect(mockDiscordClient.once).toHaveBeenCalledWith( - "ready", - expect.any(Function) - ); - expect(mockDiscordClient.once).toHaveBeenCalledWith( - "error", - expect.any(Function) - ); - expect(mockDiscordClient.on).toHaveBeenCalledWith( - "interactionCreate", - expect.any(Function) - ); - } finally { - // Restore original environment variables - process.env.BOT_TOKEN = originalToken; - process.env.BOT_CLIENT_ID = originalClientId; - process.env.GUILD_ID = originalGuildId; - } - }); - - test("getClient() returns the Discord client instance", async () => { - const discord = await Discord.new(); - const client = discord.getClient(); - expect(client).toBeDefined(); - expect(client.commands).toBeInstanceOf(Collection); - }); - - test("getGuild() retrieves guild by ID", async () => { - const discord = await Discord.new(); - const guild = await discord.getGuild("test-guild-id"); - expect(guild).toBeDefined(); - expect(mockDiscordClient.guilds.fetch).toHaveBeenCalledWith( - "test-guild-id" - ); - }); - - test("handles errors gracefully during initialization", async () => { - // Force an error condition by removing the token - const originalToken = process.env.BOT_TOKEN; - process.env.BOT_TOKEN = undefined; - - try { - // Get a reference to the login function so we can modify it - const client = new Client({ intents: [] }); - const loginSpy = mock(() => - Promise.reject(new Error("Invalid token")) - ); - client.login = loginSpy; - - // @ts-expect-error - accessing private property for test - Client.mockImplementationOnce(() => client); - - await expect(Discord.new()).rejects.toThrow(); - expect(loginSpy).toHaveBeenCalled(); - } finally { - // Restore original token - process.env.BOT_TOKEN = originalToken; - } - }); -}); diff --git a/tooling/sparta/src/test/ethereum.test.ts b/tooling/sparta/src/test/ethereum.test.ts deleted file mode 100644 index 0af1406..0000000 --- a/tooling/sparta/src/test/ethereum.test.ts +++ /dev/null @@ -1,206 +0,0 @@ -import { expect, test, beforeAll, describe, mock } from "bun:test"; -import { Ethereum, getExpectedAddress } from "../clients/ethereum.js"; -import { config } from "dotenv"; - -config({ path: ".env.local" }); - -// Mock viem and its functions -mock.module("viem", () => { - const mockPublicClient = { - waitForTransactionReceipt: mock(({ hash }) => - Promise.resolve({ - blockHash: "0xblock123", - blockNumber: 123456n, - transactionHash: hash, - status: "success", - }) - ), - }; - - const mockContract = { - address: "0xcontract123" as `0x${string}`, - write: { - mint: mock(() => "0xtxhash123"), - approve: mock(() => "0xtxhash456"), - deposit: mock(() => "0xtxhash789"), - initiateWithdraw: mock(() => "0xtxhash000"), - }, - read: { - getRollup: mock(() => "0xrollup123"), - getStakingAsset: mock(() => "0xstaking123"), - }, - }; - - const mockWalletClient = { - account: { - address: "0xwallet123" as `0x${string}`, - }, - }; - - return { - createPublicClient: mock((config) => mockPublicClient), - createWalletClient: mock(() => mockWalletClient), - encodeDeployData: mock(() => "0xencoded123"), - getContract: mock(() => mockContract), - getCreate2Address: mock(() => "0xcreated123"), - http: mock(() => "http-transport"), - padHex: mock(() => "0xpadded123"), - }; -}); - -// Mock viem/accounts -mock.module("viem/accounts", () => { - return { - privateKeyToAccount: mock(() => ({ - address: "0xaccount123" as `0x${string}`, - })), - }; -}); - -describe("Ethereum Integration Tests", () => { - let ethereum: Ethereum; - - // Set environment variables for tests - const testEnv = { - ETHEREUM_HOST: "https://test-rpc-url", - ETHEREUM_REGISTRY_ADDRESS: "0xregistry123", - MINTER_PRIVATE_KEY: "0xprivkey123", - MINIMUM_STAKE: "1000000", - APPROVAL_AMOUNT: "2000000", - WITHDRAWER_ADDRESS: "0xwithdrawer123", - WITHDRAWER_PRIVATE_KEY: "0xwithdrawerprivkey123", - L1_CHAIN_ID: "11155111", - }; - - beforeAll(() => { - // Save original env variables - const originalEnv = { ...process.env }; - - // Set test env variables - Object.entries(testEnv).forEach(([key, value]) => { - process.env[key] = value; - }); - - return () => { - // Restore original env variables - process.env = originalEnv; - }; - }); - - test("Ethereum.new() initializes client with correct configuration", async () => { - const ethereum = await Ethereum.new(); - expect(ethereum).toBeInstanceOf(Ethereum); - - // Check if required clients were initialized - const viem = await import("viem"); - expect(viem.createPublicClient).toHaveBeenCalled(); - expect(viem.createWalletClient).toHaveBeenCalled(); - expect(viem.getContract).toHaveBeenCalled(); - }); - - test("getPublicClient() returns the public client", async () => { - ethereum = await Ethereum.new(); - const client = ethereum.getPublicClient(); - expect(client).toBeDefined(); - expect(client.waitForTransactionReceipt).toBeDefined(); - }); - - test("getWalletClient() returns the wallet client", async () => { - ethereum = await Ethereum.new(); - const client = ethereum.getWalletClient(); - expect(client).toBeDefined(); - expect(client.account).toBeDefined(); - }); - - test("getRollup() returns the rollup contract", async () => { - ethereum = await Ethereum.new(); - const rollup = ethereum.getRollup(); - expect(rollup).toBeDefined(); - expect(rollup.address).toBe("0xcontract123"); - }); - - test("stakingAssetFaucet() mints tokens", async () => { - ethereum = await Ethereum.new(); - const receipt = await ethereum.stakingAssetFaucet("0xrecipient123"); - - expect(receipt).toBeDefined(); - expect(receipt.transactionHash).toBe("0xtxhash123"); - expect(receipt.status).toBe("success"); - }); - - test("addValidator() deposits stake for a validator", async () => { - ethereum = await Ethereum.new(); - const receipts = await ethereum.addValidator("0xvalidator123"); - - expect(receipts).toBeInstanceOf(Array); - expect(receipts.length).toBe(2); - expect(receipts[0].transactionHash).toBe("0xtxhash456"); - expect(receipts[1].transactionHash).toBe("0xtxhash789"); - }); - - test("removeValidator() initiates withdrawal for a validator", async () => { - ethereum = await Ethereum.new(); - const receipt = await ethereum.removeValidator("0xvalidator123"); - - expect(receipt).toBeDefined(); - expect(receipt.transactionHash).toBe("0xtxhash000"); - expect(receipt.status).toBe("success"); - }); - - test("getExpectedAddress calculates the correct address", () => { - const result = getExpectedAddress( - ["0xarg123"] as [`0x${string}`], - "0xsalt123" as `0x${string}` - ); - - expect(result).toBeDefined(); - expect(result.address).toBe("0xcreated123"); - expect(result.paddedSalt).toBe("0xpadded123"); - expect(result.calldata).toBe("0xencoded123"); - }); - - test("handles errors gracefully", async () => { - // Mock waitForTransactionReceipt to throw an error - const viem = await import("viem"); - - // Create a mock chain object with required properties - const mockChain = { - id: 11155111, - name: "Sepolia", - nativeCurrency: { - decimals: 18, - name: "Ethereum", - symbol: "ETH", - }, - rpcUrls: { - default: { - http: ["https://test-rpc-url"], - }, - public: { - http: ["https://test-rpc-url"], - }, - }, - }; - - // Create a mock http transport - const httpTransport = viem.http(); - - const mockPublicClient = viem.createPublicClient({ - chain: mockChain, - transport: httpTransport, - }); - - mockPublicClient.waitForTransactionReceipt = mock(() => { - throw new Error("Transaction failed"); - }); - - ethereum = await Ethereum.new(); - - // @ts-expect-error - accessing private property for test - ethereum.publicClient = mockPublicClient; - - await expect( - ethereum.stakingAssetFaucet("0xrecipient123") - ).rejects.toThrow("Transaction failed"); - }); -}); diff --git a/tooling/sparta/src/test/google.test.ts b/tooling/sparta/src/test/google.test.ts deleted file mode 100644 index d6ee860..0000000 --- a/tooling/sparta/src/test/google.test.ts +++ /dev/null @@ -1,203 +0,0 @@ -import { expect, test, beforeAll, describe, mock } from "bun:test"; -import { GoogleSheet } from "../clients/google.js"; -import { config } from "dotenv"; - -config({ path: ".env.local" }); - -// Mock test data for our spreadsheet -const testData = [ - ["header1", "header2", "header3"], - ["value1", "value2", "value3"], - ["value4", "value5", "value6"], -]; - -// Mock Google Sheets API -mock.module("@googleapis/sheets", () => { - const mockSheetsGet = mock((params) => { - const range = params.range; - - // Handle single cell requests (e.g., Sheet1!B2) - const cellMatch = range.match(/.*!([A-Z])([0-9]+)$/); - if (cellMatch) { - const col = cellMatch[1].charCodeAt(0) - 65; // Convert A->0, B->1, etc. - const row = parseInt(cellMatch[2]) - 1; // Convert to 0-based index - - // Return just the value at that position in a 2D array - // This is how the real API would respond for a cell request - if ( - row >= 0 && - row < testData.length && - col >= 0 && - col < testData[row].length - ) { - return { - data: { - values: [[testData[row][col]]], - }, - }; - } - } - - // Default case: return all data - return { - data: { - values: testData, - }, - }; - }); - - const mockSheetsUpdate = mock(() => ({ - data: { - updatedCells: 3, - updatedRange: "Sheet1!A1:C2", - }, - })); - - return { - sheets: mock((options) => ({ - spreadsheets: { - values: { - get: mockSheetsGet, - update: mockSheetsUpdate, - }, - }, - })), - }; -}); - -describe("Google Sheets Integration Tests", () => { - let googleSheet: GoogleSheet; - - beforeAll(() => { - // Set environment variable for tests - process.env.GOOGLE_API_KEY = "test-api-key"; - - // Create an instance with a test spreadsheet ID - googleSheet = new GoogleSheet("test-spreadsheet-id"); - }); - - test("GoogleSheet constructor initializes with correct spreadsheet ID", () => { - // @ts-expect-error - accessing private property for test - expect(googleSheet.spreadsheetId).toBe("test-spreadsheet-id"); - }); - - test("fetchData retrieves values from the spreadsheet", async () => { - // @ts-expect-error - accessing private method for test - const values = await googleSheet.fetchData( - "test-spreadsheet-id", - "Sheet1!A1:C3" - ); - - expect(values).toBeDefined(); - expect(values.length).toBe(3); - expect(values[0][0]).toBe("header1"); - expect(values[1][0]).toBe("value1"); - }); - - test("fetchCellValue retrieves a specific cell value", async () => { - const value = await googleSheet.fetchCellValue( - "test-spreadsheet-id", - "Sheet1!B2" - ); - expect(value).toBe("value2"); - }); - - test("updateValues updates data in the spreadsheet", async () => { - const newValues = [ - ["newValue1", "newValue2", "newValue3"], - ["newValue4", "newValue5", "newValue6"], - ]; - - await googleSheet.updateValues( - "test-spreadsheet-id", - "Sheet1!A1:C2", - newValues - ); - - // The update verification is handled by the mock system automatically - }); - - test("watchColumn correctly sets up watching for changes", async () => { - // Mock setTimeout for testing interval setting - const originalSetInterval = global.setInterval; - const mockSetInterval = mock(() => 123); - global.setInterval = mockSetInterval as any; - - // Mock fetchData to resolve immediately - // @ts-expect-error - accessing private method for test - const originalFetchData = googleSheet.fetchData; - // @ts-expect-error - accessing private method for test - googleSheet.fetchData = mock(() => Promise.resolve([["data"]])); - - try { - // Define a callback function - const callback = mock( - (newVal: any, oldVal: any, row: number, rowData: any[]) => {} - ); - - // Set up watching a column - googleSheet.watchColumn("Sheet1!A1:C10", 1, callback, 5000); - - // Allow any pending promises to resolve - await new Promise(process.nextTick); - - // Verify setInterval was called with the correct interval - expect(mockSetInterval).toHaveBeenCalledWith( - expect.any(Function), - 5000 - ); - - // @ts-expect-error - accessing private property for test - expect(googleSheet.watchInterval).toBe(123); - } finally { - // Restore original functions - global.setInterval = originalSetInterval; - // @ts-expect-error - accessing private method for test - googleSheet.fetchData = originalFetchData; - } - }); - - test("stopWatching clears the interval", () => { - // Mock clearInterval - const originalClearInterval = global.clearInterval; - const mockClearInterval = mock((id: number) => {}); - global.clearInterval = mockClearInterval as any; - - try { - // @ts-expect-error - accessing private property for test - googleSheet.watchInterval = 123; - - // Call stopWatching - googleSheet.stopWatching(); - - // Verify clearInterval was called with the correct ID - expect(mockClearInterval).toHaveBeenCalledWith(123); - - // @ts-expect-error - accessing private property for test - expect(googleSheet.watchInterval).toBeNull(); - } finally { - // Restore original clearInterval - global.clearInterval = originalClearInterval; - } - }); - - test("handles API errors gracefully", async () => { - // Save original fetchCellValue implementation - const originalFetchCellValue = googleSheet.fetchCellValue; - - try { - // Replace fetchCellValue with a version that returns a rejected promise - googleSheet.fetchCellValue = mock(() => { - return Promise.reject(new Error("API Error")); - }); - - // Test that the rejected promise is properly caught - await expect( - googleSheet.fetchCellValue("test-spreadsheet-id", "Sheet1!A1") - ).rejects.toThrow("API Error"); - } finally { - // Restore original method - googleSheet.fetchCellValue = originalFetchCellValue; - } - }); -}); diff --git a/tooling/sparta/src/tsconfig.json b/tooling/sparta/src/tsconfig.json deleted file mode 100644 index f1ae592..0000000 --- a/tooling/sparta/src/tsconfig.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "compilerOptions": { - "target": "ES2020", - "module": "NodeNext", - "moduleResolution": "nodenext", - "outDir": "./dist", - "rootDir": "./", - "strict": true, - "esModuleInterop": true, - "skipLibCheck": true, - "forceConsistentCasingInFileNames": true, - "resolveJsonModule": true - }, - "include": ["**/*.ts"], - "exclude": ["node_modules", "dist"] -} diff --git a/tooling/sparta/src/utils/README.md b/tooling/sparta/src/utils/README.md deleted file mode 100644 index 707b113..0000000 --- a/tooling/sparta/src/utils/README.md +++ /dev/null @@ -1,7 +0,0 @@ -# Utils - -This directory contains utility functions and helpers that are used across the codebase. - -- `inputValidator.ts` - Input validation utilities -- `pagination.ts` - Pagination helpers -- `abis/` - Ethereum contract ABIs (Application Binary Interfaces) diff --git a/tooling/sparta/src/utils/abis/forwarder.ts b/tooling/sparta/src/utils/abis/forwarder.ts deleted file mode 100644 index 7f63d6f..0000000 --- a/tooling/sparta/src/utils/abis/forwarder.ts +++ /dev/null @@ -1,1608 +0,0 @@ -/** - * Forwarder ABI. - */ -export const ForwarderAbi = [ - { - type: "constructor", - inputs: [ - { - name: "__owner", - type: "address", - internalType: "address", - }, - ], - stateMutability: "nonpayable", - }, - { - type: "error", - name: "AddressEmptyCode", - inputs: [ - { - name: "target", - type: "address", - internalType: "address", - }, - ], - }, - { - type: "error", - name: "CoinIssuer__InsufficientMintAvailable", - inputs: [ - { - name: "available", - type: "uint256", - internalType: "uint256", - }, - { - name: "needed", - type: "uint256", - internalType: "uint256", - }, - ], - }, - { - type: "error", - name: "DevNet__InvalidProposer", - inputs: [ - { - name: "expected", - type: "address", - internalType: "address", - }, - { - name: "actual", - type: "address", - internalType: "address", - }, - ], - }, - { - type: "error", - name: "DevNet__NoPruningAllowed", - inputs: [], - }, - { - type: "error", - name: "FailedCall", - inputs: [], - }, - { - type: "error", - name: "FeeJuicePortal__AlreadyInitialized", - inputs: [], - }, - { - type: "error", - name: "FeeJuicePortal__InvalidInitialization", - inputs: [], - }, - { - type: "error", - name: "FeeJuicePortal__Unauthorized", - inputs: [], - }, - { - type: "error", - name: "FeeLib__InvalidFeeAssetPriceModifier", - inputs: [], - }, - { - type: "error", - name: "ForwarderLengthMismatch", - inputs: [ - { - name: "toLength", - type: "uint256", - internalType: "uint256", - }, - { - name: "dataLength", - type: "uint256", - internalType: "uint256", - }, - ], - }, - { - type: "error", - name: "GovernanceProposer__CanOnlyExecuteProposalInPast", - inputs: [], - }, - { - type: "error", - name: "GovernanceProposer__FailedToPropose", - inputs: [ - { - name: "proposal", - type: "address", - internalType: "contract IPayload", - }, - ], - }, - { - type: "error", - name: "GovernanceProposer__InstanceHaveNoCode", - inputs: [ - { - name: "instance", - type: "address", - internalType: "address", - }, - ], - }, - { - type: "error", - name: "GovernanceProposer__InsufficientVotes", - inputs: [ - { - name: "votesCast", - type: "uint256", - internalType: "uint256", - }, - { - name: "votesNeeded", - type: "uint256", - internalType: "uint256", - }, - ], - }, - { - type: "error", - name: "GovernanceProposer__InvalidNAndMValues", - inputs: [ - { - name: "n", - type: "uint256", - internalType: "uint256", - }, - { - name: "m", - type: "uint256", - internalType: "uint256", - }, - ], - }, - { - type: "error", - name: "GovernanceProposer__NCannotBeLargerTHanM", - inputs: [ - { - name: "n", - type: "uint256", - internalType: "uint256", - }, - { - name: "m", - type: "uint256", - internalType: "uint256", - }, - ], - }, - { - type: "error", - name: "GovernanceProposer__OnlyProposerCanVote", - inputs: [ - { - name: "caller", - type: "address", - internalType: "address", - }, - { - name: "proposer", - type: "address", - internalType: "address", - }, - ], - }, - { - type: "error", - name: "GovernanceProposer__ProposalAlreadyExecuted", - inputs: [ - { - name: "roundNumber", - type: "uint256", - internalType: "uint256", - }, - ], - }, - { - type: "error", - name: "GovernanceProposer__ProposalCannotBeAddressZero", - inputs: [], - }, - { - type: "error", - name: "GovernanceProposer__ProposalHaveNoCode", - inputs: [ - { - name: "proposal", - type: "address", - internalType: "contract IPayload", - }, - ], - }, - { - type: "error", - name: "GovernanceProposer__ProposalTooOld", - inputs: [ - { - name: "roundNumber", - type: "uint256", - internalType: "uint256", - }, - { - name: "currentRoundNumber", - type: "uint256", - internalType: "uint256", - }, - ], - }, - { - type: "error", - name: "GovernanceProposer__VoteAlreadyCastForSlot", - inputs: [ - { - name: "slot", - type: "uint256", - internalType: "Slot", - }, - ], - }, - { - type: "error", - name: "Governance__CallFailed", - inputs: [ - { - name: "target", - type: "address", - internalType: "address", - }, - ], - }, - { - type: "error", - name: "Governance__CallerNotGovernanceProposer", - inputs: [ - { - name: "caller", - type: "address", - internalType: "address", - }, - { - name: "governanceProposer", - type: "address", - internalType: "address", - }, - ], - }, - { - type: "error", - name: "Governance__CallerNotSelf", - inputs: [ - { - name: "caller", - type: "address", - internalType: "address", - }, - { - name: "self", - type: "address", - internalType: "address", - }, - ], - }, - { - type: "error", - name: "Governance__CannotCallAsset", - inputs: [], - }, - { - type: "error", - name: "Governance__ConfigurationLib__DifferentialTooBig", - inputs: [], - }, - { - type: "error", - name: "Governance__ConfigurationLib__DifferentialTooSmall", - inputs: [], - }, - { - type: "error", - name: "Governance__ConfigurationLib__InvalidMinimumVotes", - inputs: [], - }, - { - type: "error", - name: "Governance__ConfigurationLib__LockAmountTooSmall", - inputs: [], - }, - { - type: "error", - name: "Governance__ConfigurationLib__QuorumTooBig", - inputs: [], - }, - { - type: "error", - name: "Governance__ConfigurationLib__QuorumTooSmall", - inputs: [], - }, - { - type: "error", - name: "Governance__ConfigurationLib__TimeTooBig", - inputs: [ - { - name: "name", - type: "string", - internalType: "string", - }, - ], - }, - { - type: "error", - name: "Governance__ConfigurationLib__TimeTooSmall", - inputs: [ - { - name: "name", - type: "string", - internalType: "string", - }, - ], - }, - { - type: "error", - name: "Governance__InsufficientPower", - inputs: [ - { - name: "voter", - type: "address", - internalType: "address", - }, - { - name: "have", - type: "uint256", - internalType: "uint256", - }, - { - name: "required", - type: "uint256", - internalType: "uint256", - }, - ], - }, - { - type: "error", - name: "Governance__InvalidConfiguration", - inputs: [], - }, - { - type: "error", - name: "Governance__NoCheckpointsFound", - inputs: [], - }, - { - type: "error", - name: "Governance__ProposalAlreadyDropped", - inputs: [], - }, - { - type: "error", - name: "Governance__ProposalCannotBeDropped", - inputs: [], - }, - { - type: "error", - name: "Governance__ProposalDoesNotExists", - inputs: [ - { - name: "proposalId", - type: "uint256", - internalType: "uint256", - }, - ], - }, - { - type: "error", - name: "Governance__ProposalLib__MoreVoteThanExistNeeded", - inputs: [], - }, - { - type: "error", - name: "Governance__ProposalLib__MoreYeaVoteThanExistNeeded", - inputs: [], - }, - { - type: "error", - name: "Governance__ProposalLib__ZeroMinimum", - inputs: [], - }, - { - type: "error", - name: "Governance__ProposalLib__ZeroVotesNeeded", - inputs: [], - }, - { - type: "error", - name: "Governance__ProposalLib__ZeroYeaVotesNeeded", - inputs: [], - }, - { - type: "error", - name: "Governance__ProposalNotActive", - inputs: [], - }, - { - type: "error", - name: "Governance__ProposalNotExecutable", - inputs: [], - }, - { - type: "error", - name: "Governance__UserLib__NotInPast", - inputs: [], - }, - { - type: "error", - name: "Governance__WithdrawalAlreadyclaimed", - inputs: [], - }, - { - type: "error", - name: "Governance__WithdrawalNotUnlockedYet", - inputs: [ - { - name: "currentTime", - type: "uint256", - internalType: "Timestamp", - }, - { - name: "unlocksAt", - type: "uint256", - internalType: "Timestamp", - }, - ], - }, - { - type: "error", - name: "HeaderLib__InvalidHeaderSize", - inputs: [ - { - name: "expected", - type: "uint256", - internalType: "uint256", - }, - { - name: "actual", - type: "uint256", - internalType: "uint256", - }, - ], - }, - { - type: "error", - name: "HeaderLib__InvalidSlotNumber", - inputs: [ - { - name: "expected", - type: "uint256", - internalType: "Slot", - }, - { - name: "actual", - type: "uint256", - internalType: "Slot", - }, - ], - }, - { - type: "error", - name: "Inbox__ActorTooLarge", - inputs: [ - { - name: "actor", - type: "bytes32", - internalType: "bytes32", - }, - ], - }, - { - type: "error", - name: "Inbox__ContentTooLarge", - inputs: [ - { - name: "content", - type: "bytes32", - internalType: "bytes32", - }, - ], - }, - { - type: "error", - name: "Inbox__MustBuildBeforeConsume", - inputs: [], - }, - { - type: "error", - name: "Inbox__SecretHashTooLarge", - inputs: [ - { - name: "secretHash", - type: "bytes32", - internalType: "bytes32", - }, - ], - }, - { - type: "error", - name: "Inbox__Unauthorized", - inputs: [], - }, - { - type: "error", - name: "InsufficientBalance", - inputs: [ - { - name: "balance", - type: "uint256", - internalType: "uint256", - }, - { - name: "needed", - type: "uint256", - internalType: "uint256", - }, - ], - }, - { - type: "error", - name: "MerkleLib__InvalidRoot", - inputs: [ - { - name: "expected", - type: "bytes32", - internalType: "bytes32", - }, - { - name: "actual", - type: "bytes32", - internalType: "bytes32", - }, - { - name: "leaf", - type: "bytes32", - internalType: "bytes32", - }, - { - name: "leafIndex", - type: "uint256", - internalType: "uint256", - }, - ], - }, - { - type: "error", - name: "Outbox__AlreadyNullified", - inputs: [ - { - name: "l2BlockNumber", - type: "uint256", - internalType: "uint256", - }, - { - name: "leafIndex", - type: "uint256", - internalType: "uint256", - }, - ], - }, - { - type: "error", - name: "Outbox__BlockNotProven", - inputs: [ - { - name: "l2BlockNumber", - type: "uint256", - internalType: "uint256", - }, - ], - }, - { - type: "error", - name: "Outbox__IncompatibleEntryArguments", - inputs: [ - { - name: "messageHash", - type: "bytes32", - internalType: "bytes32", - }, - { - name: "storedFee", - type: "uint64", - internalType: "uint64", - }, - { - name: "feePassed", - type: "uint64", - internalType: "uint64", - }, - { - name: "storedVersion", - type: "uint32", - internalType: "uint32", - }, - { - name: "versionPassed", - type: "uint32", - internalType: "uint32", - }, - { - name: "storedDeadline", - type: "uint32", - internalType: "uint32", - }, - { - name: "deadlinePassed", - type: "uint32", - internalType: "uint32", - }, - ], - }, - { - type: "error", - name: "Outbox__InvalidChainId", - inputs: [], - }, - { - type: "error", - name: "Outbox__InvalidPathLength", - inputs: [ - { - name: "expected", - type: "uint256", - internalType: "uint256", - }, - { - name: "actual", - type: "uint256", - internalType: "uint256", - }, - ], - }, - { - type: "error", - name: "Outbox__InvalidRecipient", - inputs: [ - { - name: "expected", - type: "address", - internalType: "address", - }, - { - name: "actual", - type: "address", - internalType: "address", - }, - ], - }, - { - type: "error", - name: "Outbox__InvalidVersion", - inputs: [ - { - name: "entry", - type: "uint256", - internalType: "uint256", - }, - { - name: "message", - type: "uint256", - internalType: "uint256", - }, - ], - }, - { - type: "error", - name: "Outbox__NothingToConsume", - inputs: [ - { - name: "messageHash", - type: "bytes32", - internalType: "bytes32", - }, - ], - }, - { - type: "error", - name: "Outbox__NothingToConsumeAtBlock", - inputs: [ - { - name: "l2BlockNumber", - type: "uint256", - internalType: "uint256", - }, - ], - }, - { - type: "error", - name: "Outbox__RootAlreadySetAtBlock", - inputs: [ - { - name: "l2BlockNumber", - type: "uint256", - internalType: "uint256", - }, - ], - }, - { - type: "error", - name: "Outbox__Unauthorized", - inputs: [], - }, - { - type: "error", - name: "OwnableInvalidOwner", - inputs: [ - { - name: "owner", - type: "address", - internalType: "address", - }, - ], - }, - { - type: "error", - name: "OwnableUnauthorizedAccount", - inputs: [ - { - name: "account", - type: "address", - internalType: "address", - }, - ], - }, - { - type: "event", - name: "OwnershipTransferred", - inputs: [ - { - name: "previousOwner", - type: "address", - indexed: true, - internalType: "address", - }, - { - name: "newOwner", - type: "address", - indexed: true, - internalType: "address", - }, - ], - anonymous: false, - }, - { - type: "error", - name: "ProofCommitmentEscrow__InsufficientBalance", - inputs: [ - { - name: "balance", - type: "uint256", - internalType: "uint256", - }, - { - name: "requested", - type: "uint256", - internalType: "uint256", - }, - ], - }, - { - type: "error", - name: "ProofCommitmentEscrow__NotOwner", - inputs: [ - { - name: "caller", - type: "address", - internalType: "address", - }, - ], - }, - { - type: "error", - name: "ProofCommitmentEscrow__WithdrawRequestNotReady", - inputs: [ - { - name: "current", - type: "uint256", - internalType: "uint256", - }, - { - name: "readyAt", - type: "uint256", - internalType: "Timestamp", - }, - ], - }, - { - type: "error", - name: "Registry__RollupAlreadyRegistered", - inputs: [ - { - name: "rollup", - type: "address", - internalType: "address", - }, - ], - }, - { - type: "error", - name: "Registry__RollupNotRegistered", - inputs: [ - { - name: "rollup", - type: "address", - internalType: "address", - }, - ], - }, - { - type: "error", - name: "RewardDistributor__InvalidCaller", - inputs: [ - { - name: "caller", - type: "address", - internalType: "address", - }, - { - name: "canonical", - type: "address", - internalType: "address", - }, - ], - }, - { - type: "error", - name: "Rollup__AlreadyClaimed", - inputs: [ - { - name: "prover", - type: "address", - internalType: "address", - }, - { - name: "epoch", - type: "uint256", - internalType: "Epoch", - }, - ], - }, - { - type: "error", - name: "Rollup__InsufficientBondAmount", - inputs: [ - { - name: "minimum", - type: "uint256", - internalType: "uint256", - }, - { - name: "provided", - type: "uint256", - internalType: "uint256", - }, - ], - }, - { - type: "error", - name: "Rollup__InsufficientFundsInEscrow", - inputs: [ - { - name: "required", - type: "uint256", - internalType: "uint256", - }, - { - name: "available", - type: "uint256", - internalType: "uint256", - }, - ], - }, - { - type: "error", - name: "Rollup__InvalidArchive", - inputs: [ - { - name: "expected", - type: "bytes32", - internalType: "bytes32", - }, - { - name: "actual", - type: "bytes32", - internalType: "bytes32", - }, - ], - }, - { - type: "error", - name: "Rollup__InvalidBasisPointFee", - inputs: [ - { - name: "basisPointFee", - type: "uint256", - internalType: "uint256", - }, - ], - }, - { - type: "error", - name: "Rollup__InvalidBlobHash", - inputs: [ - { - name: "blobHash", - type: "bytes32", - internalType: "bytes32", - }, - ], - }, - { - type: "error", - name: "Rollup__InvalidBlobProof", - inputs: [ - { - name: "blobHash", - type: "bytes32", - internalType: "bytes32", - }, - ], - }, - { - type: "error", - name: "Rollup__InvalidBlobPublicInputsHash", - inputs: [ - { - name: "expected", - type: "bytes32", - internalType: "bytes32", - }, - { - name: "actual", - type: "bytes32", - internalType: "bytes32", - }, - ], - }, - { - type: "error", - name: "Rollup__InvalidBlockHash", - inputs: [ - { - name: "expected", - type: "bytes32", - internalType: "bytes32", - }, - { - name: "actual", - type: "bytes32", - internalType: "bytes32", - }, - ], - }, - { - type: "error", - name: "Rollup__InvalidBlockNumber", - inputs: [ - { - name: "expected", - type: "uint256", - internalType: "uint256", - }, - { - name: "actual", - type: "uint256", - internalType: "uint256", - }, - ], - }, - { - type: "error", - name: "Rollup__InvalidChainId", - inputs: [ - { - name: "expected", - type: "uint256", - internalType: "uint256", - }, - { - name: "actual", - type: "uint256", - internalType: "uint256", - }, - ], - }, - { - type: "error", - name: "Rollup__InvalidInHash", - inputs: [ - { - name: "expected", - type: "bytes32", - internalType: "bytes32", - }, - { - name: "actual", - type: "bytes32", - internalType: "bytes32", - }, - ], - }, - { - type: "error", - name: "Rollup__InvalidManaBaseFee", - inputs: [ - { - name: "expected", - type: "uint256", - internalType: "uint256", - }, - { - name: "actual", - type: "uint256", - internalType: "uint256", - }, - ], - }, - { - type: "error", - name: "Rollup__InvalidPreviousArchive", - inputs: [ - { - name: "expected", - type: "bytes32", - internalType: "bytes32", - }, - { - name: "actual", - type: "bytes32", - internalType: "bytes32", - }, - ], - }, - { - type: "error", - name: "Rollup__InvalidPreviousBlockHash", - inputs: [ - { - name: "expected", - type: "bytes32", - internalType: "bytes32", - }, - { - name: "actual", - type: "bytes32", - internalType: "bytes32", - }, - ], - }, - { - type: "error", - name: "Rollup__InvalidProof", - inputs: [], - }, - { - type: "error", - name: "Rollup__InvalidProposedArchive", - inputs: [ - { - name: "expected", - type: "bytes32", - internalType: "bytes32", - }, - { - name: "actual", - type: "bytes32", - internalType: "bytes32", - }, - ], - }, - { - type: "error", - name: "Rollup__InvalidTimestamp", - inputs: [ - { - name: "expected", - type: "uint256", - internalType: "Timestamp", - }, - { - name: "actual", - type: "uint256", - internalType: "Timestamp", - }, - ], - }, - { - type: "error", - name: "Rollup__InvalidVersion", - inputs: [ - { - name: "expected", - type: "uint256", - internalType: "uint256", - }, - { - name: "actual", - type: "uint256", - internalType: "uint256", - }, - ], - }, - { - type: "error", - name: "Rollup__ManaLimitExceeded", - inputs: [], - }, - { - type: "error", - name: "Rollup__NoEpochToProve", - inputs: [], - }, - { - type: "error", - name: "Rollup__NonSequentialProving", - inputs: [], - }, - { - type: "error", - name: "Rollup__NonZeroDaFee", - inputs: [], - }, - { - type: "error", - name: "Rollup__NotPastDeadline", - inputs: [ - { - name: "deadline", - type: "uint256", - internalType: "Slot", - }, - { - name: "currentSlot", - type: "uint256", - internalType: "Slot", - }, - ], - }, - { - type: "error", - name: "Rollup__NothingToPrune", - inputs: [], - }, - { - type: "error", - name: "Rollup__PastDeadline", - inputs: [ - { - name: "deadline", - type: "uint256", - internalType: "Slot", - }, - { - name: "currentSlot", - type: "uint256", - internalType: "Slot", - }, - ], - }, - { - type: "error", - name: "Rollup__ProverHaveAlreadySubmitted", - inputs: [ - { - name: "prover", - type: "address", - internalType: "address", - }, - { - name: "epoch", - type: "uint256", - internalType: "Epoch", - }, - ], - }, - { - type: "error", - name: "Rollup__SlotAlreadyInChain", - inputs: [ - { - name: "lastSlot", - type: "uint256", - internalType: "Slot", - }, - { - name: "proposedSlot", - type: "uint256", - internalType: "Slot", - }, - ], - }, - { - type: "error", - name: "Rollup__StartAndEndNotSameEpoch", - inputs: [ - { - name: "start", - type: "uint256", - internalType: "Epoch", - }, - { - name: "end", - type: "uint256", - internalType: "Epoch", - }, - ], - }, - { - type: "error", - name: "Rollup__StartIsNotBuildingOnProven", - inputs: [], - }, - { - type: "error", - name: "Rollup__StartIsNotFirstBlockOfEpoch", - inputs: [], - }, - { - type: "error", - name: "Rollup__TimestampInFuture", - inputs: [ - { - name: "max", - type: "uint256", - internalType: "Timestamp", - }, - { - name: "actual", - type: "uint256", - internalType: "Timestamp", - }, - ], - }, - { - type: "error", - name: "Rollup__TimestampTooOld", - inputs: [], - }, - { - type: "error", - name: "Rollup__TryingToProveNonExistingBlock", - inputs: [], - }, - { - type: "error", - name: "Rollup__UnavailableTxs", - inputs: [ - { - name: "txsHash", - type: "bytes32", - internalType: "bytes32", - }, - ], - }, - { - type: "error", - name: "SampleLib__IndexOutOfBounds", - inputs: [ - { - name: "requested", - type: "uint256", - internalType: "uint256", - }, - { - name: "bound", - type: "uint256", - internalType: "uint256", - }, - ], - }, - { - type: "error", - name: "SignatureLib__CannotVerifyEmpty", - inputs: [], - }, - { - type: "error", - name: "SignatureLib__InvalidSignature", - inputs: [ - { - name: "expected", - type: "address", - internalType: "address", - }, - { - name: "recovered", - type: "address", - internalType: "address", - }, - ], - }, - { - type: "error", - name: "Staking__AlreadyActive", - inputs: [ - { - name: "attester", - type: "address", - internalType: "address", - }, - ], - }, - { - type: "error", - name: "Staking__AlreadyRegistered", - inputs: [ - { - name: "", - type: "address", - internalType: "address", - }, - ], - }, - { - type: "error", - name: "Staking__CannotSlashExitedStake", - inputs: [ - { - name: "", - type: "address", - internalType: "address", - }, - ], - }, - { - type: "error", - name: "Staking__FailedToRemove", - inputs: [ - { - name: "", - type: "address", - internalType: "address", - }, - ], - }, - { - type: "error", - name: "Staking__InsufficientStake", - inputs: [ - { - name: "", - type: "uint256", - internalType: "uint256", - }, - { - name: "", - type: "uint256", - internalType: "uint256", - }, - ], - }, - { - type: "error", - name: "Staking__InvalidDeposit", - inputs: [ - { - name: "attester", - type: "address", - internalType: "address", - }, - { - name: "proposer", - type: "address", - internalType: "address", - }, - ], - }, - { - type: "error", - name: "Staking__NoOneToSlash", - inputs: [ - { - name: "", - type: "address", - internalType: "address", - }, - ], - }, - { - type: "error", - name: "Staking__NotExiting", - inputs: [ - { - name: "", - type: "address", - internalType: "address", - }, - ], - }, - { - type: "error", - name: "Staking__NotSlasher", - inputs: [ - { - name: "", - type: "address", - internalType: "address", - }, - { - name: "", - type: "address", - internalType: "address", - }, - ], - }, - { - type: "error", - name: "Staking__NotWithdrawer", - inputs: [ - { - name: "", - type: "address", - internalType: "address", - }, - { - name: "", - type: "address", - internalType: "address", - }, - ], - }, - { - type: "error", - name: "Staking__NothingToExit", - inputs: [ - { - name: "", - type: "address", - internalType: "address", - }, - ], - }, - { - type: "error", - name: "Staking__WithdrawalNotUnlockedYet", - inputs: [ - { - name: "", - type: "uint256", - internalType: "Timestamp", - }, - { - name: "", - type: "uint256", - internalType: "Timestamp", - }, - ], - }, - { - type: "error", - name: "ValidatorSelection__EpochNotSetup", - inputs: [], - }, - { - type: "error", - name: "ValidatorSelection__InsufficientAttestations", - inputs: [ - { - name: "minimumNeeded", - type: "uint256", - internalType: "uint256", - }, - { - name: "provided", - type: "uint256", - internalType: "uint256", - }, - ], - }, - { - type: "error", - name: "ValidatorSelection__InsufficientAttestationsProvided", - inputs: [ - { - name: "minimumNeeded", - type: "uint256", - internalType: "uint256", - }, - { - name: "provided", - type: "uint256", - internalType: "uint256", - }, - ], - }, - { - type: "error", - name: "ValidatorSelection__InvalidDeposit", - inputs: [ - { - name: "attester", - type: "address", - internalType: "address", - }, - { - name: "proposer", - type: "address", - internalType: "address", - }, - ], - }, - { - type: "error", - name: "ValidatorSelection__InvalidProposer", - inputs: [ - { - name: "expected", - type: "address", - internalType: "address", - }, - { - name: "actual", - type: "address", - internalType: "address", - }, - ], - }, - { - type: "function", - name: "forward", - inputs: [ - { - name: "_to", - type: "address[]", - internalType: "address[]", - }, - { - name: "_data", - type: "bytes[]", - internalType: "bytes[]", - }, - ], - outputs: [], - stateMutability: "nonpayable", - }, - { - type: "function", - name: "owner", - inputs: [], - outputs: [ - { - name: "", - type: "address", - internalType: "address", - }, - ], - stateMutability: "view", - }, - { - type: "function", - name: "renounceOwnership", - inputs: [], - outputs: [], - stateMutability: "nonpayable", - }, - { - type: "function", - name: "transferOwnership", - inputs: [ - { - name: "newOwner", - type: "address", - internalType: "address", - }, - ], - outputs: [], - stateMutability: "nonpayable", - }, -] as const; - -export const ForwarderBytecode = - "0x6080604052348015600e575f5ffd5b506040516105f13803806105f1833981016040819052602b9160b4565b806001600160a01b038116605857604051631e4fbdf760e01b81525f600482015260240160405180910390fd5b605f816065565b505060df565b5f80546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b5f6020828403121560c3575f5ffd5b81516001600160a01b038116811460d8575f5ffd5b9392505050565b610505806100ec5f395ff3fe608060405234801561000f575f5ffd5b506004361061004a575f3560e01c8063715018a61461004e5780638da5cb5b14610058578063b028e60714610076578063f2fde38b14610089575b5f5ffd5b61005661009c565b005b5f54604080516001600160a01b039092168252519081900360200190f35b6100566100843660046103d0565b6100af565b61005661009736600461043c565b610197565b6100a46101d4565b6100ad5f610200565b565b6100b76101d4565b82818181146100e757604051633a2aeb4d60e01b8152600481019290925260248201526044015b60405180910390fd5b505f90505b838110156101905761018783838381811061010957610109610462565b905060200281019061011b9190610476565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525089925088915085905081811061016357610163610462565b9050602002016020810190610178919061043c565b6001600160a01b03169061024f565b506001016100ec565b5050505050565b61019f6101d4565b6001600160a01b0381166101c857604051631e4fbdf760e01b81525f60048201526024016100de565b6101d181610200565b50565b5f546001600160a01b031633146100ad5760405163118cdaa760e01b81523360048201526024016100de565b5f80546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b606061025c83835f610263565b9392505050565b60608147101561028f5760405163cf47918160e01b8152476004820152602481018390526044016100de565b5f5f856001600160a01b031684866040516102aa91906104b9565b5f6040518083038185875af1925050503d805f81146102e4576040519150601f19603f3d011682016040523d82523d5f602084013e6102e9565b606091505b50915091506102f9868383610303565b9695505050505050565b606082610318576103138261035f565b61025c565b815115801561032f57506001600160a01b0384163b155b1561035857604051639996b31560e01b81526001600160a01b03851660048201526024016100de565b508061025c565b80511561036f5780518082602001fd5b60405163d6bda27560e01b815260040160405180910390fd5b5f5f83601f840112610398575f5ffd5b50813567ffffffffffffffff8111156103af575f5ffd5b6020830191508360208260051b85010111156103c9575f5ffd5b9250929050565b5f5f5f5f604085870312156103e3575f5ffd5b843567ffffffffffffffff8111156103f9575f5ffd5b61040587828801610388565b909550935050602085013567ffffffffffffffff811115610424575f5ffd5b61043087828801610388565b95989497509550505050565b5f6020828403121561044c575f5ffd5b81356001600160a01b038116811461025c575f5ffd5b634e487b7160e01b5f52603260045260245ffd5b5f5f8335601e1984360301811261048b575f5ffd5b83018035915067ffffffffffffffff8211156104a5575f5ffd5b6020019150368190038213156103c9575f5ffd5b5f82518060208501845e5f92019182525091905056fea26469706673582212201094da15988f4705d58503cdbc19677b21e89966fdc614400045372c2317a21b64736f6c634300081b0033"; diff --git a/tooling/sparta/src/utils/abis/registryAbi.ts b/tooling/sparta/src/utils/abis/registryAbi.ts deleted file mode 100644 index 5abeb60..0000000 --- a/tooling/sparta/src/utils/abis/registryAbi.ts +++ /dev/null @@ -1,1678 +0,0 @@ -/** - * Registry ABI. - */ -export const RegistryAbi = [ - { - type: "constructor", - inputs: [ - { - name: "_owner", - type: "address", - internalType: "address", - }, - ], - stateMutability: "nonpayable", - }, - { - type: "error", - name: "CoinIssuer__InsufficientMintAvailable", - inputs: [ - { - name: "available", - type: "uint256", - internalType: "uint256", - }, - { - name: "needed", - type: "uint256", - internalType: "uint256", - }, - ], - }, - { - type: "error", - name: "DevNet__InvalidProposer", - inputs: [ - { - name: "expected", - type: "address", - internalType: "address", - }, - { - name: "actual", - type: "address", - internalType: "address", - }, - ], - }, - { - type: "error", - name: "DevNet__NoPruningAllowed", - inputs: [], - }, - { - type: "error", - name: "FeeJuicePortal__AlreadyInitialized", - inputs: [], - }, - { - type: "error", - name: "FeeJuicePortal__InvalidInitialization", - inputs: [], - }, - { - type: "error", - name: "FeeJuicePortal__Unauthorized", - inputs: [], - }, - { - type: "error", - name: "FeeMath__InvalidFeeAssetPriceModifier", - inputs: [], - }, - { - type: "error", - name: "FeeMath__InvalidProvingCostModifier", - inputs: [], - }, - { - type: "error", - name: "GovernanceProposer__CanOnlyExecuteProposalInPast", - inputs: [], - }, - { - type: "error", - name: "GovernanceProposer__FailedToPropose", - inputs: [ - { - name: "proposal", - type: "address", - internalType: "contract IPayload", - }, - ], - }, - { - type: "error", - name: "GovernanceProposer__InstanceHaveNoCode", - inputs: [ - { - name: "instance", - type: "address", - internalType: "address", - }, - ], - }, - { - type: "error", - name: "GovernanceProposer__InsufficientVotes", - inputs: [ - { - name: "votesCast", - type: "uint256", - internalType: "uint256", - }, - { - name: "votesNeeded", - type: "uint256", - internalType: "uint256", - }, - ], - }, - { - type: "error", - name: "GovernanceProposer__InvalidNAndMValues", - inputs: [ - { - name: "n", - type: "uint256", - internalType: "uint256", - }, - { - name: "m", - type: "uint256", - internalType: "uint256", - }, - ], - }, - { - type: "error", - name: "GovernanceProposer__NCannotBeLargerTHanM", - inputs: [ - { - name: "n", - type: "uint256", - internalType: "uint256", - }, - { - name: "m", - type: "uint256", - internalType: "uint256", - }, - ], - }, - { - type: "error", - name: "GovernanceProposer__OnlyProposerCanVote", - inputs: [ - { - name: "caller", - type: "address", - internalType: "address", - }, - { - name: "proposer", - type: "address", - internalType: "address", - }, - ], - }, - { - type: "error", - name: "GovernanceProposer__ProposalAlreadyExecuted", - inputs: [ - { - name: "roundNumber", - type: "uint256", - internalType: "uint256", - }, - ], - }, - { - type: "error", - name: "GovernanceProposer__ProposalCannotBeAddressZero", - inputs: [], - }, - { - type: "error", - name: "GovernanceProposer__ProposalHaveNoCode", - inputs: [ - { - name: "proposal", - type: "address", - internalType: "contract IPayload", - }, - ], - }, - { - type: "error", - name: "GovernanceProposer__ProposalTooOld", - inputs: [ - { - name: "roundNumber", - type: "uint256", - internalType: "uint256", - }, - { - name: "currentRoundNumber", - type: "uint256", - internalType: "uint256", - }, - ], - }, - { - type: "error", - name: "GovernanceProposer__VoteAlreadyCastForSlot", - inputs: [ - { - name: "slot", - type: "uint256", - internalType: "Slot", - }, - ], - }, - { - type: "error", - name: "Governance__CallFailed", - inputs: [ - { - name: "target", - type: "address", - internalType: "address", - }, - ], - }, - { - type: "error", - name: "Governance__CallerNotGovernanceProposer", - inputs: [ - { - name: "caller", - type: "address", - internalType: "address", - }, - { - name: "governanceProposer", - type: "address", - internalType: "address", - }, - ], - }, - { - type: "error", - name: "Governance__CallerNotSelf", - inputs: [ - { - name: "caller", - type: "address", - internalType: "address", - }, - { - name: "self", - type: "address", - internalType: "address", - }, - ], - }, - { - type: "error", - name: "Governance__CannotCallAsset", - inputs: [], - }, - { - type: "error", - name: "Governance__ConfigurationLib__DifferentialTooBig", - inputs: [], - }, - { - type: "error", - name: "Governance__ConfigurationLib__DifferentialTooSmall", - inputs: [], - }, - { - type: "error", - name: "Governance__ConfigurationLib__InvalidMinimumVotes", - inputs: [], - }, - { - type: "error", - name: "Governance__ConfigurationLib__LockAmountTooSmall", - inputs: [], - }, - { - type: "error", - name: "Governance__ConfigurationLib__QuorumTooBig", - inputs: [], - }, - { - type: "error", - name: "Governance__ConfigurationLib__QuorumTooSmall", - inputs: [], - }, - { - type: "error", - name: "Governance__ConfigurationLib__TimeTooBig", - inputs: [ - { - name: "name", - type: "string", - internalType: "string", - }, - ], - }, - { - type: "error", - name: "Governance__ConfigurationLib__TimeTooSmall", - inputs: [ - { - name: "name", - type: "string", - internalType: "string", - }, - ], - }, - { - type: "error", - name: "Governance__InsufficientPower", - inputs: [ - { - name: "voter", - type: "address", - internalType: "address", - }, - { - name: "have", - type: "uint256", - internalType: "uint256", - }, - { - name: "required", - type: "uint256", - internalType: "uint256", - }, - ], - }, - { - type: "error", - name: "Governance__InvalidConfiguration", - inputs: [], - }, - { - type: "error", - name: "Governance__NoCheckpointsFound", - inputs: [], - }, - { - type: "error", - name: "Governance__ProposalAlreadyDropped", - inputs: [], - }, - { - type: "error", - name: "Governance__ProposalCannotBeDropped", - inputs: [], - }, - { - type: "error", - name: "Governance__ProposalDoesNotExists", - inputs: [ - { - name: "proposalId", - type: "uint256", - internalType: "uint256", - }, - ], - }, - { - type: "error", - name: "Governance__ProposalLib__MoreVoteThanExistNeeded", - inputs: [], - }, - { - type: "error", - name: "Governance__ProposalLib__MoreYeaVoteThanExistNeeded", - inputs: [], - }, - { - type: "error", - name: "Governance__ProposalLib__ZeroMinimum", - inputs: [], - }, - { - type: "error", - name: "Governance__ProposalLib__ZeroVotesNeeded", - inputs: [], - }, - { - type: "error", - name: "Governance__ProposalLib__ZeroYeaVotesNeeded", - inputs: [], - }, - { - type: "error", - name: "Governance__ProposalNotActive", - inputs: [], - }, - { - type: "error", - name: "Governance__ProposalNotExecutable", - inputs: [], - }, - { - type: "error", - name: "Governance__UserLib__NotInPast", - inputs: [], - }, - { - type: "error", - name: "Governance__WithdrawalAlreadyclaimed", - inputs: [], - }, - { - type: "error", - name: "Governance__WithdrawalNotUnlockedYet", - inputs: [ - { - name: "currentTime", - type: "uint256", - internalType: "Timestamp", - }, - { - name: "unlocksAt", - type: "uint256", - internalType: "Timestamp", - }, - ], - }, - { - type: "error", - name: "HeaderLib__InvalidHeaderSize", - inputs: [ - { - name: "expected", - type: "uint256", - internalType: "uint256", - }, - { - name: "actual", - type: "uint256", - internalType: "uint256", - }, - ], - }, - { - type: "error", - name: "HeaderLib__InvalidSlotNumber", - inputs: [ - { - name: "expected", - type: "uint256", - internalType: "Slot", - }, - { - name: "actual", - type: "uint256", - internalType: "Slot", - }, - ], - }, - { - type: "error", - name: "Inbox__ActorTooLarge", - inputs: [ - { - name: "actor", - type: "bytes32", - internalType: "bytes32", - }, - ], - }, - { - type: "error", - name: "Inbox__ContentTooLarge", - inputs: [ - { - name: "content", - type: "bytes32", - internalType: "bytes32", - }, - ], - }, - { - type: "error", - name: "Inbox__MustBuildBeforeConsume", - inputs: [], - }, - { - type: "error", - name: "Inbox__SecretHashTooLarge", - inputs: [ - { - name: "secretHash", - type: "bytes32", - internalType: "bytes32", - }, - ], - }, - { - type: "error", - name: "Inbox__Unauthorized", - inputs: [], - }, - { - type: "event", - name: "InstanceAdded", - inputs: [ - { - name: "instance", - type: "address", - indexed: true, - internalType: "address", - }, - { - name: "version", - type: "uint256", - indexed: true, - internalType: "uint256", - }, - ], - anonymous: false, - }, - { - type: "error", - name: "MerkleLib__InvalidRoot", - inputs: [ - { - name: "expected", - type: "bytes32", - internalType: "bytes32", - }, - { - name: "actual", - type: "bytes32", - internalType: "bytes32", - }, - { - name: "leaf", - type: "bytes32", - internalType: "bytes32", - }, - { - name: "leafIndex", - type: "uint256", - internalType: "uint256", - }, - ], - }, - { - type: "error", - name: "Outbox__AlreadyNullified", - inputs: [ - { - name: "l2BlockNumber", - type: "uint256", - internalType: "uint256", - }, - { - name: "leafIndex", - type: "uint256", - internalType: "uint256", - }, - ], - }, - { - type: "error", - name: "Outbox__BlockNotProven", - inputs: [ - { - name: "l2BlockNumber", - type: "uint256", - internalType: "uint256", - }, - ], - }, - { - type: "error", - name: "Outbox__IncompatibleEntryArguments", - inputs: [ - { - name: "messageHash", - type: "bytes32", - internalType: "bytes32", - }, - { - name: "storedFee", - type: "uint64", - internalType: "uint64", - }, - { - name: "feePassed", - type: "uint64", - internalType: "uint64", - }, - { - name: "storedVersion", - type: "uint32", - internalType: "uint32", - }, - { - name: "versionPassed", - type: "uint32", - internalType: "uint32", - }, - { - name: "storedDeadline", - type: "uint32", - internalType: "uint32", - }, - { - name: "deadlinePassed", - type: "uint32", - internalType: "uint32", - }, - ], - }, - { - type: "error", - name: "Outbox__InvalidChainId", - inputs: [], - }, - { - type: "error", - name: "Outbox__InvalidPathLength", - inputs: [ - { - name: "expected", - type: "uint256", - internalType: "uint256", - }, - { - name: "actual", - type: "uint256", - internalType: "uint256", - }, - ], - }, - { - type: "error", - name: "Outbox__InvalidRecipient", - inputs: [ - { - name: "expected", - type: "address", - internalType: "address", - }, - { - name: "actual", - type: "address", - internalType: "address", - }, - ], - }, - { - type: "error", - name: "Outbox__InvalidVersion", - inputs: [ - { - name: "entry", - type: "uint256", - internalType: "uint256", - }, - { - name: "message", - type: "uint256", - internalType: "uint256", - }, - ], - }, - { - type: "error", - name: "Outbox__NothingToConsume", - inputs: [ - { - name: "messageHash", - type: "bytes32", - internalType: "bytes32", - }, - ], - }, - { - type: "error", - name: "Outbox__NothingToConsumeAtBlock", - inputs: [ - { - name: "l2BlockNumber", - type: "uint256", - internalType: "uint256", - }, - ], - }, - { - type: "error", - name: "Outbox__RootAlreadySetAtBlock", - inputs: [ - { - name: "l2BlockNumber", - type: "uint256", - internalType: "uint256", - }, - ], - }, - { - type: "error", - name: "Outbox__Unauthorized", - inputs: [], - }, - { - type: "error", - name: "OwnableInvalidOwner", - inputs: [ - { - name: "owner", - type: "address", - internalType: "address", - }, - ], - }, - { - type: "error", - name: "OwnableUnauthorizedAccount", - inputs: [ - { - name: "account", - type: "address", - internalType: "address", - }, - ], - }, - { - type: "event", - name: "OwnershipTransferred", - inputs: [ - { - name: "previousOwner", - type: "address", - indexed: true, - internalType: "address", - }, - { - name: "newOwner", - type: "address", - indexed: true, - internalType: "address", - }, - ], - anonymous: false, - }, - { - type: "error", - name: "ProofCommitmentEscrow__InsufficientBalance", - inputs: [ - { - name: "balance", - type: "uint256", - internalType: "uint256", - }, - { - name: "requested", - type: "uint256", - internalType: "uint256", - }, - ], - }, - { - type: "error", - name: "ProofCommitmentEscrow__NotOwner", - inputs: [ - { - name: "caller", - type: "address", - internalType: "address", - }, - ], - }, - { - type: "error", - name: "ProofCommitmentEscrow__WithdrawRequestNotReady", - inputs: [ - { - name: "current", - type: "uint256", - internalType: "uint256", - }, - { - name: "readyAt", - type: "uint256", - internalType: "Timestamp", - }, - ], - }, - { - type: "error", - name: "Registry__RollupAlreadyRegistered", - inputs: [ - { - name: "rollup", - type: "address", - internalType: "address", - }, - ], - }, - { - type: "error", - name: "Registry__RollupNotRegistered", - inputs: [ - { - name: "rollup", - type: "address", - internalType: "address", - }, - ], - }, - { - type: "error", - name: "RewardDistributor__InvalidCaller", - inputs: [ - { - name: "caller", - type: "address", - internalType: "address", - }, - { - name: "canonical", - type: "address", - internalType: "address", - }, - ], - }, - { - type: "error", - name: "Rollup__InsufficientBondAmount", - inputs: [ - { - name: "minimum", - type: "uint256", - internalType: "uint256", - }, - { - name: "provided", - type: "uint256", - internalType: "uint256", - }, - ], - }, - { - type: "error", - name: "Rollup__InsufficientFundsInEscrow", - inputs: [ - { - name: "required", - type: "uint256", - internalType: "uint256", - }, - { - name: "available", - type: "uint256", - internalType: "uint256", - }, - ], - }, - { - type: "error", - name: "Rollup__InvalidArchive", - inputs: [ - { - name: "expected", - type: "bytes32", - internalType: "bytes32", - }, - { - name: "actual", - type: "bytes32", - internalType: "bytes32", - }, - ], - }, - { - type: "error", - name: "Rollup__InvalidBasisPointFee", - inputs: [ - { - name: "basisPointFee", - type: "uint256", - internalType: "uint256", - }, - ], - }, - { - type: "error", - name: "Rollup__InvalidBlobHash", - inputs: [ - { - name: "blobHash", - type: "bytes32", - internalType: "bytes32", - }, - ], - }, - { - type: "error", - name: "Rollup__InvalidBlobProof", - inputs: [ - { - name: "blobHash", - type: "bytes32", - internalType: "bytes32", - }, - ], - }, - { - type: "error", - name: "Rollup__InvalidBlobPublicInputsHash", - inputs: [ - { - name: "expected", - type: "bytes32", - internalType: "bytes32", - }, - { - name: "actual", - type: "bytes32", - internalType: "bytes32", - }, - ], - }, - { - type: "error", - name: "Rollup__InvalidBlockHash", - inputs: [ - { - name: "expected", - type: "bytes32", - internalType: "bytes32", - }, - { - name: "actual", - type: "bytes32", - internalType: "bytes32", - }, - ], - }, - { - type: "error", - name: "Rollup__InvalidBlockNumber", - inputs: [ - { - name: "expected", - type: "uint256", - internalType: "uint256", - }, - { - name: "actual", - type: "uint256", - internalType: "uint256", - }, - ], - }, - { - type: "error", - name: "Rollup__InvalidChainId", - inputs: [ - { - name: "expected", - type: "uint256", - internalType: "uint256", - }, - { - name: "actual", - type: "uint256", - internalType: "uint256", - }, - ], - }, - { - type: "error", - name: "Rollup__InvalidEpoch", - inputs: [ - { - name: "expected", - type: "uint256", - internalType: "Epoch", - }, - { - name: "actual", - type: "uint256", - internalType: "Epoch", - }, - ], - }, - { - type: "error", - name: "Rollup__InvalidInHash", - inputs: [ - { - name: "expected", - type: "bytes32", - internalType: "bytes32", - }, - { - name: "actual", - type: "bytes32", - internalType: "bytes32", - }, - ], - }, - { - type: "error", - name: "Rollup__InvalidManaBaseFee", - inputs: [ - { - name: "expected", - type: "uint256", - internalType: "uint256", - }, - { - name: "actual", - type: "uint256", - internalType: "uint256", - }, - ], - }, - { - type: "error", - name: "Rollup__InvalidPreviousArchive", - inputs: [ - { - name: "expected", - type: "bytes32", - internalType: "bytes32", - }, - { - name: "actual", - type: "bytes32", - internalType: "bytes32", - }, - ], - }, - { - type: "error", - name: "Rollup__InvalidPreviousBlockHash", - inputs: [ - { - name: "expected", - type: "bytes32", - internalType: "bytes32", - }, - { - name: "actual", - type: "bytes32", - internalType: "bytes32", - }, - ], - }, - { - type: "error", - name: "Rollup__InvalidProof", - inputs: [], - }, - { - type: "error", - name: "Rollup__InvalidProposedArchive", - inputs: [ - { - name: "expected", - type: "bytes32", - internalType: "bytes32", - }, - { - name: "actual", - type: "bytes32", - internalType: "bytes32", - }, - ], - }, - { - type: "error", - name: "Rollup__InvalidTimestamp", - inputs: [ - { - name: "expected", - type: "uint256", - internalType: "Timestamp", - }, - { - name: "actual", - type: "uint256", - internalType: "Timestamp", - }, - ], - }, - { - type: "error", - name: "Rollup__InvalidVersion", - inputs: [ - { - name: "expected", - type: "uint256", - internalType: "uint256", - }, - { - name: "actual", - type: "uint256", - internalType: "uint256", - }, - ], - }, - { - type: "error", - name: "Rollup__NoEpochToProve", - inputs: [], - }, - { - type: "error", - name: "Rollup__NonSequentialProving", - inputs: [], - }, - { - type: "error", - name: "Rollup__NonZeroDaFee", - inputs: [], - }, - { - type: "error", - name: "Rollup__NonZeroL2Fee", - inputs: [], - }, - { - type: "error", - name: "Rollup__NotClaimingCorrectEpoch", - inputs: [ - { - name: "expected", - type: "uint256", - internalType: "Epoch", - }, - { - name: "actual", - type: "uint256", - internalType: "Epoch", - }, - ], - }, - { - type: "error", - name: "Rollup__NotInClaimPhase", - inputs: [ - { - name: "currentSlotInEpoch", - type: "uint256", - internalType: "uint256", - }, - { - name: "claimDuration", - type: "uint256", - internalType: "uint256", - }, - ], - }, - { - type: "error", - name: "Rollup__NothingToPrune", - inputs: [], - }, - { - type: "error", - name: "Rollup__ProofRightAlreadyClaimed", - inputs: [], - }, - { - type: "error", - name: "Rollup__QuoteExpired", - inputs: [ - { - name: "currentSlot", - type: "uint256", - internalType: "Slot", - }, - { - name: "quoteSlot", - type: "uint256", - internalType: "Slot", - }, - ], - }, - { - type: "error", - name: "Rollup__SlotAlreadyInChain", - inputs: [ - { - name: "lastSlot", - type: "uint256", - internalType: "Slot", - }, - { - name: "proposedSlot", - type: "uint256", - internalType: "Slot", - }, - ], - }, - { - type: "error", - name: "Rollup__TimestampInFuture", - inputs: [ - { - name: "max", - type: "uint256", - internalType: "Timestamp", - }, - { - name: "actual", - type: "uint256", - internalType: "Timestamp", - }, - ], - }, - { - type: "error", - name: "Rollup__TimestampTooOld", - inputs: [], - }, - { - type: "error", - name: "Rollup__TryingToProveNonExistingBlock", - inputs: [], - }, - { - type: "error", - name: "Rollup__UnavailableTxs", - inputs: [ - { - name: "txsHash", - type: "bytes32", - internalType: "bytes32", - }, - ], - }, - { - type: "error", - name: "SampleLib__IndexOutOfBounds", - inputs: [ - { - name: "requested", - type: "uint256", - internalType: "uint256", - }, - { - name: "bound", - type: "uint256", - internalType: "uint256", - }, - ], - }, - { - type: "error", - name: "SignatureLib__CannotVerifyEmpty", - inputs: [], - }, - { - type: "error", - name: "SignatureLib__InvalidSignature", - inputs: [ - { - name: "expected", - type: "address", - internalType: "address", - }, - { - name: "recovered", - type: "address", - internalType: "address", - }, - ], - }, - { - type: "error", - name: "Staking__AlreadyActive", - inputs: [ - { - name: "attester", - type: "address", - internalType: "address", - }, - ], - }, - { - type: "error", - name: "Staking__AlreadyRegistered", - inputs: [ - { - name: "", - type: "address", - internalType: "address", - }, - ], - }, - { - type: "error", - name: "Staking__CannotSlashExitedStake", - inputs: [ - { - name: "", - type: "address", - internalType: "address", - }, - ], - }, - { - type: "error", - name: "Staking__FailedToRemove", - inputs: [ - { - name: "", - type: "address", - internalType: "address", - }, - ], - }, - { - type: "error", - name: "Staking__InsufficientStake", - inputs: [ - { - name: "", - type: "uint256", - internalType: "uint256", - }, - { - name: "", - type: "uint256", - internalType: "uint256", - }, - ], - }, - { - type: "error", - name: "Staking__NoOneToSlash", - inputs: [ - { - name: "", - type: "address", - internalType: "address", - }, - ], - }, - { - type: "error", - name: "Staking__NotExiting", - inputs: [ - { - name: "", - type: "address", - internalType: "address", - }, - ], - }, - { - type: "error", - name: "Staking__NotSlasher", - inputs: [ - { - name: "", - type: "address", - internalType: "address", - }, - { - name: "", - type: "address", - internalType: "address", - }, - ], - }, - { - type: "error", - name: "Staking__NotWithdrawer", - inputs: [ - { - name: "", - type: "address", - internalType: "address", - }, - { - name: "", - type: "address", - internalType: "address", - }, - ], - }, - { - type: "error", - name: "Staking__NothingToExit", - inputs: [ - { - name: "", - type: "address", - internalType: "address", - }, - ], - }, - { - type: "error", - name: "Staking__WithdrawalNotUnlockedYet", - inputs: [ - { - name: "", - type: "uint256", - internalType: "Timestamp", - }, - { - name: "", - type: "uint256", - internalType: "Timestamp", - }, - ], - }, - { - type: "error", - name: "ValidatorSelection__EpochNotSetup", - inputs: [], - }, - { - type: "error", - name: "ValidatorSelection__InsufficientAttestations", - inputs: [ - { - name: "minimumNeeded", - type: "uint256", - internalType: "uint256", - }, - { - name: "provided", - type: "uint256", - internalType: "uint256", - }, - ], - }, - { - type: "error", - name: "ValidatorSelection__InsufficientAttestationsProvided", - inputs: [ - { - name: "minimumNeeded", - type: "uint256", - internalType: "uint256", - }, - { - name: "provided", - type: "uint256", - internalType: "uint256", - }, - ], - }, - { - type: "error", - name: "ValidatorSelection__InvalidDeposit", - inputs: [ - { - name: "attester", - type: "address", - internalType: "address", - }, - { - name: "proposer", - type: "address", - internalType: "address", - }, - ], - }, - { - type: "error", - name: "ValidatorSelection__InvalidProposer", - inputs: [ - { - name: "expected", - type: "address", - internalType: "address", - }, - { - name: "actual", - type: "address", - internalType: "address", - }, - ], - }, - { - type: "function", - name: "getCurrentSnapshot", - inputs: [], - outputs: [ - { - name: "", - type: "tuple", - internalType: "struct DataStructures.RegistrySnapshot", - components: [ - { - name: "rollup", - type: "address", - internalType: "address", - }, - { - name: "blockNumber", - type: "uint256", - internalType: "uint256", - }, - ], - }, - ], - stateMutability: "view", - }, - { - type: "function", - name: "getGovernance", - inputs: [], - outputs: [ - { - name: "", - type: "address", - internalType: "address", - }, - ], - stateMutability: "view", - }, - { - type: "function", - name: "getRollup", - inputs: [], - outputs: [ - { - name: "", - type: "address", - internalType: "address", - }, - ], - stateMutability: "view", - }, - { - type: "function", - name: "getSnapshot", - inputs: [ - { - name: "_version", - type: "uint256", - internalType: "uint256", - }, - ], - outputs: [ - { - name: "", - type: "tuple", - internalType: "struct DataStructures.RegistrySnapshot", - components: [ - { - name: "rollup", - type: "address", - internalType: "address", - }, - { - name: "blockNumber", - type: "uint256", - internalType: "uint256", - }, - ], - }, - ], - stateMutability: "view", - }, - { - type: "function", - name: "getVersionFor", - inputs: [ - { - name: "_rollup", - type: "address", - internalType: "address", - }, - ], - outputs: [ - { - name: "", - type: "uint256", - internalType: "uint256", - }, - ], - stateMutability: "view", - }, - { - type: "function", - name: "isRollupRegistered", - inputs: [ - { - name: "_rollup", - type: "address", - internalType: "address", - }, - ], - outputs: [ - { - name: "", - type: "bool", - internalType: "bool", - }, - ], - stateMutability: "view", - }, - { - type: "function", - name: "numberOfVersions", - inputs: [], - outputs: [ - { - name: "", - type: "uint256", - internalType: "uint256", - }, - ], - stateMutability: "view", - }, - { - type: "function", - name: "owner", - inputs: [], - outputs: [ - { - name: "", - type: "address", - internalType: "address", - }, - ], - stateMutability: "view", - }, - { - type: "function", - name: "renounceOwnership", - inputs: [], - outputs: [], - stateMutability: "nonpayable", - }, - { - type: "function", - name: "transferOwnership", - inputs: [ - { - name: "newOwner", - type: "address", - internalType: "address", - }, - ], - outputs: [], - stateMutability: "nonpayable", - }, - { - type: "function", - name: "upgrade", - inputs: [ - { - name: "_rollup", - type: "address", - internalType: "address", - }, - ], - outputs: [ - { - name: "", - type: "uint256", - internalType: "uint256", - }, - ], - stateMutability: "nonpayable", - }, -] as const; diff --git a/tooling/sparta/src/utils/abis/rollup.ts b/tooling/sparta/src/utils/abis/rollup.ts deleted file mode 100644 index 7892cb0..0000000 --- a/tooling/sparta/src/utils/abis/rollup.ts +++ /dev/null @@ -1,3648 +0,0 @@ -/** - * Rollup ABI. - */ -export const RollupAbi = [ - { - type: "constructor", - inputs: [ - { - name: "_fpcJuicePortal", - type: "address", - internalType: "contract IFeeJuicePortal", - }, - { - name: "_rewardDistributor", - type: "address", - internalType: "contract IRewardDistributor", - }, - { - name: "_stakingAsset", - type: "address", - internalType: "contract IERC20", - }, - { - name: "_governance", - type: "address", - internalType: "address", - }, - { - name: "_genesisState", - type: "tuple", - internalType: "struct GenesisState", - components: [ - { - name: "vkTreeRoot", - type: "bytes32", - internalType: "bytes32", - }, - { - name: "protocolContractTreeRoot", - type: "bytes32", - internalType: "bytes32", - }, - { - name: "genesisArchiveRoot", - type: "bytes32", - internalType: "bytes32", - }, - { - name: "genesisBlockHash", - type: "bytes32", - internalType: "bytes32", - }, - ], - }, - { - name: "_config", - type: "tuple", - internalType: "struct RollupConfigInput", - components: [ - { - name: "aztecSlotDuration", - type: "uint256", - internalType: "uint256", - }, - { - name: "aztecEpochDuration", - type: "uint256", - internalType: "uint256", - }, - { - name: "targetCommitteeSize", - type: "uint256", - internalType: "uint256", - }, - { - name: "aztecProofSubmissionWindow", - type: "uint256", - internalType: "uint256", - }, - { - name: "minimumStake", - type: "uint256", - internalType: "uint256", - }, - { - name: "slashingQuorum", - type: "uint256", - internalType: "uint256", - }, - { - name: "slashingRoundSize", - type: "uint256", - internalType: "uint256", - }, - { - name: "manaTarget", - type: "uint256", - internalType: "uint256", - }, - { - name: "provingCostPerMana", - type: "uint256", - internalType: "EthValue", - }, - ], - }, - ], - stateMutability: "nonpayable", - }, - { - type: "error", - name: "CoinIssuer__InsufficientMintAvailable", - inputs: [ - { - name: "available", - type: "uint256", - internalType: "uint256", - }, - { - name: "needed", - type: "uint256", - internalType: "uint256", - }, - ], - }, - { - type: "event", - name: "Deposit", - inputs: [ - { - name: "attester", - type: "address", - indexed: true, - internalType: "address", - }, - { - name: "proposer", - type: "address", - indexed: true, - internalType: "address", - }, - { - name: "withdrawer", - type: "address", - indexed: true, - internalType: "address", - }, - { - name: "amount", - type: "uint256", - indexed: false, - internalType: "uint256", - }, - ], - anonymous: false, - }, - { - type: "error", - name: "DevNet__InvalidProposer", - inputs: [ - { - name: "expected", - type: "address", - internalType: "address", - }, - { - name: "actual", - type: "address", - internalType: "address", - }, - ], - }, - { - type: "error", - name: "DevNet__NoPruningAllowed", - inputs: [], - }, - { - type: "event", - name: "EIP712DomainChanged", - inputs: [], - anonymous: false, - }, - { - type: "error", - name: "FeeJuicePortal__AlreadyInitialized", - inputs: [], - }, - { - type: "error", - name: "FeeJuicePortal__InvalidInitialization", - inputs: [], - }, - { - type: "error", - name: "FeeJuicePortal__Unauthorized", - inputs: [], - }, - { - type: "error", - name: "FeeLib__InvalidFeeAssetPriceModifier", - inputs: [], - }, - { - type: "error", - name: "GovernanceProposer__CanOnlyExecuteProposalInPast", - inputs: [], - }, - { - type: "error", - name: "GovernanceProposer__FailedToPropose", - inputs: [ - { - name: "proposal", - type: "address", - internalType: "contract IPayload", - }, - ], - }, - { - type: "error", - name: "GovernanceProposer__InstanceHaveNoCode", - inputs: [ - { - name: "instance", - type: "address", - internalType: "address", - }, - ], - }, - { - type: "error", - name: "GovernanceProposer__InsufficientVotes", - inputs: [ - { - name: "votesCast", - type: "uint256", - internalType: "uint256", - }, - { - name: "votesNeeded", - type: "uint256", - internalType: "uint256", - }, - ], - }, - { - type: "error", - name: "GovernanceProposer__InvalidNAndMValues", - inputs: [ - { - name: "n", - type: "uint256", - internalType: "uint256", - }, - { - name: "m", - type: "uint256", - internalType: "uint256", - }, - ], - }, - { - type: "error", - name: "GovernanceProposer__NCannotBeLargerTHanM", - inputs: [ - { - name: "n", - type: "uint256", - internalType: "uint256", - }, - { - name: "m", - type: "uint256", - internalType: "uint256", - }, - ], - }, - { - type: "error", - name: "GovernanceProposer__OnlyProposerCanVote", - inputs: [ - { - name: "caller", - type: "address", - internalType: "address", - }, - { - name: "proposer", - type: "address", - internalType: "address", - }, - ], - }, - { - type: "error", - name: "GovernanceProposer__ProposalAlreadyExecuted", - inputs: [ - { - name: "roundNumber", - type: "uint256", - internalType: "uint256", - }, - ], - }, - { - type: "error", - name: "GovernanceProposer__ProposalCannotBeAddressZero", - inputs: [], - }, - { - type: "error", - name: "GovernanceProposer__ProposalHaveNoCode", - inputs: [ - { - name: "proposal", - type: "address", - internalType: "contract IPayload", - }, - ], - }, - { - type: "error", - name: "GovernanceProposer__ProposalTooOld", - inputs: [ - { - name: "roundNumber", - type: "uint256", - internalType: "uint256", - }, - { - name: "currentRoundNumber", - type: "uint256", - internalType: "uint256", - }, - ], - }, - { - type: "error", - name: "GovernanceProposer__VoteAlreadyCastForSlot", - inputs: [ - { - name: "slot", - type: "uint256", - internalType: "Slot", - }, - ], - }, - { - type: "error", - name: "Governance__CallFailed", - inputs: [ - { - name: "target", - type: "address", - internalType: "address", - }, - ], - }, - { - type: "error", - name: "Governance__CallerNotGovernanceProposer", - inputs: [ - { - name: "caller", - type: "address", - internalType: "address", - }, - { - name: "governanceProposer", - type: "address", - internalType: "address", - }, - ], - }, - { - type: "error", - name: "Governance__CallerNotSelf", - inputs: [ - { - name: "caller", - type: "address", - internalType: "address", - }, - { - name: "self", - type: "address", - internalType: "address", - }, - ], - }, - { - type: "error", - name: "Governance__CannotCallAsset", - inputs: [], - }, - { - type: "error", - name: "Governance__ConfigurationLib__DifferentialTooBig", - inputs: [], - }, - { - type: "error", - name: "Governance__ConfigurationLib__DifferentialTooSmall", - inputs: [], - }, - { - type: "error", - name: "Governance__ConfigurationLib__InvalidMinimumVotes", - inputs: [], - }, - { - type: "error", - name: "Governance__ConfigurationLib__LockAmountTooSmall", - inputs: [], - }, - { - type: "error", - name: "Governance__ConfigurationLib__QuorumTooBig", - inputs: [], - }, - { - type: "error", - name: "Governance__ConfigurationLib__QuorumTooSmall", - inputs: [], - }, - { - type: "error", - name: "Governance__ConfigurationLib__TimeTooBig", - inputs: [ - { - name: "name", - type: "string", - internalType: "string", - }, - ], - }, - { - type: "error", - name: "Governance__ConfigurationLib__TimeTooSmall", - inputs: [ - { - name: "name", - type: "string", - internalType: "string", - }, - ], - }, - { - type: "error", - name: "Governance__InsufficientPower", - inputs: [ - { - name: "voter", - type: "address", - internalType: "address", - }, - { - name: "have", - type: "uint256", - internalType: "uint256", - }, - { - name: "required", - type: "uint256", - internalType: "uint256", - }, - ], - }, - { - type: "error", - name: "Governance__InvalidConfiguration", - inputs: [], - }, - { - type: "error", - name: "Governance__NoCheckpointsFound", - inputs: [], - }, - { - type: "error", - name: "Governance__ProposalAlreadyDropped", - inputs: [], - }, - { - type: "error", - name: "Governance__ProposalCannotBeDropped", - inputs: [], - }, - { - type: "error", - name: "Governance__ProposalDoesNotExists", - inputs: [ - { - name: "proposalId", - type: "uint256", - internalType: "uint256", - }, - ], - }, - { - type: "error", - name: "Governance__ProposalLib__MoreVoteThanExistNeeded", - inputs: [], - }, - { - type: "error", - name: "Governance__ProposalLib__MoreYeaVoteThanExistNeeded", - inputs: [], - }, - { - type: "error", - name: "Governance__ProposalLib__ZeroMinimum", - inputs: [], - }, - { - type: "error", - name: "Governance__ProposalLib__ZeroVotesNeeded", - inputs: [], - }, - { - type: "error", - name: "Governance__ProposalLib__ZeroYeaVotesNeeded", - inputs: [], - }, - { - type: "error", - name: "Governance__ProposalNotActive", - inputs: [], - }, - { - type: "error", - name: "Governance__ProposalNotExecutable", - inputs: [], - }, - { - type: "error", - name: "Governance__UserLib__NotInPast", - inputs: [], - }, - { - type: "error", - name: "Governance__WithdrawalAlreadyclaimed", - inputs: [], - }, - { - type: "error", - name: "Governance__WithdrawalNotUnlockedYet", - inputs: [ - { - name: "currentTime", - type: "uint256", - internalType: "Timestamp", - }, - { - name: "unlocksAt", - type: "uint256", - internalType: "Timestamp", - }, - ], - }, - { - type: "error", - name: "HeaderLib__InvalidHeaderSize", - inputs: [ - { - name: "expected", - type: "uint256", - internalType: "uint256", - }, - { - name: "actual", - type: "uint256", - internalType: "uint256", - }, - ], - }, - { - type: "error", - name: "HeaderLib__InvalidSlotNumber", - inputs: [ - { - name: "expected", - type: "uint256", - internalType: "Slot", - }, - { - name: "actual", - type: "uint256", - internalType: "Slot", - }, - ], - }, - { - type: "error", - name: "Inbox__ActorTooLarge", - inputs: [ - { - name: "actor", - type: "bytes32", - internalType: "bytes32", - }, - ], - }, - { - type: "error", - name: "Inbox__ContentTooLarge", - inputs: [ - { - name: "content", - type: "bytes32", - internalType: "bytes32", - }, - ], - }, - { - type: "error", - name: "Inbox__MustBuildBeforeConsume", - inputs: [], - }, - { - type: "error", - name: "Inbox__SecretHashTooLarge", - inputs: [ - { - name: "secretHash", - type: "bytes32", - internalType: "bytes32", - }, - ], - }, - { - type: "error", - name: "Inbox__Unauthorized", - inputs: [], - }, - { - type: "error", - name: "InvalidShortString", - inputs: [], - }, - { - type: "function", - name: "L1_BLOCK_AT_GENESIS", - inputs: [], - outputs: [ - { - name: "", - type: "uint256", - internalType: "uint256", - }, - ], - stateMutability: "view", - }, - { - type: "event", - name: "L2BlockProposed", - inputs: [ - { - name: "blockNumber", - type: "uint256", - indexed: true, - internalType: "uint256", - }, - { - name: "archive", - type: "bytes32", - indexed: true, - internalType: "bytes32", - }, - { - name: "versionedBlobHashes", - type: "bytes32[]", - indexed: false, - internalType: "bytes32[]", - }, - ], - anonymous: false, - }, - { - type: "event", - name: "L2ProofVerified", - inputs: [ - { - name: "blockNumber", - type: "uint256", - indexed: true, - internalType: "uint256", - }, - { - name: "proverId", - type: "address", - indexed: true, - internalType: "address", - }, - ], - anonymous: false, - }, - { - type: "error", - name: "MerkleLib__InvalidRoot", - inputs: [ - { - name: "expected", - type: "bytes32", - internalType: "bytes32", - }, - { - name: "actual", - type: "bytes32", - internalType: "bytes32", - }, - { - name: "leaf", - type: "bytes32", - internalType: "bytes32", - }, - { - name: "leafIndex", - type: "uint256", - internalType: "uint256", - }, - ], - }, - { - type: "error", - name: "Outbox__AlreadyNullified", - inputs: [ - { - name: "l2BlockNumber", - type: "uint256", - internalType: "uint256", - }, - { - name: "leafIndex", - type: "uint256", - internalType: "uint256", - }, - ], - }, - { - type: "error", - name: "Outbox__BlockNotProven", - inputs: [ - { - name: "l2BlockNumber", - type: "uint256", - internalType: "uint256", - }, - ], - }, - { - type: "error", - name: "Outbox__IncompatibleEntryArguments", - inputs: [ - { - name: "messageHash", - type: "bytes32", - internalType: "bytes32", - }, - { - name: "storedFee", - type: "uint64", - internalType: "uint64", - }, - { - name: "feePassed", - type: "uint64", - internalType: "uint64", - }, - { - name: "storedVersion", - type: "uint32", - internalType: "uint32", - }, - { - name: "versionPassed", - type: "uint32", - internalType: "uint32", - }, - { - name: "storedDeadline", - type: "uint32", - internalType: "uint32", - }, - { - name: "deadlinePassed", - type: "uint32", - internalType: "uint32", - }, - ], - }, - { - type: "error", - name: "Outbox__InvalidChainId", - inputs: [], - }, - { - type: "error", - name: "Outbox__InvalidPathLength", - inputs: [ - { - name: "expected", - type: "uint256", - internalType: "uint256", - }, - { - name: "actual", - type: "uint256", - internalType: "uint256", - }, - ], - }, - { - type: "error", - name: "Outbox__InvalidRecipient", - inputs: [ - { - name: "expected", - type: "address", - internalType: "address", - }, - { - name: "actual", - type: "address", - internalType: "address", - }, - ], - }, - { - type: "error", - name: "Outbox__InvalidVersion", - inputs: [ - { - name: "entry", - type: "uint256", - internalType: "uint256", - }, - { - name: "message", - type: "uint256", - internalType: "uint256", - }, - ], - }, - { - type: "error", - name: "Outbox__NothingToConsume", - inputs: [ - { - name: "messageHash", - type: "bytes32", - internalType: "bytes32", - }, - ], - }, - { - type: "error", - name: "Outbox__NothingToConsumeAtBlock", - inputs: [ - { - name: "l2BlockNumber", - type: "uint256", - internalType: "uint256", - }, - ], - }, - { - type: "error", - name: "Outbox__RootAlreadySetAtBlock", - inputs: [ - { - name: "l2BlockNumber", - type: "uint256", - internalType: "uint256", - }, - ], - }, - { - type: "error", - name: "Outbox__Unauthorized", - inputs: [], - }, - { - type: "error", - name: "OwnableInvalidOwner", - inputs: [ - { - name: "owner", - type: "address", - internalType: "address", - }, - ], - }, - { - type: "error", - name: "OwnableUnauthorizedAccount", - inputs: [ - { - name: "account", - type: "address", - internalType: "address", - }, - ], - }, - { - type: "event", - name: "OwnershipTransferred", - inputs: [ - { - name: "previousOwner", - type: "address", - indexed: true, - internalType: "address", - }, - { - name: "newOwner", - type: "address", - indexed: true, - internalType: "address", - }, - ], - anonymous: false, - }, - { - type: "error", - name: "ProofCommitmentEscrow__InsufficientBalance", - inputs: [ - { - name: "balance", - type: "uint256", - internalType: "uint256", - }, - { - name: "requested", - type: "uint256", - internalType: "uint256", - }, - ], - }, - { - type: "error", - name: "ProofCommitmentEscrow__NotOwner", - inputs: [ - { - name: "caller", - type: "address", - internalType: "address", - }, - ], - }, - { - type: "error", - name: "ProofCommitmentEscrow__WithdrawRequestNotReady", - inputs: [ - { - name: "current", - type: "uint256", - internalType: "uint256", - }, - { - name: "readyAt", - type: "uint256", - internalType: "Timestamp", - }, - ], - }, - { - type: "event", - name: "PrunedPending", - inputs: [ - { - name: "provenBlockNumber", - type: "uint256", - indexed: false, - internalType: "uint256", - }, - { - name: "pendingBlockNumber", - type: "uint256", - indexed: false, - internalType: "uint256", - }, - ], - anonymous: false, - }, - { - type: "error", - name: "Registry__RollupAlreadyRegistered", - inputs: [ - { - name: "rollup", - type: "address", - internalType: "address", - }, - ], - }, - { - type: "error", - name: "Registry__RollupNotRegistered", - inputs: [ - { - name: "rollup", - type: "address", - internalType: "address", - }, - ], - }, - { - type: "error", - name: "RewardDistributor__InvalidCaller", - inputs: [ - { - name: "caller", - type: "address", - internalType: "address", - }, - { - name: "canonical", - type: "address", - internalType: "address", - }, - ], - }, - { - type: "error", - name: "Rollup__AlreadyClaimed", - inputs: [ - { - name: "prover", - type: "address", - internalType: "address", - }, - { - name: "epoch", - type: "uint256", - internalType: "Epoch", - }, - ], - }, - { - type: "error", - name: "Rollup__InsufficientBondAmount", - inputs: [ - { - name: "minimum", - type: "uint256", - internalType: "uint256", - }, - { - name: "provided", - type: "uint256", - internalType: "uint256", - }, - ], - }, - { - type: "error", - name: "Rollup__InsufficientFundsInEscrow", - inputs: [ - { - name: "required", - type: "uint256", - internalType: "uint256", - }, - { - name: "available", - type: "uint256", - internalType: "uint256", - }, - ], - }, - { - type: "error", - name: "Rollup__InvalidArchive", - inputs: [ - { - name: "expected", - type: "bytes32", - internalType: "bytes32", - }, - { - name: "actual", - type: "bytes32", - internalType: "bytes32", - }, - ], - }, - { - type: "error", - name: "Rollup__InvalidBasisPointFee", - inputs: [ - { - name: "basisPointFee", - type: "uint256", - internalType: "uint256", - }, - ], - }, - { - type: "error", - name: "Rollup__InvalidBlobHash", - inputs: [ - { - name: "blobHash", - type: "bytes32", - internalType: "bytes32", - }, - ], - }, - { - type: "error", - name: "Rollup__InvalidBlobProof", - inputs: [ - { - name: "blobHash", - type: "bytes32", - internalType: "bytes32", - }, - ], - }, - { - type: "error", - name: "Rollup__InvalidBlobPublicInputsHash", - inputs: [ - { - name: "expected", - type: "bytes32", - internalType: "bytes32", - }, - { - name: "actual", - type: "bytes32", - internalType: "bytes32", - }, - ], - }, - { - type: "error", - name: "Rollup__InvalidBlockHash", - inputs: [ - { - name: "expected", - type: "bytes32", - internalType: "bytes32", - }, - { - name: "actual", - type: "bytes32", - internalType: "bytes32", - }, - ], - }, - { - type: "error", - name: "Rollup__InvalidBlockNumber", - inputs: [ - { - name: "expected", - type: "uint256", - internalType: "uint256", - }, - { - name: "actual", - type: "uint256", - internalType: "uint256", - }, - ], - }, - { - type: "error", - name: "Rollup__InvalidChainId", - inputs: [ - { - name: "expected", - type: "uint256", - internalType: "uint256", - }, - { - name: "actual", - type: "uint256", - internalType: "uint256", - }, - ], - }, - { - type: "error", - name: "Rollup__InvalidInHash", - inputs: [ - { - name: "expected", - type: "bytes32", - internalType: "bytes32", - }, - { - name: "actual", - type: "bytes32", - internalType: "bytes32", - }, - ], - }, - { - type: "error", - name: "Rollup__InvalidManaBaseFee", - inputs: [ - { - name: "expected", - type: "uint256", - internalType: "uint256", - }, - { - name: "actual", - type: "uint256", - internalType: "uint256", - }, - ], - }, - { - type: "error", - name: "Rollup__InvalidPreviousArchive", - inputs: [ - { - name: "expected", - type: "bytes32", - internalType: "bytes32", - }, - { - name: "actual", - type: "bytes32", - internalType: "bytes32", - }, - ], - }, - { - type: "error", - name: "Rollup__InvalidPreviousBlockHash", - inputs: [ - { - name: "expected", - type: "bytes32", - internalType: "bytes32", - }, - { - name: "actual", - type: "bytes32", - internalType: "bytes32", - }, - ], - }, - { - type: "error", - name: "Rollup__InvalidProof", - inputs: [], - }, - { - type: "error", - name: "Rollup__InvalidProposedArchive", - inputs: [ - { - name: "expected", - type: "bytes32", - internalType: "bytes32", - }, - { - name: "actual", - type: "bytes32", - internalType: "bytes32", - }, - ], - }, - { - type: "error", - name: "Rollup__InvalidTimestamp", - inputs: [ - { - name: "expected", - type: "uint256", - internalType: "Timestamp", - }, - { - name: "actual", - type: "uint256", - internalType: "Timestamp", - }, - ], - }, - { - type: "error", - name: "Rollup__InvalidVersion", - inputs: [ - { - name: "expected", - type: "uint256", - internalType: "uint256", - }, - { - name: "actual", - type: "uint256", - internalType: "uint256", - }, - ], - }, - { - type: "error", - name: "Rollup__ManaLimitExceeded", - inputs: [], - }, - { - type: "error", - name: "Rollup__NoEpochToProve", - inputs: [], - }, - { - type: "error", - name: "Rollup__NonSequentialProving", - inputs: [], - }, - { - type: "error", - name: "Rollup__NonZeroDaFee", - inputs: [], - }, - { - type: "error", - name: "Rollup__NotPastDeadline", - inputs: [ - { - name: "deadline", - type: "uint256", - internalType: "Slot", - }, - { - name: "currentSlot", - type: "uint256", - internalType: "Slot", - }, - ], - }, - { - type: "error", - name: "Rollup__NothingToPrune", - inputs: [], - }, - { - type: "error", - name: "Rollup__PastDeadline", - inputs: [ - { - name: "deadline", - type: "uint256", - internalType: "Slot", - }, - { - name: "currentSlot", - type: "uint256", - internalType: "Slot", - }, - ], - }, - { - type: "error", - name: "Rollup__ProverHaveAlreadySubmitted", - inputs: [ - { - name: "prover", - type: "address", - internalType: "address", - }, - { - name: "epoch", - type: "uint256", - internalType: "Epoch", - }, - ], - }, - { - type: "error", - name: "Rollup__SlotAlreadyInChain", - inputs: [ - { - name: "lastSlot", - type: "uint256", - internalType: "Slot", - }, - { - name: "proposedSlot", - type: "uint256", - internalType: "Slot", - }, - ], - }, - { - type: "error", - name: "Rollup__StartAndEndNotSameEpoch", - inputs: [ - { - name: "start", - type: "uint256", - internalType: "Epoch", - }, - { - name: "end", - type: "uint256", - internalType: "Epoch", - }, - ], - }, - { - type: "error", - name: "Rollup__StartIsNotBuildingOnProven", - inputs: [], - }, - { - type: "error", - name: "Rollup__StartIsNotFirstBlockOfEpoch", - inputs: [], - }, - { - type: "error", - name: "Rollup__TimestampInFuture", - inputs: [ - { - name: "max", - type: "uint256", - internalType: "Timestamp", - }, - { - name: "actual", - type: "uint256", - internalType: "Timestamp", - }, - ], - }, - { - type: "error", - name: "Rollup__TimestampTooOld", - inputs: [], - }, - { - type: "error", - name: "Rollup__TryingToProveNonExistingBlock", - inputs: [], - }, - { - type: "error", - name: "Rollup__UnavailableTxs", - inputs: [ - { - name: "txsHash", - type: "bytes32", - internalType: "bytes32", - }, - ], - }, - { - type: "error", - name: "SafeCastOverflowedIntToUint", - inputs: [ - { - name: "value", - type: "int256", - internalType: "int256", - }, - ], - }, - { - type: "error", - name: "SampleLib__IndexOutOfBounds", - inputs: [ - { - name: "requested", - type: "uint256", - internalType: "uint256", - }, - { - name: "bound", - type: "uint256", - internalType: "uint256", - }, - ], - }, - { - type: "error", - name: "SignatureLib__CannotVerifyEmpty", - inputs: [], - }, - { - type: "error", - name: "SignatureLib__InvalidSignature", - inputs: [ - { - name: "expected", - type: "address", - internalType: "address", - }, - { - name: "recovered", - type: "address", - internalType: "address", - }, - ], - }, - { - type: "event", - name: "Slashed", - inputs: [ - { - name: "attester", - type: "address", - indexed: true, - internalType: "address", - }, - { - name: "amount", - type: "uint256", - indexed: false, - internalType: "uint256", - }, - ], - anonymous: false, - }, - { - type: "error", - name: "Staking__AlreadyActive", - inputs: [ - { - name: "attester", - type: "address", - internalType: "address", - }, - ], - }, - { - type: "error", - name: "Staking__AlreadyRegistered", - inputs: [ - { - name: "", - type: "address", - internalType: "address", - }, - ], - }, - { - type: "error", - name: "Staking__CannotSlashExitedStake", - inputs: [ - { - name: "", - type: "address", - internalType: "address", - }, - ], - }, - { - type: "error", - name: "Staking__FailedToRemove", - inputs: [ - { - name: "", - type: "address", - internalType: "address", - }, - ], - }, - { - type: "error", - name: "Staking__InsufficientStake", - inputs: [ - { - name: "", - type: "uint256", - internalType: "uint256", - }, - { - name: "", - type: "uint256", - internalType: "uint256", - }, - ], - }, - { - type: "error", - name: "Staking__InvalidDeposit", - inputs: [ - { - name: "attester", - type: "address", - internalType: "address", - }, - { - name: "proposer", - type: "address", - internalType: "address", - }, - ], - }, - { - type: "error", - name: "Staking__NoOneToSlash", - inputs: [ - { - name: "", - type: "address", - internalType: "address", - }, - ], - }, - { - type: "error", - name: "Staking__NotExiting", - inputs: [ - { - name: "", - type: "address", - internalType: "address", - }, - ], - }, - { - type: "error", - name: "Staking__NotSlasher", - inputs: [ - { - name: "", - type: "address", - internalType: "address", - }, - { - name: "", - type: "address", - internalType: "address", - }, - ], - }, - { - type: "error", - name: "Staking__NotWithdrawer", - inputs: [ - { - name: "", - type: "address", - internalType: "address", - }, - { - name: "", - type: "address", - internalType: "address", - }, - ], - }, - { - type: "error", - name: "Staking__NothingToExit", - inputs: [ - { - name: "", - type: "address", - internalType: "address", - }, - ], - }, - { - type: "error", - name: "Staking__WithdrawalNotUnlockedYet", - inputs: [ - { - name: "", - type: "uint256", - internalType: "Timestamp", - }, - { - name: "", - type: "uint256", - internalType: "Timestamp", - }, - ], - }, - { - type: "error", - name: "StringTooLong", - inputs: [ - { - name: "str", - type: "string", - internalType: "string", - }, - ], - }, - { - type: "error", - name: "ValidatorSelection__EpochNotSetup", - inputs: [], - }, - { - type: "error", - name: "ValidatorSelection__InsufficientAttestations", - inputs: [ - { - name: "minimumNeeded", - type: "uint256", - internalType: "uint256", - }, - { - name: "provided", - type: "uint256", - internalType: "uint256", - }, - ], - }, - { - type: "error", - name: "ValidatorSelection__InsufficientAttestationsProvided", - inputs: [ - { - name: "minimumNeeded", - type: "uint256", - internalType: "uint256", - }, - { - name: "provided", - type: "uint256", - internalType: "uint256", - }, - ], - }, - { - type: "error", - name: "ValidatorSelection__InvalidDeposit", - inputs: [ - { - name: "attester", - type: "address", - internalType: "address", - }, - { - name: "proposer", - type: "address", - internalType: "address", - }, - ], - }, - { - type: "error", - name: "ValidatorSelection__InvalidProposer", - inputs: [ - { - name: "expected", - type: "address", - internalType: "address", - }, - { - name: "actual", - type: "address", - internalType: "address", - }, - ], - }, - { - type: "event", - name: "WithdrawFinalised", - inputs: [ - { - name: "attester", - type: "address", - indexed: true, - internalType: "address", - }, - { - name: "recipient", - type: "address", - indexed: true, - internalType: "address", - }, - { - name: "amount", - type: "uint256", - indexed: false, - internalType: "uint256", - }, - ], - anonymous: false, - }, - { - type: "event", - name: "WithdrawInitiated", - inputs: [ - { - name: "attester", - type: "address", - indexed: true, - internalType: "address", - }, - { - name: "recipient", - type: "address", - indexed: true, - internalType: "address", - }, - { - name: "amount", - type: "uint256", - indexed: false, - internalType: "uint256", - }, - ], - anonymous: false, - }, - { - type: "function", - name: "archive", - inputs: [], - outputs: [ - { - name: "", - type: "bytes32", - internalType: "bytes32", - }, - ], - stateMutability: "view", - }, - { - type: "function", - name: "archiveAt", - inputs: [ - { - name: "_blockNumber", - type: "uint256", - internalType: "uint256", - }, - ], - outputs: [ - { - name: "", - type: "bytes32", - internalType: "bytes32", - }, - ], - stateMutability: "view", - }, - { - type: "function", - name: "canProposeAtTime", - inputs: [ - { - name: "_ts", - type: "uint256", - internalType: "Timestamp", - }, - { - name: "_archive", - type: "bytes32", - internalType: "bytes32", - }, - ], - outputs: [ - { - name: "", - type: "uint256", - internalType: "Slot", - }, - { - name: "", - type: "uint256", - internalType: "uint256", - }, - ], - stateMutability: "view", - }, - { - type: "function", - name: "canPruneAtTime", - inputs: [ - { - name: "_ts", - type: "uint256", - internalType: "Timestamp", - }, - ], - outputs: [ - { - name: "", - type: "bool", - internalType: "bool", - }, - ], - stateMutability: "view", - }, - { - type: "function", - name: "cheat__InitialiseValidatorSet", - inputs: [ - { - name: "_args", - type: "tuple[]", - internalType: "struct CheatDepositArgs[]", - components: [ - { - name: "attester", - type: "address", - internalType: "address", - }, - { - name: "proposer", - type: "address", - internalType: "address", - }, - { - name: "withdrawer", - type: "address", - internalType: "address", - }, - { - name: "amount", - type: "uint256", - internalType: "uint256", - }, - ], - }, - ], - outputs: [], - stateMutability: "nonpayable", - }, - { - type: "function", - name: "checkBlob", - inputs: [], - outputs: [ - { - name: "", - type: "bool", - internalType: "bool", - }, - ], - stateMutability: "view", - }, - { - type: "function", - name: "claimProverRewards", - inputs: [ - { - name: "_recipient", - type: "address", - internalType: "address", - }, - { - name: "_epochs", - type: "uint256[]", - internalType: "Epoch[]", - }, - ], - outputs: [ - { - name: "", - type: "uint256", - internalType: "uint256", - }, - ], - stateMutability: "nonpayable", - }, - { - type: "function", - name: "claimSequencerRewards", - inputs: [ - { - name: "_recipient", - type: "address", - internalType: "address", - }, - ], - outputs: [ - { - name: "", - type: "uint256", - internalType: "uint256", - }, - ], - stateMutability: "nonpayable", - }, - { - type: "function", - name: "deposit", - inputs: [ - { - name: "_attester", - type: "address", - internalType: "address", - }, - { - name: "_proposer", - type: "address", - internalType: "address", - }, - { - name: "_withdrawer", - type: "address", - internalType: "address", - }, - { - name: "_amount", - type: "uint256", - internalType: "uint256", - }, - ], - outputs: [], - stateMutability: "nonpayable", - }, - { - type: "function", - name: "eip712Domain", - inputs: [], - outputs: [ - { - name: "fields", - type: "bytes1", - internalType: "bytes1", - }, - { - name: "name", - type: "string", - internalType: "string", - }, - { - name: "version", - type: "string", - internalType: "string", - }, - { - name: "chainId", - type: "uint256", - internalType: "uint256", - }, - { - name: "verifyingContract", - type: "address", - internalType: "address", - }, - { - name: "salt", - type: "bytes32", - internalType: "bytes32", - }, - { - name: "extensions", - type: "uint256[]", - internalType: "uint256[]", - }, - ], - stateMutability: "view", - }, - { - type: "function", - name: "finaliseWithdraw", - inputs: [ - { - name: "_attester", - type: "address", - internalType: "address", - }, - ], - outputs: [], - stateMutability: "nonpayable", - }, - { - type: "function", - name: "getActiveAttesterCount", - inputs: [], - outputs: [ - { - name: "", - type: "uint256", - internalType: "uint256", - }, - ], - stateMutability: "view", - }, - { - type: "function", - name: "getAttesterAtIndex", - inputs: [ - { - name: "_index", - type: "uint256", - internalType: "uint256", - }, - ], - outputs: [ - { - name: "", - type: "address", - internalType: "address", - }, - ], - stateMutability: "view", - }, - { - type: "function", - name: "getAttesters", - inputs: [], - outputs: [ - { - name: "", - type: "address[]", - internalType: "address[]", - }, - ], - stateMutability: "view", - }, - { - type: "function", - name: "getBlobPublicInputsHash", - inputs: [ - { - name: "_blockNumber", - type: "uint256", - internalType: "uint256", - }, - ], - outputs: [ - { - name: "", - type: "bytes32", - internalType: "bytes32", - }, - ], - stateMutability: "view", - }, - { - type: "function", - name: "getBlock", - inputs: [ - { - name: "_blockNumber", - type: "uint256", - internalType: "uint256", - }, - ], - outputs: [ - { - name: "", - type: "tuple", - internalType: "struct BlockLog", - components: [ - { - name: "archive", - type: "bytes32", - internalType: "bytes32", - }, - { - name: "blockHash", - type: "bytes32", - internalType: "bytes32", - }, - { - name: "slotNumber", - type: "uint256", - internalType: "Slot", - }, - ], - }, - ], - stateMutability: "view", - }, - { - type: "function", - name: "getBurnAddress", - inputs: [], - outputs: [ - { - name: "", - type: "address", - internalType: "address", - }, - ], - stateMutability: "pure", - }, - { - type: "function", - name: "getCollectiveProverRewardsForEpoch", - inputs: [ - { - name: "_epoch", - type: "uint256", - internalType: "Epoch", - }, - ], - outputs: [ - { - name: "", - type: "uint256", - internalType: "uint256", - }, - ], - stateMutability: "view", - }, - { - type: "function", - name: "getCommitteeAt", - inputs: [ - { - name: "_ts", - type: "uint256", - internalType: "Timestamp", - }, - ], - outputs: [ - { - name: "", - type: "address[]", - internalType: "address[]", - }, - ], - stateMutability: "view", - }, - { - type: "function", - name: "getCurrentEpoch", - inputs: [], - outputs: [ - { - name: "", - type: "uint256", - internalType: "Epoch", - }, - ], - stateMutability: "view", - }, - { - type: "function", - name: "getCurrentEpochCommittee", - inputs: [], - outputs: [ - { - name: "", - type: "address[]", - internalType: "address[]", - }, - ], - stateMutability: "view", - }, - { - type: "function", - name: "getCurrentProposer", - inputs: [], - outputs: [ - { - name: "", - type: "address", - internalType: "address", - }, - ], - stateMutability: "view", - }, - { - type: "function", - name: "getCurrentSampleSeed", - inputs: [], - outputs: [ - { - name: "", - type: "uint256", - internalType: "uint256", - }, - ], - stateMutability: "view", - }, - { - type: "function", - name: "getCurrentSlot", - inputs: [], - outputs: [ - { - name: "", - type: "uint256", - internalType: "Slot", - }, - ], - stateMutability: "view", - }, - { - type: "function", - name: "getEpochAt", - inputs: [ - { - name: "_ts", - type: "uint256", - internalType: "Timestamp", - }, - ], - outputs: [ - { - name: "", - type: "uint256", - internalType: "Epoch", - }, - ], - stateMutability: "view", - }, - { - type: "function", - name: "getEpochAtSlot", - inputs: [ - { - name: "_slotNumber", - type: "uint256", - internalType: "Slot", - }, - ], - outputs: [ - { - name: "", - type: "uint256", - internalType: "Epoch", - }, - ], - stateMutability: "view", - }, - { - type: "function", - name: "getEpochCommittee", - inputs: [ - { - name: "_epoch", - type: "uint256", - internalType: "Epoch", - }, - ], - outputs: [ - { - name: "", - type: "address[]", - internalType: "address[]", - }, - ], - stateMutability: "view", - }, - { - type: "function", - name: "getEpochDuration", - inputs: [], - outputs: [ - { - name: "", - type: "uint256", - internalType: "uint256", - }, - ], - stateMutability: "view", - }, - { - type: "function", - name: "getEpochForBlock", - inputs: [ - { - name: "_blockNumber", - type: "uint256", - internalType: "uint256", - }, - ], - outputs: [ - { - name: "", - type: "uint256", - internalType: "Epoch", - }, - ], - stateMutability: "view", - }, - { - type: "function", - name: "getEpochProofPublicInputs", - inputs: [ - { - name: "_start", - type: "uint256", - internalType: "uint256", - }, - { - name: "_end", - type: "uint256", - internalType: "uint256", - }, - { - name: "_args", - type: "tuple", - internalType: "struct PublicInputArgs", - components: [ - { - name: "previousArchive", - type: "bytes32", - internalType: "bytes32", - }, - { - name: "endArchive", - type: "bytes32", - internalType: "bytes32", - }, - { - name: "previousBlockHash", - type: "bytes32", - internalType: "bytes32", - }, - { - name: "endBlockHash", - type: "bytes32", - internalType: "bytes32", - }, - { - name: "endTimestamp", - type: "uint256", - internalType: "Timestamp", - }, - { - name: "outHash", - type: "bytes32", - internalType: "bytes32", - }, - { - name: "proverId", - type: "address", - internalType: "address", - }, - ], - }, - { - name: "_fees", - type: "bytes32[]", - internalType: "bytes32[]", - }, - { - name: "_blobPublicInputs", - type: "bytes", - internalType: "bytes", - }, - { - name: "_aggregationObject", - type: "bytes", - internalType: "bytes", - }, - ], - outputs: [ - { - name: "", - type: "bytes32[]", - internalType: "bytes32[]", - }, - ], - stateMutability: "view", - }, - { - type: "function", - name: "getExit", - inputs: [ - { - name: "_attester", - type: "address", - internalType: "address", - }, - ], - outputs: [ - { - name: "", - type: "tuple", - internalType: "struct Exit", - components: [ - { - name: "exitableAt", - type: "uint256", - internalType: "Timestamp", - }, - { - name: "recipient", - type: "address", - internalType: "address", - }, - ], - }, - ], - stateMutability: "view", - }, - { - type: "function", - name: "getExitDelay", - inputs: [], - outputs: [ - { - name: "", - type: "uint256", - internalType: "Timestamp", - }, - ], - stateMutability: "view", - }, - { - type: "function", - name: "getFeeAsset", - inputs: [], - outputs: [ - { - name: "", - type: "address", - internalType: "contract IERC20", - }, - ], - stateMutability: "view", - }, - { - type: "function", - name: "getFeeAssetPerEth", - inputs: [], - outputs: [ - { - name: "", - type: "uint256", - internalType: "FeeAssetPerEthE9", - }, - ], - stateMutability: "view", - }, - { - type: "function", - name: "getFeeAssetPortal", - inputs: [], - outputs: [ - { - name: "", - type: "address", - internalType: "contract IFeeJuicePortal", - }, - ], - stateMutability: "view", - }, - { - type: "function", - name: "getFeeHeader", - inputs: [ - { - name: "_blockNumber", - type: "uint256", - internalType: "uint256", - }, - ], - outputs: [ - { - name: "", - type: "tuple", - internalType: "struct FeeHeader", - components: [ - { - name: "excessMana", - type: "uint256", - internalType: "uint256", - }, - { - name: "manaUsed", - type: "uint256", - internalType: "uint256", - }, - { - name: "feeAssetPriceNumerator", - type: "uint256", - internalType: "uint256", - }, - { - name: "congestionCost", - type: "uint256", - internalType: "uint256", - }, - { - name: "provingCost", - type: "uint256", - internalType: "uint256", - }, - ], - }, - ], - stateMutability: "view", - }, - { - type: "function", - name: "getGenesisTime", - inputs: [], - outputs: [ - { - name: "", - type: "uint256", - internalType: "Timestamp", - }, - ], - stateMutability: "view", - }, - { - type: "function", - name: "getHasSubmitted", - inputs: [ - { - name: "_epoch", - type: "uint256", - internalType: "Epoch", - }, - { - name: "_length", - type: "uint256", - internalType: "uint256", - }, - { - name: "_prover", - type: "address", - internalType: "address", - }, - ], - outputs: [ - { - name: "", - type: "bool", - internalType: "bool", - }, - ], - stateMutability: "view", - }, - { - type: "function", - name: "getInbox", - inputs: [], - outputs: [ - { - name: "", - type: "address", - internalType: "contract IInbox", - }, - ], - stateMutability: "view", - }, - { - type: "function", - name: "getInfo", - inputs: [ - { - name: "_attester", - type: "address", - internalType: "address", - }, - ], - outputs: [ - { - name: "", - type: "tuple", - internalType: "struct ValidatorInfo", - components: [ - { - name: "stake", - type: "uint256", - internalType: "uint256", - }, - { - name: "withdrawer", - type: "address", - internalType: "address", - }, - { - name: "proposer", - type: "address", - internalType: "address", - }, - { - name: "status", - type: "uint8", - internalType: "enum Status", - }, - ], - }, - ], - stateMutability: "view", - }, - { - type: "function", - name: "getL1FeesAt", - inputs: [ - { - name: "_timestamp", - type: "uint256", - internalType: "Timestamp", - }, - ], - outputs: [ - { - name: "", - type: "tuple", - internalType: "struct L1FeeData", - components: [ - { - name: "baseFee", - type: "uint256", - internalType: "uint256", - }, - { - name: "blobFee", - type: "uint256", - internalType: "uint256", - }, - ], - }, - ], - stateMutability: "view", - }, - { - type: "function", - name: "getManaBaseFeeAt", - inputs: [ - { - name: "_timestamp", - type: "uint256", - internalType: "Timestamp", - }, - { - name: "_inFeeAsset", - type: "bool", - internalType: "bool", - }, - ], - outputs: [ - { - name: "", - type: "uint256", - internalType: "uint256", - }, - ], - stateMutability: "view", - }, - { - type: "function", - name: "getManaBaseFeeComponentsAt", - inputs: [ - { - name: "_timestamp", - type: "uint256", - internalType: "Timestamp", - }, - { - name: "_inFeeAsset", - type: "bool", - internalType: "bool", - }, - ], - outputs: [ - { - name: "", - type: "tuple", - internalType: "struct ManaBaseFeeComponents", - components: [ - { - name: "congestionCost", - type: "uint256", - internalType: "uint256", - }, - { - name: "congestionMultiplier", - type: "uint256", - internalType: "uint256", - }, - { - name: "dataCost", - type: "uint256", - internalType: "uint256", - }, - { - name: "gasCost", - type: "uint256", - internalType: "uint256", - }, - { - name: "provingCost", - type: "uint256", - internalType: "uint256", - }, - ], - }, - ], - stateMutability: "view", - }, - { - type: "function", - name: "getManaLimit", - inputs: [], - outputs: [ - { - name: "", - type: "uint256", - internalType: "uint256", - }, - ], - stateMutability: "view", - }, - { - type: "function", - name: "getManaTarget", - inputs: [], - outputs: [ - { - name: "", - type: "uint256", - internalType: "uint256", - }, - ], - stateMutability: "view", - }, - { - type: "function", - name: "getMinimumStake", - inputs: [], - outputs: [ - { - name: "", - type: "uint256", - internalType: "uint256", - }, - ], - stateMutability: "view", - }, - { - type: "function", - name: "getOperatorAtIndex", - inputs: [ - { - name: "_index", - type: "uint256", - internalType: "uint256", - }, - ], - outputs: [ - { - name: "", - type: "tuple", - internalType: "struct OperatorInfo", - components: [ - { - name: "proposer", - type: "address", - internalType: "address", - }, - { - name: "attester", - type: "address", - internalType: "address", - }, - ], - }, - ], - stateMutability: "view", - }, - { - type: "function", - name: "getOutbox", - inputs: [], - outputs: [ - { - name: "", - type: "address", - internalType: "contract IOutbox", - }, - ], - stateMutability: "view", - }, - { - type: "function", - name: "getPendingBlockNumber", - inputs: [], - outputs: [ - { - name: "", - type: "uint256", - internalType: "uint256", - }, - ], - stateMutability: "view", - }, - { - type: "function", - name: "getProofSubmissionWindow", - inputs: [], - outputs: [ - { - name: "", - type: "uint256", - internalType: "uint256", - }, - ], - stateMutability: "view", - }, - { - type: "function", - name: "getProposerAt", - inputs: [ - { - name: "_ts", - type: "uint256", - internalType: "Timestamp", - }, - ], - outputs: [ - { - name: "", - type: "address", - internalType: "address", - }, - ], - stateMutability: "view", - }, - { - type: "function", - name: "getProposerAtIndex", - inputs: [ - { - name: "_index", - type: "uint256", - internalType: "uint256", - }, - ], - outputs: [ - { - name: "", - type: "address", - internalType: "address", - }, - ], - stateMutability: "view", - }, - { - type: "function", - name: "getProposerForAttester", - inputs: [ - { - name: "_attester", - type: "address", - internalType: "address", - }, - ], - outputs: [ - { - name: "", - type: "address", - internalType: "address", - }, - ], - stateMutability: "view", - }, - { - type: "function", - name: "getProvenBlockNumber", - inputs: [], - outputs: [ - { - name: "", - type: "uint256", - internalType: "uint256", - }, - ], - stateMutability: "view", - }, - { - type: "function", - name: "getProvingCostPerManaInEth", - inputs: [], - outputs: [ - { - name: "", - type: "uint256", - internalType: "EthValue", - }, - ], - stateMutability: "view", - }, - { - type: "function", - name: "getProvingCostPerManaInFeeAsset", - inputs: [], - outputs: [ - { - name: "", - type: "uint256", - internalType: "FeeAssetValue", - }, - ], - stateMutability: "view", - }, - { - type: "function", - name: "getRewardDistributor", - inputs: [], - outputs: [ - { - name: "", - type: "address", - internalType: "contract IRewardDistributor", - }, - ], - stateMutability: "view", - }, - { - type: "function", - name: "getSampleSeedAt", - inputs: [ - { - name: "_ts", - type: "uint256", - internalType: "Timestamp", - }, - ], - outputs: [ - { - name: "", - type: "uint256", - internalType: "uint256", - }, - ], - stateMutability: "view", - }, - { - type: "function", - name: "getSequencerRewards", - inputs: [ - { - name: "_sequencer", - type: "address", - internalType: "address", - }, - ], - outputs: [ - { - name: "", - type: "uint256", - internalType: "uint256", - }, - ], - stateMutability: "view", - }, - { - type: "function", - name: "getSlasher", - inputs: [], - outputs: [ - { - name: "", - type: "address", - internalType: "address", - }, - ], - stateMutability: "view", - }, - { - type: "function", - name: "getSlotAt", - inputs: [ - { - name: "_ts", - type: "uint256", - internalType: "Timestamp", - }, - ], - outputs: [ - { - name: "", - type: "uint256", - internalType: "Slot", - }, - ], - stateMutability: "view", - }, - { - type: "function", - name: "getSlotDuration", - inputs: [], - outputs: [ - { - name: "", - type: "uint256", - internalType: "uint256", - }, - ], - stateMutability: "view", - }, - { - type: "function", - name: "getSpecificProverRewardsForEpoch", - inputs: [ - { - name: "_epoch", - type: "uint256", - internalType: "Epoch", - }, - { - name: "_prover", - type: "address", - internalType: "address", - }, - ], - outputs: [ - { - name: "", - type: "uint256", - internalType: "uint256", - }, - ], - stateMutability: "view", - }, - { - type: "function", - name: "getStakingAsset", - inputs: [], - outputs: [ - { - name: "", - type: "address", - internalType: "contract IERC20", - }, - ], - stateMutability: "view", - }, - { - type: "function", - name: "getTargetCommitteeSize", - inputs: [], - outputs: [ - { - name: "", - type: "uint256", - internalType: "uint256", - }, - ], - stateMutability: "view", - }, - { - type: "function", - name: "getTimestampForSlot", - inputs: [ - { - name: "_slotNumber", - type: "uint256", - internalType: "Slot", - }, - ], - outputs: [ - { - name: "", - type: "uint256", - internalType: "Timestamp", - }, - ], - stateMutability: "view", - }, - { - type: "function", - name: "getTips", - inputs: [], - outputs: [ - { - name: "", - type: "tuple", - internalType: "struct ChainTips", - components: [ - { - name: "pendingBlockNumber", - type: "uint256", - internalType: "uint256", - }, - { - name: "provenBlockNumber", - type: "uint256", - internalType: "uint256", - }, - ], - }, - ], - stateMutability: "view", - }, - { - type: "function", - name: "getVersion", - inputs: [], - outputs: [ - { - name: "", - type: "uint256", - internalType: "uint256", - }, - ], - stateMutability: "view", - }, - { - type: "function", - name: "initiateWithdraw", - inputs: [ - { - name: "_attester", - type: "address", - internalType: "address", - }, - { - name: "_recipient", - type: "address", - internalType: "address", - }, - ], - outputs: [ - { - name: "", - type: "bool", - internalType: "bool", - }, - ], - stateMutability: "nonpayable", - }, - { - type: "function", - name: "owner", - inputs: [], - outputs: [ - { - name: "", - type: "address", - internalType: "address", - }, - ], - stateMutability: "view", - }, - { - type: "function", - name: "propose", - inputs: [ - { - name: "_args", - type: "tuple", - internalType: "struct ProposeArgs", - components: [ - { - name: "archive", - type: "bytes32", - internalType: "bytes32", - }, - { - name: "blockHash", - type: "bytes32", - internalType: "bytes32", - }, - { - name: "oracleInput", - type: "tuple", - internalType: "struct OracleInput", - components: [ - { - name: "feeAssetPriceModifier", - type: "int256", - internalType: "int256", - }, - ], - }, - { - name: "header", - type: "bytes", - internalType: "bytes", - }, - { - name: "txHashes", - type: "bytes32[]", - internalType: "bytes32[]", - }, - ], - }, - { - name: "_signatures", - type: "tuple[]", - internalType: "struct Signature[]", - components: [ - { - name: "isEmpty", - type: "bool", - internalType: "bool", - }, - { - name: "v", - type: "uint8", - internalType: "uint8", - }, - { - name: "r", - type: "bytes32", - internalType: "bytes32", - }, - { - name: "s", - type: "bytes32", - internalType: "bytes32", - }, - ], - }, - { - name: "_blobInput", - type: "bytes", - internalType: "bytes", - }, - ], - outputs: [], - stateMutability: "nonpayable", - }, - { - type: "function", - name: "prune", - inputs: [], - outputs: [], - stateMutability: "nonpayable", - }, - { - type: "function", - name: "renounceOwnership", - inputs: [], - outputs: [], - stateMutability: "nonpayable", - }, - { - type: "function", - name: "setEpochVerifier", - inputs: [ - { - name: "_verifier", - type: "address", - internalType: "address", - }, - ], - outputs: [], - stateMutability: "nonpayable", - }, - { - type: "function", - name: "setProtocolContractTreeRoot", - inputs: [ - { - name: "_protocolContractTreeRoot", - type: "bytes32", - internalType: "bytes32", - }, - ], - outputs: [], - stateMutability: "nonpayable", - }, - { - type: "function", - name: "setProvingCostPerMana", - inputs: [ - { - name: "_provingCostPerMana", - type: "uint256", - internalType: "EthValue", - }, - ], - outputs: [], - stateMutability: "nonpayable", - }, - { - type: "function", - name: "setVkTreeRoot", - inputs: [ - { - name: "_vkTreeRoot", - type: "bytes32", - internalType: "bytes32", - }, - ], - outputs: [], - stateMutability: "nonpayable", - }, - { - type: "function", - name: "setupEpoch", - inputs: [], - outputs: [], - stateMutability: "nonpayable", - }, - { - type: "function", - name: "slash", - inputs: [ - { - name: "_attester", - type: "address", - internalType: "address", - }, - { - name: "_amount", - type: "uint256", - internalType: "uint256", - }, - ], - outputs: [], - stateMutability: "nonpayable", - }, - { - type: "function", - name: "status", - inputs: [ - { - name: "_myHeaderBlockNumber", - type: "uint256", - internalType: "uint256", - }, - ], - outputs: [ - { - name: "provenBlockNumber", - type: "uint256", - internalType: "uint256", - }, - { - name: "provenArchive", - type: "bytes32", - internalType: "bytes32", - }, - { - name: "pendingBlockNumber", - type: "uint256", - internalType: "uint256", - }, - { - name: "pendingArchive", - type: "bytes32", - internalType: "bytes32", - }, - { - name: "archiveOfMyBlock", - type: "bytes32", - internalType: "bytes32", - }, - { - name: "provenEpochNumber", - type: "uint256", - internalType: "Epoch", - }, - ], - stateMutability: "view", - }, - { - type: "function", - name: "submitEpochRootProof", - inputs: [ - { - name: "_args", - type: "tuple", - internalType: "struct SubmitEpochRootProofArgs", - components: [ - { - name: "start", - type: "uint256", - internalType: "uint256", - }, - { - name: "end", - type: "uint256", - internalType: "uint256", - }, - { - name: "args", - type: "tuple", - internalType: "struct PublicInputArgs", - components: [ - { - name: "previousArchive", - type: "bytes32", - internalType: "bytes32", - }, - { - name: "endArchive", - type: "bytes32", - internalType: "bytes32", - }, - { - name: "previousBlockHash", - type: "bytes32", - internalType: "bytes32", - }, - { - name: "endBlockHash", - type: "bytes32", - internalType: "bytes32", - }, - { - name: "endTimestamp", - type: "uint256", - internalType: "Timestamp", - }, - { - name: "outHash", - type: "bytes32", - internalType: "bytes32", - }, - { - name: "proverId", - type: "address", - internalType: "address", - }, - ], - }, - { - name: "fees", - type: "bytes32[]", - internalType: "bytes32[]", - }, - { - name: "blobPublicInputs", - type: "bytes", - internalType: "bytes", - }, - { - name: "aggregationObject", - type: "bytes", - internalType: "bytes", - }, - { - name: "proof", - type: "bytes", - internalType: "bytes", - }, - ], - }, - ], - outputs: [], - stateMutability: "nonpayable", - }, - { - type: "function", - name: "transferOwnership", - inputs: [ - { - name: "newOwner", - type: "address", - internalType: "address", - }, - ], - outputs: [], - stateMutability: "nonpayable", - }, - { - type: "function", - name: "updateL1GasFeeOracle", - inputs: [], - outputs: [], - stateMutability: "nonpayable", - }, - { - type: "function", - name: "validateBlobs", - inputs: [ - { - name: "_blobsInput", - type: "bytes", - internalType: "bytes", - }, - ], - outputs: [ - { - name: "", - type: "bytes32[]", - internalType: "bytes32[]", - }, - { - name: "", - type: "bytes32", - internalType: "bytes32", - }, - { - name: "", - type: "bytes32", - internalType: "bytes32", - }, - ], - stateMutability: "view", - }, - { - type: "function", - name: "validateHeader", - inputs: [ - { - name: "_header", - type: "bytes", - internalType: "bytes", - }, - { - name: "_signatures", - type: "tuple[]", - internalType: "struct Signature[]", - components: [ - { - name: "isEmpty", - type: "bool", - internalType: "bool", - }, - { - name: "v", - type: "uint8", - internalType: "uint8", - }, - { - name: "r", - type: "bytes32", - internalType: "bytes32", - }, - { - name: "s", - type: "bytes32", - internalType: "bytes32", - }, - ], - }, - { - name: "_digest", - type: "bytes32", - internalType: "bytes32", - }, - { - name: "_currentTime", - type: "uint256", - internalType: "Timestamp", - }, - { - name: "_blobsHash", - type: "bytes32", - internalType: "bytes32", - }, - { - name: "_flags", - type: "tuple", - internalType: "struct BlockHeaderValidationFlags", - components: [ - { - name: "ignoreDA", - type: "bool", - internalType: "bool", - }, - { - name: "ignoreSignatures", - type: "bool", - internalType: "bool", - }, - ], - }, - ], - outputs: [], - stateMutability: "view", - }, -] as const; diff --git a/tooling/sparta/src/utils/abis/testERC20Abi.ts b/tooling/sparta/src/utils/abis/testERC20Abi.ts deleted file mode 100644 index da6350c..0000000 --- a/tooling/sparta/src/utils/abis/testERC20Abi.ts +++ /dev/null @@ -1,1869 +0,0 @@ -/** - * TestERC20 ABI. - */ -export const TestERC20Abi = [ - { - type: "constructor", - inputs: [ - { - name: "_name", - type: "string", - internalType: "string", - }, - { - name: "_symbol", - type: "string", - internalType: "string", - }, - { - name: "_owner", - type: "address", - internalType: "address", - }, - ], - stateMutability: "nonpayable", - }, - { - type: "event", - name: "Approval", - inputs: [ - { - name: "owner", - type: "address", - indexed: true, - internalType: "address", - }, - { - name: "spender", - type: "address", - indexed: true, - internalType: "address", - }, - { - name: "value", - type: "uint256", - indexed: false, - internalType: "uint256", - }, - ], - anonymous: false, - }, - { - type: "error", - name: "CoinIssuer__InsufficientMintAvailable", - inputs: [ - { - name: "available", - type: "uint256", - internalType: "uint256", - }, - { - name: "needed", - type: "uint256", - internalType: "uint256", - }, - ], - }, - { - type: "error", - name: "DevNet__InvalidProposer", - inputs: [ - { - name: "expected", - type: "address", - internalType: "address", - }, - { - name: "actual", - type: "address", - internalType: "address", - }, - ], - }, - { - type: "error", - name: "DevNet__NoPruningAllowed", - inputs: [], - }, - { - type: "error", - name: "ERC20InsufficientAllowance", - inputs: [ - { - name: "spender", - type: "address", - internalType: "address", - }, - { - name: "allowance", - type: "uint256", - internalType: "uint256", - }, - { - name: "needed", - type: "uint256", - internalType: "uint256", - }, - ], - }, - { - type: "error", - name: "ERC20InsufficientBalance", - inputs: [ - { - name: "sender", - type: "address", - internalType: "address", - }, - { - name: "balance", - type: "uint256", - internalType: "uint256", - }, - { - name: "needed", - type: "uint256", - internalType: "uint256", - }, - ], - }, - { - type: "error", - name: "ERC20InvalidApprover", - inputs: [ - { - name: "approver", - type: "address", - internalType: "address", - }, - ], - }, - { - type: "error", - name: "ERC20InvalidReceiver", - inputs: [ - { - name: "receiver", - type: "address", - internalType: "address", - }, - ], - }, - { - type: "error", - name: "ERC20InvalidSender", - inputs: [ - { - name: "sender", - type: "address", - internalType: "address", - }, - ], - }, - { - type: "error", - name: "ERC20InvalidSpender", - inputs: [ - { - name: "spender", - type: "address", - internalType: "address", - }, - ], - }, - { - type: "error", - name: "FeeJuicePortal__AlreadyInitialized", - inputs: [], - }, - { - type: "error", - name: "FeeJuicePortal__InvalidInitialization", - inputs: [], - }, - { - type: "error", - name: "FeeJuicePortal__Unauthorized", - inputs: [], - }, - { - type: "error", - name: "FeeMath__InvalidFeeAssetPriceModifier", - inputs: [], - }, - { - type: "error", - name: "FeeMath__InvalidProvingCostModifier", - inputs: [], - }, - { - type: "error", - name: "GovernanceProposer__CanOnlyExecuteProposalInPast", - inputs: [], - }, - { - type: "error", - name: "GovernanceProposer__FailedToPropose", - inputs: [ - { - name: "proposal", - type: "address", - internalType: "contract IPayload", - }, - ], - }, - { - type: "error", - name: "GovernanceProposer__InstanceHaveNoCode", - inputs: [ - { - name: "instance", - type: "address", - internalType: "address", - }, - ], - }, - { - type: "error", - name: "GovernanceProposer__InsufficientVotes", - inputs: [ - { - name: "votesCast", - type: "uint256", - internalType: "uint256", - }, - { - name: "votesNeeded", - type: "uint256", - internalType: "uint256", - }, - ], - }, - { - type: "error", - name: "GovernanceProposer__InvalidNAndMValues", - inputs: [ - { - name: "n", - type: "uint256", - internalType: "uint256", - }, - { - name: "m", - type: "uint256", - internalType: "uint256", - }, - ], - }, - { - type: "error", - name: "GovernanceProposer__NCannotBeLargerTHanM", - inputs: [ - { - name: "n", - type: "uint256", - internalType: "uint256", - }, - { - name: "m", - type: "uint256", - internalType: "uint256", - }, - ], - }, - { - type: "error", - name: "GovernanceProposer__OnlyProposerCanVote", - inputs: [ - { - name: "caller", - type: "address", - internalType: "address", - }, - { - name: "proposer", - type: "address", - internalType: "address", - }, - ], - }, - { - type: "error", - name: "GovernanceProposer__ProposalAlreadyExecuted", - inputs: [ - { - name: "roundNumber", - type: "uint256", - internalType: "uint256", - }, - ], - }, - { - type: "error", - name: "GovernanceProposer__ProposalCannotBeAddressZero", - inputs: [], - }, - { - type: "error", - name: "GovernanceProposer__ProposalHaveNoCode", - inputs: [ - { - name: "proposal", - type: "address", - internalType: "contract IPayload", - }, - ], - }, - { - type: "error", - name: "GovernanceProposer__ProposalTooOld", - inputs: [ - { - name: "roundNumber", - type: "uint256", - internalType: "uint256", - }, - { - name: "currentRoundNumber", - type: "uint256", - internalType: "uint256", - }, - ], - }, - { - type: "error", - name: "GovernanceProposer__VoteAlreadyCastForSlot", - inputs: [ - { - name: "slot", - type: "uint256", - internalType: "Slot", - }, - ], - }, - { - type: "error", - name: "Governance__CallFailed", - inputs: [ - { - name: "target", - type: "address", - internalType: "address", - }, - ], - }, - { - type: "error", - name: "Governance__CallerNotGovernanceProposer", - inputs: [ - { - name: "caller", - type: "address", - internalType: "address", - }, - { - name: "governanceProposer", - type: "address", - internalType: "address", - }, - ], - }, - { - type: "error", - name: "Governance__CallerNotSelf", - inputs: [ - { - name: "caller", - type: "address", - internalType: "address", - }, - { - name: "self", - type: "address", - internalType: "address", - }, - ], - }, - { - type: "error", - name: "Governance__CannotCallAsset", - inputs: [], - }, - { - type: "error", - name: "Governance__ConfigurationLib__DifferentialTooBig", - inputs: [], - }, - { - type: "error", - name: "Governance__ConfigurationLib__DifferentialTooSmall", - inputs: [], - }, - { - type: "error", - name: "Governance__ConfigurationLib__InvalidMinimumVotes", - inputs: [], - }, - { - type: "error", - name: "Governance__ConfigurationLib__LockAmountTooSmall", - inputs: [], - }, - { - type: "error", - name: "Governance__ConfigurationLib__QuorumTooBig", - inputs: [], - }, - { - type: "error", - name: "Governance__ConfigurationLib__QuorumTooSmall", - inputs: [], - }, - { - type: "error", - name: "Governance__ConfigurationLib__TimeTooBig", - inputs: [ - { - name: "name", - type: "string", - internalType: "string", - }, - ], - }, - { - type: "error", - name: "Governance__ConfigurationLib__TimeTooSmall", - inputs: [ - { - name: "name", - type: "string", - internalType: "string", - }, - ], - }, - { - type: "error", - name: "Governance__InsufficientPower", - inputs: [ - { - name: "voter", - type: "address", - internalType: "address", - }, - { - name: "have", - type: "uint256", - internalType: "uint256", - }, - { - name: "required", - type: "uint256", - internalType: "uint256", - }, - ], - }, - { - type: "error", - name: "Governance__InvalidConfiguration", - inputs: [], - }, - { - type: "error", - name: "Governance__NoCheckpointsFound", - inputs: [], - }, - { - type: "error", - name: "Governance__ProposalAlreadyDropped", - inputs: [], - }, - { - type: "error", - name: "Governance__ProposalCannotBeDropped", - inputs: [], - }, - { - type: "error", - name: "Governance__ProposalDoesNotExists", - inputs: [ - { - name: "proposalId", - type: "uint256", - internalType: "uint256", - }, - ], - }, - { - type: "error", - name: "Governance__ProposalLib__MoreVoteThanExistNeeded", - inputs: [], - }, - { - type: "error", - name: "Governance__ProposalLib__MoreYeaVoteThanExistNeeded", - inputs: [], - }, - { - type: "error", - name: "Governance__ProposalLib__ZeroMinimum", - inputs: [], - }, - { - type: "error", - name: "Governance__ProposalLib__ZeroVotesNeeded", - inputs: [], - }, - { - type: "error", - name: "Governance__ProposalLib__ZeroYeaVotesNeeded", - inputs: [], - }, - { - type: "error", - name: "Governance__ProposalNotActive", - inputs: [], - }, - { - type: "error", - name: "Governance__ProposalNotExecutable", - inputs: [], - }, - { - type: "error", - name: "Governance__UserLib__NotInPast", - inputs: [], - }, - { - type: "error", - name: "Governance__WithdrawalAlreadyclaimed", - inputs: [], - }, - { - type: "error", - name: "Governance__WithdrawalNotUnlockedYet", - inputs: [ - { - name: "currentTime", - type: "uint256", - internalType: "Timestamp", - }, - { - name: "unlocksAt", - type: "uint256", - internalType: "Timestamp", - }, - ], - }, - { - type: "error", - name: "HeaderLib__InvalidHeaderSize", - inputs: [ - { - name: "expected", - type: "uint256", - internalType: "uint256", - }, - { - name: "actual", - type: "uint256", - internalType: "uint256", - }, - ], - }, - { - type: "error", - name: "HeaderLib__InvalidSlotNumber", - inputs: [ - { - name: "expected", - type: "uint256", - internalType: "Slot", - }, - { - name: "actual", - type: "uint256", - internalType: "Slot", - }, - ], - }, - { - type: "error", - name: "Inbox__ActorTooLarge", - inputs: [ - { - name: "actor", - type: "bytes32", - internalType: "bytes32", - }, - ], - }, - { - type: "error", - name: "Inbox__ContentTooLarge", - inputs: [ - { - name: "content", - type: "bytes32", - internalType: "bytes32", - }, - ], - }, - { - type: "error", - name: "Inbox__MustBuildBeforeConsume", - inputs: [], - }, - { - type: "error", - name: "Inbox__SecretHashTooLarge", - inputs: [ - { - name: "secretHash", - type: "bytes32", - internalType: "bytes32", - }, - ], - }, - { - type: "error", - name: "Inbox__Unauthorized", - inputs: [], - }, - { - type: "error", - name: "MerkleLib__InvalidRoot", - inputs: [ - { - name: "expected", - type: "bytes32", - internalType: "bytes32", - }, - { - name: "actual", - type: "bytes32", - internalType: "bytes32", - }, - { - name: "leaf", - type: "bytes32", - internalType: "bytes32", - }, - { - name: "leafIndex", - type: "uint256", - internalType: "uint256", - }, - ], - }, - { - type: "error", - name: "Outbox__AlreadyNullified", - inputs: [ - { - name: "l2BlockNumber", - type: "uint256", - internalType: "uint256", - }, - { - name: "leafIndex", - type: "uint256", - internalType: "uint256", - }, - ], - }, - { - type: "error", - name: "Outbox__BlockNotProven", - inputs: [ - { - name: "l2BlockNumber", - type: "uint256", - internalType: "uint256", - }, - ], - }, - { - type: "error", - name: "Outbox__IncompatibleEntryArguments", - inputs: [ - { - name: "messageHash", - type: "bytes32", - internalType: "bytes32", - }, - { - name: "storedFee", - type: "uint64", - internalType: "uint64", - }, - { - name: "feePassed", - type: "uint64", - internalType: "uint64", - }, - { - name: "storedVersion", - type: "uint32", - internalType: "uint32", - }, - { - name: "versionPassed", - type: "uint32", - internalType: "uint32", - }, - { - name: "storedDeadline", - type: "uint32", - internalType: "uint32", - }, - { - name: "deadlinePassed", - type: "uint32", - internalType: "uint32", - }, - ], - }, - { - type: "error", - name: "Outbox__InvalidChainId", - inputs: [], - }, - { - type: "error", - name: "Outbox__InvalidPathLength", - inputs: [ - { - name: "expected", - type: "uint256", - internalType: "uint256", - }, - { - name: "actual", - type: "uint256", - internalType: "uint256", - }, - ], - }, - { - type: "error", - name: "Outbox__InvalidRecipient", - inputs: [ - { - name: "expected", - type: "address", - internalType: "address", - }, - { - name: "actual", - type: "address", - internalType: "address", - }, - ], - }, - { - type: "error", - name: "Outbox__InvalidVersion", - inputs: [ - { - name: "entry", - type: "uint256", - internalType: "uint256", - }, - { - name: "message", - type: "uint256", - internalType: "uint256", - }, - ], - }, - { - type: "error", - name: "Outbox__NothingToConsume", - inputs: [ - { - name: "messageHash", - type: "bytes32", - internalType: "bytes32", - }, - ], - }, - { - type: "error", - name: "Outbox__NothingToConsumeAtBlock", - inputs: [ - { - name: "l2BlockNumber", - type: "uint256", - internalType: "uint256", - }, - ], - }, - { - type: "error", - name: "Outbox__RootAlreadySetAtBlock", - inputs: [ - { - name: "l2BlockNumber", - type: "uint256", - internalType: "uint256", - }, - ], - }, - { - type: "error", - name: "Outbox__Unauthorized", - inputs: [], - }, - { - type: "error", - name: "OwnableInvalidOwner", - inputs: [ - { - name: "owner", - type: "address", - internalType: "address", - }, - ], - }, - { - type: "error", - name: "OwnableUnauthorizedAccount", - inputs: [ - { - name: "account", - type: "address", - internalType: "address", - }, - ], - }, - { - type: "event", - name: "OwnershipTransferred", - inputs: [ - { - name: "previousOwner", - type: "address", - indexed: true, - internalType: "address", - }, - { - name: "newOwner", - type: "address", - indexed: true, - internalType: "address", - }, - ], - anonymous: false, - }, - { - type: "error", - name: "ProofCommitmentEscrow__InsufficientBalance", - inputs: [ - { - name: "balance", - type: "uint256", - internalType: "uint256", - }, - { - name: "requested", - type: "uint256", - internalType: "uint256", - }, - ], - }, - { - type: "error", - name: "ProofCommitmentEscrow__NotOwner", - inputs: [ - { - name: "caller", - type: "address", - internalType: "address", - }, - ], - }, - { - type: "error", - name: "ProofCommitmentEscrow__WithdrawRequestNotReady", - inputs: [ - { - name: "current", - type: "uint256", - internalType: "uint256", - }, - { - name: "readyAt", - type: "uint256", - internalType: "Timestamp", - }, - ], - }, - { - type: "error", - name: "Registry__RollupAlreadyRegistered", - inputs: [ - { - name: "rollup", - type: "address", - internalType: "address", - }, - ], - }, - { - type: "error", - name: "Registry__RollupNotRegistered", - inputs: [ - { - name: "rollup", - type: "address", - internalType: "address", - }, - ], - }, - { - type: "error", - name: "RewardDistributor__InvalidCaller", - inputs: [ - { - name: "caller", - type: "address", - internalType: "address", - }, - { - name: "canonical", - type: "address", - internalType: "address", - }, - ], - }, - { - type: "error", - name: "Rollup__InsufficientBondAmount", - inputs: [ - { - name: "minimum", - type: "uint256", - internalType: "uint256", - }, - { - name: "provided", - type: "uint256", - internalType: "uint256", - }, - ], - }, - { - type: "error", - name: "Rollup__InsufficientFundsInEscrow", - inputs: [ - { - name: "required", - type: "uint256", - internalType: "uint256", - }, - { - name: "available", - type: "uint256", - internalType: "uint256", - }, - ], - }, - { - type: "error", - name: "Rollup__InvalidArchive", - inputs: [ - { - name: "expected", - type: "bytes32", - internalType: "bytes32", - }, - { - name: "actual", - type: "bytes32", - internalType: "bytes32", - }, - ], - }, - { - type: "error", - name: "Rollup__InvalidBasisPointFee", - inputs: [ - { - name: "basisPointFee", - type: "uint256", - internalType: "uint256", - }, - ], - }, - { - type: "error", - name: "Rollup__InvalidBlobHash", - inputs: [ - { - name: "blobHash", - type: "bytes32", - internalType: "bytes32", - }, - ], - }, - { - type: "error", - name: "Rollup__InvalidBlobProof", - inputs: [ - { - name: "blobHash", - type: "bytes32", - internalType: "bytes32", - }, - ], - }, - { - type: "error", - name: "Rollup__InvalidBlobPublicInputsHash", - inputs: [ - { - name: "expected", - type: "bytes32", - internalType: "bytes32", - }, - { - name: "actual", - type: "bytes32", - internalType: "bytes32", - }, - ], - }, - { - type: "error", - name: "Rollup__InvalidBlockHash", - inputs: [ - { - name: "expected", - type: "bytes32", - internalType: "bytes32", - }, - { - name: "actual", - type: "bytes32", - internalType: "bytes32", - }, - ], - }, - { - type: "error", - name: "Rollup__InvalidBlockNumber", - inputs: [ - { - name: "expected", - type: "uint256", - internalType: "uint256", - }, - { - name: "actual", - type: "uint256", - internalType: "uint256", - }, - ], - }, - { - type: "error", - name: "Rollup__InvalidChainId", - inputs: [ - { - name: "expected", - type: "uint256", - internalType: "uint256", - }, - { - name: "actual", - type: "uint256", - internalType: "uint256", - }, - ], - }, - { - type: "error", - name: "Rollup__InvalidEpoch", - inputs: [ - { - name: "expected", - type: "uint256", - internalType: "Epoch", - }, - { - name: "actual", - type: "uint256", - internalType: "Epoch", - }, - ], - }, - { - type: "error", - name: "Rollup__InvalidInHash", - inputs: [ - { - name: "expected", - type: "bytes32", - internalType: "bytes32", - }, - { - name: "actual", - type: "bytes32", - internalType: "bytes32", - }, - ], - }, - { - type: "error", - name: "Rollup__InvalidManaBaseFee", - inputs: [ - { - name: "expected", - type: "uint256", - internalType: "uint256", - }, - { - name: "actual", - type: "uint256", - internalType: "uint256", - }, - ], - }, - { - type: "error", - name: "Rollup__InvalidPreviousArchive", - inputs: [ - { - name: "expected", - type: "bytes32", - internalType: "bytes32", - }, - { - name: "actual", - type: "bytes32", - internalType: "bytes32", - }, - ], - }, - { - type: "error", - name: "Rollup__InvalidPreviousBlockHash", - inputs: [ - { - name: "expected", - type: "bytes32", - internalType: "bytes32", - }, - { - name: "actual", - type: "bytes32", - internalType: "bytes32", - }, - ], - }, - { - type: "error", - name: "Rollup__InvalidProof", - inputs: [], - }, - { - type: "error", - name: "Rollup__InvalidProposedArchive", - inputs: [ - { - name: "expected", - type: "bytes32", - internalType: "bytes32", - }, - { - name: "actual", - type: "bytes32", - internalType: "bytes32", - }, - ], - }, - { - type: "error", - name: "Rollup__InvalidTimestamp", - inputs: [ - { - name: "expected", - type: "uint256", - internalType: "Timestamp", - }, - { - name: "actual", - type: "uint256", - internalType: "Timestamp", - }, - ], - }, - { - type: "error", - name: "Rollup__InvalidVersion", - inputs: [ - { - name: "expected", - type: "uint256", - internalType: "uint256", - }, - { - name: "actual", - type: "uint256", - internalType: "uint256", - }, - ], - }, - { - type: "error", - name: "Rollup__NoEpochToProve", - inputs: [], - }, - { - type: "error", - name: "Rollup__NonSequentialProving", - inputs: [], - }, - { - type: "error", - name: "Rollup__NonZeroDaFee", - inputs: [], - }, - { - type: "error", - name: "Rollup__NonZeroL2Fee", - inputs: [], - }, - { - type: "error", - name: "Rollup__NotClaimingCorrectEpoch", - inputs: [ - { - name: "expected", - type: "uint256", - internalType: "Epoch", - }, - { - name: "actual", - type: "uint256", - internalType: "Epoch", - }, - ], - }, - { - type: "error", - name: "Rollup__NotInClaimPhase", - inputs: [ - { - name: "currentSlotInEpoch", - type: "uint256", - internalType: "uint256", - }, - { - name: "claimDuration", - type: "uint256", - internalType: "uint256", - }, - ], - }, - { - type: "error", - name: "Rollup__NothingToPrune", - inputs: [], - }, - { - type: "error", - name: "Rollup__ProofRightAlreadyClaimed", - inputs: [], - }, - { - type: "error", - name: "Rollup__QuoteExpired", - inputs: [ - { - name: "currentSlot", - type: "uint256", - internalType: "Slot", - }, - { - name: "quoteSlot", - type: "uint256", - internalType: "Slot", - }, - ], - }, - { - type: "error", - name: "Rollup__SlotAlreadyInChain", - inputs: [ - { - name: "lastSlot", - type: "uint256", - internalType: "Slot", - }, - { - name: "proposedSlot", - type: "uint256", - internalType: "Slot", - }, - ], - }, - { - type: "error", - name: "Rollup__TimestampInFuture", - inputs: [ - { - name: "max", - type: "uint256", - internalType: "Timestamp", - }, - { - name: "actual", - type: "uint256", - internalType: "Timestamp", - }, - ], - }, - { - type: "error", - name: "Rollup__TimestampTooOld", - inputs: [], - }, - { - type: "error", - name: "Rollup__TryingToProveNonExistingBlock", - inputs: [], - }, - { - type: "error", - name: "Rollup__UnavailableTxs", - inputs: [ - { - name: "txsHash", - type: "bytes32", - internalType: "bytes32", - }, - ], - }, - { - type: "error", - name: "SampleLib__IndexOutOfBounds", - inputs: [ - { - name: "requested", - type: "uint256", - internalType: "uint256", - }, - { - name: "bound", - type: "uint256", - internalType: "uint256", - }, - ], - }, - { - type: "error", - name: "SignatureLib__CannotVerifyEmpty", - inputs: [], - }, - { - type: "error", - name: "SignatureLib__InvalidSignature", - inputs: [ - { - name: "expected", - type: "address", - internalType: "address", - }, - { - name: "recovered", - type: "address", - internalType: "address", - }, - ], - }, - { - type: "error", - name: "Staking__AlreadyActive", - inputs: [ - { - name: "attester", - type: "address", - internalType: "address", - }, - ], - }, - { - type: "error", - name: "Staking__AlreadyRegistered", - inputs: [ - { - name: "", - type: "address", - internalType: "address", - }, - ], - }, - { - type: "error", - name: "Staking__CannotSlashExitedStake", - inputs: [ - { - name: "", - type: "address", - internalType: "address", - }, - ], - }, - { - type: "error", - name: "Staking__FailedToRemove", - inputs: [ - { - name: "", - type: "address", - internalType: "address", - }, - ], - }, - { - type: "error", - name: "Staking__InsufficientStake", - inputs: [ - { - name: "", - type: "uint256", - internalType: "uint256", - }, - { - name: "", - type: "uint256", - internalType: "uint256", - }, - ], - }, - { - type: "error", - name: "Staking__NoOneToSlash", - inputs: [ - { - name: "", - type: "address", - internalType: "address", - }, - ], - }, - { - type: "error", - name: "Staking__NotExiting", - inputs: [ - { - name: "", - type: "address", - internalType: "address", - }, - ], - }, - { - type: "error", - name: "Staking__NotSlasher", - inputs: [ - { - name: "", - type: "address", - internalType: "address", - }, - { - name: "", - type: "address", - internalType: "address", - }, - ], - }, - { - type: "error", - name: "Staking__NotWithdrawer", - inputs: [ - { - name: "", - type: "address", - internalType: "address", - }, - { - name: "", - type: "address", - internalType: "address", - }, - ], - }, - { - type: "error", - name: "Staking__NothingToExit", - inputs: [ - { - name: "", - type: "address", - internalType: "address", - }, - ], - }, - { - type: "error", - name: "Staking__WithdrawalNotUnlockedYet", - inputs: [ - { - name: "", - type: "uint256", - internalType: "Timestamp", - }, - { - name: "", - type: "uint256", - internalType: "Timestamp", - }, - ], - }, - { - type: "event", - name: "Transfer", - inputs: [ - { - name: "from", - type: "address", - indexed: true, - internalType: "address", - }, - { - name: "to", - type: "address", - indexed: true, - internalType: "address", - }, - { - name: "value", - type: "uint256", - indexed: false, - internalType: "uint256", - }, - ], - anonymous: false, - }, - { - type: "error", - name: "ValidatorSelection__EpochNotSetup", - inputs: [], - }, - { - type: "error", - name: "ValidatorSelection__InsufficientAttestations", - inputs: [ - { - name: "minimumNeeded", - type: "uint256", - internalType: "uint256", - }, - { - name: "provided", - type: "uint256", - internalType: "uint256", - }, - ], - }, - { - type: "error", - name: "ValidatorSelection__InsufficientAttestationsProvided", - inputs: [ - { - name: "minimumNeeded", - type: "uint256", - internalType: "uint256", - }, - { - name: "provided", - type: "uint256", - internalType: "uint256", - }, - ], - }, - { - type: "error", - name: "ValidatorSelection__InvalidDeposit", - inputs: [ - { - name: "attester", - type: "address", - internalType: "address", - }, - { - name: "proposer", - type: "address", - internalType: "address", - }, - ], - }, - { - type: "error", - name: "ValidatorSelection__InvalidProposer", - inputs: [ - { - name: "expected", - type: "address", - internalType: "address", - }, - { - name: "actual", - type: "address", - internalType: "address", - }, - ], - }, - { - type: "function", - name: "allowance", - inputs: [ - { - name: "owner", - type: "address", - internalType: "address", - }, - { - name: "spender", - type: "address", - internalType: "address", - }, - ], - outputs: [ - { - name: "", - type: "uint256", - internalType: "uint256", - }, - ], - stateMutability: "view", - }, - { - type: "function", - name: "approve", - inputs: [ - { - name: "spender", - type: "address", - internalType: "address", - }, - { - name: "value", - type: "uint256", - internalType: "uint256", - }, - ], - outputs: [ - { - name: "", - type: "bool", - internalType: "bool", - }, - ], - stateMutability: "nonpayable", - }, - { - type: "function", - name: "balanceOf", - inputs: [ - { - name: "account", - type: "address", - internalType: "address", - }, - ], - outputs: [ - { - name: "", - type: "uint256", - internalType: "uint256", - }, - ], - stateMutability: "view", - }, - { - type: "function", - name: "decimals", - inputs: [], - outputs: [ - { - name: "", - type: "uint8", - internalType: "uint8", - }, - ], - stateMutability: "view", - }, - { - type: "function", - name: "freeForAll", - inputs: [], - outputs: [ - { - name: "", - type: "bool", - internalType: "bool", - }, - ], - stateMutability: "view", - }, - { - type: "function", - name: "mint", - inputs: [ - { - name: "_to", - type: "address", - internalType: "address", - }, - { - name: "_amount", - type: "uint256", - internalType: "uint256", - }, - ], - outputs: [], - stateMutability: "nonpayable", - }, - { - type: "function", - name: "name", - inputs: [], - outputs: [ - { - name: "", - type: "string", - internalType: "string", - }, - ], - stateMutability: "view", - }, - { - type: "function", - name: "owner", - inputs: [], - outputs: [ - { - name: "", - type: "address", - internalType: "address", - }, - ], - stateMutability: "view", - }, - { - type: "function", - name: "renounceOwnership", - inputs: [], - outputs: [], - stateMutability: "nonpayable", - }, - { - type: "function", - name: "setFreeForAll", - inputs: [ - { - name: "_freeForAll", - type: "bool", - internalType: "bool", - }, - ], - outputs: [], - stateMutability: "nonpayable", - }, - { - type: "function", - name: "symbol", - inputs: [], - outputs: [ - { - name: "", - type: "string", - internalType: "string", - }, - ], - stateMutability: "view", - }, - { - type: "function", - name: "totalSupply", - inputs: [], - outputs: [ - { - name: "", - type: "uint256", - internalType: "uint256", - }, - ], - stateMutability: "view", - }, - { - type: "function", - name: "transfer", - inputs: [ - { - name: "to", - type: "address", - internalType: "address", - }, - { - name: "value", - type: "uint256", - internalType: "uint256", - }, - ], - outputs: [ - { - name: "", - type: "bool", - internalType: "bool", - }, - ], - stateMutability: "nonpayable", - }, - { - type: "function", - name: "transferFrom", - inputs: [ - { - name: "from", - type: "address", - internalType: "address", - }, - { - name: "to", - type: "address", - internalType: "address", - }, - { - name: "value", - type: "uint256", - internalType: "uint256", - }, - ], - outputs: [ - { - name: "", - type: "bool", - internalType: "bool", - }, - ], - stateMutability: "nonpayable", - }, - { - type: "function", - name: "transferOwnership", - inputs: [ - { - name: "newOwner", - type: "address", - internalType: "address", - }, - ], - outputs: [], - stateMutability: "nonpayable", - }, -] as const; diff --git a/tooling/sparta/src/utils/inputValidator.ts b/tooling/sparta/src/utils/inputValidator.ts deleted file mode 100644 index c9d8ac3..0000000 --- a/tooling/sparta/src/utils/inputValidator.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { ChatInputCommandInteraction, MessageFlags } from "discord.js"; - -export const validateAddress = (interaction: ChatInputCommandInteraction) => { - const address = interaction.options.getString("address"); - if (!address) { - return interaction.reply({ - content: "Please provide an address.", - flags: MessageFlags.Ephemeral, - }); - } - if (!address.match(/^0x[a-fA-F0-9]{40}$/)) { - return interaction.reply({ - content: "Please provide a valid Ethereum address.", - flags: MessageFlags.Ephemeral, - }); - } - return address; -}; diff --git a/tooling/sparta/src/utils/logger.ts b/tooling/sparta/src/utils/logger.ts deleted file mode 100644 index b4ec3d6..0000000 --- a/tooling/sparta/src/utils/logger.ts +++ /dev/null @@ -1,109 +0,0 @@ -import { pino } from "pino"; - -// Log level hierarchy: trace < debug < info < warn < error < fatal -type LogLevel = "trace" | "debug" | "info" | "warn" | "error" | "fatal"; - -// Configuration for the logger -interface LoggerConfig { - level: LogLevel; - prettyPrint: boolean; -} - -// Get log level from environment or default to 'info' -const getLoggerConfig = (): LoggerConfig => { - return { - level: (process.env.LOG_LEVEL as LogLevel) || "info", - prettyPrint: process.env.LOG_PRETTY_PRINT !== "false", // Default to true - }; -}; - -// Create the logger instance -const createLogger = () => { - const config = getLoggerConfig(); - - const transport = config.prettyPrint - ? { - target: "pino-pretty", - options: { - colorize: true, - translateTime: "SYS:standard", - ignore: "pid,hostname", - }, - } - : undefined; - - return pino({ - level: config.level, - transport, - timestamp: pino.stdTimeFunctions.isoTime, - }); -}; - -// Export a singleton logger instance -export const logger = createLogger(); - -// Log HTTP requests -export const requestLogger = (req: any, res: any, next?: () => void) => { - logger.debug( - { - method: req.method, - url: req.url, - query: req.query, - params: req.params, - body: req.body, - headers: req.headers, - }, - "Incoming request" - ); - - if (next) next(); -}; - -// Re-export log methods for convenience -export const trace = (obj: object | string, msg?: string) => { - if (typeof obj === "string") { - logger.trace(obj); - } else { - logger.trace(obj, msg); - } -}; - -export const debug = (obj: object | string, msg?: string) => { - if (typeof obj === "string") { - logger.debug(obj); - } else { - logger.debug(obj, msg); - } -}; - -export const info = (obj: object | string, msg?: string) => { - if (typeof obj === "string") { - logger.info(obj); - } else { - logger.info(obj, msg); - } -}; - -export const warn = (obj: object | string, msg?: string) => { - if (typeof obj === "string") { - logger.warn(obj); - } else { - logger.warn(obj, msg); - } -}; - -export const error = (obj: object | string, msg?: string) => { - if (typeof obj === "string") { - logger.error(obj); - } else { - logger.error(obj, msg); - } -}; - -export const fatal = (obj: object | string, msg?: string) => { - if (typeof obj === "string") { - logger.fatal(obj); - } else { - logger.fatal(obj, msg); - } -}; diff --git a/tooling/sparta/src/utils/pagination.ts b/tooling/sparta/src/utils/pagination.ts deleted file mode 100644 index d7ccd5b..0000000 --- a/tooling/sparta/src/utils/pagination.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { MessageFlags } from "discord.js"; - -import { ChatInputCommandInteraction } from "discord.js"; - -export const paginate = async ( - array: string[], - total: number, - perMessage: number, - interaction: ChatInputCommandInteraction, - message: string -) => { - const numMessages = Math.ceil(array.length / perMessage); - if (!numMessages) { - await interaction.followUp({ - content: "No validators present", - flags: MessageFlags.Ephemeral, - }); - } - - for (let i = 0; i < numMessages; i++) { - const start = i * perMessage; - const end = Math.min(start + perMessage, array.length); - const validatorSlice = array.slice(start, end) as string[]; - - if (i === 0) { - await interaction.editReply({ - content: `${message} total: ${total}.\n${message} (excl. Aztec Labs) (${ - start + 1 - }-${end} of ${array.length}):\n${validatorSlice.join("\n")}`, - }); - } else { - await interaction.followUp({ - content: `${message} total: ${total}.\n${message} (excl. Aztec Labs) (${ - start + 1 - }-${end} of ${array.length}):\n${validatorSlice.join("\n")}`, - flags: MessageFlags.Ephemeral, - }); - } - } -}; diff --git a/tooling/sparta/terraform/README.md b/tooling/sparta/terraform/README.md deleted file mode 100644 index 43ccbee..0000000 --- a/tooling/sparta/terraform/README.md +++ /dev/null @@ -1,158 +0,0 @@ -# Sparta Discord Bot - Terraform Deployment - -This directory contains the Terraform configuration for deploying the Sparta Discord bot to AWS. - -## Architecture - -The Terraform configuration deploys the following AWS resources: - -- **ECS Cluster**: Manages the Docker containers running the bot -- **ECS Task Definition**: Defines the Docker container configuration -- **ECS Service**: Maintains the desired count of container instances -- **CloudWatch Log Group**: Collects and stores logs from the bot -- **IAM Roles**: Provides necessary permissions for the services -- **Security Groups**: Controls network access to the resources -- **Secrets Manager**: Securely stores sensitive credentials - -## Prerequisites - -Before deploying, ensure you have: - -1. **AWS CLI** installed and configured with appropriate credentials -2. **Terraform** (v1.0+) installed -3. Discord bot credentials (token, client ID) -4. Ethereum node access information -5. Google Sheets API credentials (if using role management) - -## Configuration Variables - -The deployment is configured using the following variables: - -| Variable | Description | Default | -| --------------------------- | -------------------------------------------------------------------------- | ------------ | -| `aws_region` | AWS region to deploy to | `us-west-2` | -| `environment` | Environment name (e.g., production, staging) | `production` | -| `bot_token` | Discord bot token | Required | -| `bot_client_id` | Discord bot client ID | Required | -| `guild_id` | Discord server/guild ID | Required | -| `ethereum_host` | Ethereum RPC endpoint | Required | -| `ethereum_registry_address` | Address of validator registry contract | Required | -| `minter_private_key` | Private key for minting/transactions | Required | -| `withdrawer_address` | Address for withdrawing funds | Required | -| `ethereum_chain_id` | Ethereum chain ID | Required | -| `google_api_key` | Google API key for Sheets access | Required | -| `spreadsheet_id` | Google Spreadsheet ID to monitor | Required | -| `log_level` | The log level for the application (trace, debug, info, warn, error, fatal) | `string` | `"info"` | -| `log_pretty_print` | Enable or disable colorful, pretty-printed logs | `bool` | `true` | - -## Deployment Steps - -1. **Initialize Terraform**: - -```bash -terraform init -``` - -2. **Create Variable Configuration**: - -Create a `terraform.tfvars` file based on the example: - -```bash -cp terraform.tfvars.example terraform.tfvars -``` - -Edit `terraform.tfvars` with your specific values. - -3. **Plan Deployment**: - -```bash -terraform plan -out=tfplan -``` - -Review the planned changes to ensure they match your expectations. - -4. **Apply Deployment**: - -```bash -terraform apply tfplan -``` - -5. **Verify Deployment**: - -After deployment completes, verify the service is running in the AWS Console: -- Check ECS service status -- Verify CloudWatch logs are being generated -- Confirm Discord bot is online - -## Environment-Specific Deployments - -For multiple environments (production, staging, etc.): - -```bash -# For staging -terraform apply -var-file=terraform.staging.tfvars - -# For production -terraform apply -var-file=terraform.production.tfvars -``` - -## Destroying Resources - -To tear down all resources: - -```bash -terraform destroy -``` - -**⚠️ Warning**: This will permanently delete all resources created by Terraform. - -## Updating the Deployment - -To update the deployment with new bot code: - -1. **Build and push a new Docker image** with your changes -2. **Update the task definition** with the new image -3. **Apply the changes**: - -```bash -terraform apply -var="container_image=" -``` - -## Troubleshooting - -### Common Issues - -1. **Bot not coming online**: - - Check ECS service logs in CloudWatch - - Verify Discord token is correct - - Check task definition for environment variables - -2. **Permission errors**: - - Verify IAM roles have sufficient permissions - - Check security group configurations - -3. **State file issues**: - - Consider using remote state with S3 and DynamoDB for team environments - -### Logging - -Access logs through: -- AWS CloudWatch console -- AWS CLI: - ```bash - aws logs get-log-events --log-group-name /ecs/sparta-bot --log-stream-name - ``` - -## Security Best Practices - -- Use AWS Secrets Manager for sensitive values -- Rotate credentials regularly -- Use the principle of least privilege for IAM roles -- Encrypt data at rest and in transit -- Enable CloudTrail for AWS API auditing - -### Logging Configuration - -For production environments, it's recommended to: -- Set `log_level` to `info` or `warn` to reduce log volume -- Set `log_pretty_print` to `false` for better performance and compatibility with log aggregation services diff --git a/tooling/sparta/terraform/main.tf b/tooling/sparta/terraform/main.tf deleted file mode 100644 index fa6f801..0000000 --- a/tooling/sparta/terraform/main.tf +++ /dev/null @@ -1,336 +0,0 @@ -terraform { - required_providers { - aws = { - source = "hashicorp/aws" - version = "~> 5.0" # Using AWS Provider version 5.x for latest features - } - } - - backend "s3" { - bucket = "sparta-tf-state" - key = "sparta/terraform" - region = "eu-west-2" - } -} - -provider "aws" { - profile = "default" - region = var.aws_region -} - -resource "aws_iam_role" "ecs_task_execution_role" { - name = "ecs_task_execution_role-${var.environment}" - - assume_role_policy = jsonencode({ - Version = "2012-10-17", - Statement = [{ - Action = "sts:AssumeRole", - Principal = { - Service = "ecs-tasks.amazonaws.com", - }, - Effect = "Allow", - Sid = "", - }] - }) -} - -resource "aws_iam_role_policy_attachment" "ecs_task_execution_policy" { - role = aws_iam_role.ecs_task_execution_role.name - policy_arn = "arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy" -} - -# Add CloudWatch logs permissions -resource "aws_iam_role_policy" "cloudwatch_logs_policy" { - name = "cloudwatch-logs-policy-${var.environment}" - role = aws_iam_role.ecs_task_execution_role.id - - policy = jsonencode({ - Version = "2012-10-17" - Statement = [ - { - Effect = "Allow" - Action = [ - "logs:CreateLogGroup", - "logs:CreateLogStream", - "logs:PutLogEvents", - "logs:DescribeLogStreams" - ] - Resource = [ - "arn:aws:logs:${var.aws_region}:*:log-group:/fargate/service/${var.environment}/sparta-discord-bot:*", - "arn:aws:logs:${var.aws_region}:*:log-group:/fargate/service/${var.environment}/sparta-discord-bot:*:*" - ] - } - ] - }) -} - -# Add ECR pull permissions -resource "aws_iam_role_policy" "ecr_pull_policy" { - name = "ecr_pull_policy-${var.environment}" - role = aws_iam_role.ecs_task_execution_role.id - - policy = jsonencode({ - Version = "2012-10-17" - Statement = [ - { - Effect = "Allow" - Action = [ - "ecr:GetAuthorizationToken", - "ecr:BatchCheckLayerAvailability", - "ecr:GetDownloadUrlForLayer", - "ecr:BatchGetImage" - ] - Resource = "*" - } - ] - }) -} - -# Create ECR Repository -resource "aws_ecr_repository" "sparta_bot" { - name = "sparta-bot-${var.environment}" - image_tag_mutability = "MUTABLE" - force_delete = true - - image_scanning_configuration { - scan_on_push = true - } -} - -# Build and push Docker image -resource "null_resource" "docker_build" { - triggers = { - always_run = "${timestamp()}" # This ensures it runs on every apply - } - - provisioner "local-exec" { - command = <