diff --git a/content/monitor/1.0.x/architecture.mdx b/content/monitor/1.0.x/architecture.mdx new file mode 100644 index 00000000..94d0d6a0 --- /dev/null +++ b/content/monitor/1.0.x/architecture.mdx @@ -0,0 +1,362 @@ +--- +title: Architecture Guide +--- + +This document describes the high-level architecture of OpenZeppelin Monitor, including the core components, their interactions, and the overall system design. It provides a technical overview of how the service processes blockchain data and triggers notifications based on configurable conditions. + +## System Overview + +OpenZeppelin Monitor is organized as a data processing pipeline that spans from blockchain data collection to notification delivery. The system follows a modular architecture with distinct components for each step in the monitoring process, designed for scalability and extensibility. + +### High-Level Architecture + +The diagram below shows the core processing pipeline of OpenZeppelin Monitor, from blockchain networks and configuration through to notification channels: + +```mermaid +flowchart LR + subgraph "Blockchain Networks" + EVMN["EVM Networks"] + STLN["Stellar Networks"] + end + subgraph "Configuration" + NETCFG["Network Configs"] + MONCFG["Monitor Configs"] + TRICFG["Trigger Configs"] + end + subgraph "Core Processing Pipeline" + BWS["BlockWatcherService"] + FS["FilterService"] + TS["TriggerService"] + NS["NotificationService"] + end + subgraph "Notification Channels" + Slack + Email + Discord + Telegram + Webhook + Scripts["Custom Scripts"] + end + + %% Data and config flow + EVMN --> BWS + STLN --> BWS + NETCFG --> BWS + MONCFG --> FS + TRICFG --> TS + BWS --> FS + FS --> TS + TS --> NS + NS --> Slack + NS --> Email + NS --> Discord + NS --> Telegram + NS --> Webhook + NS --> Scripts + + %% Styling for major blocks and notification channels + classDef blockchain fill:#fff3e0,stroke:#ef6c00,stroke-width:2px; + classDef config fill:#e8f5e9,stroke:#2e7d32,stroke-width:2px; + classDef mainBlock fill:#e1f5fe,stroke:#01579b,stroke-width:2px; + classDef notification fill:#fce4ec,stroke:#c2185b,stroke-width:2px; + class EVMN,STLN blockchain; + class NETCFG,MONCFG,TRICFG config; + class BWS,FS,TS,NS mainBlock; + class Slack,Email,Discord,Telegram,Webhook,Scripts notification; +``` + +## Component Architecture + +The system consists of several core services that are initialized at startup and work together to process blockchain data and trigger notifications. The service initialization and dependencies are managed through the bootstrap module. + +### Service Initialization Flow + +```mermaid +graph TD + subgraph Entry Point + MAIN[main.rs] + end + + subgraph Bootstrap + BOOTSTRAP[Bootstrap::initialize_service] + end + + subgraph Block Processing + BT[BlockTracker] + BS[BlockStorage] + BWS[BlockWatcherService] + BH[create_block_handler] + end + + subgraph Core Services + MS[MonitorService] + NS[NetworkService] + TS[TriggerService] + FS[FilterService] + TES[TriggerExecutionService] + NOTS[NotificationService] + end + + subgraph Client Layer + CP[ClientPool] + EVMC[EVMClient] + SC[StellarClient] + end + + %% Initialization Flow + MAIN --> BOOTSTRAP + BOOTSTRAP --> CP + BOOTSTRAP --> NS + BOOTSTRAP --> MS + BOOTSTRAP --> TS + BOOTSTRAP --> FS + BOOTSTRAP --> TES + BOOTSTRAP --> NOTS + + %% Block Processing Setup + BOOTSTRAP --> BT + BOOTSTRAP --> BS + BOOTSTRAP --> BWS + BOOTSTRAP --> BH + + %% Client Dependencies + CP --> EVMC + CP --> SC + BWS --> CP + + %% Service Dependencies + BWS --> BS + BWS --> BT + MS --> NS + MS --> TS + FS --> TES + TES --> NOTS + + %% Block Handler Connection + BH --> FS + BWS --> BH + + style MAIN fill:#e1f5fe,stroke:#01579b + style BOOTSTRAP fill:#fff3e0,stroke:#ef6c00 + classDef blockProcessing fill:#e8f5e9,stroke:#2e7d32 + classDef coreServices fill:#f3e5f5,stroke:#7b1fa2 + classDef clients fill:#fce4ec,stroke:#c2185b + + class BT,BS,BWS,BH blockProcessing + class MS,NS,TS,FS,TES,NOTS coreServices + class CP,EVMC,SC clients +``` + +### Core Components + +#### Block Processing Components + +* ***BlockWatcherService***: Orchestrates the block monitoring process by polling blockchain networks for new blocks and coordinating the processing pipeline. +* ***BlockTracker***: Tracks processed block numbers to prevent duplicate processing and ensure data consistency across service restarts. +* ***BlockStorage***: Persists block processing state for recovery and maintains the last processed block number for each network. + +#### Client Layer Components + +* ***ClientPool***: Manages blockchain client instances and provides network connectivity with connection pooling and failover capabilities. +* ***EVMClient***: Handles communication with Ethereum Virtual Machine compatible networks (Ethereum, Polygon, BSC, etc.). +* ***StellarClient***: Manages connections to Stellar blockchain networks with protocol-specific optimizations. + +#### Processing Pipeline Components + +* ***FilterService***: Applies monitor filters to blockchain data, evaluating conditions and match expressions to identify relevant transactions and events. +* ***TriggerExecutionService***: Executes triggers based on matched monitor conditions, evaluating trigger logic and preparing notification payloads. +* ***NotificationService***: Delivers notifications through configured channels (Slack, Email, Discord, Telegram, Webhooks, Scripts). + +#### Configuration Management Components + +* ***MonitorService***: Manages monitor configurations and provides access to active monitors with validation and lifecycle management. +* ***NetworkService***: Manages network configurations and provides network details for client connections and monitoring operations. +* ***TriggerService***: Manages trigger configurations and provides trigger details for notification execution. + +### Service Responsibilities + +The following table describes the key responsibilities of each service in the OpenZeppelin Monitor architecture: + +| Service | Responsibility | +| --- | --- | +| **MonitorService** | Manages monitor configurations and provides access to active monitors | +| **NetworkService** | Manages network configurations and provides network details | +| **TriggerService** | Manages trigger configurations and provides trigger details | +| **FilterService** | Filters blockchain data based on monitor conditions and match expressions | +| **TriggerExecutionService** | Executes triggers based on matched monitor conditions | +| **NotificationService** | Delivers notifications through configured channels | +| **BlockWatcherService** | Polls blockchain networks for new blocks and coordinates processing | +| **BlockTracker** | Tracks processed block numbers to prevent duplicate processing | +| **BlockStorage** | Persists block processing state for recovery | +| **ClientPool** | Manages blockchain client instances and provides network connectivity | + +### Block Processing Workflow + +The following _runtime flow_ illustrates how data moves through the system, from blockchain networks to notification channels. This sequence represents the core monitoring loop that executes for each configured network. + +```mermaid +sequenceDiagram + participant BWS as BlockWatcherService + participant BS as BlockStorage + participant BC as BlockchainClient + participant FS as FilterService + participant TES as TriggerExecutionService + participant NS as NotificationService + + rect rgb(232, 245, 233) + Note over BWS: Orchestrates block processing + BWS->>BS: Get last processed block + end + + rect rgb(225, 245, 254) + Note over BC: Blockchain interface + BWS->>BC: Get latest block number + BWS->>BC: Get blocks (last+1 to latest) + end + + loop For each block + rect rgb(243, 229, 245) + Note over FS: Applies monitor filters + BWS->>FS: filter_block(block) + FS->>FS: Apply monitor filters + FS-->>BWS: Monitor matches + end + + rect rgb(255, 248, 225) + Note over TES: Evaluates trigger conditions + BWS->>TES: Process monitor matches + TES->>TES: Run trigger conditions + end + + rect rgb(252, 228, 236) + Note over NS: Delivers notifications + TES->>NS: Execute notifications + end + end + + rect rgb(255, 243, 224) + Note over BS: Persists processing state + BWS->>BS: Store latest processed block + end +``` + +### Data Flow Architecture + +#### 1. Block Discovery Phase +The `BlockWatcherService` initiates the monitoring cycle by: + +* Retrieving the last processed block number from `BlockStorage` +* Querying the blockchain for the latest block number +* Calculating the range of new blocks to process + +#### 2. Data Retrieval Phase +The `BlockchainClient` fetches block data: + +* Connects to the appropriate blockchain network via RPC +* Retrieves full block data including transactions and events +* Handles network-specific data formats and protocols + +#### 3. Filtering Phase +The `FilterService` processes each block: + +* Applies monitor-specific filters to transactions and events +* Evaluates match expressions and conditions +* Identifies relevant data that matches monitoring criteria + +#### 4. Trigger Evaluation Phase +The `TriggerExecutionService` processes matches: + +* Evaluates trigger conditions for matched data +* Prepares notification payloads with relevant context +* Determines which notification channels to activate + +#### 5. Notification Delivery Phase +The `NotificationService` delivers alerts: + +* Formats messages for each notification channel +* Handles channel-specific delivery protocols +* Manages delivery retries and error handling + +#### 6. State Persistence Phase +The `BlockStorage` updates processing state: + +* Records the latest processed block number +* Ensures data consistency for recovery scenarios +* Maintains processing history for debugging + +### Error Handling and Resilience + +The architecture includes several resilience mechanisms: + +* ***Connection Pooling***: The `ClientPool` manages multiple connections to prevent single points of failure +* ***State Recovery***: `BlockStorage` enables the service to resume from the last known good state after restarts +* ***Retry Logic***: Notification delivery includes configurable retry mechanisms for transient failures +* ***Graceful Degradation***: Individual component failures don’t cascade to the entire system + +For detailed information about RPC logic and network communication, see the [RPC section](/monitor/1.0.x/rpc). + +## Configuration Architecture + +The system uses a JSON-based configuration system organized into distinct categories: + +### Configuration Categories + +* ***Network Configurations***: Define blockchain network connections, RPC endpoints, and network parameters +* ***Monitor Configurations***: Specify monitoring rules, conditions, and network/trigger references +* ***Trigger Configurations***: Define notification settings and script definitions +* ***Filter Configurations***: Contain match filter scripts for data filtering + +### Configuration Validation + +The system implements comprehensive validation: + +* Cross-reference validation between monitors, networks, and triggers +* Schema validation for all configuration files +* Runtime validation of configuration references during service startup + + + +For configuration examples and best practices, see the [Configuration Guidelines](/monitor/1.0.x#configuration-guidelines) section in the user documentation. + + +## Extensibility Points + +The architecture is designed for extensibility in several key areas: + +### Blockchain Support +* ***Client Layer***: New blockchain protocols can be added by implementing the `BlockchainClient` trait +* ***Transport Layer***: Protocol-specific transport clients handle network communication details +* ***Filter Layer***: Chain-specific filters process protocol-dependent data formats + +### Notification Channels +* ***Channel Plugins***: New notification channels can be added by implementing the notification interface +* ***Script Support***: Custom notification logic can be implemented using Python, JavaScript, or Bash scripts + +### Monitoring Logic +* ***Expression Engine***: Flexible expression evaluation for complex monitoring conditions +* ***Script Triggers***: Custom trigger logic can be implemented using supported scripting languages + +## Performance Considerations + +The architecture is optimized for: + +* ***Concurrent Processing***: Multiple networks can be monitored simultaneously +* ***Efficient Block Processing***: Batch processing of blocks to minimize RPC calls +* ***Memory Management***: Streaming processing of large blocks to prevent memory issues +* ***Connection Reuse***: Client pooling reduces connection overhead + +## Security Architecture + +The system implements several security measures: + +* ***Secure Protocols***: Support for HTTPS/WSS +* ***Secret Management***: Secure handling of API keys and sensitive configuration data +* ***Input Validation***: Comprehensive validation of all external inputs and configurations + +## Related Documentation + +For detailed information about the project structure, source code organization, and development resources, see the [Project Structure](/monitor/1.0.x/project-structure) guide. + +For information about RPC logic and network communication, see the [RPC section](/monitor/1.0.x/rpc). + +For configuration examples and best practices, see the [Configuration Guidelines](/monitor/1.0.x#configuration-guidelines) section in the user documentation. diff --git a/content/monitor/1.0.x/changelog.mdx b/content/monitor/1.0.x/changelog.mdx new file mode 100644 index 00000000..276fa8ad --- /dev/null +++ b/content/monitor/1.0.x/changelog.mdx @@ -0,0 +1,300 @@ +--- +title: Changelog +--- + + +# [v1.1.0](https://github.com/OpenZeppelin/openzeppelin-monitor/releases/tag/v1.1.0) - 2025-10-22 + +## [1.1.0](https://github.com/OpenZeppelin/openzeppelin-monitor/compare/v1.0.0...v1.1.0) (2025-10-22) + + +### πŸš€ Features + +* add block tracker ([#11](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/11)) ([1d4d117](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/1d4d117aab56e2c31c0747d6bf681fe60b2d8b10)) +* Add CLA assistant bot ([#107](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/107)) ([47e490e](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/47e490e4a5657a48bc60f85c38d72aca16334ac0)) +* Add client rpc pool ([#75](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/75)) ([28cd940](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/28cd940a8aea5c97fb15a4ca0d415debaa2864b1)) +* add email support ([#7](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/7)) ([decb56d](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/decb56d45d3f1000346c24e137d1a5d952c4a9dd)) +* Add endpoint rotation manager ([#69](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/69)) ([454a630](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/454a630cf92c305ea5d9254b211a7b60abf8804d)) +* Add environment vars and Hashicorp cloud vault support (breaking) ([#199](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/199)) ([558304f](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/558304f335a645c1de2d348a041337ccba2c2a06)) +* Add events and functions summary in notifications ([#339](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/339)) ([000ae24](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/000ae24e896cd0867c6252111a71151942d820bc)) +* Add new error context ([#77](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/77)) ([612bb76](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/612bb76b9c8e9a470fc68685c2f06481663a9474)) +* Add rc workflow file ([#156](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/156)) ([8907591](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/890759186570a64a9d0b0ef4dc9e512d0110d7a0)) +* Add support for webhook, telegram, discord notifications ([#65](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/65)) ([829967d](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/829967da45062dc22ffb0cb3376e68101a46b3e9)) +* Enhance filter expression parsing and evaluation ([#222](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/222)) ([3cb0849](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/3cb084919b3d477f329a85fbafce1ce6d696b16d)) +* Extend support for EVM transaction properties ([#187](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/187)) ([f20086b](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/f20086b0431a787dd55aa8928a09aece80b9a731)) +* Handle Stellar JSON-RPC outside of retention window error for `getTransactions` and `getEvents` ([#270](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/270)) ([ae116ff](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/ae116ff10f393a04c19d3b845df656027c6be4b9)) +* Implement client pooling for Webhook-based notifiers ([#281](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/281)) ([4f480c6](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/4f480c6a05aeb949cfd8e227c5c08f19a5e60180)) +* Introduce `TransportError` ([#259](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/259)) ([0e04cfb](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/0e04cfb57109251095ef8ee526fb5e05f5792792)) +* Introduce centralized retryable HTTP client creation ([#273](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/273)) ([5f6edaf](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/5f6edaf5deb77a5d9dfead52a162e923aad6a2ab)) +* Introduce retry mechanism for Email notifier ([#282](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/282)) ([b6301aa](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/b6301aaac963ae904d93e07674d9d01543ecfcd0)) +* Leverage contract spec (SEP-48) for Stellar functions (breaking) ([#208](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/208)) ([5ebc2a4](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/5ebc2a441b9ac6ed66a0807cac2795af2ae5b1c8)) +* Markdown for telegram, discord, slack and email ([#197](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/197)) ([791bf4b](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/791bf4b347d8cfe03ccd53e9797f179c15629a33)) +* Plat 6187 write metrics to prometheus ([#95](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/95)) ([2dc08d5](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/2dc08d51670834f453498299937debfca67fa1b7)) +* PLAT-6148 Adding post filter to monitor model ([#58](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/58)) ([920a0bf](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/920a0bf27953b67eb722d17d5ebf50b51237d4d4)) +* PLAT-6151 Integrate custom script execution with notification service ([#79](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/79)) ([bd5f218](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/bd5f218507dfc30bd4b2182077e2997cf04b8877)) +* PLAT-6477 Adding rust toolchain file ([#117](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/117)) ([ea6fb1e](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/ea6fb1ee6bba46cfa66a0c81665e17930bbbed93)) +* Separate code test coverage into different categories of tests ([#84](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/84)) ([a3ad89c](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/a3ad89cdcf0bab5883af7ec36b854fedc2f060cd)) +* spawn block-watcher per network ([#4](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/4)) ([d7a19ec](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/d7a19ec57344e4fb28dffc6f2025e809d0f5d946)) +* Test execute the monitor against specific block ([#133](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/133)) ([563c34f](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/563c34fde3c0f334a7c5884de5510bf27e4fca48)) +* Update payload builder to support formatted titles ([#336](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/336)) ([12213b3](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/12213b32d609bf6a1ba69ce548f70809971f9fb3)) +* Upgrade stellar crates and read events from specs ([#371](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/371)) ([7273a3f](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/7273a3f8d9249692db6b6ca53f4d8b28b21670f4)) + + +### πŸ› Bug Fixes + +* Add thread flag when running tests in CI ([#41](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/41)) ([4312669](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/4312669d8da84f5cf7e7817b10c377fe3a6992af)) +* Adding validation for unknown field names ([#223](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/223)) ([cadf4da](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/cadf4dac293e2c24a02a2eb188540e1eb312b75f)) +* Adjust netlify toml settings ([#47](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/47)) ([af9fe55](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/af9fe553a92cfc47a306a7dcfc43be0b2257f835)) +* Bump MSRV ([#291](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/291)) ([f2d7953](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/f2d795310cd1417ad2fac854ea5f80cf6296b761)) +* CLA labels and assistant ([#176](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/176)) ([b14f060](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/b14f0600dc4cac5a5f00d3772328abe123114b2a)) +* correct env var value in semgrep.yml ([#317](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/317)) ([7a8253f](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/7a8253fd23ae27c73b3971e2a688c39051c08a84)) +* Deprecate Stellar `paging_token` in `GetEvents` response ([#344](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/344)) ([68d20f9](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/68d20f91b643ef3a7c85ee897308d4f92d43698b)) +* Docs link ([#106](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/106)) ([f12d95d](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/f12d95d85ad9230bece0342c39cb5c3c1cd62832)) +* Docs pipeline ([#167](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/167)) ([1e78ec4](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/1e78ec4f98f70ac12dea353c1605ac4ac2c5734b)) +* Documentation name for antora ([#105](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/105)) ([5a8c4bd](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/5a8c4bd8315e62bb2dedb066f6b6bfcaa09c2d37)) +* Duplicate name in triggers config ([#274](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/274)) ([00f58f4](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/00f58f4be3f9452792f9fdcf5dd8696947a274cb)) +* Environment adjustments and cargo lock file improvements ([#219](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/219)) ([1b4d5d8](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/1b4d5d8dbe8cba26fbb84a8f847fc22b1a1dc096)) +* Event and function signatures from matched_on ([#198](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/198)) ([cdd9f1d](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/cdd9f1d7333ee2f3ef9c476a08e918388b3c35f0)) +* Fix cargo lock ([#110](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/110)) ([c440ca4](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/c440ca43542e919cd473a7d533b0820cf5474d3e)) +* Fix cargo lock file ([#116](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/116)) ([1bd3658](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/1bd3658ab507c2dde90a2132b6eaec6d849e0e3c)) +* Fix the codecov yaml syntax ([#97](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/97)) ([fcafcbf](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/fcafcbf5765014a65c3f2c8718ee0f24a4531ebe)) +* fixed check ([1d36aaa](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/1d36aaa63ca12b4a660ec7e7bfcb18f722d8adf2)) +* Generate SBOM step in release pipeline ([#294](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/294)) ([327269d](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/327269d1ce2a16e9c8419e872ca02503c318c480)) +* Linter ([b0e27ca](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/b0e27ca21f8e39b3a3c16d356df00dfcd0a868e5)) +* Monitor match template var signature collission (breaking) ([#203](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/203)) ([283b724](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/283b724a88f45f82c3c5fc81742a564b70909d45)) +* Multi arch. docker images and binary mismatch ([#382](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/382)) ([a61701e](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/a61701e11a13af03cdf86689b58e670b7d984a38)) +* Pagination logic in stellar getEvents relies only on cursor data ([#265](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/265)) ([fca4057](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/fca4057ff5847e04981e5903eebe6ccf3931726c)) +* PLAT-6301 Remove logic for checking file descriptors open and fixing readme ([#90](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/90)) ([71dbd24](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/71dbd24a9ba5ab4c37cf4be432a4614c2e68166b)) +* Reduce USDC ABI and fix trailing comma ([#62](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/62)) ([92e343c](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/92e343c09dc2da565912b6cd5bc83fbdc591cdb5)) +* Release binaries and enable nightly workflows to create binary artifacts and images ([#313](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/313)) ([43a0091](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/43a0091ed7b57a4ca33ca25a73423a73929802f7)) +* Remove deprecated reviewers field from dependabot.yml ([#316](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/316)) ([152843d](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/152843df396b089e1c6054221206097339502f1b)) +* remove the create-github-app-token action from the scorecard workflow ([#174](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/174)) ([48ca0b1](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/48ca0b106dbee225b5d4824013c2a28b773b23b3)) +* rename docker binaries ([#2](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/2)) ([78d438a](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/78d438a1ca4931651d3ca106c5dbda1ea1357574)) +* rename import ([#6](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/6)) ([745e591](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/745e591faba06f557b2f6a091434250ed559df6e)) +* Replace automatic minor version bumps ([#285](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/285)) ([0c9e14a](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/0c9e14a542cae2d2c7ff580ff7de28b0d9aab22a)) +* Risk of key collision for monitor custom scripts ([#258](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/258)) ([2aa4cd7](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/2aa4cd730dbcbbd1cf0892394cedc4ea06332375)) +* Running duplicate tests ([#181](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/181)) ([ad0f741](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/ad0f741608b2719a1db16dd22bf8c457e5814f86)) +* Semgrep CI integration ([#315](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/315)) ([a2bc23b](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/a2bc23baa27630ba914fca12ac40b191cbbad525)) +* Stellar ledgers are deterministic ([#257](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/257)) ([56a9f9e](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/56a9f9e10e533ea96c01cb1f0f67024600ad89df)) +* syntax error in codeql.yml ([#322](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/322)) ([7068e9e](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/7068e9ee3845a007ed9d6c80157cbe86555ad14e)) +* trigger execution order ([#24](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/24)) ([26581fe](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/26581fec9ec1078ea4284fd6b43509616c66ad64)) +* Update the Semgrep config ([#306](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/306)) ([d4ed740](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/d4ed7405e790098a0b1a0df3701feccb1908c56c)) +* Use unicode character for emoji ([#295](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/295)) ([bdccda5](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/bdccda5f2ca72612a4455a293c30647618476f95)) +* Variable resolving ([#49](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/49)) ([e26d173](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/e26d17314e9b2e78c0772a46f3139da70c6ca144)) + +[Changes][v1.1.0] + + + +# [v1.0.0](https://github.com/OpenZeppelin/openzeppelin-monitor/releases/tag/v1.0.0) - 2025-06-30 + +## [1.0.0](https://github.com/OpenZeppelin/openzeppelin-monitor/compare/v0.2.0...v1.0.0) (2025-06-30) + + +### πŸš€ Features + +* add block tracker ([#11](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/11)) ([1d4d117](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/1d4d117aab56e2c31c0747d6bf681fe60b2d8b10)) +* Add CLA assistant bot ([#107](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/107)) ([47e490e](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/47e490e4a5657a48bc60f85c38d72aca16334ac0)) +* Add client rpc pool ([#75](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/75)) ([28cd940](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/28cd940a8aea5c97fb15a4ca0d415debaa2864b1)) +* add email support ([#7](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/7)) ([decb56d](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/decb56d45d3f1000346c24e137d1a5d952c4a9dd)) +* Add endpoint rotation manager ([#69](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/69)) ([454a630](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/454a630cf92c305ea5d9254b211a7b60abf8804d)) +* Add environment vars and Hashicorp cloud vault support (breaking) ([#199](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/199)) ([558304f](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/558304f335a645c1de2d348a041337ccba2c2a06)) +* Add new error context ([#77](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/77)) ([612bb76](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/612bb76b9c8e9a470fc68685c2f06481663a9474)) +* Add rc workflow file ([#156](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/156)) ([8907591](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/890759186570a64a9d0b0ef4dc9e512d0110d7a0)) +* Add support for webhook, telegram, discord notifications ([#65](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/65)) ([829967d](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/829967da45062dc22ffb0cb3376e68101a46b3e9)) +* Enhance filter expression parsing and evaluation ([#222](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/222)) ([3cb0849](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/3cb084919b3d477f329a85fbafce1ce6d696b16d)) +* Extend support for EVM transaction properties ([#187](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/187)) ([f20086b](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/f20086b0431a787dd55aa8928a09aece80b9a731)) +* Handle Stellar JSON-RPC outside of retention window error for `getTransactions` and `getEvents` ([#270](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/270)) ([ae116ff](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/ae116ff10f393a04c19d3b845df656027c6be4b9)) +* Implement client pooling for Webhook-based notifiers ([#281](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/281)) ([4f480c6](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/4f480c6a05aeb949cfd8e227c5c08f19a5e60180)) +* Introduce `TransportError` ([#259](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/259)) ([0e04cfb](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/0e04cfb57109251095ef8ee526fb5e05f5792792)) +* Introduce centralized retryable HTTP client creation ([#273](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/273)) ([5f6edaf](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/5f6edaf5deb77a5d9dfead52a162e923aad6a2ab)) +* Leverage contract spec (SEP-48) for Stellar functions (breaking) ([#208](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/208)) ([5ebc2a4](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/5ebc2a441b9ac6ed66a0807cac2795af2ae5b1c8)) +* Markdown for telegram, discord, slack and email ([#197](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/197)) ([791bf4b](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/791bf4b347d8cfe03ccd53e9797f179c15629a33)) +* Plat 6187 write metrics to prometheus ([#95](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/95)) ([2dc08d5](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/2dc08d51670834f453498299937debfca67fa1b7)) +* PLAT-6148 Adding post filter to monitor model ([#58](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/58)) ([920a0bf](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/920a0bf27953b67eb722d17d5ebf50b51237d4d4)) +* PLAT-6151 Integrate custom script execution with notification service ([#79](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/79)) ([bd5f218](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/bd5f218507dfc30bd4b2182077e2997cf04b8877)) +* PLAT-6477 Adding rust toolchain file ([#117](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/117)) ([ea6fb1e](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/ea6fb1ee6bba46cfa66a0c81665e17930bbbed93)) +* Separate code test coverage into different categories of tests ([#84](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/84)) ([a3ad89c](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/a3ad89cdcf0bab5883af7ec36b854fedc2f060cd)) +* spawn block-watcher per network ([#4](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/4)) ([d7a19ec](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/d7a19ec57344e4fb28dffc6f2025e809d0f5d946)) +* Test execute the monitor against specific block ([#133](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/133)) ([563c34f](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/563c34fde3c0f334a7c5884de5510bf27e4fca48)) + + +### πŸ› Bug Fixes + +* Add thread flag when running tests in CI ([#41](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/41)) ([4312669](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/4312669d8da84f5cf7e7817b10c377fe3a6992af)) +* Adding validation for unknown field names ([#223](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/223)) ([cadf4da](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/cadf4dac293e2c24a02a2eb188540e1eb312b75f)) +* Adjust netlify toml settings ([#47](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/47)) ([af9fe55](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/af9fe553a92cfc47a306a7dcfc43be0b2257f835)) +* CLA labels and assistant ([#176](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/176)) ([b14f060](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/b14f0600dc4cac5a5f00d3772328abe123114b2a)) +* Docs link ([#106](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/106)) ([f12d95d](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/f12d95d85ad9230bece0342c39cb5c3c1cd62832)) +* Docs pipeline ([#167](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/167)) ([1e78ec4](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/1e78ec4f98f70ac12dea353c1605ac4ac2c5734b)) +* Documentation name for antora ([#105](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/105)) ([5a8c4bd](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/5a8c4bd8315e62bb2dedb066f6b6bfcaa09c2d37)) +* Duplicate name in triggers config ([#274](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/274)) ([00f58f4](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/00f58f4be3f9452792f9fdcf5dd8696947a274cb)) +* Environment adjustments and cargo lock file improvements ([#219](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/219)) ([1b4d5d8](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/1b4d5d8dbe8cba26fbb84a8f847fc22b1a1dc096)) +* Event and function signatures from matched_on ([#198](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/198)) ([cdd9f1d](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/cdd9f1d7333ee2f3ef9c476a08e918388b3c35f0)) +* Fix cargo lock ([#110](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/110)) ([c440ca4](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/c440ca43542e919cd473a7d533b0820cf5474d3e)) +* Fix cargo lock file ([#116](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/116)) ([1bd3658](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/1bd3658ab507c2dde90a2132b6eaec6d849e0e3c)) +* Fix the codecov yaml syntax ([#97](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/97)) ([fcafcbf](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/fcafcbf5765014a65c3f2c8718ee0f24a4531ebe)) +* fixed check ([1d36aaa](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/1d36aaa63ca12b4a660ec7e7bfcb18f722d8adf2)) +* Linter ([b0e27ca](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/b0e27ca21f8e39b3a3c16d356df00dfcd0a868e5)) +* Monitor match template var signature collission (breaking) ([#203](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/203)) ([283b724](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/283b724a88f45f82c3c5fc81742a564b70909d45)) +* Pagination logic in stellar getEvents relies only on cursor data ([#265](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/265)) ([fca4057](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/fca4057ff5847e04981e5903eebe6ccf3931726c)) +* PLAT-6301 Remove logic for checking file descriptors open and fixing readme ([#90](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/90)) ([71dbd24](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/71dbd24a9ba5ab4c37cf4be432a4614c2e68166b)) +* Reduce USDC ABI and fix trailing comma ([#62](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/62)) ([92e343c](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/92e343c09dc2da565912b6cd5bc83fbdc591cdb5)) +* remove the create-github-app-token action from the scorecard workflow ([#174](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/174)) ([48ca0b1](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/48ca0b106dbee225b5d4824013c2a28b773b23b3)) +* rename docker binaries ([#2](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/2)) ([78d438a](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/78d438a1ca4931651d3ca106c5dbda1ea1357574)) +* rename import ([#6](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/6)) ([745e591](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/745e591faba06f557b2f6a091434250ed559df6e)) +* Replace automatic minor version bumps ([#285](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/285)) ([0c9e14a](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/0c9e14a542cae2d2c7ff580ff7de28b0d9aab22a)) +* Risk of key collision for monitor custom scripts ([#258](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/258)) ([2aa4cd7](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/2aa4cd730dbcbbd1cf0892394cedc4ea06332375)) +* Running duplicate tests ([#181](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/181)) ([ad0f741](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/ad0f741608b2719a1db16dd22bf8c457e5814f86)) +* Stellar ledgers are deterministic ([#257](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/257)) ([56a9f9e](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/56a9f9e10e533ea96c01cb1f0f67024600ad89df)) +* trigger execution order ([#24](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/24)) ([26581fe](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/26581fec9ec1078ea4284fd6b43509616c66ad64)) +* Variable resolving ([#49](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/49)) ([e26d173](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/e26d17314e9b2e78c0772a46f3139da70c6ca144)) + +[Changes][v1.0.0] + + + +# [v0.2.0](https://github.com/OpenZeppelin/openzeppelin-monitor/releases/tag/v0.2.0) - 2025-05-14 + +## [0.2.0](https://github.com/OpenZeppelin/openzeppelin-monitor/compare/v0.1.0...v0.2.0) (2025-05-14) + + +## ⚠️ ⚠️ Breaking Changes in v0.2.0 + +* Renamed abi to contract_spec in monitor configurations. +* Stellar function expressions now use named parameters instead of positional indexes, for example; + + ``` + (Transfer(address,address,amount)): + 2 > 1000 β†’ amount > 1000 + ``` +* Template variables now follow dot notation rather than underscores, for example: + * monitor_name β†’ monitor.name + * transaction_hash β†’ transaction.hash + * function_0_amount β†’ functions.0.args.amount + * event_0_signature β†’ events.0.signature +* Sensitive configuration values (e.g., URLs, usernames, passwords, tokens) must now be defined using the SecretValue object structure, for example: + + * RPC URLs: + + ``` + "rpc_urls": [ + { + "type_": "rpc", + "url": { + "type": "plain", + "value": "https://eth.drpc.org" + }, + "weight": 100 + } + ] + ``` + + * Webhook URLs: + + ``` + "discord_url": { + "type": "plain", + "value": "https://discord.com/api/webhooks/123-456-789" + } + ``` + + +### πŸš€ Features + +* Add environment vars and Hashicorp cloud vault support (breaking) ([#199](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/199)) ([558304f](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/558304f335a645c1de2d348a041337ccba2c2a06)) +* Extend support for EVM transaction properties ([#187](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/187)) ([f20086b](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/f20086b0431a787dd55aa8928a09aece80b9a731)) +* Leverage contract spec (SEP-48) for Stellar functions (breaking) ([#208](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/208)) ([5ebc2a4](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/5ebc2a441b9ac6ed66a0807cac2795af2ae5b1c8)) +* Markdown for telegram, discord, slack and email ([#197](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/197)) ([791bf4b](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/791bf4b347d8cfe03ccd53e9797f179c15629a33)) +* Test execute the monitor against specific block ([#133](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/133)) ([563c34f](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/563c34fde3c0f334a7c5884de5510bf27e4fca48)) + + +### πŸ› Bug Fixes + +* Adding validation for unknown field names ([#223](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/223)) ([cadf4da](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/cadf4dac293e2c24a02a2eb188540e1eb312b75f)) +* CLA labels and assistant ([#176](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/176)) ([b14f060](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/b14f0600dc4cac5a5f00d3772328abe123114b2a)) +* Docs pipeline ([#167](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/167)) ([1e78ec4](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/1e78ec4f98f70ac12dea353c1605ac4ac2c5734b)) +* Environment adjustments and cargo lock file improvements ([#219](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/219)) ([1b4d5d8](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/1b4d5d8dbe8cba26fbb84a8f847fc22b1a1dc096)) +* Event and function signatures from matched_on ([#198](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/198)) ([cdd9f1d](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/cdd9f1d7333ee2f3ef9c476a08e918388b3c35f0)) +* Monitor match template var signature collission (breaking) ([#203](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/203)) ([283b724](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/283b724a88f45f82c3c5fc81742a564b70909d45)) +* remove the create-github-app-token action from the scorecard workflow ([#174](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/174)) ([48ca0b1](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/48ca0b106dbee225b5d4824013c2a28b773b23b3)) +* Running duplicate tests ([#181](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/181)) ([ad0f741](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/ad0f741608b2719a1db16dd22bf8c457e5814f86)) + +[Changes][v0.2.0] + + + +# [v0.1.0](https://github.com/OpenZeppelin/openzeppelin-monitor/releases/tag/v0.1.0) - 2025-04-07 + +## 0.1.0 (2025-04-07) + + +### πŸš€ Features + +* add block tracker ([#11](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/11)) ([1d4d117](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/1d4d117aab56e2c31c0747d6bf681fe60b2d8b10)) +* Add CLA assistant bot ([#107](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/107)) ([47e490e](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/47e490e4a5657a48bc60f85c38d72aca16334ac0)) +* Add client rpc pool ([#75](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/75)) ([28cd940](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/28cd940a8aea5c97fb15a4ca0d415debaa2864b1)) +* add email support ([#7](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/7)) ([decb56d](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/decb56d45d3f1000346c24e137d1a5d952c4a9dd)) +* Add endpoint rotation manager ([#69](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/69)) ([454a630](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/454a630cf92c305ea5d9254b211a7b60abf8804d)) +* Add new error context ([#77](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/77)) ([612bb76](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/612bb76b9c8e9a470fc68685c2f06481663a9474)) +* Add rc workflow file ([#156](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/156)) ([8907591](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/890759186570a64a9d0b0ef4dc9e512d0110d7a0)) +* Add support for webhook, telegram, discord notifications ([#65](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/65)) ([829967d](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/829967da45062dc22ffb0cb3376e68101a46b3e9)) +* Plat 6187 write metrics to prometheus ([#95](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/95)) ([2dc08d5](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/2dc08d51670834f453498299937debfca67fa1b7)) +* PLAT-6148 Adding post filter to monitor model ([#58](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/58)) ([920a0bf](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/920a0bf27953b67eb722d17d5ebf50b51237d4d4)) +* PLAT-6151 Integrate custom script execution with notification service ([#79](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/79)) ([bd5f218](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/bd5f218507dfc30bd4b2182077e2997cf04b8877)) +* PLAT-6477 Adding rust toolchain file ([#117](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/117)) ([ea6fb1e](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/ea6fb1ee6bba46cfa66a0c81665e17930bbbed93)) +* Separate code test coverage into different categories of tests ([#84](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/84)) ([a3ad89c](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/a3ad89cdcf0bab5883af7ec36b854fedc2f060cd)) +* spawn block-watcher per network ([#4](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/4)) ([d7a19ec](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/d7a19ec57344e4fb28dffc6f2025e809d0f5d946)) + + +### πŸ› Bug Fixes + +* Add thread flag when running tests in CI ([#41](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/41)) ([4312669](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/4312669d8da84f5cf7e7817b10c377fe3a6992af)) +* Adjust netlify toml settings ([#47](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/47)) ([af9fe55](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/af9fe553a92cfc47a306a7dcfc43be0b2257f835)) +* Docs link ([#106](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/106)) ([f12d95d](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/f12d95d85ad9230bece0342c39cb5c3c1cd62832)) +* Documentation name for antora ([#105](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/105)) ([5a8c4bd](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/5a8c4bd8315e62bb2dedb066f6b6bfcaa09c2d37)) +* Fix cargo lock ([#110](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/110)) ([c440ca4](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/c440ca43542e919cd473a7d533b0820cf5474d3e)) +* Fix cargo lock file ([#116](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/116)) ([1bd3658](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/1bd3658ab507c2dde90a2132b6eaec6d849e0e3c)) +* Fix the codecov yaml syntax ([#97](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/97)) ([fcafcbf](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/fcafcbf5765014a65c3f2c8718ee0f24a4531ebe)) +* fixed check ([1d36aaa](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/1d36aaa63ca12b4a660ec7e7bfcb18f722d8adf2)) +* Linter ([b0e27ca](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/b0e27ca21f8e39b3a3c16d356df00dfcd0a868e5)) +* Netlify integration & Release workflow doc ([#162](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/162)) ([3b77025](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/3b7702569e7c5828ca55fb67f7eec2672bf768b2)) +* PLAT-6301 Remove logic for checking file descriptors open and fixing readme ([#90](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/90)) ([71dbd24](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/71dbd24a9ba5ab4c37cf4be432a4614c2e68166b)) +* Reduce USDC ABI and fix trailing comma ([#62](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/62)) ([92e343c](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/92e343c09dc2da565912b6cd5bc83fbdc591cdb5)) +* rename docker binaries ([#2](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/2)) ([78d438a](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/78d438a1ca4931651d3ca106c5dbda1ea1357574)) +* rename import ([#6](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/6)) ([745e591](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/745e591faba06f557b2f6a091434250ed559df6e)) +* trigger execution order ([#24](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/24)) ([26581fe](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/26581fec9ec1078ea4284fd6b43509616c66ad64)) +* Variable resolving ([#49](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/49)) ([e26d173](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/e26d17314e9b2e78c0772a46f3139da70c6ca144)) + + +### πŸ“š Documentation + +* Add Antora documentation ([#48](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/48)) ([2f737c4](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/2f737c4c040090bd3acd0af90d3f24045b8ff173)) +* add link to contributing in README ([#33](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/33)) ([5abb548](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/5abb548c199f3a033860b027461e5fb3cd60e565)) +* Add list of RPC calls ([#67](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/67)) ([aae9577](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/aae9577f4e011eaca12adb7997bf5fd28a558f83)) +* Add quickstart guide ([#56](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/56)) ([e422353](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/e422353873335540afce5a9a5702c786c71eea75)) +* add readme documentation ([#8](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/8)) ([357006d](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/357006d98f6cc8d160920e702dc78662008d39a3)) +* add rust documentation ([#5](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/5)) ([3832570](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/3832570adf4854279fcda215fbbba5eb0d5396a1)) +* Adding node to docker images - custom scripts ([#76](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/76)) ([da6516c](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/da6516c6f3afccb297cb1c1251f673e02ceaeaa5)) +* Custom scripts documentation to antora and readme ([#91](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/91)) ([2b81058](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/2b81058f810e6b4d18a2c79e96002fb77890e9e0)) +* Fix quickstart closing tag ([#118](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/118)) ([d360379](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/d3603796f39c15ed5247efab90ab95c5537c76d2)) +* Fix telegram channel ([9899259](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/98992599ab8998113b6202781787a48ce0aab3db)) +* Implement README feedback ([#50](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/50)) ([5b6ba64](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/5b6ba6419a06b9abd60412fa02b09da2a416e38c)) +* Improve docs ([#100](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/100)) ([9586a25](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/9586a253f2a76993bbf82d4834b37863edabab60)) +* improve readme section and examples ([#9](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/9)) ([009db37](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/009db3719e1be03120733755ade3c1c45e13f8a5)) +* Improvements to custom scripts ([#98](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/98)) ([69047d9](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/69047d90a2fe057446f7c1b3f3526ab31bc6afcb)) +* Re-order example and fix test flag ([#52](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/52)) ([f90b6df](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/f90b6df73ef7a6040eab59d71402b34877c88fc5)) +* Readability improvements ([#109](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/109)) ([8e23389](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/8e23389ea0dcb3b221227a6cddd17de39603acbb)) +* Update project structure ([#101](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/101)) ([207edd2](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/207edd28f3fb0a805d40d6ba9109abe9e6553d23)) +* Update README and antora docs ([#57](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/57)) ([6a2299e](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/6a2299e0c41052ef9523aec1aa6f5852990e9179)) +* Update RPC documentation after client pool feature ([#96](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/96)) ([ade2811](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/ade2811431c07c6b46730cbce5e357934df14cd5)) +* Update telegram channel in docs ([#99](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/99)) ([9899259](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/98992599ab8998113b6202781787a48ce0aab3db)) +* Updated Quickstart guide ([#108](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/108)) ([b81c7cd](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/b81c7cd22143a7d2854ef496ab59e114d70c360f)) + +[Changes][v0.1.0] + + +[v1.1.0]: https://github.com/OpenZeppelin/openzeppelin-monitor/compare/v1.0.0...v1.1.0 +[v1.0.0]: https://github.com/OpenZeppelin/openzeppelin-monitor/compare/v0.2.0...v1.0.0 +[v0.2.0]: https://github.com/OpenZeppelin/openzeppelin-monitor/compare/v0.1.0...v0.2.0 +[v0.1.0]: https://github.com/OpenZeppelin/openzeppelin-monitor/tree/v0.1.0 diff --git a/content/monitor/1.0.x/contribution.mdx b/content/monitor/1.0.x/contribution.mdx new file mode 100644 index 00000000..5cbd528b --- /dev/null +++ b/content/monitor/1.0.x/contribution.mdx @@ -0,0 +1,303 @@ +--- +title: Contribution Guidelines +--- + +Welcome to the OpenZeppelin Monitor project! We appreciate your interest in contributing. This guide outlines the requirements and processes for contributing to the project. + +## Getting Started + +The OpenZeppelin Monitor project has comprehensive contribution guidelines documented in the [`CONTRIBUTING.md`](https://github.com/OpenZeppelin/openzeppelin-monitor/blob/main/CONTRIBUTING.md) file. This documentation provides a summary of key requirements, but for complete details including GitHub workflow, labeling guidelines, and advanced topics, please refer to the full CONTRIBUTING.md file. + + + +For the most up-to-date and comprehensive contribution guidelines, always refer to the [CONTRIBUTING.md](https://github.com/OpenZeppelin/openzeppelin-monitor/blob/main/CONTRIBUTING.md) file in the repository. + + +## Key Requirements + +### Contributor License Agreement (CLA) + +***You must sign the CLA before contributing.*** The CLA process is automated through GitHub workflows that check and label PRs accordingly. + +* All contributors must complete the CLA process +* The CLA bot will automatically check your PR status +* PRs cannot be merged without a signed CLA + +### Signed Commits + +***All commits must be GPG-signed*** as a security requirement. + +* Configure GPG signing for your commits +* Unsigned commits will not be accepted +* This helps ensure code integrity and authenticity + +## Development Environment Setup + +### Prerequisites + +Before contributing, ensure you have: + +* ***Rust 2021 edition*** - Required for development +* ***Git*** - For version control +* ***Python/pip*** - For pre-commit hooks + +### Initial Setup + +```bash +# Clone and set up the repository +git clone https://github.com/openzeppelin/openzeppelin-monitor +cd openzeppelin-monitor + +# Build the project +cargo build + +# Set up environment variables +cp .env.example .env +``` + +### Running Tests + +```bash +# All tests +RUST_TEST_THREADS=1 cargo test + +# Integration tests +RUST_TEST_THREADS=1 cargo test integration + +# Property-based tests +RUST_TEST_THREADS=1 cargo test properties +``` + +## Development Workflow + +### 1. Pre-commit Hooks + +***Required for code quality checks*** including `rustfmt`, `clippy`, and commit message validation. + +* Install and configure pre-commit hooks +* Automatic formatting and linting checks +* Commit message format validation + +#### Installing Pre-commit Hooks + +Install and configure pre-commit hooks to ensure code quality: + +```bash +# Install pre-commit (use pipx for global installation if preferred) +pip install pre-commit + +# Install and configure hooks for commit-msg, pre-commit, and pre-push +pre-commit install --install-hooks -t commit-msg -t pre-commit -t pre-push +``` + + + +If you encounter issues with pip install, you may need to install [pipx](https://github.com/pypa/pipx) for global installation. Use `pipx install pre-commit` instead. + + +The pre-commit hooks will automatically run on every commit and push, checking for: +* Code formatting with `rustfmt` +* Linting with `clippy` +* Commit message format validation +* Other code quality checks + +### 2. GitHub Workflow + +#### Fork and Clone + +1. ***Fork the repository*** on GitHub +2. ***Clone your fork*** locally: + +```bash +# Set up your working directory +export working_dir="$HOME/repos" +export user= + +# Clone your fork +mkdir -p $working_dir +cd $working_dir +git clone https://github.com/$user/openzeppelin-monitor.git + +# Add upstream remote +cd openzeppelin-monitor +git remote add upstream https://github.com/openzeppelin/openzeppelin-monitor.git +git remote set-url --push upstream no_push +``` + +#### Branch Management + +* Create feature branches from an up-to-date main branch +* Regularly sync with upstream +* Use descriptive branch names + +```bash +# Keep main updated +git fetch upstream +git checkout main +git rebase upstream/main + +# Create feature branch +git checkout -b feature/your-feature-name + +# Keep branch updated +git fetch upstream +git rebase upstream/main +``` + + + +Use `git rebase` instead of `git pull` to avoid merge commits and maintain a clean history. + + +### 3. Pull Request Process + +#### Creating a Pull Request + +1. ***Push your changes*** to your fork: + + ```bash + git push -f origin feature/your-feature-name + ``` +2. ***Create a Pull Request*** on GitHub +3. ***Add appropriate labels*** (see Labeling Guidelines below) +4. ***Include a clear description*** of your changes + +#### Best Practices for PRs + +* Write clear and meaningful commit messages +* Include `fixes #123` in PR body (not commit messages) to auto-close issues +* Break large changes into smaller, logical commits +* Ensure all tests pass +* Include sufficient information for reviewers + +## Code Standards + +### Rust Standards + +Rust API Guidelines: + +* Format code with `rustfmt` +* Pass all `clippy` linting checks +* Follow Rust naming conventions + +```bash +# Format code +cargo fmt + +# Check linting +cargo clippy --all-targets --all-features + +# Run tests +RUST_TEST_THREADS=1 cargo test +``` + +### Testing Requirements + +***All contributions must pass existing tests*** and include new tests when applicable: + +* Write unit tests for new functionality +* Add integration tests for complex features +* Ensure all tests pass before submitting +* Maintain or improve code coverage + +For detailed testing information, see the [Testing Guide](/monitor/1.0.x/testing). + +### Commit Message Format + +***Follow conventional commit format*** with types like: + +* `feat:` - New features +* `fix:` - Bug fixes +* `docs:` - Documentation changes +* `test:` - Test additions or modifications +* `refactor:` - Code refactoring +* `chore:` - Maintenance tasks + +## Issue and Pull Request Labeling + +The project uses a structured labeling system to organize issues and PRs. Key label categories include: + +### Area Labels (`A-`) +* `A-arch` - Architectural concerns +* `A-blocks` - Block processing +* `A-clients` - Blockchain clients +* `A-configs` - Configuration issues +* `A-docs` - Documentation +* `A-tests` - Testing + +### Type Labels (`T-`) +* `T-bug` - Bug reports +* `T-feature` - New features +* `T-task` - General tasks +* `T-documentation` - Documentation updates + +### Priority Labels (`P-`) +* `P-high` - Critical tasks +* `P-medium` - Important tasks +* `P-low` - Low priority + +### Difficulty Labels (`D-`) +* `D-easy` - Beginner-friendly +* `D-medium` - Intermediate +* `D-hard` - Complex issues + + + +For complete labeling guidelines and all available labels, see the [labeling section](https://github.com/OpenZeppelin/openzeppelin-monitor/blob/main/CONTRIBUTING.md#issue-and-pull-request-labeling-guidelines) in CONTRIBUTING.md. + + +## Code Review Process + +### Review Requirements + +* All PRs require review and approval +* At least one Reviewer and one Approver must approve +* Address all review comments before merging +* Commits are automatically squashed when merging + +### Review Guidelines + +Reviewers should focus on: + +1. ***Soundness*** - Is the idea behind the contribution sound? +2. ***Architecture*** - Is the contribution architected correctly? +3. ***Polish*** - Is the contribution polished and ready? + +### Getting Reviews + +If your PR isn’t getting attention: + +* Contact the team on [Telegram](https://t.me/openzeppelin_tg/4) +* Ensure your PR has appropriate labels +* Keep PRs focused and reasonably sized + +## Security + +* Follow the [Security Policy](https://github.com/OpenZeppelin/openzeppelin-monitor/blob/main/SECURITY.md) +* Report security vulnerabilities through the proper channels +* Never commit sensitive information or credentials + +## Community Guidelines + +### Code of Conduct + +Contributors must follow the [Code of Conduct](https://github.com/OpenZeppelin/openzeppelin-monitor/blob/main/CODE_OF_CONDUCT.md), which: + +* Establishes standards for respectful collaboration +* Outlines enforcement procedures +* Promotes an inclusive environment + +## Getting Help + +### Community Support + +* ***GitHub Discussions***: For questions and community interaction +* ***Issues***: For bug reports and feature requests +* ***Telegram***: [Join our community chat](https://t.me/openzeppelin_tg/4) +* ***Good First Issues***: [Find beginner-friendly issues](https://github.com/openzeppelin/openzeppelin-monitor/issues?q=is%3Aissue+is%3Aopen+label%3Agood-first-issue) + +### Additional Resources + +* ***Full CONTRIBUTING.md***: [Complete contribution guidelines](https://github.com/OpenZeppelin/openzeppelin-monitor/blob/main/CONTRIBUTING.md) +* ***User Documentation***: [Monitor documentation](https://docs.openzeppelin.com/monitor) +* ***OpenZeppelin Website***: [Main website](https://openzeppelin.com/) diff --git a/content/monitor/1.0.x/error.mdx b/content/monitor/1.0.x/error.mdx new file mode 100644 index 00000000..3b9c1dab --- /dev/null +++ b/content/monitor/1.0.x/error.mdx @@ -0,0 +1,167 @@ +--- +title: Error Handling +--- + +## Overview + +The OpenZeppelin Monitor uses a structured error handling system that provides rich context and tracing capabilities across service boundaries. Let’s start with a real-world example of how errors flow through our system. + +## Error Flow Example + +Let’s follow how an error propagates through our blockchain monitoring system: + +**Low-level Transport (`endpoint_manager.rs`)** + +```rust +// Creates basic errors with specific context +async fn send_raw_request(...) -> Result + let response = client.post(...) + .await + .map_err(|e| anyhow::anyhow!("Failed to send request: {", e))?; + + if !status.is_success() + return Err(anyhow::anyhow!("HTTP error {: {}", status, error_body)); + } +} +``` + +**Client Layer (`evm/client.rs`)** + +```rust +// Adds business context to low-level errors +async fn get_transaction_receipt(...) -> Result + let response = self.alloy_client + .send_raw_request(...) + .await + .with_context(|| format!("Failed to get transaction receipt: {", tx_hash))?; + + if receipt_data.is_null() + return Err(anyhow::anyhow!("Transaction receipt not found")); + +} +``` + +**Filter Layer (`evm/filter.rs`)** + +```rust +// Converts to domain-specific errors +async fn filter_block(...) -> Result, FilterError> + let receipts = match futures::future::join_all(receipt_futures).await { + Ok(receipts) => receipts, + Err(e) => { + return Err(FilterError::network_error( + format!("Failed to get transaction receipts for block {", block_num), + Some(e.into()), + None, + )); + } + }; +} +``` + +When this error occurs, it produces the following log: + +```text +ERROR filter_block: openzeppelin_monitor::utils::error: Error occurred, + error.message: Failed to get transaction receipts for block 15092829, + error.trace_id: a464d73c-5992-4cb5-a002-c8d705bfef8d, + error.timestamp: 2025-03-14T09:42:03.412341+00:00, + error.chain: Failed to get receipt for transaction 0x7722194b65953085fe1e9ec01003f1d7bdd6258a0ea5c91a59da80419513d95d + Caused by: HTTP error 429 Too Many Requests: "code":-32007,"message":"[Exceeded request limit per second]" + network: ethereum_mainnet +``` + +## Error Structure + +### Error Context +Every error in our system includes detailed context information: + +```rust +pub struct ErrorContext + /// The error message + pub message: String, + /// The source error (if any) + pub source: Option>, + /// Unique trace ID for error tracking + pub trace_id: String, + /// Timestamp when the error occurred + pub timestamp: DateTime, + /// Optional key-value metadata + pub metadata: HashMap, + +``` + +### Domain-Specific Error Types + +| Module | Error Type | Description | +| --- | --- | --- | +| `**Configuration**` | `ConfigError` | * `ValidationError` - Configuration validation failures * `ParseError` - Configuration parsing issues * `FileError` - File system related errors * `Other` - Unclassified errors | +| `**Security**` | `SecurityError` | * `ValidationError` - Security validation failures * `ParseError` - Security data parsing issues * `NetworkError` - Security service connectivity issues * `Other` - Unclassified security-related errors | +| `**Blockchain Service**` | `BlockChainError` | * `ConnectionError` - Network connectivity issues * `RequestError` - Malformed requests or invalid responses * `BlockNotFound` - Requested block not found * `TransactionError` - Transaction processing failures * `InternalError` - Internal client errors * `ClientPoolError` - Client pool related issues * `Other` - Unclassified errors | +| `**Block Watcher Service**` | `BlockWatcherError` | * `SchedulerError` - Block watching scheduling issues * `NetworkError` - Network connectivity problems * `ProcessingError` - Block processing failures * `StorageError` - Storage operation failures * `BlockTrackerError` - Block tracking issues * `Other` - Unclassified errors | +| `**Filter Service**` | `FilterError` | * `BlockTypeMismatch` - Block type validation failures * `NetworkError` - Network connectivity issues * `InternalError` - Internal processing errors * `Other` - Unclassified errors | +| `**Notification Service**` | `NotificationError` | * `NetworkError` - Network connectivity issues * `ConfigError` - Configuration problems * `InternalError` - Internal processing errors * `ExecutionError` - Script execution failures * `Other` - Unclassified errors | +| `**Repository**` | `RepositoryError` | * `ValidationError` - Data validation failures * `LoadError` - Data loading issues * `InternalError` - Internal processing errors * `Other` - Unclassified errors | +| `**Script Utils**` | `ScriptError` | * `NotFound` - Resource not found errors * `ExecutionError` - Script execution failures * `ParseError` - Script parsing issues * `SystemError` - System-level errors * `Other` - Unclassified errors | +| `**Trigger Service**` | `TriggerError` | * `NotFound` - Resource not found errors * `ExecutionError` - Trigger execution failures * `ConfigurationError` - Trigger configuration issues * `Other` - Unclassified errors | +| `**Monitor Executor**` | `MonitorExecutionError` | * `NotFound` - Resource not found errors * `ExecutionError` - Monitor execution failures * `Other` - Unclassified errors | + +## Error Handling Guidelines + +### When to Use Each Pattern + +| Scenario | Approach | +| --- | --- | +| Crossing Domain Boundaries | Convert to domain-specific error type using custom error constructors | +| Within Same Domain | Use `.with_context()` to add information while maintaining error type | +| External API Boundaries | Always convert to your domain’s error type to avoid leaking implementation details | + +### Error Creation Examples + +**Creating a Configuration Error without a source** + +```rust +let error = ConfigError::validation_error( + "Invalid network configuration", + None, + Some(HashMap::from([ + ("network", "ethereum"), + ("field", "rpc_url") + ])) +); +``` + +**Creating a Configuration Error with a source** + +```rust + +let io_error = std::io::Error::new(std::io::ErrorKind::Other, "Failed to read file"); + +let error = ConfigError::validation_error( + "Invalid network configuration", + Some(io_error.into()), + None +); +``` + +### Tracing with #[instrument] + +```rust +#[instrument(skip_all, fields(network = %_network.slug))] +async fn filter_block( + &self, + client: &T, + _network: &Network, + block: &BlockType, + monitors: &[Monitor], +) -> Result, FilterError> + tracing::debug!("Processing block {", block_number); + // ... +} +``` + +Key aspects: + +1. `skip_all` - Skips automatic instrumentation of function parameters for performance +2. `fields(...)` - Adds specific fields we want to track (like network slug) +3. `tracing::debug!` - Adds debug-level spans for important operations diff --git a/content/monitor/1.0.x/index.mdx b/content/monitor/1.0.x/index.mdx new file mode 100644 index 00000000..690766ad --- /dev/null +++ b/content/monitor/1.0.x/index.mdx @@ -0,0 +1,1438 @@ +--- +title: OpenZeppelin Monitor +--- + +## Overview + +In the rapidly evolving world of blockchain technology, effective monitoring is crucial for ensuring security and performance. OpenZeppelin Monitor is a blockchain monitoring service that watches for specific on-chain activities and triggers notifications based on configurable conditions. The service offers multi-chain support with configurable monitoring schedules, flexible trigger conditions, and an extensible architecture for adding new chains. + +### Key Capabilities + +* ***Real-time Monitoring***: Watch blockchain networks in real-time for specific events and transactions +* ***Smart Filtering***: Use flexible expressions to define exactly what you want to monitor +* ***Multi-notification Support***: Send alerts via Slack, Discord, Email, Telegram, Webhooks, or custom scripts +* ***Configurable Scheduling***: Set custom monitoring schedules using cron expressions +* ***Data Persistence***: Store monitoring data and resume from checkpoints +* ***Extensible Architecture***: Easy to add support for new blockchains and notification types + +### Supported Networks + +* ***EVM-Compatible Networks*** +* ***Stellar*** + +### Notification Channels + +* ***Slack*** - Send formatted messages to Slack channels +* ***Discord*** - Post alerts to Discord channels via webhooks +* ***Email*** - Send email notifications with SMTP support +* ***Telegram*** - Send messages to Telegram chats via bot API +* ***Webhooks*** - Send HTTP requests to custom endpoints +* ***Custom Scripts*** - Execute Python, JavaScript, or Bash scripts + + + +To get started immediately, see [Quickstart](/monitor/1.0.x/quickstart). + + +## Installation + +### Prerequisites + +* Use ***Rust 2021 edition***, version `1.86` or later. +* ***Docker*** (optional, for containerized deployment) + +### Local Installation + +1. ***Clone the repository:*** + + ```bash + git clone https://github.com/openzeppelin/openzeppelin-monitor + cd openzeppelin-monitor + ``` +2. ***Build the application:*** + + ```bash + cargo build --release + ``` +3. ***Move binary to project root:*** + + ```bash + mv ./target/release/openzeppelin-monitor . + ``` +4. ***Verify installation:*** + + ```bash + ./openzeppelin-monitor --help + ``` +5. ***View available options:*** + + ```bash + ./openzeppelin-monitor --help + + # Enable logging to file + ./openzeppelin-monitor --log-file + + # Enable metrics server + ./openzeppelin-monitor --metrics + + # Validate configuration files without starting the service + ./openzeppelin-monitor --check + ``` + +### Docker Installation + +1. ***Clone the repository:*** + + ```bash + git clone https://github.com/openzeppelin/openzeppelin-monitor + cd openzeppelin-monitor + ``` +2. ***Set up environment:*** + + ```bash + cp .env.example .env + # Edit .env file with your configuration + ``` +3. ***Start with Docker Compose:*** + + ```bash + cargo make docker-compose-up + ``` + +#### Metrics Configuration + +The metrics server, Prometheus, and Grafana can be enabled by setting `METRICS_ENABLED=true` in your `.env` file. + +You can start services directly with Docker Compose: + +```bash +# without metrics profile ( METRICS_ENABLED=false by default ) +docker compose up -d + +# With metrics enabled +docker compose --profile metrics up -d +``` + +To view prometheus metrics in a UI, you can use `http://localhost:9090` on your browser. + +To view grafana dashboard, you can use `http://localhost:3000` on your browser. + +By default, predefined metrics within a dashboard is populated in grafana. + +### Configuration Guidelines + +#### Recommended File Naming Conventions + +* Network configurations: `_.json` + * Example: `ethereum_mainnet.json`, `stellar_testnet.json` + * Should match the `slug` property inside the file +* Monitor configurations: `__monitor.json` + * Example: `usdc_transfer_monitor.json`, `dai_liquidation_monitor.json` + * Referenced by monitors using their `name` property +* Trigger configurations: `_.json` + * Example: `slack_notifications.json`, `email_alerts.json` + * Individual triggers referenced by their configuration key + +#### Configuration References + +* Monitor, network, and trigger names ***must be unique*** across all configurations files +* Monitor’s `networks` array must contain valid network `slug` values from network configuration files +* Monitor’s `triggers` array must contain valid trigger configuration keys +* Example valid references: + + ```json + // networks/ethereum_mainnet.json + { + "slug": "ethereum_mainnet", + ... + } + + // triggers/slack_notifications.json + { + "large_transfer_slack": { + ... + } + } + + // monitors/usdc_transfer_monitor.json + { + "networks": ["ethereum_mainnet"], + "triggers": ["large_transfer_slack"], + ... + } + ``` + + + + +Ensure all referenced slugs and trigger keys exist in their respective configuration files. The monitor will fail to start if it cannot resolve these references. + + + +#### Safe Protocol Guidelines + +The monitor implements protocol security validations across different components and will issue warnings when potentially insecure configurations are detected. While insecure protocols are not blocked, we strongly recommend following these security guidelines: + +##### Network Protocols + +###### RPC URLs +* **HTTPS Recommended**: Using `https://` for RPC endpoints is strongly recommended +* **WSS Recommended**: For WebSocket connections, `wss://` (secure WebSocket) is strongly recommended +* **Warning**: Using `http://` or `ws://` will trigger security warnings as they transmit data unencrypted + +##### Notification Protocols + +###### Webhook Notifications +* **HTTPS Recommended**: URLs should use HTTPS protocol +* **Authentication Recommended**: Including either: + * `X-API-Key` header + * `Authorization` header +* **Optional Secret**: Can include a secret for HMAC authentication + * When a secret is provided, the monitor will: + * Generate a timestamp in milliseconds + * Create an HMAC-SHA256 signature of the payload and timestamp + * Add the signature in the `X-Signature` header + * Add the timestamp in the `X-Timestamp` header + * The signature is computed as: `HMAC-SHA256(secret, payload + timestamp)` +* **Warning**: Non-HTTPS URLs or missing authentication headers will trigger security warnings + +###### Slack Notifications +* **HTTPS Recommended**: Webhook URLs should start with `https://hooks.slack.com/` +* **Warning**: Non-HTTPS URLs will trigger security warnings + +###### Discord Notifications +* **HTTPS Recommended**: Webhook URLs should start with `https://discord.com/api/webhooks/` +* **Warning**: Non-HTTPS URLs will trigger security warnings + +###### Telegram Notifications +* ***Protocol:*** `POST` request with a `application/json` payload to the `sendMessage` method. +* ***Endpoint:*** `https://api.telegram.org/bot/sendMessage` +* ***Security:*** + * ***HTTPS Required:*** The API endpoint uses HTTPS. + * Authentication is handled via the ***Bot Token*** in the URL. Keep this token secure. +* ***Formatting:*** Messages are sent with `parse_mode` set to `MarkdownV2`. Special characters in the message title and body are automatically escaped to prevent formatting errors. + +###### Email Notifications +* **Secure Ports Recommended**: The following ports are considered secure: + * 465: SMTPS (SMTP over SSL) + * 587: SMTP with STARTTLS + * 993: IMAPS (IMAP over SSL) +* **Warning**: Using other ports will trigger security warnings +* **Valid Format**: Email addresses must follow RFC 5322 format + +###### Notifications Retry Policy + +Following notification protocols support retry policies: + +* Slack +* Discord +* Telegram +* Webhook +* Email + +Default retry policy is using exponential backoff with the following parameters: +| | | | +| --- | --- | --- | +| Parameter | Default Value | Description | +| `max_retries` | `3` | Maximum number of retries before giving up | +| `base_for_backoff` | `2` | Base duration for exponential backoff calculations in seconds | +| `initial_backoff` | `250` | Initial backoff duration in milliseconds | +| `max_backoff` | `10` | Maximum backoff duration in seconds | +| `jitter` | `Full` | Jitter strategy to apply to the backoff duration, currently supports `Full` and `None` | + +These parameters can be overridden by providing custom `RetryConfig` struct in `retry_policy` field in trigger configuration. + +##### Script Security + +###### File Permissions (Unix Systems) +* **Restricted Write Access**: Script files should not have overly permissive write permissions +* **Recommended Permissions**: Use `644` (`rw-r--r--`) for script files +* **Warning**: Files with mode `022` or more permissive will trigger security warnings + +**Example Setting Recommended Permissions** + +```bash +chmod 644 ./config/filters/my_script.sh +``` + +#### Secret Management + +The monitor implements a secure secret management system with support for multiple secret sources and automatic memory zeroization. + +##### Secret Sources + +The monitor supports three types of secret sources: + +* **Plain Text**: Direct secret values (wrapped in `SecretString` for secure memory handling) +* **Environment Variables**: Secrets stored in environment variables +* **Hashicorp Cloud Vault**: Secrets stored in Hashicorp Cloud Vault + +##### Security Features + +* **Automatic Zeroization**: Secrets are automatically zeroized from memory when no longer needed +* **Type-Safe Resolution**: Secure handling of secret resolution with proper error handling +* **Configuration Support**: Serde support for configuration files + +##### Configuration + +Secrets can be configured in the JSON files using the following format: + +```json +{ + "type": "Plain", + "value": "my-secret-value" +} +``` + +```json +{ + "type": "Environment", + "value": "MY_SECRET_ENV_VAR" +} +``` + +```json +{ + "type": "HashicorpCloudVault", + "value": "my-secret-name" +} +``` + +##### Hashicorp Cloud Vault Integration + +To use Hashicorp Cloud Vault, configure the following environment variables: + +| Environment Variable | Description | +| --- | --- | +| `HCP_CLIENT_ID` | Hashicorp Cloud Vault client ID | +| `HCP_CLIENT_SECRET` | Hashicorp Cloud Vault client secret | +| `HCP_ORG_ID` | Hashicorp Cloud Vault organization ID | +| `HCP_PROJECT_ID` | Hashicorp Cloud Vault project ID | +| `HCP_APP_NAME` | Hashicorp Cloud Vault application name | + +##### Best Practices + +* Use environment variables or vault for production secrets +* Avoid storing plain text secrets in configuration files +* Use appropriate access controls for vault secrets +* Monitor vault access patterns for suspicious activity + +#### Basic Configuration + +* Set up environment variables: + +Copy the example environment file and update values according to your needs + +```bash +cp .env.example .env +``` + +This table lists the environment variables and their default values. + +| Environment Variable | Default Value | Accepted Values | Description | +| --- | --- | --- | --- | +| `RUST_LOG` | `info` | `info, debug, warn, error, trace` | Log level. | +| `LOG_MODE` | `stdout` | `stdout, file` | Write logs either to console or to file. | +| `LOG_DATA_DIR` | `logs/` | `` | Directory to write log files on host. | +| `MONITOR_DATA_DIR` | `null` | `` | Persist monitor data between container restarts. | +| `LOG_MAX_SIZE` | `1073741824` | `` | Size after which logs needs to be rolled. Accepts both raw bytes (e.g., "1073741824") or human-readable formats (e.g., "1GB", "500MB"). | +| `METRICS_ENABLED` | `false` | `true`, `false` | Enable metrics server for external tools to scrape metrics. | +| `METRICS_PORT` | `8081` | `` | Port to use for metrics server. | +| `HCP_CLIENT_ID` | - | `` | Hashicorp Cloud Vault client ID for secret management. | +| `HCP_CLIENT_SECRET` | - | `` | Hashicorp Cloud Vault client secret for secret management. | +| `HCP_ORG_ID` | - | `` | Hashicorp Cloud Vault organization ID for secret management. | +| `HCP_PROJECT_ID` | - | `` | Hashicorp Cloud Vault project ID for secret management. | +| `HCP_APP_NAME` | - | `` | Hashicorp Cloud Vault application name for secret management. | +* Copy and configure some example files: + +```bash +# EVM Configuration +cp examples/config/monitors/evm_transfer_usdc.json config/monitors/evm_transfer_usdc.json +cp examples/config/networks/ethereum_mainnet.json config/networks/ethereum_mainnet.json + +# Stellar Configuration +cp examples/config/monitors/stellar_swap_dex.json config/monitors/stellar_swap_dex.json +cp examples/config/networks/stellar_mainnet.json config/networks/stellar_mainnet.json + +# Notification Configuration +cp examples/config/triggers/slack_notifications.json config/triggers/slack_notifications.json +cp examples/config/triggers/email_notifications.json config/triggers/email_notifications.json + +# Filter Configuration +cp examples/config/filters/evm_filter_block_number.sh config/filters/evm_filter_block_number.sh +cp examples/config/filters/stellar_filter_block_number.sh config/filters/stellar_filter_block_number.sh +``` +### Command Line Options + +The monitor supports several command-line options for configuration and control: + +| **Option** | **Default** | **Description** | +| --- | --- | --- | +| `**--log-file**` | `false` | Write logs to file instead of stdout | +| `**--log-level**` | `info` | Set log level (trace, debug, info, warn, error) | +| `**--log-path**` | `logs/` | Path to store log files | +| `**--log-max-size**` | `1GB` | Maximum log file size before rolling | +| `**--metrics-address**` | `127.0.0.1:8081` | Address to start the metrics server on | +| `**--metrics**` | `false` | Enable metrics server | +| `**--monitor-path**` | - | Path to the monitor to execute (for testing) | +| `**--network**` | - | Network to execute the monitor for (for testing) | +| `**--block**` | - | Block number to execute the monitor for (for testing) | +| `**--check**` | `false` | Validate configuration files without starting the service | + +## Data Storage Configuration + +The monitor uses file-based storage by default. + +### File Storage + +When `store_blocks` is enabled in the network configuration, the monitor stores: + +* Processed blocks: `./data/_blocks_.json` +* Missed blocks: `./data/_missed_blocks.txt` (used to store missed blocks) + +The content of the `missed_blocks.txt` file may help to determine the right `max_past_blocks` value based on the network’s block time and the monitor’s cron schedule. + +Additionally, the monitor will always store: + +* Last processed block: `./data/_last_block.txt` (enables resuming from last checkpoint) + +## Configuration Files + +### Network Configuration + +A Network configuration defines connection details and operational parameters for a specific blockchain network, supporting both EVM and Stellar-based chains. + +**Example Network Configuration** + +```json +{ + "network_type": "Stellar", + "slug": "stellar_mainnet", + "name": "Stellar Mainnet", + "rpc_urls": [ + { + "type_": "rpc", + "url": { + "type": "plain", + "value": "https://soroban.stellar.org" + }, + "weight": 100 + } + ], + "network_passphrase": "Public Global Stellar Network ; September 2015", + "block_time_ms": 5000, + "confirmation_blocks": 2, + "cron_schedule": "0 */1 * * * *", + "max_past_blocks": 20, + "store_blocks": true +} +``` + +#### Available Fields + +| **Field** | **Type** | **Description** | +| --- | --- | --- | +| `**network_type**` | `String` | Type of blockchain (**"EVM"** or **"Stellar"**) | +| `**slug**` | `String` | **Required** - **_Unique_** identifier for the network | +| `**name**` | `String` | **Required** - **_Unique_** Human-readable network name | +| `**rpc_urls**` | `Array[Object]` | List of RPC endpoints with weights for load balancing | +| `**chain_id**` | `Number` | Network chain ID (**EVM only**) | +| `**network_passphrase**` | `String` | Network identifier (**Stellar only**) | +| `**block_time_ms**` | `Number` | Average block time in milliseconds | +| `**confirmation_blocks**` | `Number` | Number of blocks to wait for confirmation | +| `**cron_schedule**` | `String` | Monitor scheduling in cron format | +| `**max_past_blocks**` | `Number` | Maximum number of past blocks to process | +| `**store_blocks**` | `Boolean` | Whether to store processed blocks (defaults output to `./data/` directory) | + +#### Important Considerations + +* We strongly recommend using private RPC providers for improved reliability. + +### Trigger Configuration + +A Trigger defines actions to take when monitored conditions are met. Triggers can send notifications, make HTTP requests, or execute scripts. + +**Example Trigger Configuration** + +```json +{ + "evm_large_transfer_usdc_slack": { + "name": "Large Transfer Slack Notification", + "trigger_type": "slack", + "config": { + "slack_url": { + "type": "plain", + "value": "https://hooks.slack.com/services/A/B/C" + }, + "message": { + "title": "large_transfer_slack triggered", + "body": "Large transfer of ${events.0.args.value} USDC from $events.0.args.from to $events.0.args.to | https://etherscan.io/tx/$transaction.hash#eventlog" + } + } + }, + "stellar_large_transfer_usdc_slack": { + "name": "Large Transfer Slack Notification", + "trigger_type": "slack", + "config": { + "slack_url": { + "type": "environment", + "value": "SLACK_WEBHOOK_URL" + }, + "message": { + "title": "large_transfer_usdc_slack triggered", + "body": "${monitor.name} triggered because of a large transfer of $functions.0.args.amount USDC to $functions.0.args.to | https://stellar.expert/explorer/testnet/tx/$transaction.hash" + } + } + } +} +``` + +#### Trigger Types + +##### Slack Notifications +```json +{ + "slack_url": { + "type": "HashicorpCloudVault", + "value": "slack-webhook-url" + }, + "message": { + "title": "Alert Title", + "body": "Alert message for ${transaction.hash}" + } +} +``` + +##### Slack Notification Fields +| **Field** | **Type** | **Description** | +| --- | --- | --- | +| `**name**` | `String` | **Required** - **_Unique_** Human-readable name for the notification | +| `**trigger_type**` | `String` | Must be **"slack"** for Slack notifications | +| `**config.slack_url.type**` | `String` | Secret type (**"Plain"**, **"Environment"**, or **"HashicorpCloudVault"**) | +| `**config.slack_url.value**` | `String` | Secret value (URL, environment variable name, or vault secret name) | +| `**config.message.title**` | `String` | Title that appears in the Slack message | +| `**config.message.body**` | `String` | Message template with variable substitution | + +##### Email Notifications +```json +{ + "host": "smtp.gmail.com", + "port": 465, + "username": { + "type": "plain", + "value": "sender@example.com" + }, + "password": { + "type": "environment", + "value": "SMTP_PASSWORD" + }, + "message": { + "title": "Alert Subject", + "body": "Alert message for ${transaction.hash}" + }, + "sender": "sender@example.com", + "recipients": ["recipient@example.com"] +} +``` + +##### Email Notification Fields +| **Field** | **Type** | **Description** | +| --- | --- | --- | +| `**name**` | `String` | **Required** - **_Unique_** Human-readable name for the notification | +| `**trigger_type**` | `String` | Must be **"email"** for email notifications | +| `**config.host**` | `String` | SMTP server hostname | +| `**config.port**` | `Number` | SMTP port (defaults to **465**) | +| `**config.username.type**` | `String` | Secret type (**"Plain"**, **"Environment"**, or **"HashicorpCloudVault"**) | +| `**config.username.value**` | `String` | Secret value (username, environment variable name, or vault secret name) | +| `**config.password.type**` | `String` | Secret type (**"Plain"**, **"Environment"**, or **"HashicorpCloudVault"**) | +| `**config.password.value**` | `String` | Secret value (password, environment variable name, or vault secret name) | +| `**config.message.title**` | `String` | Email subject line | +| `**config.message.body**` | `String` | Email body template with variable substitution | +| `**config.sender**` | `String` | Sender email address | +| `**config.recipients**` | `Array[String]` | List of recipient email addresses | + +##### Webhook Notifications +```json +{ + "url": { + "type": "HashicorpCloudVault", + "value": "webhook-url" + }, + "method": "POST", + "secret": { + "type": "environment", + "value": "WEBHOOK_SECRET" + }, + "headers": { + "Content-Type": "application/json" + }, + "message": { + "title": "Alert Title", + "body": "Alert message for ${transaction.hash}" + } +} +``` + +##### Webhook Notification Fields +| **Field** | **Type** | **Description** | +| --- | --- | --- | +| `**name**` | `String` | **Required** - **_Unique_** Human-readable name for the notification | +| `**trigger_type**` | `String` | Must be **"webhook"** for webhook notifications | +| `**config.url.type**` | `String` | Secret type (**"Plain"**, **"Environment"**, or **"HashicorpCloudVault"**) | +| `**config.url.value**` | `String` | Secret value (URL, environment variable name, or vault secret name) | +| `**config.method**` | `String` | HTTP method (POST, GET, etc.) defaults to POST | +| `**config.secret.type**` | `String` | Secret type (**"Plain"**, **"Environment"**, or **"HashicorpCloudVault"**) | +| `**config.secret.value**` | `String` | Secret value (HMAC secret, environment variable name, or vault secret name) | +| `**config.headers**` | `Object` | Headers to include in the webhook request | +| `**config.message.title**` | `String` | Title that appears in the webhook message | +| `**config.message.body**` | `String` | Message template with variable substitution | + +##### Discord Notifications +```json +{ + "discord_url": { + "type": "plain", + "value": "https://discord.com/api/webhooks/123-456-789" + }, + "message": { + "title": "Alert Title", + "body": "Alert message for ${transaction.hash}" + } +} +``` + +##### Discord Notification Fields +| **Field** | **Type** | **Description** | +| --- | --- | --- | +| `**name**` | `String` | **Required** - **_Unique_** Human-readable name for the notification | +| `**trigger_type**` | `String` | Must be **"discord"** for Discord notifications | +| `**config.discord_url.type**` | `String` | Secret type (**"Plain"**, **"Environment"**, or **"HashicorpCloudVault"**) | +| `**config.discord_url.value**` | `String` | Secret value (URL, environment variable name, or vault secret name) | +| `**config.message.title**` | `String` | Title that appears in the Discord message | +| `**config.message.body**` | `String` | Message template with variable substitution | + +##### Telegram Notifications +```json +{ + "token": { + "type": "HashicorpCloudVault", + "value": "telegram-bot-token" + }, + "chat_id": "9876543210", + "message": { + "title": "Alert Title", + "body": "Alert message for ${transaction.hash}" + } +} +``` + +##### Telegram Notification Fields +| **Field** | **Type** | **Description** | +| --- | --- | --- | +| `**name**` | `String` | **Required** - **_Unique_** Human-readable name for the notification | +| `**trigger_type**` | `String` | Must be **"telegram"** for Telegram notifications | +| `**config.token.type**` | `String` | Secret type (**"Plain"**, **"Environment"**, or **"HashicorpCloudVault"**) | +| `**config.token.value**` | `String` | Secret value (bot token, environment variable name, or vault secret name) | +| `**config.chat_id**` | `String` | Telegram chat ID | +| `**config.disable_web_preview**` | `Boolean` | Whether to disable web preview in Telegram messages (defaults to false) | +| `**config.message.title**` | `String` | Title that appears in the Telegram message | +| `**config.message.body**` | `String` | Message template with variable substitution | + +##### Custom Script Notifications +```json +{ + "language": "Bash", + "script_path": "./config/triggers/scripts/custom_notification.sh", + "arguments": ["--verbose"], + "timeout_ms": 1000 +} +``` + +##### Script Notification Fields +| **Field** | **Type** | **Description** | +| --- | --- | --- | +| `**name**` | `String` | **Required** - **_Unique_** Human-readable name for the notification | +| `**trigger_type**` | `String` | Must be **"script"** for Custom Script notifications | +| `**language**` | `String` | The language of the script | +| `**script_path**` | `String` | The path to the script | +| `**arguments**` | `Array[String]` | The arguments of the script (optional). | +| `**timeout_ms**` | `Number` | The timeout of the script is important to avoid infinite loops during the execution. If the script takes longer than the timeout, it will be killed. | + +For more information about custom scripts, see [Custom Scripts Section](/monitor/1.0.x/scripts). + + + +***Security Risk***: Only run scripts that you trust and fully understand. Malicious scripts can harm your system or expose sensitive data. Always review script contents and verify their source before execution. + + +#### Available Template Variables + +The monitor uses a structured JSON format with nested objects for template variables. The data is flattened into dot notation for template use. + +##### Common Variables +| **Variable** | **Description** | +| --- | --- | +| `**monitor.name**` | Name of the triggered monitor | +| `**transaction.hash**` | Hash of the transaction | +| `**functions.[index].signature**` | Function signature | +| `**events.[index].signature**` | Event signature | + +##### Network-Specific Variables + +###### EVM Variables +| **Variable** | **Description** | +| --- | --- | +| `**transaction.from**` | Sender address | +| `**transaction.to**` | Recipient address | +| `**transaction.value**` | Transaction value | +| `**events.[index].args.[param]**` | Event parameters by name | +| `**functions.[index].args.[param]**` | Function parameters by name | + +###### Stellar Variables +| **Variable** | **Description** | +| --- | --- | +| `**events.[index].args.[position]**` | Event parameters by position | +| `**functions.[index].args.[param]**` | Function parameters by name | + + + +Transaction-related variables (`transaction.from`, `transaction.to`, `transaction.value`) are not available for Stellar networks. + + +#### Message Formatting + +Slack, Discord, Telegram, Email and Webhook support Markdown formatting in their message bodies. You can use Markdown syntax to enhance your notifications. + +##### Example Email Notification with Markdown +```json +{ + "email_notification": { + "name": "Formatted Alert", + "trigger_type": "email", + "config": { + "host": "smtp.example.com", + "port": 465, + "username": {"type": "plain", "value": "alerts@example.com"}, + "password": {"type": "plain", "value": "password"}, + "message": { + "title": "**High Value Transfer Alert**", + "body": "### Transaction Details\n\n* **Amount:** ${events.0.args.value} USDC\n* **From:** `$events.0.args.from`\n* **To:** `$events.0.args.to`\n\n> Transaction Hash: $transaction.hash\n\n[View on Explorer](https://etherscan.io/tx/$transaction.hash)" + }, + "sender": "alerts@example.com", + "recipients": ["recipient@example.com"] + } + } +} +``` + +##### Example Slack Notification with Markdown +```json +{ + "slack_notification": { + "name": "Formatted Alert", + "trigger_type": "slack", + "config": { + "slack_url": {"type": "plain", "value": "https://hooks.slack.com/services/XXX/YYY/ZZZ"}, + "message": { + "title": "*🚨 High Value Transfer Alert*", + "body": "*Transaction Details*\n\nβ€’ *Amount:* `${events.0.args.value}` USDC\nβ€’ *From:* `$events.0.args.from`\nβ€’ *To:* `$events.0.args.to`\n\n>Transaction Hash: `$transaction.hash`\n\n" + } + } + } +} +``` + +##### Example Discord Notification with Markdown +```json +{ + "discord_notification": { + "name": "Formatted Alert", + "trigger_type": "discord", + "config": { + "discord_url": {"type": "plain", "value": "https://discord.com/api/webhooks/XXX/YYY"}, + "message": { + "title": "**🚨 High Value Transfer Alert**", + "body": "# Transaction Details\n\n* **Amount:** `${events.0.args.value}` USDC\n* **From:** `$events.0.args.from`\n* **To:** `$events.0.args.to`\n\n>>> Transaction Hash: `$transaction.hash`\n\n**[View on Explorer](https://etherscan.io/tx/$transaction.hash)" + } + } + } +} +``` + +##### Example Telegram Notification with Markdown +```json +{ + "telegram_notification": { + "name": "Formatted Alert", + "trigger_type": "telegram", + "config": { + "token": {"type": "plain", "value": "1234567890:ABCDEFGHIJKLMNOPQRSTUVWXYZ"}, + "chat_id": "9876543210", + "message": { + "title": "*🚨 High Value Transfer Alert*", + "body": "*Transaction Details*\n\nβ€’ *Amount:* `${events.0.args.value}` USDC\nβ€’ *From:* `$events.0.args.from`\nβ€’ *To:* `$events.0.args.to`\n\n`Transaction Hash: $transaction.hash`\n\n[View on Explorer](https://etherscan.io/tx/$transaction.hash)" + } + } + } +} +``` + +#### Important Considerations + +* Email notification port defaults to 465 if not specified. +* Template variables are context-dependent: + * Event-triggered notifications only populate event variables. + * Function-triggered notifications only populate function variables. + * Mixing contexts results in empty values. +* Credentials in configuration files should be properly secured. +* Consider using environment variables for sensitive information. + +### Monitor Configuration + +A Monitor defines what blockchain activity to watch and what actions to take when conditions are met. Each monitor combines: + +* Network targets (which chains to monitor) +* Contract addresses to watch +* Conditions to match (functions, events, transactions) +* Trigger conditions (custom scripts that act as filters for each monitor match to determine whether a trigger should be activated). +* Triggers to execute when conditions are met + +**Example Monitor Configuration** + +```json +{ + "name": "Large USDC Transfers", + "networks": ["ethereum_mainnet"], + "paused": false, + "addresses": [ + { + "address": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", + "contract_spec": [ ... ] + } + ], + "match_conditions": { + "functions": [ + { + "signature": "transfer(address,uint256)", + "expression": "value > 1000000" + } + ], + "events": [ + { + "signature": "Transfer(address,address,uint256)", + "expression": "value > 1000000" + } + ], + "transactions": [ + { + "status": "Success", + "expression": "value > 1500000000000000000" + } + ] + }, + "trigger_conditions": [ + { + "script_path": "./config/filters/evm_filter_block_number.sh", + "language": "bash", + "arguments": ["--verbose"], + "timeout_ms": 1000 + } + ], + "triggers": ["evm_large_transfer_usdc_slack", "evm_large_transfer_usdc_email"] +} +``` + +#### Available Fields + +| **Field** | **Type** | **Description** | +| --- | --- | --- | +| `**name**` | `String` | **Required** - **_Unique_** identifier for this monitor | +| `**networks**` | `Array[String]` | List of network slugs this monitor should watch | +| `**paused**` | `Boolean` | Whether this monitor is currently paused | +| `**addresses**` | `Array[Object]` | Contract addresses to monitor with optional ABIs | +| `**match_conditions**` | `Object` | Collection of conditions that can trigger the monitor | +| `**trigger_conditions**` | `Array[Object]` | Collection of filters to apply to monitor matches before executing triggers | +| `**triggers**` | `Array[String]` | IDs of triggers to execute when conditions match | + +#### Match Conditions + +Monitors support three types of match conditions that can be combined: + +##### Function Conditions +Match specific function calls to monitored contracts: + +```json +{ + "functions": [ + { + "signature": "transfer(address,uint256)", + "expression": "value > 1000" + } + ] +} +``` + +##### Event Conditions +Match events emitted by monitored contracts: + +```json +{ + "events": [ + { + "signature": "Transfer(address,address,uint256)", + "expression": "value > 1000000" + } + ] +} +``` + +##### Transaction Conditions +Match transaction properties. The available fields and expression syntax depend on the network type (EVM/Stellar) + +```json +{ + "transactions": [ + { + "status": "Success", // Only match successful transactions + "expression": "value > 1500000000000000000" // Match transactions with value greater than 1.5 ETH + } + ] +} +``` + +#### Available Transaction Fields (EVM) +| **Field** | **Type** | **Description** | +| --- | --- | --- | +| `**value**` | `uint256` | Transaction value in wei | +| `**from**` | `address` | Sender address (case-insensitive comparison) | +| `**to**` | `address` | Recipient address (case-insensitive comparison) | +| `**hash**` | `string` | Transaction hash | +| `**gas_price**` | `uint256` | Gas price in wei (legacy transactions) | +| `**max_fee_per_gas**` | `uint256` | EIP-1559 maximum fee per gas | +| `**max_priority_fee_per_gas**` | `uint256` | EIP-1559 priority fee | +| `**gas_limit**` | `uint256` | Gas limit for transaction | +| `**nonce**` | `uint256` | Sender nonce | +| `**input**` | `string` | Hex-encoded input data (e.g., **"0xa9059cbb..."**) | +| `**gas_used**` | `uint256` | Actual gas used (from receipt) | +| `**transaction_index**` | `uint64` | Position in block | + +#### Available Transaction Fields (Stellar) +| **Field** | **Type** | **Description** | +| --- | --- | --- | +| `**hash**` | `string` | Transaction hash | +| `**ledger**` | `i64` | Ledger sequence number where the transaction was included | +| `**value**` | `i64` | Value associated with the **first** relevant operation (e.g., payment amount). Defaults to 0 if no relevant operation or value is found. | +| `**from**` | `address` | Source account address of the **first** relevant operation (e.g., payment sender). Case-insensitive comparison. | +| `**to**` | `address` | Destination account address of the **first** relevant operation (e.g., payment recipient or invoked contract). Case-insensitive comparison. | + +#### Matching Rules + +* If no conditions are specified, all transactions match +* For multiple condition types: + * Transaction conditions are checked first + * Then either function OR event conditions must match + * Both transaction AND (function OR event) must match if both specified + +### Expressions + +Expressions allow for condition checking of function arguments, event parameters, and transaction fields. + +**Supported Parameter/Field Types and Basic Operations:** + +| Type | Description | Example Operators | Notes | +| --- | --- | --- | --- | +| `**Numeric (uint/int variants)**` | Integer values (e.g., `42`, `-100`) or decimal values (e.g., `3.14`, `-0.5`). | `>`, `>=`, `<`, `<=`, `==`, `!=` | Numbers must have digits before and after a decimal point if one is present (e.g., `.5` or `5.` are not valid standalone numbers). | +| `**Address**` | Blockchain addresses. | `==`, `!=` | Comparisons (e.g., `from == '0xABC...'`) are typically case-insensitive regarding the hex characters of the address value itself. | +| `**String**` | Text values. Can be single-quoted (e.g., ’hello'`) or, on the right-hand side of a comparison, unquoted (e.g., `active`). | `==`, `!=`, `starts_with`, `ends_with`, `contains` | Quoted strings support `\'` to escape a single quote and `\\` to escape a backslash. All string comparison operations (e.g., `name == 'Alice'`, `description contains 'error'`) are performed case-insensitively during evaluation. See the dedicated "String Operations" section for more examples and details. | +| `**Boolean**` | True or false values. | `==`, `!=` | Represented as `true` or `false`. These keywords are parsed case-insensitively (e.g., `TRUE`, `False` are also valid in expressions). | +| `**Hex String Literal**` | A string literal starting with `0x` or `0X` followed by hexadecimal characters (0-9, a-f, A-F). | `==`, `!=`, `starts_with`, `ends_with`, `contains` | Treated as a string for comparison purposes (e.g., `input_data starts_with '0xa9059cbb'`). Comparison is case-sensitive for the hex characters after `0x`. | +| `**Array (EVM/Stellar)**` | Ordered list of items. For Stellar, often a JSON string in config (e.g., ’["a", "id":1]'`). For EVM, typically decoded from ABI parameters. | `contains`, `==`, `!=`, `[index]` | Detailed operations, including indexed access and behavior of `contains`, vary by network. See "Operations on Complex Types" below. | +| `**Object/Map (Stellar)**` | Key-value pairs, typically represented as a JSON string in config (e.g., ’"key": "value", "id": 123'`). | `.key_access`, `==`, `!=` | Supports dot notation for field access (e.g., `data.id`). See "Operations on Complex Types" for details. | +| `**Vec (Stellar)**` | Ordered list, where the parameter’s value can be a CSV string (e.g., `"foo,bar"`) or a JSON array string (e.g., ’["foo","bar"]'`). | `contains`, `==`, `!=` | Behavior of `contains` and `==` differs based on whether the value is CSV or a JSON array string. See "Operations on Complex Types" for details. | + +**Logical Operators:** + +* AND - All conditions must be true +* OR - At least one condition must be true +* () - Parentheses for grouping +* AND has higher precedence than OR (i.e., AND operations are evaluated before OR operations if not grouped by parentheses) + +**Variable Naming and Access (Left-hand side of conditions):** + +The left-hand side (LHS) of a condition specifies the data field or parameter whose value you want to evaluate. + +**Base Names:** + +* These are the direct names of parameters or fields, such as `amount`, `from`, `status`, or event parameter indices like `0`, `1` (common in Stellar events). +* Base names can consist of alphanumeric characters (a-z, A-Z, 0-9) and underscores (`_`). +* They can start with a letter, an underscore, or a digit. Starting with a digit is primarily relevant for numerically indexed parameters (e.g., Stellar event parameters). +* **Important:** Variable names are case-sensitive during evaluation. The name used in the expression must exactly match the casing of the field name in the source data (e.g., from an ABI or blockchain data structure). For example, if a field is named `TotalValue` in the data, an expression using `totalvalue` will not find it. +* Variable names cannot be keywords (e.g., `true`, `AND`, `OR`, `contains`). Keywords themselves are parsed case-insensitively. + +**Path Accessors (for complex types):** + +If a base parameter is a complex type like an object, map, or array, you can access its internal data using accessors: + +**Key Access:** Use dot notation (`.`) to access properties of an object or map. + +* Examples: `transaction.value`, `user.name`, `data.0` (if `0` is a valid key name as a string). +* Keys typically consist of alphanumeric characters and underscores. They usually start with a letter or underscore, but purely numeric keys (e.g., `.0`, `.123`) are also supported for map-like structures where keys might be strings representing numbers. +* Keys cannot contain hyphens (`-`). + +**Index Access:** Use bracket notation (`[]`) to access elements of an array by their zero-based integer index. + +* Examples: `my_array[0]`, `log_entries[3]`. +* The index must be a non-negative integer. + +**Combined Access:** You can combine key and index accessors to navigate nested structures. + +* Example: `event.data_array[0].property` (accesses the `property` field of the first object in `data_array`, which is part of `event`). +* Example: `map.numeric_key_as_string_0[1].name` (accesses the `name` property of the second element of an array stored under the key `0` in `map`). + +**String Operations:** + +Several operators are available for matching patterns and comparing string values. These are particularly useful for EVM transaction `input` data, Stellar parameters defined with `kind: "string"`, or any other field that contains text. + +* `string_param starts_with 'prefix'`:: + Checks if the string parameter’s value begins with the specified `prefix`. + Example: `transaction.input starts_with '0xa9059cbb'` (checks for ERC20 transfer function selector). +* `string_param ends_with 'suffix'`:: + Checks if the string parameter’s value ends with the specified `suffix`. + Example: `file_name ends_with '.txt'` +* `string_param contains 'substring'`:: + Checks if the string parameter’s value contains the specified `substring` anywhere within it. + Example: `message contains 'error'` +* `string_param == 'exact_string'`:: + Checks if the string parameter’s value is exactly equal to `exact_string`. +* `string_param != 'different_string'`:: + Checks if the string parameter’s value is not equal to `different_string`. + +**Important Notes on String Operations:** + +* **Operator Keywords:** The operator keywords themselves (`starts_with`, `ends_with`, `contains`, `AND`, `OR`, `true`, `false`, comparison symbols like `==`, `>`) are parsed case-insensitively. For example, `CONTAINS` is treated the same as `contains`, and `TRUE` is the same as `true`. +* **Case-Insensitive Evaluation for String Comparisons:** When comparing string data (e.g., from event parameters, transaction fields, or function arguments) with literal string values in your expression, all standard string operations perform a ***case-insensitive*** comparison during evaluation. + * Equality (`==`) and Inequality (`!=`) + * Pattern matching (`starts_with`, `ends_with`, `contains`) +* **Variable Name Case Sensitivity:** It is important to distinguish this from variable names (the left-hand side of your condition, e.g., `status`). Variable names **are** case-sensitive and must exactly match the field names in your source data (ABI, etc.). + +**Whitespace Handling:** +Flexible whitespace is generally allowed around operators, parentheses, and keywords for readability. However, whitespace within quoted string literals is significant and preserved. + +#### Operations on Complex Types + +Beyond simple primitive types, expressions can also interact with more complex data structures like arrays, objects, and vectors. + +##### EVM Specifics + +**Array Operations (`kind: "array"`)** + +When an EVM parameter is an array (often represented internally or configured with `kind: "array"` and its value being a JSON string representation if manually configured), the following operations are supported: + +* `array_param contains 'value'` checks if the string ’value'` exists within the array. +* `array_param == '["raw_json_array_string"]'` string comparison of the array’s entire JSON string representation against the provided string +* `array_param != '["raw_json_array_string"]'` the negation of the above +* `array_param[0]` indexed access + +##### Stellar Specifics + +**Object (`kind: "object"`) / Map (`kind: "Map"`) Operations** + +* `object_param.key == 'value'` checks if the object or map has a key named `key` with the value ’value'`. +* `object_param.nested_key.another_key > 100` checks if the nested key `another_key` within `nested_key` has a value greater than 100. +* `object_param == '"raw_json_object_string"'` checks if the object or map matches the provided JSON string representation. +* `object_param != '"raw_json_object_string"'` the negation of the above + +**Array (`kind: "array"`) Operations** + +* `array_param[index]` accesses the element at the specified `index` in the array. +* `array_param[0] == 'value'` checks if the first element in the array is equal to ’value'`. +* `array_param[1].property == 'value'` checks if the second element in the array has a property named `property` with the value ’value'`. +* `array_param contains 'value'` checks if the array contains the string ’value'`. +* `array_param == '["raw_json_array_string"]'` checks if the array matches the provided JSON string representation. +* `array_param != '["raw_json_array_string"]'` the negation of the above + +**Vector (`kind: "vec"`) Operations** +When a Stellar parameter has `kind: "vec"`, its value can be either a CSV string or a JSON array string. + +* `vec_param contains 'item'` checks if the vector contains the string ’item'`. This works for both CSV and JSON array strings. +* `vec_param == 'raw_string_value'` checks if the vector matches the provided raw string value. This works for both CSV and JSON array strings. +* `vec_param != 'raw_string_value'` the negation of the above + +**Event Parameter Access (Stellar)** + +Stellar event parameters are typically accessed by their numeric index as the base variable name (e.g., `0`, `1`, `2`). If an indexed event parameter is itself a complex type (like an array or map, represented as a JSON string), you can then apply the respective access methods: + +* If event parameter `0` (kind: "Map") is ’"id": 123, "name": "Test"'`: + * `0.id == 123` + * `0.name contains 'est'` (case-insensitive) +* If event parameter `1` (kind: "array") is ’["alpha", "val": "beta"]'`: + * `1[0] == 'ALPHA'` (case-insensitive) + * `1[1].val == 'Beta'` (case-insensitive) + * `1 contains 'beta'` (case-insensitive deep search) + +##### EVM Examples + +These examples assume common EVM event parameters or transaction fields. + +**Basic Comparisons** + +```json +// Numeric +"transaction.value > 1000000000000000000" // Value greater than 1 ETH +"event.amount <= 500" +"block.number == 12345678" + +// String (case-insensitive evaluation for '==' and 'contains') +"transaction.to == '0xdeadbeef...'" // Address check (address value comparison itself is case-insensitive) +"event.token_name == 'mytoken'" +"transaction.input contains 'a9059cbb'" // Checks for ERC20 transfer selector + +// Boolean +"receipt.status == true" // or simply "receipt.status" if boolean field can be evaluated directly +"event.isFinalized == false" +``` + +**Logical Operators** + +```json +"transaction.value > 1000 AND event.type == 'Deposit'" +"(receipt.status == true OR event.fallback_triggered == true) AND user.is_whitelisted == false" +``` + +**String Operations** + +```json +"transaction.input starts_with '0xa9059cbb'" // Case-insensitive for the operation +"event.message ends_with 'failed'" +"event.details contains 'critical alert'" +``` + +**Array Operations** + +Assume `event.ids` is `[10, 20, 30]` and `event.participants` is `["user": "Alice", "role": "admin", "user": "Bob", "role": "editor"]`. +```json +"event.ids[0] == 10" +"event.ids contains '20'" // Checks for string '20' (case-insensitive) + +"event.participants contains 'Alice'" // True (deep search, case-insensitive) +"event.participants contains 'editor'" // True (deep search, case-insensitive) +"event.participants == '[\"user\": \"Alice\", \"role\": \"admin\", \"user\": \"Bob\", \"role\": \"editor\"]'" // Raw JSON match (case-sensitive for structure and keys) +``` + +##### Stellar Examples + +**Basic Comparisons** + +```json +// Numeric +"event.params.amount > 10000000" // Accessing 'amount' field in an object 'params' +"ledger.sequence >= 123456" + +// String (case-insensitive evaluation for '==' and 'contains') +"event.params.recipient == 'GBD22...'" // Address check +"event.type == 'payment_processed'" + +// Boolean +"transaction.successful == true" +"event.data.is_verified == false" +``` + +**Logical Operators** + +```json +"event.data.value > 500 AND event.source_account == 'GCA7Z...'" +"(event.type == 'TRANSFER' OR event.type == 'PAYMENT') AND event.params.asset_code == 'XLM'" +``` + +**String Operations** + +```json +"event.contract_id starts_with 'CA23...'" +"event.memo ends_with '_TEST'" +"event.params.description contains 'urgent'" +``` + +**Object (`kind: "object"`) / Map (`kind: "Map"`) Operations** + +Assume `event.details` (kind: "Map") is ’"id": 123, "user": "name": "CHarlie", "status": "Active", "tags": ["new"]'`. +```json +"event.details.id == 123" +"event.details.user.name == 'charlie'" // Case-insensitive string comparison +"event.details.user.status contains 'act'" // Case-insensitive contains +"event.details.tags == '[\"new\"]'" // Raw JSON string match for the 'tags' field +``` + +**Array (`kind: "array"`) Operations** + +Assume `event.items` (kind: "array") is ’["sku": "A1", "qty": 10, "sku": "B2", "qty": 5, "notes":"Rush order"]'`. +```json +"event.items[0].sku == 'a1'" +"event.items[1].qty < 10" +"event.items contains 'A1'" // Deep search (case-insensitive) +"event.items contains 'rush order'" // Deep search (case-insensitive) +``` + +**Vector (`kind: "vec"`) Operations** + +Assume `csv_data` (kind: "vec") is `"ALPHA,Bravo,Charlie"` and `json_array_data` (kind: "vec") is ’["Delta", "id": "ECHO", "Foxtrot"]'`. +```json +"csv_data contains 'bravo'" // Case-insensitive CSV element match +"csv_data == 'ALPHA,Bravo,Charlie'" // Raw string match + +"json_array_data contains 'delta'" // Case-insensitive deep search (like array) +"json_array_data contains 'ECHO'" // Case-insensitive deep search (like array) +``` + +**Event Parameter Access (Numerically Indexed)** + +Assume event parameter `0` is `12345` (u64), `1` (kind: "array") is ’["Val1", "VAL2"]'`, and `2` (kind: "Map") is ’"keyA": "dataX", "keyB": 789'`. +```json +"0 > 10000" +"1[0] == 'val1'" +"1 contains 'val2'" +"2.keyA == 'DATAX'" +"2.keyB < 1000" +``` + + + +With SEP-48 support, Stellar functions can now reference parameters by name (e.g., `amount > 1000`) instead of position (e.g., `2 > 1000`). Events still use indexed parameters until SEP-48 support is added for events. + +You can find the contract specification through Stellar contract explorer tool. For example: +[Stellar DEX Contract Interface](https://lab.stellar.org/smart-contracts/contract-explorer?$=network$id=mainnet&label=Mainnet&horizonUrl=https:////horizon.stellar.org&rpcUrl=https:////mainnet.sorobanrpc.com&passphrase=Public%20Global%20Stellar%20Network%20/;%20September%202015;&smartContracts$explorer$contractId=CA6PUJLBYKZKUEKLZJMKBZLEKP2OTHANDEOWSFF44FTSYLKQPIICCJBE;;) + + +#### Trigger Conditions (Custom filters) + +Custom filters allow you to create sophisticated filtering logic for processing monitor matches. These filters act as additional validation layers that determine whether a match should trigger the execution of a trigger or not. + +For more information about custom scripts, see [Custom Scripts Section](/monitor/1.0.x/scripts). + + + +***Security Risk***: Only run scripts that you trust and fully understand. Malicious scripts can harm your system or expose sensitive data. Always review script contents and verify their source before execution. + + +**Example Trigger Conditions Configuration** + +```json +{ + "script_path": "./config/filters/evm_filter_block_number.sh", + "language": "Bash", + "arguments": ["--verbose"], + "timeout_ms": 1000 +} +``` + +#### Available Fields + +##### Trigger Conditions Fields +| Field | Type | Description | +| --- | --- | --- | +| `**script_path**` | String | The path to the script | +| `**language**` | String | The language of the script | +| `**arguments**` | Array[String] | The arguments of the script (optional). | +| `**timeout_ms**` | Number | The timeout of the script is important to avoid infinite loops during the execution. If the script takes longer than the timeout, it will be killed and the match will be included by default. | + +#### Important Considerations + +* Network slugs in the monitor must match valid network configurations. +* Trigger IDs must match configured triggers. +* Expression syntax and available variables differ between EVM and Stellar networks. +* ABIs can be provided in two ways: + * For EVM networks: Through the monitor configuration using standard Ethereum ABI format + * For Stellar networks: Through the monitor configuration using SEP-48 format, or automatically fetched from the chain if not provided +* The monitoring frequency is controlled by the network’s `cron_schedule`. +* Each monitor can watch multiple networks and addresses simultaneously. +* Monitors can be paused without removing their configuration. + +## Running the Monitor + +### Local Execution + +1. ***Basic startup:*** + + ```bash + ./openzeppelin-monitor + ``` +2. ***With logging to file:*** + + ```bash + ./openzeppelin-monitor --log-file + ``` +3. ***With metrics enabled:*** + + ```bash + ./openzeppelin-monitor --metrics + ``` +4. ***Validate configuration without starting:*** + + ```bash + ./openzeppelin-monitor --check + ``` + +### Docker Execution + +1. ***Start all services:*** + + ```bash + cargo make docker-compose-up + ``` +2. ***With metrics and monitoring (Prometheus + Grafana):*** + + ```bash + # Set METRICS_ENABLED=true in .env file, then: + docker compose --profile metrics up -d + ``` +3. ***View logs:*** + + ```bash + docker compose logs -f monitor + ``` +4. ***Stop services:*** + + ```bash + cargo make docker-compose-down + ``` + +### Command Line Options + +| | | | +| --- | --- | --- | +| Option | Default | Description | +| `--log-file` | `false` | Write logs to file instead of stdout | +| `--log-level` | `info` | Set log level (trace, debug, info, warn, error) | +| `--metrics` | `false` | Enable metrics server on port 8081 | +| `--check` | `false` | Validate configuration files only | +| `--help` | - | Show all available options | + +### Testing your configuration + +#### Network Configuration +The `validate_network_config.sh` script helps ensure your network configuration is properly set up and operational. The script: + +* Tests the health of all configured RPC endpoints +* Validates connectivity using network-specific methods +* Provides clear visual feedback for each endpoint + +```bash +# Test default networks directory (/config/networks/) +./scripts/validate_network_config.sh + +# Test a specific configuration directory +./scripts/validate_network_config.sh -f /path/to/configs +``` + + +Run this script when setting up new networks, before deploying configuration changes, or when troubleshooting connectivity issues. + + +#### Validating Configuration Files + +Before starting the monitor service, you can validate your configuration files using the `--check` option: + +```bash +./openzeppelin-monitor --check +``` + +This command will: + +* Parse and validate all configuration files +* Check for syntax errors +* Verify references between monitors, networks, and triggers +* Report any issues without starting the service + +It’s recommended to run this check after making changes to any configuration files. + +#### Monitor Configuration +The monitor can be tested in two modes: + +#### 1. Latest Block Mode + +This mode processes the most recent blocks across all configured networks. + +```bash +./openzeppelin-monitor --monitor-path="config/monitors/evm_transfer_usdc.json" +``` + +What this does: + +* Runs the "Large Transfer of USDC Token" monitor +* Targets all networks specified in the configuration +* Processes only the latest block for each network +* Sends a notification to all associated channels for every match that is found + +#### 2. Specific Block Mode + +This mode allows you to analyze a particular block on a specific network, which is useful for debugging specific transactions, verifying monitor behavior on known events, and testing monitor performance on historical data. + +```bash +./openzeppelin-monitor \ + --monitor-path="config/monitors/evm_transfer_usdc.json" \ + --network=ethereum_mainnet \ + --block=12345678 +``` + +What this does: + +* Runs the "Large Transfer of USDC Token" monitor +* Targets only the specified network (`ethereum_mainnet`) +* Processes only the specified block (`12345678`) +* Sends a notification to all associated channels for every match that is found + + + + +Specific Block Mode requires both parameters: + +* `--network`: The network to analyze +* `--block`: The block number to process + + + +#### Data Persistence (Optional) + +* Set `LOG_MODE` as file will persist the log data in `logs/` on host. To change it to a different directory use `LOG_DATA_DIR`. +* Set `MONITOR_DATA_DIR` to specific dir on your host system which will persist data between container restarts. + +## Error Handling + +The monitor implements a comprehensive error handling system with rich context and tracing capabilities. For detailed information about error handling, see [Error Handling Guide](/monitor/1.0.x/error). + +## Important Considerations + +### Performance Considerations + +* Monitor performance depends on network congestion and RPC endpoint reliability. + * View the [list of RPC calls](/monitor/1.0.x/rpc#list-of-rpc-calls) made by the monitor. +* The `max_past_blocks` configuration is critical: + * Calculate as: `(cron_interval_ms/block_time_ms) + confirmation_blocks + 1` (defaults to this calculation if not specified). + * Example for 1-minute Ethereum cron: `(60000/12000) + 12 + 1 = 18 blocks`. + * Too low settings may result in missed blocks. +* Trigger conditions are executed sequentially based on their position in the trigger conditions array. Proper execution also depends on the number of available file descriptors on your system. To ensure optimal performance, it is recommended to increase the limit for open file descriptors to at least 2048 or higher. On Unix-based systems you can check the current limit by running `ulimit -n` and _***temporarily***_ increase it with `ulimit -n 2048`. +* Since scripts are loaded at startup, any modifications to script files require restarting the monitor to take effect. +* See performance considerations about custom scripts [here](/monitor/1.0.x/scripts#performance-considerations). + +### Notification Considerations + +* Template variables are context-dependent: + * Event-triggered notifications only populate event variables. + * Function-triggered notifications only populate function variables. + * Mixing contexts results in empty values. +* Custom script notifications have additional considerations: + * Scripts receive monitor match data and arguments as JSON input + * Scripts must complete within their configured timeout_ms or they will be terminated + * Script modifications require monitor restart to take effect + * Supported languages are limited to Python, JavaScript, and Bash + +## Support + +For support or inquiries, contact us on [Telegram](https://t.me/openzeppelin_tg/4). + +Have feature requests or want to contribute? Join our community on [GitHub](https://github.com/OpenZeppelin/openzeppelin-monitor/) + +## License +This project is licensed under the GNU Affero General Public License v3.0 - see the LICENSE file for details. + +## Security +For security concerns, please refer to our [Security Policy](https://github.com/OpenZeppelin/openzeppelin-monitor/blob/main/SECURITY.md). diff --git a/content/monitor/1.0.x/project-structure.mdx b/content/monitor/1.0.x/project-structure.mdx new file mode 100644 index 00000000..0f6e170f --- /dev/null +++ b/content/monitor/1.0.x/project-structure.mdx @@ -0,0 +1,206 @@ +--- +title: Project Structure +--- + +This document describes the project structure and organization of the OpenZeppelin Monitor codebase, including the source code layout, configuration files, and development resources. + +## Project Layout + +The project follows a standard Rust project layout with additional directories for configuration, documentation, and operational resources: + +``` +openzeppelin-monitor/ +β”œβ”€β”€ src/ # Source code +β”‚ β”œβ”€β”€ bootstrap/ # Bootstrap functions for the application +β”‚ β”œβ”€β”€ models/ # Data structures and types +β”‚ β”œβ”€β”€ repositories/ # Configuration storage +β”‚ β”œβ”€β”€ services/ # Core business logic +β”‚ β”œβ”€β”€ utils/ # Helper functions +β”‚ +β”œβ”€β”€ config/ # Configuration files +β”œβ”€β”€ tests/ # Integration and property-based tests +β”œβ”€β”€ data/ # Runtime data storage +β”œβ”€β”€ docs/ # Documentation +β”œβ”€β”€ scripts/ # Utility scripts +β”œβ”€β”€ cmd/ # Metrics and monitoring +β”œβ”€β”€ examples/ # Example configuration files +└── ... other root files (Cargo.toml, README.md, etc.) +``` + +## Source Code Organization + +### `src/` Directory + +The main source code directory contains the core implementation files organized into several modules: + +#### `bootstrap/` +Application initialization and setup for `main.rs`: + +* Handles service initialization and dependency injection +* Manages the startup sequence and service lifecycle + +#### `models/` +Core data structures and types: + +* `blockchain/`: Platform-specific implementations + * `evm/`: Ethereum Virtual Machine specific types + * `stellar/`: Stellar blockchain specific types +* `config/`: Configuration loading and validation +* `core/`: Core domain models +* `security/`: Security and secret management + +#### `repositories/` +Configuration storage: + +* Handles loading and validating configuration files +* Provides storage interfaces for monitors, networks, and triggers +* Implements validation of configuration references + +#### `services/` +Core business logic: + +* `blockchain/`: Blockchain client interfaces + * `transports/`: Transport clients + * `evm/`: Ethereum Virtual Machine transport client + * `stellar/`: Stellar transport client + * `clients/`: Client implementations + * `evm/`: Ethereum Virtual Machine client + * `stellar/`: Stellar client +* `blockwatcher/`: Block monitoring and processing +* `filter/`: Transaction and event filtering + * `filters/`: Filter implementations + * `evm/`: Ethereum Virtual Machine filter + * `stellar/`: Stellar filter +* `notification/`: Alert handling +* `trigger/`: Trigger evaluation and execution + * `script/`: Script execution utilities + +#### `utils/` +Helper functions: + +* `cron_utils`: Cron schedule utilities +* `expression`: Expression evaluation +* `logging/`: Logging utilities +* `macros/`: Macros for common functionality +* `metrics/`: Metrics utilities +* `monitor/`: Monitor configuration test utilities +* `tests/`: Contains test utilities and helper functions + * `builders/`: Test builder patterns implementing fluent interfaces for creating test fixtures + * `evm/`: Builder implementations specific to Ethereum Virtual Machine (EVM) testing + * `stellar/`: Builder implementations specific to Stellar blockchain testing + +## Configuration and Data + +### `config/` Directory + +Contains JSON configuration files for: + +* ***Network configurations*** (`networks/`) + * Connection details for blockchain networks + * RPC endpoints and network parameters +* ***Monitor configurations*** (`monitors/`) + * Monitoring rules and conditions + * Network and trigger references +* ***Trigger configurations*** (`triggers/`) + * Notification settings + * Script definitions +* ***Filter configurations*** (`filters/`) + * Match filter scripts + + + +The `examples/config/` directory contains example JSON configuration files for each (network, monitor, trigger and filters). + + +### `data/` Directory + +Runtime data storage: + +* Block processing state +* Operational data +* Temporary files + + + +The `data/`, `logs/` and `config/` directories are gitignored except for example files. These directories are mounted to persist the configs and runtime data. + + +## Examples and Resources + +### `examples/` Directory + +Provides practical examples and sample configurations to help users get started: + +* Demonstrates typical service configurations for various networks +* Acts as a quick-start guide for customizing the monitor +* Serves as a reference for best practices in configuration + +## Metrics and Monitoring + +### `cmd/prometheus/` Directory + +Prometheus exporters and monitoring infrastructure: + +* `dashboards/`: Grafana dashboards +* `datasources/`: Prometheus datasources +* `prometheus.yml`: Prometheus configuration +* `grafana.ini`: Grafana configuration + +## Testing and Documentation + +### `tests/` Directory + +Contains comprehensive test suites: + +* Integration tests +* Property-based tests +* Mock implementations +* Test utilities and helpers + +### `docs/` Directory + +Project documentation: + +* User guides +* API documentation +* Configuration examples +* Architecture diagrams + +### `scripts/` Directory + +Utility scripts for: + +* Development workflows +* Documentation generation +* Build processes +* Deployment helpers + +## Development Tools + +### Pre-commit Hooks + +Located in the project root: + +* Code formatting checks +* Linting rules +* Commit message validation + +### Build Configuration + +Core build files: + +* `Cargo.toml`: Project dependencies and metadata +* `rustfmt.toml`: Code formatting rules +* `rust-toolchain.toml`: Rust version and components + +## Docker Support + +The project includes Docker configurations for different environments: + +* `Dockerfile.development`: Development container setup +* `Dockerfile.production`: Production-ready container +* Before running the docker compose set your env variables in `.env` according to your needs + + + +For detailed information about running the monitor in containers, see the Docker deployment [section](/monitor/1.0.x#docker-installation) in the user documentation. diff --git a/content/monitor/1.0.x/quickstart.mdx b/content/monitor/1.0.x/quickstart.mdx new file mode 100644 index 00000000..d6bd9786 --- /dev/null +++ b/content/monitor/1.0.x/quickstart.mdx @@ -0,0 +1,614 @@ +--- +title: Quick Start Guide +--- + +OpenZeppelin Monitor is a powerful tool for monitoring blockchain events and transactions. This guide will help you get up and running quickly with practical examples for both EVM and Stellar networks. + +## What You'll Learn + +* How to set up OpenZeppelin Monitor locally or with Docker +* How to configure monitoring for USDC transfers on Ethereum +* How to monitor DEX swaps on Stellar +* How to set up notifications via Slack and email + +## Prerequisites + +Before you begin, ensure you have the following installed: + +* ***Rust 2021 edition*** - Required for building from source +* ***Docker*** - Optional, for containerized deployment +* ***Git*** - For cloning the repository + + + +If you don’t have Rust installed, visit https://rustup.rs/ to install it. + + +## Quick Setup Options + +We provide two setup paths to get you started: + +### Option 1: Automated Setup (Recommended) + +For the fastest setup experience, use our automated script that handles everything for you. + +#### What the Automated Setup Does + +The `setup_and_run.sh` script provides a complete solution that: + +* ***Builds the monitor application*** from source +* ***Copies example configurations*** from `examples/` to `config/` + * Network configurations for major blockchains + * Pre-configured monitor examples (USDC transfers, Stellar DEX swaps) + * Required filter scripts and basic trigger notifications +* ***Validates all configurations*** to ensure proper setup +* ***Optionally runs the monitor*** to verify everything works + +#### Running the Automated Setup + +1. ***Clone the repository:*** + + ```bash + git clone https://github.com/openzeppelin/openzeppelin-monitor + cd openzeppelin-monitor + ``` +2. ***Make the script executable:*** + + ```bash + chmod +x setup_and_run.sh + ``` +3. ***Run the automated setup:*** + + ```bash + ./setup_and_run.sh + ``` + +The script provides colored output and clear guidance throughout the process. + +#### After Automated Setup + +Once complete, you’ll have: + +* A fully built OpenZeppelin Monitor +* Example configurations ready for customization +* Clear guidance on next steps + +***Next Steps:*** +. Customize the copied configurations in `config/` directories +. Update RPC URLs and notification credentials +. Run the monitor with `./openzeppelin-monitor` + + + +The setup script creates working configurations with placeholder values. ***Remember to update your files with actual RPC endpoints and notification credentials*** before starting real monitoring. + + +### Option 2: Manual Setup + +For users who prefer more control over the setup process. + +#### Building from Source + +1. ***Clone and build:*** + + ```bash + git clone https://github.com/openzeppelin/openzeppelin-monitor + cd openzeppelin-monitor + cargo build --release + ``` +2. ***Move the binary to project root:*** + + ```bash + mv ./target/release/openzeppelin-monitor . + ``` + +#### Docker Setup + +For containerized deployment: + +1. ***Start services:*** + + ```bash + docker compose up + ``` + + + +By default, Docker Compose uses `Dockerfile.development`. For production, set: +`DOCKERFILE=Dockerfile.production` before running the command. + + +#### Docker Management Commands + +| Command | Description | +| --- | --- | +| `docker ps -a` | Verify container status | +| `docker compose down` | Stop services (without metrics) | +| `docker compose --profile metrics down` | Stop services (with metrics) | +| `docker compose logs -f` | View logs (follow mode) | + +## Environment Configuration + +### Logging Configuration + +Configure logging verbosity by setting the `RUST_LOG` environment variable: + +| Level | Description | +| --- | --- | +| `error` | Only error messages | +| `warn` | Warnings and errors | +| `info` | General information (recommended) | +| `debug` | Detailed debugging information | +| `trace` | Very detailed trace information | + +```bash +export RUST_LOG=info +``` + +### Local Configuration + +Copy the example environment file and customize it: + +```bash +cp .env.example .env +``` + +For detailed configuration options, see [Basic Configuration](/monitor/1.0.x#basic-configuration). + +## Practical Examples + +Now let’s set up real monitoring scenarios. Choose the example that matches your needs: + +### Example 1: Monitor USDC Transfers (Ethereum) + +This example monitors large USDC transfers on Ethereum mainnet and sends notifications when transfers exceed 10,000 USDC. + +#### Step 1: Network Configuration + +Create the Ethereum mainnet configuration: + +```bash +# Only necessary if you haven't already run the automated setup script (Option 1: Automated Setup) +cp examples/config/networks/ethereum_mainnet.json config/networks/ethereum_mainnet.json +``` + +***Key Configuration Details:*** + +```json + + "network_type": "EVM", + "slug": "ethereum_mainnet", + "name": "Ethereum Mainnet", + "rpc_urls": [ + { + "type_": "rpc", + "url": { + "type": "plain", + "value": "YOUR_RPC_URL_HERE" + , + "weight": 100 + } + ], + "chain_id": 1, + "block_time_ms": 12000, + "confirmation_blocks": 12, + "cron_schedule": "0 */1 * * * *", + "max_past_blocks": 18, + "store_blocks": false +} +``` + + + +***Important:*** Replace `YOUR_RPC_URL_HERE` with your actual Ethereum RPC endpoint. You can use providers like Infura, Alchemy, or run your own node. + + +#### Step 2: Monitor Configuration + +Set up the USDC transfer monitor: + +```bash +# Only necessary if you haven't already run the automated setup script (Option 1: Automated Setup) +cp examples/config/monitors/evm_transfer_usdc.json config/monitors/evm_transfer_usdc.json +cp examples/config/filters/evm_filter_block_number.sh config/filters/evm_filter_block_number.sh +``` + +***Monitor Configuration Overview:*** + +```json + + "name": "Large Transfer of USDC Token", + "paused": false, + "networks": ["ethereum_mainnet"], + "addresses": [ + { + "address": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", + "contract_spec": [ + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "from", + "type": "address" + , + + "indexed": true, + "internalType": "address", + "name": "to", + "type": "address" + , + + "indexed": false, + "internalType": "uint256", + "name": "value", + "type": "uint256" + + ], + "name": "Transfer", + "type": "event" + } + ] + } + ], + "match_conditions": + "functions": [], + "events": [ + { + "signature": "Transfer(address,address,uint256)", + "expression": "value > 10000000000" + + ], + "transactions": [ + + "status": "Success", + "expression": null + + ] + }, + "trigger_conditions": [ + + "script_path": "./config/filters/evm_filter_block_number.sh", + "language": "bash", + "arguments": ["--verbose"], + "timeout_ms": 1000 + + ], + "triggers": ["evm_large_transfer_usdc_slack", "evm_large_transfer_usdc_email"] +} +``` + + + +* The `expression: "value > 10000000000"` monitors transfers over 10,000 USDC (USDC has 6 decimals) +* Remove the `trigger_conditions` array to disable additional filtering +* The USDC contract address `0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48` is the official USDC contract on Ethereum mainnet + + +#### Step 3: Notification Setup + +##### Slack Notifications + +```bash +# Only necessary if you haven't already run the automated setup script (Option 1: Automated Setup) +cp examples/config/triggers/slack_notifications.json config/triggers/slack_notifications.json +``` + +***Slack Configuration:*** + +```json + + "evm_large_transfer_usdc_slack": { + "name": "Large Transfer Slack Notification", + "trigger_type": "slack", + "config": { + "slack_url": { + "type": "plain", + "value": "SLACK_WEBHOOK_URL" + , + "message": + "title": "large_transfer_slack triggered", + "body": "Large transfer of ${events.0.args.value USDC from $events.0.args.from to $events.0.args.to | https://etherscan.io/tx/$transaction.hash#eventlog" + } + } + } +} +``` + + + +To get a Slack webhook URL: + +1. Go to https://api.slack.com/apps +2. Create a new app or select existing one +3. Enable "Incoming Webhooks" +4. Create a webhook for your channel + + +##### Email Notifications + +```bash +# Only necessary if you haven't already run the automated setup script (Option 1: Automated Setup) +cp examples/config/triggers/email_notifications.json config/triggers/email_notifications.json +``` + +***Email Configuration:*** + +```json + + "evm_large_transfer_usdc_email": { + "name": "Large Transfer Email Notification", + "trigger_type": "email", + "config": { + "host": "smtp.gmail.com", + "port": 465, + "username": { + "type": "plain", + "value": "your_email@gmail.com" + , + "password": + "type": "plain", + "value": "SMTP_PASSWORD" + , + "message": + "title": "large_transfer_usdc_email triggered", + "body": "Large transfer of ${events.0.args.value USDC from $events.0.args.from to $events.0.args.to | https://etherscan.io/tx/$transaction.hash#eventlog" + }, + "sender": "your_email@gmail.com", + "recipients": [ + "recipient1@example.com", + "recipient2@example.com" + ] + } + } +} +``` + + + +For Gmail, you’ll need to use an "App Password" instead of your regular password. Enable 2FA and generate an app password in your Google Account settings. + + +#### Step 4: Run the Monitor + +***Local Deployment:*** + +```bash +./openzeppelin-monitor +``` + +***Docker Deployment:*** + +```bash +cargo make docker-compose-up +``` + +#### What Happens Next + +Once running, the monitor will: + +1. Check for new Ethereum blocks every minute +2. Watch for USDC transfers over 10,000 USDC +3. Send notifications via Slack and email when large transfers occur + +#### Customization Options + +* ***Adjust threshold:*** Modify `"value > 10000000000"` to change the minimum transfer amount +* ***Monitor other tokens:*** Create new monitor configurations for different ERC20 tokens +* ***Add more networks:*** Configure additional EVM networks (Polygon, BSC, etc.) + +### Example 2: Monitor DEX Swaps (Stellar) + +This example monitors large DEX swaps on Stellar mainnet. + +#### Step 1: Network Configuration + +Create the Stellar mainnet configuration: + +```bash +# Only necessary if you haven't already run the automated setup script (Option 1: Automated Setup) +cp examples/config/networks/stellar_mainnet.json config/networks/stellar_mainnet.json +``` + +***Key Configuration Details:*** + +```json + + "network_type": "Stellar", + "slug": "stellar_mainnet", + "name": "Stellar Mainnet", + "rpc_urls": [ + { + "type_": "rpc", + "url": { + "type": "plain", + "value": "YOUR_RPC_URL_HERE" + , + "weight": 100 + } + ], + "network_passphrase": "Public Global Stellar Network ; September 2015", + "block_time_ms": 5000, + "confirmation_blocks": 2, + "cron_schedule": "0 */1 * * * *", + "max_past_blocks": 20, + "store_blocks": true +} +``` + +#### Step 2: Monitor Configuration + +Set up the DEX swap monitor: + +```bash +# Only necessary if you haven't already run the automated setup script (Option 1: Automated Setup) +cp examples/config/monitors/stellar_swap_dex.json config/monitors/stellar_swap_dex.json +cp examples/config/filters/stellar_filter_block_number.sh config/filters/stellar_filter_block_number.sh +``` + +***Monitor Configuration Overview:*** + +```json + + "name": "Large Swap By Dex", + "paused": false, + "networks": ["stellar_mainnet"], + "addresses": [ + { + "address": "CA6PUJLBYKZKUEKLZJMKBZLEKP2OTHANDEOWSFF44FTSYLKQPIICCJBE", + "contract_spec": [ + { + "function_v0": { + "doc": "", + "name": "swap", + "inputs": [ + { + "doc": "", + "name": "user", + "type_": "address" + , + + "doc": "", + "name": "in_idx", + "type_": "u32" + , + + "doc": "", + "name": "out_idx", + "type_": "u32" + , + + "doc": "", + "name": "in_amount", + "type_": "u128" + , + + "doc": "", + "name": "out_min", + "type_": "u128" + + ], + "outputs": ["u128"] + } + } + ] + } + ], + "match_conditions": + "functions": [ + { + "signature": "swap(Address,U32,U32,U128,U128)", + "expression": "out_min > 1000000000" + + ], + "events": [], + "transactions": [ + + "status": "Success", + "expression": null + + ] + }, + "trigger_conditions": [ + + "script_path": "./config/filters/stellar_filter_block_number.sh", + "language": "bash", + "arguments": ["--verbose"], + "timeout_ms": 1000 + + ], + "triggers": ["stellar_large_swap_by_dex_slack"] +} +``` + + + +* The `contract_spec` field is optional for Stellar contracts. If not provided, the monitor automatically fetches the contract’s SEP-48 interface from the chain +* You can explore Stellar contract interfaces using the [Stellar Contract Explorer](https://lab.stellar.org/smart-contracts/contract-explorer) +* The expression `"out_min > 1000000000"` monitors swaps with minimum output over 1 billion tokens + + +#### Step 3: Notification Setup + +Set up Slack notifications for Stellar swaps: + +```bash +# Only necessary if you haven't already run the automated setup script (Option 1: Automated Setup) +cp examples/config/triggers/slack_notifications.json config/triggers/slack_notifications.json +``` + +***Slack Configuration:*** + +```json + + "stellar_large_swap_by_dex_slack": { + "name": "Large Swap By Dex Slack Notification", + "trigger_type": "slack", + "config": { + "slack_url": { + "type": "plain", + "value": "slack-webhook-url" + , + "message": + "title": "large_swap_by_dex_slack triggered", + "body": "${monitor.name triggered because of a large swap of $functions.0.args.out_min tokens | https://stellar.expert/explorer/public/tx/$transaction.hash" + } + } + } +} +``` + +#### Step 4: Run the Monitor + +***Local Deployment:*** + +```bash +./openzeppelin-monitor +``` + +***Docker Deployment:*** + +```bash +cargo make docker-compose-up +``` + +#### What Happens Next + +Once running, the monitor will: + +1. Check for new Stellar blocks every minute +2. Watch for large DEX swaps +3. Send notifications via Slack when large swaps occur + +## Next Steps + +Now that you have OpenZeppelin Monitor running, here are some suggestions for what to do next: + +### Testing and Validation + +* [Test your configuration](/monitor/1.0.x#testing-your-configuration) against specific block numbers +* Verify your RPC endpoints are working correctly +* Test notification channels with small transactions + +### Security and Best Practices + +* [Configure secure secret management](/monitor/1.0.x#secret-management) for sensitive data +* Use environment variables or Hashicorp Cloud Vault for credentials +* Regularly update your RPC endpoints and monitor configurations + +### Advanced Configuration + +* Explore additional examples in the [`examples/config/monitors` directory](https://github.com/OpenZeppelin/openzeppelin-monitor/tree/main/examples/config/monitors) +* Set up monitoring for multiple networks simultaneously +* Configure custom filter scripts for complex conditions + +### Getting Help + +* Check the [GitHub Issues](https://github.com/OpenZeppelin/openzeppelin-monitor/issues) for known problems +* Review the [User Documentation](/monitor/1.0.x) for detailed configuration options +* Join the OpenZeppelin community for support + + + +Start with simple monitoring scenarios and gradually add complexity. This helps you understand how the system works and makes troubleshooting easier. diff --git a/content/monitor/1.0.x/rpc.mdx b/content/monitor/1.0.x/rpc.mdx new file mode 100644 index 00000000..3655be8e --- /dev/null +++ b/content/monitor/1.0.x/rpc.mdx @@ -0,0 +1,303 @@ +--- +title: RPC Client +--- + +## Overview + +The OpenZeppelin Monitor includes a robust RPC client implementation with automatic endpoint rotation and fallback capabilities. This ensures reliable blockchain monitoring even when individual RPC endpoints experience issues. + +* Multiple RPC endpoint support with weighted load balancing +* Automatic fallback on endpoint failures +* Rate limit handling (429 responses) +* Connection health checks +* Thread-safe endpoint rotation + +## Configuration + +### RPC URLs + +RPC endpoints are configured in the network configuration files with weights for load balancing: +```json +{ + "rpc_urls": [ + { + "type_": "rpc", + "url": {"type": "plain", "value": "https://primary-endpoint.example.com"}, + "weight": 100 + }, + { + "type_": "rpc", + "url": {"type": "plain", "value": "https://backup-endpoint.example.com"}, + "weight": 50 + } + ] +} +``` + +For high-availability setups, configure at least 3 (private) RPC endpoints with appropriate weights to ensure continuous operation even if multiple endpoints fail. + + +### Configuration Fields + +| Field | Type | Description | +| --- | --- | --- | +| `type_` | `String` | Type of endpoint (currently only "rpc" is supported) | +| `url.type` | `String` | Secret type ("Plain", "Environment", or "HashicorpCloudVault") | +| `url.value` | `String` | The RPC endpoint URL | +| `weight` | `Number` | Load balancing weight (0-100) | + +## Endpoint Management + +The endpoint manager handles: + +* Initial endpoint selection based on weights +* Automatic rotation on failures +* Connection health checks +* Thread-safe endpoint updates + +Each blockchain network type has its own specialized transport client that wraps the base `HttpTransportClient`. +The transport clients are implemented as: + +1. **Core HTTP Transport**: `HttpTransportClient` provides core HTTP functionality, including the integrated retryable client. +2. **Network-Specific Transports**: + * `EVMTransportClient` for EVM networks + * `StellarTransportClient` for Stellar networks + +### Rotation Strategy + +The RPC client includes an automatic rotation strategy for handling specific types of failures: + +* For 429 (Too Many Requests) responses: + * Immediately rotates to a fallback URL + * Retries the request with the new endpoint + * Continues this process until successful or all endpoints are exhausted + +#### Configuration Options + +The error codes that trigger RPC endpoint rotation can be customized in the `src/services/blockchain/transports/mod.rs` file. + +```rust +pub const ROTATE_ON_ERROR_CODES: [u16; 1] = [429]; +``` + +### Retry Strategy + +The transport layer uses a combination of same-endpoint retries and endpoint rotation to handle transient failures and maintain service availability. + +#### Same-Endpoint Retry (via `reqwest-retry`) + +The `HttpTransportClient` (and by extension, EVM and Stellar clients) utilizes a `reqwest_middleware::ClientWithMiddleware`. This client is configured during initialization using the `utils::http::create_retryable_http_client` utility. This utility layers `reqwest_retry::RetryTransientMiddleware` on top of a shared base `reqwest::Client`. + +This middleware handles: + +* Automatic retries for transient HTTP errors (e.g., 5xx server errors, network timeouts) for requests made to the **currently active RPC URL**. +* An exponential backoff policy between these retry attempts. +* Parameters like the number of retries, backoff durations, and jitter are defined in an `RetryConfig` struct (see [Configuration Options](#configuration-options)). +* This same-endpoint retry mechanism is independent of, and operates before, the endpoint rotation logic. If all same-endpoint retries fail for the current URL, the error is then processed by the `EndpointManager`. + +#### Endpoint Rotation (via `EndpointManager`) + +If all same-endpoint retries fail for the currently active RPC URL, or if certain HTTP status codes (e.g., 429 Too Many Requests, as defined in `ROTATE_ON_ERROR_CODES`) are received, the `EndpointManager` (used by `HttpTransportClient`) will attempt to rotate to a healthy fallback URL. This ensures that if one endpoint becomes persistently unavailable, the system can switch to an alternative. The health check for a fallback URL also benefits from the same-endpoint retry mechanism. + +#### Configuration Options + +The same-endpoint retry behavior is configured via the `RetryConfig` struct, which is used by `create_retryable_http_client` to set up the `ExponentialBackoff` policy for `reqwest-retry`. + +The default settings for `RetryConfig` result in an `ExponentialBackoff` policy approximately equivalent to: +```rust +// This illustrates the default policy created by RetryConfig::default() +// and create_retryable_http_client. +let http_retry_config = RetryConfig::default(); +let retry_policy = ExponentialBackoff::builder() + .base(http_retry_config.base_for_backoff) + .retry_bounds(http_retry_config.initial_backoff, http_retry_config.max_backoff) + .jitter(http_retry_config.jitter) + .build_with_max_retries(http_retry_config.max_retries); +``` + +The configurable options are defined in the `RetryConfig` struct: +```rust +// In utils::http +pub struct RetryConfig { + /// Maximum number of retries for transient errors (after the initial attempt). + pub max_retries: u32, + /// Initial backoff duration before the first retry. + pub initial_backoff: Duration, + /// Maximum backoff duration for retries. + pub max_backoff: Duration, + /// Base for the exponential backoff calculation (e.g., 2). + pub base_for_backoff: u64, + /// Jitter to apply to the backoff duration. + pub jitter: Jitter, +} +``` + +The client architecture ensures efficient resource use and consistent retry behavior: + +1. A single base `reqwest::Client` is created by `HttpTransportClient` with optimized connection pool settings. This base client is shared. +2. The `create_retryable_http_client` utility takes this base client and an `RetryConfig` to produce a `ClientWithMiddleware`. +3. This `ClientWithMiddleware` (the "retryable client") is then used for all HTTP operations within `HttpTransportClient`, including initial health checks, requests sent via `EndpointManager`, and `try_connect` calls during rotation. This ensures all operations benefit from the configured retry policy and the shared connection pool. + +Each transport client may define its own retry policy: + +```rust +// src/services/transports/http.rs +pub struct HttpTransportClient { + pub client: ClientWithMiddleware, + endpoint_manager: EndpointManager, + test_connection_payload: Option, +} + +// Example of client creation with retry mechanism +// Use default retry policy +let http_retry_config = RetryConfig::default(); + +// Create the base HTTP client +let base_http_client = reqwest::ClientBuilder::new() + .pool_idle_timeout(Duration::from_secs(90)) + .pool_max_idle_per_host(32) + .timeout(Duration::from_secs(30)) + .connect_timeout(Duration::from_secs(20)) + .build() + .context("Failed to create base HTTP client")?; + +// Create a retryable HTTP client with the base client and retry policy +let retryable_client = create_retryable_http_client( + &http_retry_config, + base_http_client, + Some(TransientErrorRetryStrategy), // Use custom or default retry strategy +); +``` + +### Implementation Details +The `EndpointManager` uses the retry-enabled `ClientWithMiddleware` provided by `HttpTransportClient` for its attempts on the primary URL. If these attempts (including internal `reqwest-retry` retries) ultimately fail with an error that warrants rotation (e.g., a 429 status code, or persistent network errors), then `EndpointManager` initiates the URL rotation sequence. + +```mermaid +sequenceDiagram + participant User as User/Application + participant HTC as HttpTransportClient + participant EM as EndpointManager + participant RetryClient as ClientWithMiddleware (reqwest-retry) + participant RPC_Primary as Primary RPC + participant RPC_Fallback as Fallback RPC + + User->>HTC: send_raw_request() + HTC->>EM: send_raw_request(self, ...) + EM->>RetryClient: POST to RPC_Primary + Note over RetryClient, RPC_Primary: RetryClient handles same-endpoint retries internally (e.g., for 5xx) + alt Retries on RPC_Primary succeed + RPC_Primary-->>RetryClient: Success + RetryClient-->>EM: Success + EM-->>HTC: Success + HTC-->>User: Response + else All retries on RPC_Primary fail (e.g. network error or 429) + RPC_Primary-->>RetryClient: Final Error (e.g. 429 or network error) + RetryClient-->>EM: Final Error from RPC_Primary + EM->>EM: Decide to Rotate (based on error type) + EM->>HTC: try_connect(Fallback_URL) (HTC uses its RetryClient for this) + HTC->>RetryClient: POST to RPC_Fallback (health check) + alt Fallback health check succeeds + RPC_Fallback-->>RetryClient: Success (health check) + RetryClient-->>HTC: Success (health check) + HTC-->>EM: Success (health check) + EM->>EM: Update active URL to RPC_Fallback + EM->>RetryClient: POST to RPC_Fallback (actual request) + RPC_Fallback-->>RetryClient: Success + RetryClient-->>EM: Success + EM-->>HTC: Success + HTC-->>User: Response + else Fallback health check fails + RPC_Fallback-->>RetryClient: Error (health check) + RetryClient-->>HTC: Error (health check) + HTC-->>EM: Error (health check) + EM-->>HTC: Final Error (all URLs failed) + HTC-->>User: Error Response + end + end +``` + +## List of RPC Calls + +Below is a list of RPC calls made by the monitor for each network type for each iteration of the cron schedule. +As the number of blocks being processed increases, the number of RPC calls grows, potentially leading to rate limiting issues or increased costs if not properly managed. + +```mermaid +graph TD + subgraph Common Operations + A[Main] --> D[Process New Blocks] + end + + subgraph EVM Network Calls + B[Network Init] -->|net_version| D + D -->|eth_blockNumber| E[For every block in range] + E -->|eth_getBlockByNumber| G1[Process Block] + G1 -->|eth_getLogs| H[Get Block Logs] + H -->|Only when needed| J[Get Transaction Receipt] + J -->|eth_getTransactionReceipt| I[Complete] + end + + subgraph Stellar Network Calls + C[Network Init] -->|getNetwork| D + D -->|getLatestLedger| F[In batches of 200 blocks] + F -->|getLedgers| G2[Process Block] + G2 -->|For each monitored contract without ABI| M[Fetch Contract Spec] + M -->|getLedgerEntries| N[Get WASM Hash] + N -->|getLedgerEntries| O[Get WASM Code] + O --> G2 + G2 -->|In batches of 200| P[Fetch Block Data] + P -->|getTransactions| L1[Get Transactions] + P -->|getEvents| L2[Get Events] + L1 --> Q[Complete] + L2 --> Q + end +``` + +**EVM** + +* RPC Client initialization (per active network): `net_version` +* Fetching the latest block number (per cron iteration): `eth_blockNumber` +* Fetching block data (per block): `eth_getBlockByNumber` +* Fetching block logs (per block): `eth_getLogs` +* Fetching transaction receipt (only when needed): + * When monitor condition requires receipt-specific fields (e.g., `gas_used`) + * When monitoring transaction status and no logs are present to validate status + +**Stellar** + +* RPC Client initialization (per active network): `getNetwork` +* Fetching the latest ledger (per cron iteration): `getLatestLedger` +* Fetching ledger data (batched up to 200 in a single request): `getLedgers` +* During block filtering, for each monitored contract without an ABI in config: + * Fetching contract instance data: `getLedgerEntries` + * Fetching contract WASM code: `getLedgerEntries` +* Fetching transactions (batched up to 200 in a single request): `getTransactions` +* Fetching events (batched up to 200 in a single request): `getEvents` + +## Best Practices + +* Configure multiple private endpoints with appropriate weights +* Use geographically distributed endpoints when possible +* Monitor endpoint health and adjust weights as needed +* Set appropriate retry policies based on network characteristics + +## Troubleshooting + +### Common Issues + +* **429 Too Many Requests**: Increase the number of fallback URLs, adjust weights or reduce monitoring frequency +* **Connection Timeouts**: Check endpoint health and network connectivity +* **Invalid Responses**: Verify endpoint compatibility with your network type + +### Logging + +Enable debug logging for detailed transport information: + +```bash +RUST_LOG=debug +``` + +This will show: + +* Endpoint rotations +* Connection attempts +* Request/response details diff --git a/content/monitor/1.0.x/scripts.mdx b/content/monitor/1.0.x/scripts.mdx new file mode 100644 index 00000000..f58eaf03 --- /dev/null +++ b/content/monitor/1.0.x/scripts.mdx @@ -0,0 +1,616 @@ +--- +title: Custom Scripts +--- + +OpenZeppelin Monitor allows you to implement custom scripts for additional filtering of monitor matches and custom notification handling. + + + +***Security Risk:*** Only run scripts that you trust and fully understand. Malicious scripts can harm your system or expose sensitive data. Always review script contents and verify their source before execution. + + +## Custom Filter Scripts + +Custom filter scripts allow you to apply additional conditions to matches detected by the monitor. This helps you refine the alerts you receive based on criteria specific to your use case. + +### Implementation Guide + +1. Create a script in one of the supported languages: + * Bash + * Python + * JavaScript +2. Your script will receive a JSON object with the following structure: + * EVM + + ```json + { + "args": ["--verbose"], + "monitor_match": { + "EVM": { + "matched_on": { + "events": [], + "functions": [ + { + "expression": null, + "signature": "transfer(address,uint256)" + } + ], + "transactions": [ + { + "expression": null, + "status": "Success" + } + ] + }, + "matched_on_args": { + "events": null, + "functions": [ + { + "args": [ + { + "indexed": false, + "kind": "address", + "name": "to", + "value": "0x94d953b148d4d7143028f397de3a65a1800f97b3" + }, + { + "indexed": false, + "kind": "uint256", + "name": "value", + "value": "434924400" + } + ], + "hex_signature": "a9059cbb", + "signature": "transfer(address,uint256)" + } + ] + }, + "monitor": { + "addresses": [ + { + "contract_spec": null, + "address": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48" + } + ], + "match_conditions": { + "events": [ + { + "expression": "value > 10000000000", + "signature": "Transfer(address,address,uint256)" + } + ], + "functions": [ + { + "expression": null, + "signature": "transfer(address,uint256)" + } + ], + "transactions": [ + { + "expression": null, + "status": "Success" + } + ] + }, + "name": "Large Transfer of USDC Token", + "networks": ["ethereum_mainnet"], + "paused": false, + "trigger_conditions": [ + { + "arguments": ["--verbose"], + "language": "Bash", + "script_path": "./config/filters/evm_filter_block_number.sh", + "timeout_ms": 1000 + } + ], + "triggers": ["evm_large_transfer_usdc_script"] + }, + "receipt": { + "blockHash": "0x...", + "blockNumber": "0x...", + "contractAddress": null, + "cumulativeGasUsed": "0x...", + "effectiveGasPrice": "0x...", + "from": "0x...", + "gasUsed": "0xb068", + "status": "0x1", + "to": "0x...", + "transactionHash": "0x...", + "transactionIndex": "0x1fc", + "type": "0x2" + }, + "logs": [ + { + "address": "0xd1f2586790a5bd6da1e443441df53af6ec213d83", + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x00000000000000000000000060af8cf92e5aa9ead4a592d657cd6debecfbc616", + "0x000000000000000000000000d1f2586790a5bd6da1e443441df53af6ec213d83" + ], + "data": "0x00000000000000000000000000000000000000000000106015728793d21f77ac", + "blockNumber": "0x1451aca", + "transactionHash": "0xa39d1b9b3edda74414bd6ffaf6596f8ea12cf0012fd9a930f71ed69df6ff34d0", + "transactionIndex": "0x0", + "blockHash": "0x9432868b7fc57e85f0435ca3047f6a76add86f804b3c1af85647520061e30f80", + "logIndex": "0x2", + "removed": false + } + ], + "transaction": { + "accessList": [], + "blockHash": "0x...", + "blockNumber": "0x1506545", + "chainId": "0x1", + "from": "0x...", + "gas": "0x7a120", + "gasPrice": "0x...", + "hash": "0x...", + "maxFeePerGas": "0x...", + "maxPriorityFeePerGas": "0x...", + "nonce": "0x14779f", + "to": "0x...", + "transactionIndex": "0x...", + "type": "0x2", + "value": "0x0" + } + } + } + } + ``` + * Stellar + + ```json + { + "args": ["--verbose"], + "monitor_match": { + "Stellar": { + "monitor": { + "name": "Large Swap By Dex", + "networks": ["stellar_mainnet"], + "paused": false, + "addresses": [ + { + "address": "GCXYK...", + "contract_spec": null + } + ], + "match_conditions": { + "functions": [ + { + "signature": "swap(Address,U32,U32,U128,U128)", + "expression": "out_min > 1000000000" + } + ], + "events": [], + "transactions": [] + }, + "trigger_conditions": [ + { + "arguments": ["--verbose"], + "language": "Bash", + "script_path": "./config/filters/stellar_filter_block_number.sh", + "timeout_ms": 1000 + } + ], + "triggers": ["stellar_large_transfer_usdc_script"] + }, + "transaction": { + "status": "SUCCESS", + "txHash": "2b5a0c...", + "applicationOrder": 3, + "feeBump": false, + "envelopeXdr": "AAAAAA...", + "envelopeJson": { + "type": "ENVELOPE_TYPE_TX", + "tx": {/* transaction details */} + }, + "resultXdr": "AAAAAA...", + "resultJson": /* result details */, + "resultMetaXdr": "AAAAAA...", + "resultMetaJson": /* metadata details */, + "diagnosticEventsXdr": ["AAAAAA..."], + "diagnosticEventsJson": [/* event details */], + "ledger": 123456, + "createdAt": 1679644800, + "decoded": { + "envelope": {/* decoded envelope */}, + "result": /* decoded result */, + "meta": /* decoded metadata */ + } + }, + "ledger": { + "hash": "abc1...", + "sequence": 123456, + "ledgerCloseTime": "2024-03-20T10:00:00Z", + "headerXdr": "AAAAAA...", + "headerJson": {/* header details */}, + "metadataXdr": "AAAAAA...", + "metadataJSON": /* metadata details */ + }, + "matched_on": { + "functions": [ + { + "signature": "swap(Address,U32,U32,U128,U128)", + "expression": "out_min > 1000000000" + } + ], + "events": [], + "transactions": [] + }, + "matched_on_args": { + "functions": [], + "events": null + } + } + } + } + ``` + +### Script Output Requirements + +* Your script should print a boolean value indicating whether the match should be filtered. +* Print `true` if the match should be filtered out (not trigger an alert). +* Print `false` if the match should be processed (trigger an alert). +* Only the **last** printed line will be considered for evaluation. + +### Example Filter Script (Bash) + +```bash +#!/bin/bash + +main() { + # Read JSON input from stdin + input_json=$(cat) + + # Parse arguments from the input JSON and initialize verbose flag + verbose=false + args=$(echo "$input_json" | jq -r '.args[]? // empty') + if [ ! -z "$args" ]; then + while IFS= read -r arg; do + if [ "$arg" = "--verbose" ]; then + verbose=true + echo "Verbose mode enabled" + fi + done <<< "$args" + fi + + # Extract the monitor match data from the input + monitor_data=$(echo "$input_json" | jq -r '.monitor_match') + + if [ "$verbose" = true ]; then + echo "Input JSON received:" + fi + + # Extract blockNumber from the EVM receipt or transaction + block_number_hex=$(echo "$monitor_data" | jq -r '.EVM.transaction.blockNumber' || echo "") + + # Validate that block_number_hex is not empty + if [ -z "$block_number_hex" ]; then + echo "Invalid JSON or missing blockNumber" + echo "false" + exit 1 + fi + + # Remove 0x prefix if present and clean the string + block_number_hex=$(echo "$block_number_hex" | tr -d '\n' | tr -d ' ') + block_number_hex=${block_number_hex#0x} + + if [ "$verbose" = true ]; then + echo "Extracted block number (hex): $block_number_hex" + fi + + # Convert hex to decimal with error checking + if ! block_number=$(printf "%d" $((16#$block_number_hex)) 2>/dev/null); then + echo "Failed to convert hex to decimal" + echo "false" + exit 1 + fi + + if [ "$verbose" = true ]; then + echo "Converted block number (decimal): $block_number" + fi + + # Check if even or odd using modulo + is_even=$((block_number % 2)) + + if [ $is_even -eq 0 ]; then + echo "Block number $block_number is even" + echo "Verbose mode: $verbose" + echo "true" + exit 0 + else + echo "Block number $block_number is odd" + echo "Verbose mode: $verbose" + echo "false" + exit 0 + fi +} + +# Call main function +main +``` + +### Example Filter Script (JavaScript) + +```javascript +#!/usr/bin/env node + +try { + let inputData = ''; + // Read from stdin + process.stdin.on('data', chunk => { + inputData += chunk; + }); + + process.stdin.on('end', () => { + const data = JSON.parse(inputData); + const monitorMatch = data.monitor_match; + const args = data.args; + + // Extract block_number + let blockNumber = null; + if (monitorMatch.EVM) { + const hexBlock = monitorMatch.EVM.transaction?.blockNumber; + if (hexBlock) { + // Convert hex string to integer + blockNumber = parseInt(hexBlock, 16); + } + } + + if (blockNumber === null) { + console.log('false'); + return; + } + + const result = blockNumber % 2 === 0; + console.log(`Block number ${blockNumber} is ${result ? 'even' : 'odd'}`); + console.log(result.toString()); + }); +} catch (e) { + console.log(`Error processing input: ${e}`); + console.log('false'); +} + +``` + +### Example Filter Script (Python) + +```python +#!/usr/bin/env python3 + +import sys +import json + +def main(): + try: + # Read input from stdin + input_data = sys.stdin.read() + if not input_data: + print("No input JSON provided", flush=True) + return False + + # Parse input JSON + try: + data = json.loads(input_data) + monitor_match = data['monitor_match'] + args = data['args'] + except json.JSONDecodeError as e: + print(f"Invalid JSON input: {e}", flush=True) + return False + + # Extract block_number + block_number = None + if "EVM" in monitor_match: + hex_block = monitor_match['EVM']['transaction'].get('blockNumber') + if hex_block: + # Convert hex string to integer + block_number = int(hex_block, 16) + + if block_number is None: + print("Block number is None") + return False + + result = block_number % 2 == 0 + print(f"Block number {block_number} is {'even' if result else 'odd'}", flush=True) + return result + + except Exception as e: + print(f"Error processing input: {e}", flush=True) + return False + +if __name__ == "__main__": + result = main() + # Print the final boolean result + print(str(result).lower(), flush=True) + +``` + +This examples script filters EVM transactions based on their block number: + +* Returns `true` (filter out) for transactions in even-numbered blocks +* Returns `false` (allow) for transactions in odd-numbered blocks +* Accepts a `--verbose` flag for detailed logging +* Explore other examples in the [`examples/config/filters` directory](https://github.com/OpenZeppelin/openzeppelin-monitor/tree/main/examples/config/filters). + +### Integration + +Integrate your custom filter script with the monitor by following the [configuration guidelines](/monitor/1.0.x#trigger-conditions-custom-filters). + + + +Trigger conditions are executed sequentially based on their position in the trigger conditions array. Every filter must return `false` for the match to be included and are only considered if they were executed successfully. + + +## Custom Notification Scripts + +Custom notification scripts allow you to define how alerts are delivered when specific conditions are met. This can include sending alerts to different channels or formatting notifications in a particular way. + +### Implementation Guide + +1. Create a script in one of the supported languages: + * Bash + * Python + * JavaScript +2. Your script will receive the same JSON input format as [filter scripts](#implementation-guide) + +### Script Output Requirements + +* A non-zero exit code indicates an error occurred +* Error messages should be written to `stderr` +* A zero exit code indicates successful execution + +### Example Notification Script (Bash) + +```bash +#!/bin/bash + +main() { + # Read JSON input from stdin + input_json=$(cat) + + # Parse arguments from the input JSON and initialize verbose flag + verbose=false + args=$(echo "$input_json" | jq -r '.args[]? // empty') + if [ ! -z "$args" ]; then + while IFS= read -r arg; do + if [ "$arg" = "--verbose" ]; then + verbose=true + echo "Verbose mode enabled" + fi + done <<< "$args" + fi + + # Extract the monitor match data from the input + monitor_data=$(echo "$input_json" | jq -r '.monitor_match') + + # Validate input + if [ -z "$input_json" ]; then + echo "No input JSON provided" + exit 1 + fi + + # Validate JSON structure + if ! echo "$input_json" | jq . >/dev/null 2>&1; then + echo "Invalid JSON input" + exit 1 + fi + + if [ "$verbose" = true ]; then + echo "Input JSON received:" + echo "$input_json" | jq '.' + echo "Monitor match data:" + echo "$monitor_data" | jq '.' + fi + + # Process args if they exist + args_data=$(echo "$input_json" | jq -r '.args') + if [ "$args_data" != "null" ]; then + echo "Args: $args_data" + fi + + # If we made it here, everything worked + echo "Verbose mode: $verbose" + # return a non zero exit code and an error message + echo "Error: This is a test error" >&2 + exit 1 +} + +# Call main function +main +``` + +### Example Notification Script (JavaScript) + +```javascript +#!/usr/bin/env node + +try { + let inputData = ''; + // Read from stdin + process.stdin.on('data', chunk => { + inputData += chunk; + }); + + process.stdin.on('end', () => { + // Parse input JSON + const data = JSON.parse(inputData); + const monitorMatch = data.monitor_match; + const args = data.args; + + // Log args if they exist + if (args && args.length > 0) { + console.log(`Args: ${JSON.stringify(args)}`); + } + + // Validate monitor match data + if (!monitorMatch) { + console.log("No monitor match data provided"); + return; + } + }); +} catch (e) { + console.log(`Error processing input: ${e}`); +} + +``` + +### Example Notification Script (Python) + +```python +#!/usr/bin/env python3 + +import sys +import json + +def main(): + try: + # Read input from stdin + input_data = sys.stdin.read() + if not input_data: + print("No input JSON provided", flush=True) + return + + # Parse input JSON + try: + data = json.loads(input_data) + monitor_match = data['monitor_match'] + args = data['args'] + if args: + print(f"Args: {args}") + except json.JSONDecodeError as e: + print(f"Invalid JSON input: {e}", flush=True) + return + + except Exception as e: + print(f"Error processing input: {e}", flush=True) + +if __name__ == "__main__": + main() + +``` + +This examples demonstrates how to: + +* Process the input JSON data +* Handle verbose mode for debugging +* Return error messages via `stderr` +* Set appropriate exit codes +* Explore other examples in the [`examples/config/triggers/scripts` directory](https://github.com/OpenZeppelin/openzeppelin-monitor/tree/main/examples/config/triggers/scripts). + +### Integration + +Integrate your custom notification script with the triggers by following the [configuration guidelines](/monitor/1.0.x#custom-script-notifications). + +## Performance Considerations + +* **File descriptor limits**: Each script execution requires file descriptors for `stdin`, `stdout`, and `stderr` + * Ensure your system allows at least 2,048 open file descriptors + * Check your current limit on Unix-based systems with `ulimit -n` + * Temporarily increase the limit with `ulimit -n 2048` + * For permanent changes, modify `/etc/security/limits.conf` or equivalent for your system +* **Script timeout**: Configure appropriate timeout values in your trigger conditions to prevent long-running scripts from blocking the pipeline + * The `timeout_ms` parameter controls how long a script can run before being terminated +* **Resource usage**: Complex scripts may consume significant CPU or memory resources + * Consider optimizing resource-intensive operations in your scripts + * Monitor system performance during high-volume periods +* **Script reloading**: Since scripts are loaded at startup, any modifications to script files require restarting the monitor to take effect diff --git a/content/monitor/1.0.x/testing.mdx b/content/monitor/1.0.x/testing.mdx new file mode 100644 index 00000000..7f9c5e27 --- /dev/null +++ b/content/monitor/1.0.x/testing.mdx @@ -0,0 +1,125 @@ +--- +title: Testing Guide +--- + +This document provides information about testing OpenZeppelin Monitor, including running tests, generating coverage reports, and understanding the test structure. + +## Test Organization + +The project includes comprehensive test suites organized into different categories: + +### Test Types + +* ***Unit Tests***: Located within `src/` modules alongside the code they test +* ***Integration Tests***: Located in `tests/integration/` directory +* ***Property-based Tests***: Located in `tests/properties/` directory +* ***Mock Implementations***: Located in `tests/integration/mocks/` + +### Test Structure + +``` +tests/ +β”œβ”€β”€ integration/ # Integration tests +β”‚ β”œβ”€β”€ blockchain/ # Blockchain client tests +β”‚ β”œβ”€β”€ blockwatcher/ # Block monitoring tests +β”‚ β”œβ”€β”€ filters/ # Filter logic tests +β”‚ β”œβ”€β”€ fixtures/ # Test data and configurations +β”‚ β”œβ”€β”€ mocks/ # Mock implementations +β”‚ └── ... +β”œβ”€β”€ properties/ # Property-based tests +β”‚ β”œβ”€β”€ filters/ # Filter property tests +β”‚ β”œβ”€β”€ notifications/ # Notification property tests +β”‚ └── ... +└── integration.rs # Integration test entry point +``` + +## Running Tests + +### All Tests + +Run the complete test suite: + +```bash +RUST_TEST_THREADS=1 cargo test +``` + + + +`RUST_TEST_THREADS=1` is required to prevent test conflicts when accessing shared resources like configuration files or network connections. + + +### Specific Test Categories + +***Property-based Tests:*** +```bash +RUST_TEST_THREADS=1 cargo test properties +``` + +***Integration Tests:*** +```bash +RUST_TEST_THREADS=1 cargo test integration +``` + +***Unit Tests Only:*** +```bash +RUST_TEST_THREADS=1 cargo test --lib +``` + +## Coverage Reports + +### Prerequisites + +Install the coverage tool: +```bash +rustup component add llvm-tools-preview +cargo install cargo-llvm-cov +``` + +### Generating Coverage + +***HTML Coverage Report:*** +```bash +RUST_TEST_THREADS=1 cargo +stable llvm-cov --html --open +``` + +This generates an HTML report in `target/llvm-cov/html/` and opens it in your browser. + +***Terminal Coverage Report:*** +```bash +RUST_TEST_THREADS=1 cargo +stable llvm-cov +``` + +## Troubleshooting + +### Common Issues + +***Tests hanging or timing out:*** +- Ensure `RUST_TEST_THREADS=1` is set +- Verify mock setups are correct + +***Coverage tool not found:*** +- Install with `cargo install cargo-llvm-cov` +- Add component with `rustup component add llvm-tools-preview` + +***Permission errors:*** +- Ensure test directories are writable +- Check file permissions on test fixtures + +### Debug Output + +Enable debug logging for tests: +```bash +RUST_LOG=debug RUST_TEST_THREADS=1 cargo test -- --nocapture +``` + +## Contributing Tests + +When contributing new features: + +1. ***Add comprehensive tests*** for new functionality +2. ***Ensure all tests pass*** locally before submitting +3. ***Include both unit and integration tests*** where appropriate +4. ***Update test documentation*** if adding new test patterns +5. ***Maintain or improve code coverage*** + +For more information about contributing, see the project’s contributing guidelines. diff --git a/content/monitor/1.1.x/architecture.mdx b/content/monitor/1.1.x/architecture.mdx new file mode 100644 index 00000000..0a4dc1f8 --- /dev/null +++ b/content/monitor/1.1.x/architecture.mdx @@ -0,0 +1,386 @@ +--- +title: Architecture Guide +--- + +This document describes the high-level architecture of OpenZeppelin Monitor, including the core components, their interactions, and the overall system design. It provides a technical overview of how the service processes blockchain data and triggers notifications based on configurable conditions. + +## System Overview + +OpenZeppelin Monitor is organized as a data processing pipeline that spans from blockchain data collection to notification delivery. The system follows a modular architecture with distinct components for each step in the monitoring process, designed for scalability and extensibility. + +### High-Level Architecture + +The diagram below shows the core processing pipeline of OpenZeppelin Monitor, from blockchain networks and configuration through to notification channels: + +```mermaid +%%{init: { + 'theme': 'base', + 'themeVariables': { + 'background': '#ffffff', + 'mainBkg': '#ffffff', + 'primaryBorderColor': '#cccccc' + } +}}%% +flowchart LR + subgraph "Blockchain Networks" + EVMN["EVM Networks"] + STLN["Stellar Networks"] + end + subgraph "Configuration" + NETCFG["Network Configs"] + MONCFG["Monitor Configs"] + TRICFG["Trigger Configs"] + end + subgraph "Core Processing Pipeline" + BWS["BlockWatcherService"] + FS["FilterService"] + TS["TriggerService"] + NS["NotificationService"] + end + subgraph "Notification Channels" + Slack + Email + Discord + Telegram + Webhook + Scripts["Custom Scripts"] + end + + %% Data and config flow + EVMN --> BWS + STLN --> BWS + NETCFG --> BWS + MONCFG --> FS + TRICFG --> TS + BWS --> FS + FS --> TS + TS --> NS + NS --> Slack + NS --> Email + NS --> Discord + NS --> Telegram + NS --> Webhook + NS --> Scripts + + %% Styling for major blocks and notification channels + classDef blockchain fill:#fff3e0,stroke:#ef6c00,stroke-width:2px; + classDef config fill:#e8f5e9,stroke:#2e7d32,stroke-width:2px; + classDef mainBlock fill:#e1f5fe,stroke:#01579b,stroke-width:2px; + classDef notification fill:#fce4ec,stroke:#c2185b,stroke-width:2px; + class EVMN,STLN blockchain; + class NETCFG,MONCFG,TRICFG config; + class BWS,FS,TS,NS mainBlock; + class Slack,Email,Discord,Telegram,Webhook,Scripts notification; +``` + +## Component Architecture + +The system consists of several core services that are initialized at startup and work together to process blockchain data and trigger notifications. The service initialization and dependencies are managed through the bootstrap module. + +### Service Initialization Flow + +```mermaid +%%{init: { + 'theme': 'base', + 'themeVariables': { + 'background': '#ffffff', + 'mainBkg': '#ffffff', + 'primaryBorderColor': '#cccccc' + } +}}%% +graph TD + subgraph Entry Point + MAIN[main.rs] + end + + subgraph Bootstrap + BOOTSTRAP[Bootstrap::initialize_service] + end + + subgraph Block Processing + BT[BlockTracker] + BS[BlockStorage] + BWS[BlockWatcherService] + BH[create_block_handler] + end + + subgraph Core Services + MS[MonitorService] + NS[NetworkService] + TS[TriggerService] + FS[FilterService] + TES[TriggerExecutionService] + NOTS[NotificationService] + end + + subgraph Client Layer + CP[ClientPool] + EVMC[EVMClient] + SC[StellarClient] + end + + %% Initialization Flow + MAIN --> BOOTSTRAP + BOOTSTRAP --> CP + BOOTSTRAP --> NS + BOOTSTRAP --> MS + BOOTSTRAP --> TS + BOOTSTRAP --> FS + BOOTSTRAP --> TES + BOOTSTRAP --> NOTS + + %% Block Processing Setup + BOOTSTRAP --> BT + BOOTSTRAP --> BS + BOOTSTRAP --> BWS + BOOTSTRAP --> BH + + %% Client Dependencies + CP --> EVMC + CP --> SC + BWS --> CP + + %% Service Dependencies + BWS --> BS + BWS --> BT + MS --> NS + MS --> TS + FS --> TES + TES --> NOTS + + %% Block Handler Connection + BH --> FS + BWS --> BH + + style MAIN fill:#e1f5fe,stroke:#01579b + style BOOTSTRAP fill:#fff3e0,stroke:#ef6c00 + classDef blockProcessing fill:#e8f5e9,stroke:#2e7d32 + classDef coreServices fill:#f3e5f5,stroke:#7b1fa2 + classDef clients fill:#fce4ec,stroke:#c2185b + + class BT,BS,BWS,BH blockProcessing + class MS,NS,TS,FS,TES,NOTS coreServices + class CP,EVMC,SC clients +``` + +### Core Components + +#### Block Processing Components + +* ***BlockWatcherService***: Orchestrates the block monitoring process by polling blockchain networks for new blocks and coordinating the processing pipeline. +* ***BlockTracker***: Tracks processed block numbers to prevent duplicate processing and ensure data consistency across service restarts. +* ***BlockStorage***: Persists block processing state for recovery and maintains the last processed block number for each network. + +#### Client Layer Components + +* ***ClientPool***: Manages blockchain client instances and provides network connectivity with connection pooling and failover capabilities. +* ***EVMClient***: Handles communication with Ethereum Virtual Machine compatible networks (Ethereum, Polygon, BSC, etc.). +* ***StellarClient***: Manages connections to Stellar blockchain networks with protocol-specific optimizations. + +#### Processing Pipeline Components + +* ***FilterService***: Applies monitor filters to blockchain data, evaluating conditions and match expressions to identify relevant transactions and events. +* ***TriggerExecutionService***: Executes triggers based on matched monitor conditions, evaluating trigger logic and preparing notification payloads. +* ***NotificationService***: Delivers notifications through configured channels (Slack, Email, Discord, Telegram, Webhooks, Scripts). + +#### Configuration Management Components + +* ***MonitorService***: Manages monitor configurations and provides access to active monitors with validation and lifecycle management. +* ***NetworkService***: Manages network configurations and provides network details for client connections and monitoring operations. +* ***TriggerService***: Manages trigger configurations and provides trigger details for notification execution. + +### Service Responsibilities + +The following table describes the key responsibilities of each service in the OpenZeppelin Monitor architecture: + +| Service | Responsibility | +| --- | --- | +| **MonitorService** | Manages monitor configurations and provides access to active monitors | +| **NetworkService** | Manages network configurations and provides network details | +| **TriggerService** | Manages trigger configurations and provides trigger details | +| **FilterService** | Filters blockchain data based on monitor conditions and match expressions | +| **TriggerExecutionService** | Executes triggers based on matched monitor conditions | +| **NotificationService** | Delivers notifications through configured channels | +| **BlockWatcherService** | Polls blockchain networks for new blocks and coordinates processing | +| **BlockTracker** | Tracks processed block numbers to prevent duplicate processing | +| **BlockStorage** | Persists block processing state for recovery | +| **ClientPool** | Manages blockchain client instances and provides network connectivity | + +### Block Processing Workflow + +The following _runtime flow_ illustrates how data moves through the system, from blockchain networks to notification channels. This sequence represents the core monitoring loop that executes for each configured network. + +```mermaid +%%{init: { + 'theme': 'base', + 'themeVariables': { + 'background': '#ffffff', + 'mainBkg': '#ffffff', + 'primaryBorderColor': '#cccccc' + } +}}%% +sequenceDiagram + participant BWS as BlockWatcherService + participant BS as BlockStorage + participant BC as BlockchainClient + participant FS as FilterService + participant TES as TriggerExecutionService + participant NS as NotificationService + + rect rgb(232, 245, 233) + Note over BWS: Orchestrates block processing + BWS->>BS: Get last processed block + end + + rect rgb(225, 245, 254) + Note over BC: Blockchain interface + BWS->>BC: Get latest block number + BWS->>BC: Get blocks (last+1 to latest) + end + + loop For each block + rect rgb(243, 229, 245) + Note over FS: Applies monitor filters + BWS->>FS: filter_block(block) + FS->>FS: Apply monitor filters + FS-->>BWS: Monitor matches + end + + rect rgb(255, 248, 225) + Note over TES: Evaluates trigger conditions + BWS->>TES: Process monitor matches + TES->>TES: Run trigger conditions + end + + rect rgb(252, 228, 236) + Note over NS: Delivers notifications + TES->>NS: Execute notifications + end + end + + rect rgb(255, 243, 224) + Note over BS: Persists processing state + BWS->>BS: Store latest processed block + end +``` + +### Data Flow Architecture + +#### 1. Block Discovery Phase +The `BlockWatcherService` initiates the monitoring cycle by: + +* Retrieving the last processed block number from `BlockStorage` +* Querying the blockchain for the latest block number +* Calculating the range of new blocks to process + +#### 2. Data Retrieval Phase +The `BlockchainClient` fetches block data: + +* Connects to the appropriate blockchain network via RPC +* Retrieves full block data including transactions and events +* Handles network-specific data formats and protocols + +#### 3. Filtering Phase +The `FilterService` processes each block: + +* Applies monitor-specific filters to transactions and events +* Evaluates match expressions and conditions +* Identifies relevant data that matches monitoring criteria + +#### 4. Trigger Evaluation Phase +The `TriggerExecutionService` processes matches: + +* Evaluates trigger conditions for matched data +* Prepares notification payloads with relevant context +* Determines which notification channels to activate + +#### 5. Notification Delivery Phase +The `NotificationService` delivers alerts: + +* Formats messages for each notification channel +* Handles channel-specific delivery protocols +* Manages delivery retries and error handling + +#### 6. State Persistence Phase +The `BlockStorage` updates processing state: + +* Records the latest processed block number +* Ensures data consistency for recovery scenarios +* Maintains processing history for debugging + +### Error Handling and Resilience + +The architecture includes several resilience mechanisms: + +* ***Connection Pooling***: The `ClientPool` manages multiple connections to prevent single points of failure +* ***State Recovery***: `BlockStorage` enables the service to resume from the last known good state after restarts +* ***Retry Logic***: Notification delivery includes configurable retry mechanisms for transient failures +* ***Graceful Degradation***: Individual component failures don’t cascade to the entire system + +For detailed information about RPC logic and network communication, see the [RPC section](/monitor/1.1.x/rpc). + +## Configuration Architecture + +The system uses a JSON-based configuration system organized into distinct categories: + +### Configuration Categories + +* ***Network Configurations***: Define blockchain network connections, RPC endpoints, and network parameters +* ***Monitor Configurations***: Specify monitoring rules, conditions, and network/trigger references +* ***Trigger Configurations***: Define notification settings and script definitions +* ***Filter Configurations***: Contain match filter scripts for data filtering + +### Configuration Validation + +The system implements comprehensive validation: + +* Cross-reference validation between monitors, networks, and triggers +* Schema validation for all configuration files +* Runtime validation of configuration references during service startup + + + +For configuration examples and best practices, see the [Configuration Guidelines](/monitor/1.1.x#configuration_guidelines) section in the user documentation. + + +## Extensibility Points + +The architecture is designed for extensibility in several key areas: + +### Blockchain Support +* ***Client Layer***: New blockchain protocols can be added by implementing the `BlockchainClient` trait +* ***Transport Layer***: Protocol-specific transport clients handle network communication details +* ***Filter Layer***: Chain-specific filters process protocol-dependent data formats + +### Notification Channels +* ***Channel Plugins***: New notification channels can be added by implementing the notification interface +* ***Script Support***: Custom notification logic can be implemented using Python, JavaScript, or Bash scripts + +### Monitoring Logic +* ***Expression Engine***: Flexible expression evaluation for complex monitoring conditions +* ***Script Triggers***: Custom trigger logic can be implemented using supported scripting languages + +## Performance Considerations + +The architecture is optimized for: + +* ***Concurrent Processing***: Multiple networks can be monitored simultaneously +* ***Efficient Block Processing***: Batch processing of blocks to minimize RPC calls +* ***Memory Management***: Streaming processing of large blocks to prevent memory issues +* ***Connection Reuse***: Client pooling reduces connection overhead + +## Security Architecture + +The system implements several security measures: + +* ***Secure Protocols***: Support for HTTPS/WSS +* ***Secret Management***: Secure handling of API keys and sensitive configuration data +* ***Input Validation***: Comprehensive validation of all external inputs and configurations + +## Related Documentation + +For detailed information about the project structure, source code organization, and development resources, see the [Project Structure](/monitor/1.1.x/project-structure) guide. + +For information about RPC logic and network communication, see the [RPC section](/monitor/1.1.x/rpc). + +For configuration examples and best practices, see the [Configuration Guidelines](/monitor/1.1.x#configuration_guidelines) section in the user documentation. diff --git a/content/monitor/1.1.x/changelog.mdx b/content/monitor/1.1.x/changelog.mdx new file mode 100644 index 00000000..276fa8ad --- /dev/null +++ b/content/monitor/1.1.x/changelog.mdx @@ -0,0 +1,300 @@ +--- +title: Changelog +--- + + +# [v1.1.0](https://github.com/OpenZeppelin/openzeppelin-monitor/releases/tag/v1.1.0) - 2025-10-22 + +## [1.1.0](https://github.com/OpenZeppelin/openzeppelin-monitor/compare/v1.0.0...v1.1.0) (2025-10-22) + + +### πŸš€ Features + +* add block tracker ([#11](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/11)) ([1d4d117](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/1d4d117aab56e2c31c0747d6bf681fe60b2d8b10)) +* Add CLA assistant bot ([#107](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/107)) ([47e490e](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/47e490e4a5657a48bc60f85c38d72aca16334ac0)) +* Add client rpc pool ([#75](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/75)) ([28cd940](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/28cd940a8aea5c97fb15a4ca0d415debaa2864b1)) +* add email support ([#7](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/7)) ([decb56d](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/decb56d45d3f1000346c24e137d1a5d952c4a9dd)) +* Add endpoint rotation manager ([#69](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/69)) ([454a630](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/454a630cf92c305ea5d9254b211a7b60abf8804d)) +* Add environment vars and Hashicorp cloud vault support (breaking) ([#199](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/199)) ([558304f](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/558304f335a645c1de2d348a041337ccba2c2a06)) +* Add events and functions summary in notifications ([#339](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/339)) ([000ae24](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/000ae24e896cd0867c6252111a71151942d820bc)) +* Add new error context ([#77](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/77)) ([612bb76](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/612bb76b9c8e9a470fc68685c2f06481663a9474)) +* Add rc workflow file ([#156](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/156)) ([8907591](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/890759186570a64a9d0b0ef4dc9e512d0110d7a0)) +* Add support for webhook, telegram, discord notifications ([#65](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/65)) ([829967d](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/829967da45062dc22ffb0cb3376e68101a46b3e9)) +* Enhance filter expression parsing and evaluation ([#222](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/222)) ([3cb0849](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/3cb084919b3d477f329a85fbafce1ce6d696b16d)) +* Extend support for EVM transaction properties ([#187](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/187)) ([f20086b](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/f20086b0431a787dd55aa8928a09aece80b9a731)) +* Handle Stellar JSON-RPC outside of retention window error for `getTransactions` and `getEvents` ([#270](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/270)) ([ae116ff](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/ae116ff10f393a04c19d3b845df656027c6be4b9)) +* Implement client pooling for Webhook-based notifiers ([#281](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/281)) ([4f480c6](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/4f480c6a05aeb949cfd8e227c5c08f19a5e60180)) +* Introduce `TransportError` ([#259](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/259)) ([0e04cfb](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/0e04cfb57109251095ef8ee526fb5e05f5792792)) +* Introduce centralized retryable HTTP client creation ([#273](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/273)) ([5f6edaf](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/5f6edaf5deb77a5d9dfead52a162e923aad6a2ab)) +* Introduce retry mechanism for Email notifier ([#282](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/282)) ([b6301aa](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/b6301aaac963ae904d93e07674d9d01543ecfcd0)) +* Leverage contract spec (SEP-48) for Stellar functions (breaking) ([#208](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/208)) ([5ebc2a4](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/5ebc2a441b9ac6ed66a0807cac2795af2ae5b1c8)) +* Markdown for telegram, discord, slack and email ([#197](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/197)) ([791bf4b](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/791bf4b347d8cfe03ccd53e9797f179c15629a33)) +* Plat 6187 write metrics to prometheus ([#95](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/95)) ([2dc08d5](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/2dc08d51670834f453498299937debfca67fa1b7)) +* PLAT-6148 Adding post filter to monitor model ([#58](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/58)) ([920a0bf](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/920a0bf27953b67eb722d17d5ebf50b51237d4d4)) +* PLAT-6151 Integrate custom script execution with notification service ([#79](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/79)) ([bd5f218](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/bd5f218507dfc30bd4b2182077e2997cf04b8877)) +* PLAT-6477 Adding rust toolchain file ([#117](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/117)) ([ea6fb1e](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/ea6fb1ee6bba46cfa66a0c81665e17930bbbed93)) +* Separate code test coverage into different categories of tests ([#84](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/84)) ([a3ad89c](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/a3ad89cdcf0bab5883af7ec36b854fedc2f060cd)) +* spawn block-watcher per network ([#4](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/4)) ([d7a19ec](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/d7a19ec57344e4fb28dffc6f2025e809d0f5d946)) +* Test execute the monitor against specific block ([#133](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/133)) ([563c34f](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/563c34fde3c0f334a7c5884de5510bf27e4fca48)) +* Update payload builder to support formatted titles ([#336](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/336)) ([12213b3](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/12213b32d609bf6a1ba69ce548f70809971f9fb3)) +* Upgrade stellar crates and read events from specs ([#371](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/371)) ([7273a3f](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/7273a3f8d9249692db6b6ca53f4d8b28b21670f4)) + + +### πŸ› Bug Fixes + +* Add thread flag when running tests in CI ([#41](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/41)) ([4312669](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/4312669d8da84f5cf7e7817b10c377fe3a6992af)) +* Adding validation for unknown field names ([#223](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/223)) ([cadf4da](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/cadf4dac293e2c24a02a2eb188540e1eb312b75f)) +* Adjust netlify toml settings ([#47](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/47)) ([af9fe55](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/af9fe553a92cfc47a306a7dcfc43be0b2257f835)) +* Bump MSRV ([#291](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/291)) ([f2d7953](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/f2d795310cd1417ad2fac854ea5f80cf6296b761)) +* CLA labels and assistant ([#176](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/176)) ([b14f060](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/b14f0600dc4cac5a5f00d3772328abe123114b2a)) +* correct env var value in semgrep.yml ([#317](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/317)) ([7a8253f](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/7a8253fd23ae27c73b3971e2a688c39051c08a84)) +* Deprecate Stellar `paging_token` in `GetEvents` response ([#344](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/344)) ([68d20f9](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/68d20f91b643ef3a7c85ee897308d4f92d43698b)) +* Docs link ([#106](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/106)) ([f12d95d](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/f12d95d85ad9230bece0342c39cb5c3c1cd62832)) +* Docs pipeline ([#167](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/167)) ([1e78ec4](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/1e78ec4f98f70ac12dea353c1605ac4ac2c5734b)) +* Documentation name for antora ([#105](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/105)) ([5a8c4bd](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/5a8c4bd8315e62bb2dedb066f6b6bfcaa09c2d37)) +* Duplicate name in triggers config ([#274](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/274)) ([00f58f4](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/00f58f4be3f9452792f9fdcf5dd8696947a274cb)) +* Environment adjustments and cargo lock file improvements ([#219](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/219)) ([1b4d5d8](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/1b4d5d8dbe8cba26fbb84a8f847fc22b1a1dc096)) +* Event and function signatures from matched_on ([#198](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/198)) ([cdd9f1d](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/cdd9f1d7333ee2f3ef9c476a08e918388b3c35f0)) +* Fix cargo lock ([#110](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/110)) ([c440ca4](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/c440ca43542e919cd473a7d533b0820cf5474d3e)) +* Fix cargo lock file ([#116](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/116)) ([1bd3658](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/1bd3658ab507c2dde90a2132b6eaec6d849e0e3c)) +* Fix the codecov yaml syntax ([#97](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/97)) ([fcafcbf](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/fcafcbf5765014a65c3f2c8718ee0f24a4531ebe)) +* fixed check ([1d36aaa](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/1d36aaa63ca12b4a660ec7e7bfcb18f722d8adf2)) +* Generate SBOM step in release pipeline ([#294](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/294)) ([327269d](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/327269d1ce2a16e9c8419e872ca02503c318c480)) +* Linter ([b0e27ca](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/b0e27ca21f8e39b3a3c16d356df00dfcd0a868e5)) +* Monitor match template var signature collission (breaking) ([#203](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/203)) ([283b724](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/283b724a88f45f82c3c5fc81742a564b70909d45)) +* Multi arch. docker images and binary mismatch ([#382](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/382)) ([a61701e](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/a61701e11a13af03cdf86689b58e670b7d984a38)) +* Pagination logic in stellar getEvents relies only on cursor data ([#265](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/265)) ([fca4057](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/fca4057ff5847e04981e5903eebe6ccf3931726c)) +* PLAT-6301 Remove logic for checking file descriptors open and fixing readme ([#90](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/90)) ([71dbd24](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/71dbd24a9ba5ab4c37cf4be432a4614c2e68166b)) +* Reduce USDC ABI and fix trailing comma ([#62](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/62)) ([92e343c](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/92e343c09dc2da565912b6cd5bc83fbdc591cdb5)) +* Release binaries and enable nightly workflows to create binary artifacts and images ([#313](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/313)) ([43a0091](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/43a0091ed7b57a4ca33ca25a73423a73929802f7)) +* Remove deprecated reviewers field from dependabot.yml ([#316](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/316)) ([152843d](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/152843df396b089e1c6054221206097339502f1b)) +* remove the create-github-app-token action from the scorecard workflow ([#174](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/174)) ([48ca0b1](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/48ca0b106dbee225b5d4824013c2a28b773b23b3)) +* rename docker binaries ([#2](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/2)) ([78d438a](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/78d438a1ca4931651d3ca106c5dbda1ea1357574)) +* rename import ([#6](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/6)) ([745e591](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/745e591faba06f557b2f6a091434250ed559df6e)) +* Replace automatic minor version bumps ([#285](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/285)) ([0c9e14a](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/0c9e14a542cae2d2c7ff580ff7de28b0d9aab22a)) +* Risk of key collision for monitor custom scripts ([#258](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/258)) ([2aa4cd7](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/2aa4cd730dbcbbd1cf0892394cedc4ea06332375)) +* Running duplicate tests ([#181](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/181)) ([ad0f741](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/ad0f741608b2719a1db16dd22bf8c457e5814f86)) +* Semgrep CI integration ([#315](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/315)) ([a2bc23b](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/a2bc23baa27630ba914fca12ac40b191cbbad525)) +* Stellar ledgers are deterministic ([#257](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/257)) ([56a9f9e](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/56a9f9e10e533ea96c01cb1f0f67024600ad89df)) +* syntax error in codeql.yml ([#322](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/322)) ([7068e9e](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/7068e9ee3845a007ed9d6c80157cbe86555ad14e)) +* trigger execution order ([#24](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/24)) ([26581fe](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/26581fec9ec1078ea4284fd6b43509616c66ad64)) +* Update the Semgrep config ([#306](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/306)) ([d4ed740](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/d4ed7405e790098a0b1a0df3701feccb1908c56c)) +* Use unicode character for emoji ([#295](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/295)) ([bdccda5](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/bdccda5f2ca72612a4455a293c30647618476f95)) +* Variable resolving ([#49](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/49)) ([e26d173](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/e26d17314e9b2e78c0772a46f3139da70c6ca144)) + +[Changes][v1.1.0] + + + +# [v1.0.0](https://github.com/OpenZeppelin/openzeppelin-monitor/releases/tag/v1.0.0) - 2025-06-30 + +## [1.0.0](https://github.com/OpenZeppelin/openzeppelin-monitor/compare/v0.2.0...v1.0.0) (2025-06-30) + + +### πŸš€ Features + +* add block tracker ([#11](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/11)) ([1d4d117](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/1d4d117aab56e2c31c0747d6bf681fe60b2d8b10)) +* Add CLA assistant bot ([#107](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/107)) ([47e490e](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/47e490e4a5657a48bc60f85c38d72aca16334ac0)) +* Add client rpc pool ([#75](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/75)) ([28cd940](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/28cd940a8aea5c97fb15a4ca0d415debaa2864b1)) +* add email support ([#7](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/7)) ([decb56d](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/decb56d45d3f1000346c24e137d1a5d952c4a9dd)) +* Add endpoint rotation manager ([#69](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/69)) ([454a630](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/454a630cf92c305ea5d9254b211a7b60abf8804d)) +* Add environment vars and Hashicorp cloud vault support (breaking) ([#199](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/199)) ([558304f](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/558304f335a645c1de2d348a041337ccba2c2a06)) +* Add new error context ([#77](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/77)) ([612bb76](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/612bb76b9c8e9a470fc68685c2f06481663a9474)) +* Add rc workflow file ([#156](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/156)) ([8907591](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/890759186570a64a9d0b0ef4dc9e512d0110d7a0)) +* Add support for webhook, telegram, discord notifications ([#65](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/65)) ([829967d](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/829967da45062dc22ffb0cb3376e68101a46b3e9)) +* Enhance filter expression parsing and evaluation ([#222](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/222)) ([3cb0849](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/3cb084919b3d477f329a85fbafce1ce6d696b16d)) +* Extend support for EVM transaction properties ([#187](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/187)) ([f20086b](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/f20086b0431a787dd55aa8928a09aece80b9a731)) +* Handle Stellar JSON-RPC outside of retention window error for `getTransactions` and `getEvents` ([#270](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/270)) ([ae116ff](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/ae116ff10f393a04c19d3b845df656027c6be4b9)) +* Implement client pooling for Webhook-based notifiers ([#281](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/281)) ([4f480c6](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/4f480c6a05aeb949cfd8e227c5c08f19a5e60180)) +* Introduce `TransportError` ([#259](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/259)) ([0e04cfb](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/0e04cfb57109251095ef8ee526fb5e05f5792792)) +* Introduce centralized retryable HTTP client creation ([#273](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/273)) ([5f6edaf](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/5f6edaf5deb77a5d9dfead52a162e923aad6a2ab)) +* Leverage contract spec (SEP-48) for Stellar functions (breaking) ([#208](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/208)) ([5ebc2a4](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/5ebc2a441b9ac6ed66a0807cac2795af2ae5b1c8)) +* Markdown for telegram, discord, slack and email ([#197](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/197)) ([791bf4b](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/791bf4b347d8cfe03ccd53e9797f179c15629a33)) +* Plat 6187 write metrics to prometheus ([#95](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/95)) ([2dc08d5](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/2dc08d51670834f453498299937debfca67fa1b7)) +* PLAT-6148 Adding post filter to monitor model ([#58](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/58)) ([920a0bf](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/920a0bf27953b67eb722d17d5ebf50b51237d4d4)) +* PLAT-6151 Integrate custom script execution with notification service ([#79](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/79)) ([bd5f218](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/bd5f218507dfc30bd4b2182077e2997cf04b8877)) +* PLAT-6477 Adding rust toolchain file ([#117](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/117)) ([ea6fb1e](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/ea6fb1ee6bba46cfa66a0c81665e17930bbbed93)) +* Separate code test coverage into different categories of tests ([#84](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/84)) ([a3ad89c](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/a3ad89cdcf0bab5883af7ec36b854fedc2f060cd)) +* spawn block-watcher per network ([#4](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/4)) ([d7a19ec](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/d7a19ec57344e4fb28dffc6f2025e809d0f5d946)) +* Test execute the monitor against specific block ([#133](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/133)) ([563c34f](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/563c34fde3c0f334a7c5884de5510bf27e4fca48)) + + +### πŸ› Bug Fixes + +* Add thread flag when running tests in CI ([#41](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/41)) ([4312669](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/4312669d8da84f5cf7e7817b10c377fe3a6992af)) +* Adding validation for unknown field names ([#223](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/223)) ([cadf4da](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/cadf4dac293e2c24a02a2eb188540e1eb312b75f)) +* Adjust netlify toml settings ([#47](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/47)) ([af9fe55](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/af9fe553a92cfc47a306a7dcfc43be0b2257f835)) +* CLA labels and assistant ([#176](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/176)) ([b14f060](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/b14f0600dc4cac5a5f00d3772328abe123114b2a)) +* Docs link ([#106](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/106)) ([f12d95d](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/f12d95d85ad9230bece0342c39cb5c3c1cd62832)) +* Docs pipeline ([#167](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/167)) ([1e78ec4](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/1e78ec4f98f70ac12dea353c1605ac4ac2c5734b)) +* Documentation name for antora ([#105](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/105)) ([5a8c4bd](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/5a8c4bd8315e62bb2dedb066f6b6bfcaa09c2d37)) +* Duplicate name in triggers config ([#274](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/274)) ([00f58f4](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/00f58f4be3f9452792f9fdcf5dd8696947a274cb)) +* Environment adjustments and cargo lock file improvements ([#219](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/219)) ([1b4d5d8](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/1b4d5d8dbe8cba26fbb84a8f847fc22b1a1dc096)) +* Event and function signatures from matched_on ([#198](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/198)) ([cdd9f1d](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/cdd9f1d7333ee2f3ef9c476a08e918388b3c35f0)) +* Fix cargo lock ([#110](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/110)) ([c440ca4](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/c440ca43542e919cd473a7d533b0820cf5474d3e)) +* Fix cargo lock file ([#116](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/116)) ([1bd3658](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/1bd3658ab507c2dde90a2132b6eaec6d849e0e3c)) +* Fix the codecov yaml syntax ([#97](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/97)) ([fcafcbf](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/fcafcbf5765014a65c3f2c8718ee0f24a4531ebe)) +* fixed check ([1d36aaa](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/1d36aaa63ca12b4a660ec7e7bfcb18f722d8adf2)) +* Linter ([b0e27ca](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/b0e27ca21f8e39b3a3c16d356df00dfcd0a868e5)) +* Monitor match template var signature collission (breaking) ([#203](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/203)) ([283b724](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/283b724a88f45f82c3c5fc81742a564b70909d45)) +* Pagination logic in stellar getEvents relies only on cursor data ([#265](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/265)) ([fca4057](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/fca4057ff5847e04981e5903eebe6ccf3931726c)) +* PLAT-6301 Remove logic for checking file descriptors open and fixing readme ([#90](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/90)) ([71dbd24](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/71dbd24a9ba5ab4c37cf4be432a4614c2e68166b)) +* Reduce USDC ABI and fix trailing comma ([#62](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/62)) ([92e343c](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/92e343c09dc2da565912b6cd5bc83fbdc591cdb5)) +* remove the create-github-app-token action from the scorecard workflow ([#174](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/174)) ([48ca0b1](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/48ca0b106dbee225b5d4824013c2a28b773b23b3)) +* rename docker binaries ([#2](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/2)) ([78d438a](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/78d438a1ca4931651d3ca106c5dbda1ea1357574)) +* rename import ([#6](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/6)) ([745e591](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/745e591faba06f557b2f6a091434250ed559df6e)) +* Replace automatic minor version bumps ([#285](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/285)) ([0c9e14a](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/0c9e14a542cae2d2c7ff580ff7de28b0d9aab22a)) +* Risk of key collision for monitor custom scripts ([#258](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/258)) ([2aa4cd7](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/2aa4cd730dbcbbd1cf0892394cedc4ea06332375)) +* Running duplicate tests ([#181](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/181)) ([ad0f741](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/ad0f741608b2719a1db16dd22bf8c457e5814f86)) +* Stellar ledgers are deterministic ([#257](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/257)) ([56a9f9e](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/56a9f9e10e533ea96c01cb1f0f67024600ad89df)) +* trigger execution order ([#24](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/24)) ([26581fe](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/26581fec9ec1078ea4284fd6b43509616c66ad64)) +* Variable resolving ([#49](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/49)) ([e26d173](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/e26d17314e9b2e78c0772a46f3139da70c6ca144)) + +[Changes][v1.0.0] + + + +# [v0.2.0](https://github.com/OpenZeppelin/openzeppelin-monitor/releases/tag/v0.2.0) - 2025-05-14 + +## [0.2.0](https://github.com/OpenZeppelin/openzeppelin-monitor/compare/v0.1.0...v0.2.0) (2025-05-14) + + +## ⚠️ ⚠️ Breaking Changes in v0.2.0 + +* Renamed abi to contract_spec in monitor configurations. +* Stellar function expressions now use named parameters instead of positional indexes, for example; + + ``` + (Transfer(address,address,amount)): + 2 > 1000 β†’ amount > 1000 + ``` +* Template variables now follow dot notation rather than underscores, for example: + * monitor_name β†’ monitor.name + * transaction_hash β†’ transaction.hash + * function_0_amount β†’ functions.0.args.amount + * event_0_signature β†’ events.0.signature +* Sensitive configuration values (e.g., URLs, usernames, passwords, tokens) must now be defined using the SecretValue object structure, for example: + + * RPC URLs: + + ``` + "rpc_urls": [ + { + "type_": "rpc", + "url": { + "type": "plain", + "value": "https://eth.drpc.org" + }, + "weight": 100 + } + ] + ``` + + * Webhook URLs: + + ``` + "discord_url": { + "type": "plain", + "value": "https://discord.com/api/webhooks/123-456-789" + } + ``` + + +### πŸš€ Features + +* Add environment vars and Hashicorp cloud vault support (breaking) ([#199](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/199)) ([558304f](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/558304f335a645c1de2d348a041337ccba2c2a06)) +* Extend support for EVM transaction properties ([#187](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/187)) ([f20086b](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/f20086b0431a787dd55aa8928a09aece80b9a731)) +* Leverage contract spec (SEP-48) for Stellar functions (breaking) ([#208](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/208)) ([5ebc2a4](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/5ebc2a441b9ac6ed66a0807cac2795af2ae5b1c8)) +* Markdown for telegram, discord, slack and email ([#197](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/197)) ([791bf4b](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/791bf4b347d8cfe03ccd53e9797f179c15629a33)) +* Test execute the monitor against specific block ([#133](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/133)) ([563c34f](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/563c34fde3c0f334a7c5884de5510bf27e4fca48)) + + +### πŸ› Bug Fixes + +* Adding validation for unknown field names ([#223](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/223)) ([cadf4da](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/cadf4dac293e2c24a02a2eb188540e1eb312b75f)) +* CLA labels and assistant ([#176](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/176)) ([b14f060](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/b14f0600dc4cac5a5f00d3772328abe123114b2a)) +* Docs pipeline ([#167](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/167)) ([1e78ec4](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/1e78ec4f98f70ac12dea353c1605ac4ac2c5734b)) +* Environment adjustments and cargo lock file improvements ([#219](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/219)) ([1b4d5d8](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/1b4d5d8dbe8cba26fbb84a8f847fc22b1a1dc096)) +* Event and function signatures from matched_on ([#198](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/198)) ([cdd9f1d](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/cdd9f1d7333ee2f3ef9c476a08e918388b3c35f0)) +* Monitor match template var signature collission (breaking) ([#203](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/203)) ([283b724](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/283b724a88f45f82c3c5fc81742a564b70909d45)) +* remove the create-github-app-token action from the scorecard workflow ([#174](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/174)) ([48ca0b1](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/48ca0b106dbee225b5d4824013c2a28b773b23b3)) +* Running duplicate tests ([#181](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/181)) ([ad0f741](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/ad0f741608b2719a1db16dd22bf8c457e5814f86)) + +[Changes][v0.2.0] + + + +# [v0.1.0](https://github.com/OpenZeppelin/openzeppelin-monitor/releases/tag/v0.1.0) - 2025-04-07 + +## 0.1.0 (2025-04-07) + + +### πŸš€ Features + +* add block tracker ([#11](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/11)) ([1d4d117](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/1d4d117aab56e2c31c0747d6bf681fe60b2d8b10)) +* Add CLA assistant bot ([#107](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/107)) ([47e490e](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/47e490e4a5657a48bc60f85c38d72aca16334ac0)) +* Add client rpc pool ([#75](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/75)) ([28cd940](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/28cd940a8aea5c97fb15a4ca0d415debaa2864b1)) +* add email support ([#7](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/7)) ([decb56d](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/decb56d45d3f1000346c24e137d1a5d952c4a9dd)) +* Add endpoint rotation manager ([#69](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/69)) ([454a630](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/454a630cf92c305ea5d9254b211a7b60abf8804d)) +* Add new error context ([#77](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/77)) ([612bb76](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/612bb76b9c8e9a470fc68685c2f06481663a9474)) +* Add rc workflow file ([#156](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/156)) ([8907591](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/890759186570a64a9d0b0ef4dc9e512d0110d7a0)) +* Add support for webhook, telegram, discord notifications ([#65](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/65)) ([829967d](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/829967da45062dc22ffb0cb3376e68101a46b3e9)) +* Plat 6187 write metrics to prometheus ([#95](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/95)) ([2dc08d5](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/2dc08d51670834f453498299937debfca67fa1b7)) +* PLAT-6148 Adding post filter to monitor model ([#58](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/58)) ([920a0bf](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/920a0bf27953b67eb722d17d5ebf50b51237d4d4)) +* PLAT-6151 Integrate custom script execution with notification service ([#79](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/79)) ([bd5f218](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/bd5f218507dfc30bd4b2182077e2997cf04b8877)) +* PLAT-6477 Adding rust toolchain file ([#117](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/117)) ([ea6fb1e](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/ea6fb1ee6bba46cfa66a0c81665e17930bbbed93)) +* Separate code test coverage into different categories of tests ([#84](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/84)) ([a3ad89c](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/a3ad89cdcf0bab5883af7ec36b854fedc2f060cd)) +* spawn block-watcher per network ([#4](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/4)) ([d7a19ec](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/d7a19ec57344e4fb28dffc6f2025e809d0f5d946)) + + +### πŸ› Bug Fixes + +* Add thread flag when running tests in CI ([#41](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/41)) ([4312669](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/4312669d8da84f5cf7e7817b10c377fe3a6992af)) +* Adjust netlify toml settings ([#47](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/47)) ([af9fe55](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/af9fe553a92cfc47a306a7dcfc43be0b2257f835)) +* Docs link ([#106](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/106)) ([f12d95d](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/f12d95d85ad9230bece0342c39cb5c3c1cd62832)) +* Documentation name for antora ([#105](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/105)) ([5a8c4bd](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/5a8c4bd8315e62bb2dedb066f6b6bfcaa09c2d37)) +* Fix cargo lock ([#110](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/110)) ([c440ca4](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/c440ca43542e919cd473a7d533b0820cf5474d3e)) +* Fix cargo lock file ([#116](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/116)) ([1bd3658](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/1bd3658ab507c2dde90a2132b6eaec6d849e0e3c)) +* Fix the codecov yaml syntax ([#97](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/97)) ([fcafcbf](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/fcafcbf5765014a65c3f2c8718ee0f24a4531ebe)) +* fixed check ([1d36aaa](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/1d36aaa63ca12b4a660ec7e7bfcb18f722d8adf2)) +* Linter ([b0e27ca](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/b0e27ca21f8e39b3a3c16d356df00dfcd0a868e5)) +* Netlify integration & Release workflow doc ([#162](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/162)) ([3b77025](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/3b7702569e7c5828ca55fb67f7eec2672bf768b2)) +* PLAT-6301 Remove logic for checking file descriptors open and fixing readme ([#90](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/90)) ([71dbd24](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/71dbd24a9ba5ab4c37cf4be432a4614c2e68166b)) +* Reduce USDC ABI and fix trailing comma ([#62](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/62)) ([92e343c](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/92e343c09dc2da565912b6cd5bc83fbdc591cdb5)) +* rename docker binaries ([#2](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/2)) ([78d438a](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/78d438a1ca4931651d3ca106c5dbda1ea1357574)) +* rename import ([#6](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/6)) ([745e591](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/745e591faba06f557b2f6a091434250ed559df6e)) +* trigger execution order ([#24](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/24)) ([26581fe](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/26581fec9ec1078ea4284fd6b43509616c66ad64)) +* Variable resolving ([#49](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/49)) ([e26d173](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/e26d17314e9b2e78c0772a46f3139da70c6ca144)) + + +### πŸ“š Documentation + +* Add Antora documentation ([#48](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/48)) ([2f737c4](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/2f737c4c040090bd3acd0af90d3f24045b8ff173)) +* add link to contributing in README ([#33](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/33)) ([5abb548](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/5abb548c199f3a033860b027461e5fb3cd60e565)) +* Add list of RPC calls ([#67](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/67)) ([aae9577](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/aae9577f4e011eaca12adb7997bf5fd28a558f83)) +* Add quickstart guide ([#56](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/56)) ([e422353](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/e422353873335540afce5a9a5702c786c71eea75)) +* add readme documentation ([#8](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/8)) ([357006d](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/357006d98f6cc8d160920e702dc78662008d39a3)) +* add rust documentation ([#5](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/5)) ([3832570](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/3832570adf4854279fcda215fbbba5eb0d5396a1)) +* Adding node to docker images - custom scripts ([#76](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/76)) ([da6516c](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/da6516c6f3afccb297cb1c1251f673e02ceaeaa5)) +* Custom scripts documentation to antora and readme ([#91](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/91)) ([2b81058](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/2b81058f810e6b4d18a2c79e96002fb77890e9e0)) +* Fix quickstart closing tag ([#118](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/118)) ([d360379](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/d3603796f39c15ed5247efab90ab95c5537c76d2)) +* Fix telegram channel ([9899259](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/98992599ab8998113b6202781787a48ce0aab3db)) +* Implement README feedback ([#50](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/50)) ([5b6ba64](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/5b6ba6419a06b9abd60412fa02b09da2a416e38c)) +* Improve docs ([#100](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/100)) ([9586a25](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/9586a253f2a76993bbf82d4834b37863edabab60)) +* improve readme section and examples ([#9](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/9)) ([009db37](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/009db3719e1be03120733755ade3c1c45e13f8a5)) +* Improvements to custom scripts ([#98](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/98)) ([69047d9](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/69047d90a2fe057446f7c1b3f3526ab31bc6afcb)) +* Re-order example and fix test flag ([#52](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/52)) ([f90b6df](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/f90b6df73ef7a6040eab59d71402b34877c88fc5)) +* Readability improvements ([#109](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/109)) ([8e23389](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/8e23389ea0dcb3b221227a6cddd17de39603acbb)) +* Update project structure ([#101](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/101)) ([207edd2](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/207edd28f3fb0a805d40d6ba9109abe9e6553d23)) +* Update README and antora docs ([#57](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/57)) ([6a2299e](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/6a2299e0c41052ef9523aec1aa6f5852990e9179)) +* Update RPC documentation after client pool feature ([#96](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/96)) ([ade2811](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/ade2811431c07c6b46730cbce5e357934df14cd5)) +* Update telegram channel in docs ([#99](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/99)) ([9899259](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/98992599ab8998113b6202781787a48ce0aab3db)) +* Updated Quickstart guide ([#108](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/108)) ([b81c7cd](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/b81c7cd22143a7d2854ef496ab59e114d70c360f)) + +[Changes][v0.1.0] + + +[v1.1.0]: https://github.com/OpenZeppelin/openzeppelin-monitor/compare/v1.0.0...v1.1.0 +[v1.0.0]: https://github.com/OpenZeppelin/openzeppelin-monitor/compare/v0.2.0...v1.0.0 +[v0.2.0]: https://github.com/OpenZeppelin/openzeppelin-monitor/compare/v0.1.0...v0.2.0 +[v0.1.0]: https://github.com/OpenZeppelin/openzeppelin-monitor/tree/v0.1.0 diff --git a/content/monitor/1.1.x/contribution.mdx b/content/monitor/1.1.x/contribution.mdx new file mode 100644 index 00000000..429f5a9d --- /dev/null +++ b/content/monitor/1.1.x/contribution.mdx @@ -0,0 +1,335 @@ +--- +title: Contribution Guidelines +--- + +Welcome to the OpenZeppelin Monitor project! We appreciate your interest in contributing. This guide outlines the requirements and processes for contributing to the project. + +## Getting Started + +The OpenZeppelin Monitor project has comprehensive contribution guidelines documented in the [`CONTRIBUTING.md`](https://github.com/OpenZeppelin/openzeppelin-monitor/blob/main/CONTRIBUTING.md) file. This documentation provides a summary of key requirements, but for complete details including GitHub workflow, labeling guidelines, and advanced topics, please refer to the full CONTRIBUTING.md file. + + + +For the most up-to-date and comprehensive contribution guidelines, always refer to the [CONTRIBUTING.md](https://github.com/OpenZeppelin/openzeppelin-monitor/blob/main/CONTRIBUTING.md) file in the repository. + + +## Key Requirements + +### Contributor License Agreement (CLA) + +***You must sign the CLA before contributing.*** The CLA process is automated through GitHub workflows that check and label PRs accordingly. + +* All contributors must complete the CLA process +* The CLA bot will automatically check your PR status +* PRs cannot be merged without a signed CLA + +### Signed Commits + +***All commits must be GPG-signed*** as a security requirement. + +* Configure GPG signing for your commits +* Unsigned commits will not be accepted +* This helps ensure code integrity and authenticity + +## Development Environment Setup + +### Prerequisites + +Before contributing, ensure you have: + +* ***Rust 2021 edition*** - Required for development +* ***Git*** - For version control +* ***Python/pip*** - For pre-commit hooks + +### System Dependencies (Linux) + +For Ubuntu 22.04+ or Debian-based systems (both x86 and ARM64 architectures), install required packages: + +***Note:*** Python 3.9+ is required for pre-commit hooks compatibility. + +```bash +# Install required packages directly +sudo apt update +sudo apt install -y \ + build-essential \ + curl \ + git \ + pkg-config \ + libssl-dev \ + libffi-dev \ + libyaml-dev \ + python3 \ + python3-venv \ + python3-pip +``` + +Or use the provided system package script (automatically ensures Python 3.9+ compatibility): + +```bash +chmod +x ./scripts/linux/sys_pkgs_core.sh +chmod +x ./scripts/linux/sys_pkgs_dev.sh +# Installs required packages and ensures compatible Python version +./scripts/linux/sys_pkgs_core.sh // For runtime dependencies only +./scripts/linux/sys_pkgs_dev.sh // For Python/dev dependencies (calls core script) +``` + +### Initial Setup + +```bash +# Clone and set up the repository +git clone https://github.com/openzeppelin/openzeppelin-monitor +cd openzeppelin-monitor + +# Build the project +cargo build + +# Set up environment variables +cp .env.example .env +``` + +### Running Tests + +```bash +# All tests +RUST_TEST_THREADS=1 cargo test + +# Integration tests +RUST_TEST_THREADS=1 cargo test integration + +# Property-based tests +RUST_TEST_THREADS=1 cargo test properties +``` + +## Development Workflow + +### 1. Pre-commit Hooks + +***Required for code quality checks*** including `rustfmt`, `clippy`, and commit message validation. + +* Install and configure pre-commit hooks +* Automatic formatting and linting checks +* Commit message format validation + +#### Installing Pre-commit Hooks + +Install and configure pre-commit hooks to ensure code quality: + +```bash +# Install pre-commit (use pipx for global installation if preferred) +pip install pre-commit + +# Install and configure hooks for commit-msg, pre-commit, and pre-push +pre-commit install --install-hooks -t commit-msg -t pre-commit -t pre-push +``` + + + +If you encounter issues with pip install, you may need to install [pipx](https://github.com/pypa/pipx) for global installation. Use `pipx install pre-commit` instead. + + +The pre-commit hooks will automatically run on every commit and push, checking for: +* Code formatting with `rustfmt` +* Linting with `clippy` +* Commit message format validation +* Other code quality checks + +### 2. GitHub Workflow + +#### Fork and Clone + +1. ***Fork the repository*** on GitHub +2. ***Clone your fork*** locally: + +```bash +# Set up your working directory +export working_dir="${HOME}/repos" +export user= + +# Clone your fork +mkdir -p $working_dir +cd $working_dir +git clone https://github.com/$user/openzeppelin-monitor.git + +# Add upstream remote +cd openzeppelin-monitor +git remote add upstream https://github.com/openzeppelin/openzeppelin-monitor.git +git remote set-url --push upstream no_push +``` + +#### Branch Management + +* Create feature branches from an up-to-date main branch +* Regularly sync with upstream +* Use descriptive branch names + +```bash +# Keep main updated +git fetch upstream +git checkout main +git rebase upstream/main + +# Create feature branch +git checkout -b feature/your-feature-name + +# Keep branch updated +git fetch upstream +git rebase upstream/main +``` + + + +Use `git rebase` instead of `git pull` to avoid merge commits and maintain a clean history. + + +### 3. Pull Request Process + +#### Creating a Pull Request + +1. ***Push your changes*** to your fork: + + ```bash + git push -f origin feature/your-feature-name + ``` +2. ***Create a Pull Request*** on GitHub +3. ***Add appropriate labels*** (see Labeling Guidelines below) +4. ***Include a clear description*** of your changes + +#### Best Practices for PRs + +* Write clear and meaningful commit messages +* Include `fixes #123` in PR body (not commit messages) to auto-close issues +* Break large changes into smaller, logical commits +* Ensure all tests pass +* Include sufficient information for reviewers + +## Code Standards + +### Rust Standards + +Rust API Guidelines: + +* Format code with `rustfmt` +* Pass all `clippy` linting checks +* Follow Rust naming conventions + +```bash +# Format code +cargo fmt + +# Check linting +cargo clippy --all-targets --all-features + +# Run tests +RUST_TEST_THREADS=1 cargo test +``` + +### Testing Requirements + +***All contributions must pass existing tests*** and include new tests when applicable: + +* Write unit tests for new functionality +* Add integration tests for complex features +* Ensure all tests pass before submitting +* Maintain or improve code coverage + +For detailed testing information, see the [Testing Guide](/monitor/1.1.x/testing). + +### Commit Message Format + +***Follow conventional commit format*** with types like: + +* `feat:` - New features +* `fix:` - Bug fixes +* `docs:` - Documentation changes +* `test:` - Test additions or modifications +* `refactor:` - Code refactoring +* `chore:` - Maintenance tasks + +## Issue and Pull Request Labeling + +The project uses a structured labeling system to organize issues and PRs. Key label categories include: + +### Area Labels (`A-`) +* `A-arch` - Architectural concerns +* `A-blocks` - Block processing +* `A-clients` - Blockchain clients +* `A-configs` - Configuration issues +* `A-docs` - Documentation +* `A-tests` - Testing + +### Type Labels (`T-`) +* `T-bug` - Bug reports +* `T-feature` - New features +* `T-task` - General tasks +* `T-documentation` - Documentation updates + +### Priority Labels (`P-`) +* `P-high` - Critical tasks +* `P-medium` - Important tasks +* `P-low` - Low priority + +### Difficulty Labels (`D-`) +* `D-easy` - Beginner-friendly +* `D-medium` - Intermediate +* `D-hard` - Complex issues + + + +For complete labeling guidelines and all available labels, see the [labeling section](https://github.com/OpenZeppelin/openzeppelin-monitor/blob/main/CONTRIBUTING.md#issue-and-pull-request-labeling-guidelines) in CONTRIBUTING.md. + + +## Code Review Process + +### Review Requirements + +* All PRs require review and approval +* At least one Reviewer and one Approver must approve +* Address all review comments before merging +* Commits are automatically squashed when merging + +### Review Guidelines + +Reviewers should focus on: + +1. ***Soundness*** - Is the idea behind the contribution sound? +2. ***Architecture*** - Is the contribution architected correctly? +3. ***Polish*** - Is the contribution polished and ready? + +### Getting Reviews + +If your PR isn’t getting attention: + +* Contact the team on [Telegram](https://t.me/openzeppelin_tg/4) +* Ensure your PR has appropriate labels +* Keep PRs focused and reasonably sized + +## Security + +* Follow the [Security Policy](https://github.com/OpenZeppelin/openzeppelin-monitor/blob/main/SECURITY.md) +* Report security vulnerabilities through the proper channels +* Never commit sensitive information or credentials + +## Community Guidelines + +### Code of Conduct + +Contributors must follow the [Code of Conduct](https://github.com/OpenZeppelin/openzeppelin-monitor/blob/main/CODE_OF_CONDUCT.md), which: + +* Establishes standards for respectful collaboration +* Outlines enforcement procedures +* Promotes an inclusive environment + +## Getting Help + +### Community Support + +* ***GitHub Discussions***: For questions and community interaction +* ***Issues***: For bug reports and feature requests +* ***Telegram***: [Join our community chat](https://t.me/openzeppelin_tg/4) +* ***Good First Issues***: [Find beginner-friendly issues](https://github.com/openzeppelin/openzeppelin-monitor/issues?q=is%3Aissue+is%3Aopen+label%3Agood-first-issue) + +### Additional Resources + +* ***Full CONTRIBUTING.md***: [Complete contribution guidelines](https://github.com/OpenZeppelin/openzeppelin-monitor/blob/main/CONTRIBUTING.md) +* ***User Documentation***: [Monitor documentation](https://docs.openzeppelin.com/monitor) +* ***OpenZeppelin Website***: [Main website](https://openzeppelin.com/) diff --git a/content/monitor/1.1.x/error.mdx b/content/monitor/1.1.x/error.mdx new file mode 100644 index 00000000..0bc23a81 --- /dev/null +++ b/content/monitor/1.1.x/error.mdx @@ -0,0 +1,167 @@ +--- +title: Error Handling +--- + +## Overview + +The OpenZeppelin Monitor uses a structured error handling system that provides rich context and tracing capabilities across service boundaries. Let’s start with a real-world example of how errors flow through our system. + +## Error Flow Example + +Let’s follow how an error propagates through our blockchain monitoring system: + +**Low-level Transport (`endpoint_manager.rs`)** + +```rust +// Creates basic errors with specific context +async fn send_raw_request(...) -> Result { + let response = client.post(...) + .await + .map_err(|e| anyhow::anyhow!("Failed to send request: {}", e))?; + + if !status.is_success() { + return Err(anyhow::anyhow!("HTTP error {}: {}", status, error_body)); + } +} +``` + +**Client Layer (`evm/client.rs`)** + +```rust +// Adds business context to low-level errors +async fn get_transaction_receipt(...) -> Result { + let response = self.alloy_client + .send_raw_request(...) + .await + .with_context(|| format!("Failed to get transaction receipt: {}", tx_hash))?; + + if receipt_data.is_null() { + return Err(anyhow::anyhow!("Transaction receipt not found")); + } +} +``` + +**Filter Layer (`evm/filter.rs`)** + +```rust +// Converts to domain-specific errors +async fn filter_block(...) -> Result, FilterError> { + let receipts = match futures::future::join_all(receipt_futures).await { + Ok(receipts) => receipts, + Err(e) => { + return Err(FilterError::network_error( + format!("Failed to get transaction receipts for block {}", block_num), + Some(e.into()), + None, + )); + } + }; +} +``` + +When this error occurs, it produces the following log: + +```text +ERROR filter_block: openzeppelin_monitor::utils::error: Error occurred, + error.message: Failed to get transaction receipts for block 15092829, + error.trace_id: a464d73c-5992-4cb5-a002-c8d705bfef8d, + error.timestamp: 2025-03-14T09:42:03.412341+00:00, + error.chain: Failed to get receipt for transaction 0x7722194b65953085fe1e9ec01003f1d7bdd6258a0ea5c91a59da80419513d95d + Caused by: HTTP error 429 Too Many Requests: {"code":-32007,"message":"[Exceeded request limit per second]"} + network: ethereum_mainnet +``` + +## Error Structure + +### Error Context +Every error in our system includes detailed context information: + +```rust +pub struct ErrorContext { + /// The error message + pub message: String, + /// The source error (if any) + pub source: Option>, + /// Unique trace ID for error tracking + pub trace_id: String, + /// Timestamp when the error occurred + pub timestamp: DateTime, + /// Optional key-value metadata + pub metadata: HashMap, +} +``` + +### Domain-Specific Error Types + +| Module | Error Type | Description | +| --- | --- | --- | +| `**Configuration**` | `ConfigError` | * `ValidationError` - Configuration validation failures * `ParseError` - Configuration parsing issues * `FileError` - File system related errors * `Other` - Unclassified errors | +| `**Security**` | `SecurityError` | * `ValidationError` - Security validation failures * `ParseError` - Security data parsing issues * `NetworkError` - Security service connectivity issues * `Other` - Unclassified security-related errors | +| `**Blockchain Service**` | `BlockChainError` | * `ConnectionError` - Network connectivity issues * `RequestError` - Malformed requests or invalid responses * `BlockNotFound` - Requested block not found * `TransactionError` - Transaction processing failures * `InternalError` - Internal client errors * `ClientPoolError` - Client pool related issues * `Other` - Unclassified errors | +| `**Block Watcher Service**` | `BlockWatcherError` | * `SchedulerError` - Block watching scheduling issues * `NetworkError` - Network connectivity problems * `ProcessingError` - Block processing failures * `StorageError` - Storage operation failures * `BlockTrackerError` - Block tracking issues * `Other` - Unclassified errors | +| `**Filter Service**` | `FilterError` | * `BlockTypeMismatch` - Block type validation failures * `NetworkError` - Network connectivity issues * `InternalError` - Internal processing errors * `Other` - Unclassified errors | +| `**Notification Service**` | `NotificationError` | * `NetworkError` - Network connectivity issues * `ConfigError` - Configuration problems * `InternalError` - Internal processing errors * `ExecutionError` - Script execution failures * `Other` - Unclassified errors | +| `**Repository**` | `RepositoryError` | * `ValidationError` - Data validation failures * `LoadError` - Data loading issues * `InternalError` - Internal processing errors * `Other` - Unclassified errors | +| `**Script Utils**` | `ScriptError` | * `NotFound` - Resource not found errors * `ExecutionError` - Script execution failures * `ParseError` - Script parsing issues * `SystemError` - System-level errors * `Other` - Unclassified errors | +| `**Trigger Service**` | `TriggerError` | * `NotFound` - Resource not found errors * `ExecutionError` - Trigger execution failures * `ConfigurationError` - Trigger configuration issues * `Other` - Unclassified errors | +| `**Monitor Executor**` | `MonitorExecutionError` | * `NotFound` - Resource not found errors * `ExecutionError` - Monitor execution failures * `Other` - Unclassified errors | + +## Error Handling Guidelines + +### When to Use Each Pattern + +| Scenario | Approach | +| --- | --- | +| Crossing Domain Boundaries | Convert to domain-specific error type using custom error constructors | +| Within Same Domain | Use `.with_context()` to add information while maintaining error type | +| External API Boundaries | Always convert to your domain’s error type to avoid leaking implementation details | + +### Error Creation Examples + +**Creating a Configuration Error without a source** + +```rust +let error = ConfigError::validation_error( + "Invalid network configuration", + None, + Some(HashMap::from([ + ("network", "ethereum"), + ("field", "rpc_url") + ])) +); +``` + +**Creating a Configuration Error with a source** + +```rust + +let io_error = std::io::Error::new(std::io::ErrorKind::Other, "Failed to read file"); + +let error = ConfigError::validation_error( + "Invalid network configuration", + Some(io_error.into()), + None +); +``` + +### Tracing with #[instrument] + +```rust +#[instrument(skip_all, fields(network = %_network.slug))] +async fn filter_block( + &self, + client: &T, + _network: &Network, + block: &BlockType, + monitors: &[Monitor], +) -> Result, FilterError> { + tracing::debug!("Processing block {}", block_number); + // ... +} +``` + +Key aspects: + +1. `skip_all` - Skips automatic instrumentation of function parameters for performance +2. `fields(...)` - Adds specific fields we want to track (like network slug) +3. `tracing::debug!` - Adds debug-level spans for important operations diff --git a/content/monitor/1.1.x/index.mdx b/content/monitor/1.1.x/index.mdx new file mode 100644 index 00000000..3709460d --- /dev/null +++ b/content/monitor/1.1.x/index.mdx @@ -0,0 +1,1533 @@ +--- +title: OpenZeppelin Monitor +--- + +## Overview + +In the rapidly evolving world of blockchain technology, effective monitoring is crucial for ensuring security and performance. OpenZeppelin Monitor is a blockchain monitoring service that watches for specific on-chain activities and triggers notifications based on configurable conditions. The service offers multi-chain support with configurable monitoring schedules, flexible trigger conditions, and an extensible architecture for adding new chains. + +### Key Capabilities + +* ***Real-time Monitoring***: Watch blockchain networks in real-time for specific events and transactions +* ***Smart Filtering***: Use flexible expressions to define exactly what you want to monitor +* ***Multi-notification Support***: Send alerts via Slack, Discord, Email, Telegram, Webhooks, or custom scripts +* ***Configurable Scheduling***: Set custom monitoring schedules using cron expressions +* ***Data Persistence***: Store monitoring data and resume from checkpoints +* ***Extensible Architecture***: Easy to add support for new blockchains and notification types + +### Supported Networks + +* ***EVM-Compatible Networks*** +* ***Stellar*** + +### Notification Channels + +* ***Slack*** - Send formatted messages to Slack channels +* ***Discord*** - Post alerts to Discord channels via webhooks +* ***Email*** - Send email notifications with SMTP support +* ***Telegram*** - Send messages to Telegram chats via bot API +* ***Webhooks*** - Send HTTP requests to custom endpoints +* ***Custom Scripts*** - Execute Python, JavaScript, or Bash scripts + + + + +To get started immediately, see [Quickstart](/monitor/1.1.x/quickstart). + + + +## Installation + +### Prerequisites + +* Use ***Rust 2021 edition***, version `1.86` or later. +* ***Docker*** (optional, for containerized deployment) + +#### System Dependencies (Linux) + +For Ubuntu 22.04+ or Debian-based systems (both x86 and ARM64 architectures), install required packages: + +***Note:*** Python 3.9+ is required for pre-commit hooks compatibility. + +```bash +# Install required packages directly +sudo apt update +sudo apt install -y \ + build-essential \ + curl \ + git \ + pkg-config \ + libssl-dev \ + libffi-dev \ + libyaml-dev \ + python3 \ + python3-venv \ + python3-pip +``` + +Or use the provided system package script (automatically ensures Python 3.9+ compatibility): + +```bash +chmod +x ./scripts/linux/sys_pkgs_core.sh +chmod +x ./scripts/linux/sys_pkgs_dev.sh +# Installs required packages and ensures compatible Python version +./scripts/linux/sys_pkgs_core.sh // For runtime dependencies only +./scripts/linux/sys_pkgs_dev.sh // For Python/dev dependencies (calls core script) +``` + +### Local Installation + +1. ***Clone the repository:*** + + ```bash + git clone https://github.com/openzeppelin/openzeppelin-monitor + cd openzeppelin-monitor + ``` +2. ***Build the application:*** + + ```bash + cargo build --release + ``` +3. ***Move binary to project root:*** + + ```bash + mv ./target/release/openzeppelin-monitor . + ``` +4. ***Verify installation:*** + + ```bash + ./openzeppelin-monitor --help + ``` +5. ***View available options:*** + + ```bash + ./openzeppelin-monitor --help + + # Enable logging to file + ./openzeppelin-monitor --log-file + + # Enable metrics server + ./openzeppelin-monitor --metrics + + # Validate configuration files without starting the service + ./openzeppelin-monitor --check + ``` + +### Docker Installation + +1. ***Clone the repository:*** + + ```bash + git clone https://github.com/openzeppelin/openzeppelin-monitor + cd openzeppelin-monitor + ``` +2. ***Set up environment:*** + + ```bash + cp .env.example .env + # Edit .env file with your configuration + ``` +3. ***Start with Docker Compose:*** + + ```bash + cargo make docker-compose-up + ``` + +#### Metrics Configuration + +The metrics server, Prometheus, and Grafana can be enabled by setting `METRICS_ENABLED=true` in your `.env` file. + +You can start services directly with Docker Compose: + +```bash +# without metrics profile ( METRICS_ENABLED=false by default ) +docker compose up -d + +# With metrics enabled +docker compose --profile metrics up -d +``` + +To view prometheus metrics in a UI, you can use `http://localhost:9090` on your browser. + +To view grafana dashboard, you can use `http://localhost:3000` on your browser. + +By default, predefined metrics within a dashboard is populated in grafana. + +### Configuration Guidelines + +#### Recommended File Naming Conventions + +* Network configurations: `_.json` + * Example: `ethereum_mainnet.json`, `stellar_testnet.json` + * Should match the `slug` property inside the file +* Monitor configurations: `__monitor.json` + * Example: `usdc_transfer_monitor.json`, `dai_liquidation_monitor.json` + * Referenced by monitors using their `name` property +* Trigger configurations: `_.json` + * Example: `slack_notifications.json`, `email_alerts.json` + * Individual triggers referenced by their configuration key + +#### Configuration References + +* Monitor, network, and trigger names ***must be unique*** across all configurations files +* Monitor’s `networks` array must contain valid network `slug` values from network configuration files +* Monitor’s `triggers` array must contain valid trigger configuration keys +* Example valid references: + + ```json + // networks/ethereum_mainnet.json + { + "slug": "ethereum_mainnet", + ... + } + + // triggers/slack_notifications.json + { + "large_transfer_slack": { + ... + } + } + + // monitors/usdc_transfer_monitor.json + { + "networks": ["ethereum_mainnet"], + "triggers": ["large_transfer_slack"], + ... + } + + ``` + + + + +Ensure all referenced slugs and trigger keys exist in their respective configuration files. The monitor will fail to start if it cannot resolve these references. + + + +#### Safe Protocol Guidelines + +The monitor implements protocol security validations across different components and will issue warnings when potentially insecure configurations are detected. While insecure protocols are not blocked, we strongly recommend following these security guidelines: + +##### Network Protocols + +###### RPC URLs +* **HTTPS Recommended**: Using `https://` for RPC endpoints is strongly recommended +* **WSS Recommended**: For WebSocket connections, `wss://` (secure WebSocket) is strongly recommended +* **Warning**: Using `http://` or `ws://` will trigger security warnings as they transmit data unencrypted + +##### Notification Protocols + +###### Webhook Notifications +* **HTTPS Recommended**: URLs should use HTTPS protocol +* **Authentication Recommended**: Including either: + * `X-API-Key` header + * `Authorization` header +* **Optional Secret**: Can include a secret for HMAC authentication + * When a secret is provided, the monitor will: + * Generate a timestamp in milliseconds + * Create an HMAC-SHA256 signature of the payload and timestamp + * Add the signature in the `X-Signature` header + * Add the timestamp in the `X-Timestamp` header + * The signature is computed as: `HMAC-SHA256(secret, payload + timestamp)` +* **Warning**: Non-HTTPS URLs or missing authentication headers will trigger security warnings + +###### Slack Notifications +* **HTTPS Recommended**: Webhook URLs should start with `https://hooks.slack.com/` +* **Warning**: Non-HTTPS URLs will trigger security warnings + +###### Discord Notifications +* **HTTPS Recommended**: Webhook URLs should start with `https://discord.com/api/webhooks/` +* **Warning**: Non-HTTPS URLs will trigger security warnings + +###### Telegram Notifications +* ***Protocol:*** `POST` request with a `application/json` payload to the `sendMessage` method. +* ***Endpoint:*** `https://api.telegram.org/bot/sendMessage` +* ***Security:*** + * ***HTTPS Required:*** The API endpoint uses HTTPS. + * Authentication is handled via the ***Bot Token*** in the URL. Keep this token secure. +* ***Formatting:*** Messages are sent with `parse_mode` set to `MarkdownV2`. Special characters in the message title and body are automatically escaped to prevent formatting errors. + +###### Email Notifications +* **Secure Ports Recommended**: The following ports are considered secure: + * 465: SMTPS (SMTP over SSL) + * 587: SMTP with STARTTLS + * 993: IMAPS (IMAP over SSL) +* **Warning**: Using other ports will trigger security warnings +* **Valid Format**: Email addresses must follow RFC 5322 format + +###### Notifications Retry Policy + +Following notification protocols support retry policies: + +* Slack +* Discord +* Telegram +* Webhook +* Email + +Default retry policy is using exponential backoff with the following parameters: +| | | | +| --- | --- | --- | +| Parameter | Default Value | Description | +| `max_retries` | `3` | Maximum number of retries before giving up | +| `base_for_backoff` | `2` | Base duration for exponential backoff calculations in seconds | +| `initial_backoff` | `250` | Initial backoff duration in milliseconds | +| `max_backoff` | `10` | Maximum backoff duration in seconds | +| `jitter` | `Full` | Jitter strategy to apply to the backoff duration, currently supports `Full` and `None` | + +These parameters can be overridden by providing custom `RetryConfig` struct in `retry_policy` field in trigger configuration. + +##### Script Security + +###### File Permissions (Unix Systems) +* **Restricted Write Access**: Script files should not have overly permissive write permissions +* **Recommended Permissions**: Use `644` (`rw-r--r--`) for script files +* **Warning**: Files with mode `022` or more permissive will trigger security warnings + +**Example Setting Recommended Permissions** + +```bash +chmod 644 ./config/filters/my_script.sh +``` + +#### Secret Management + +The monitor implements a secure secret management system with support for multiple secret sources and automatic memory zeroization. + +##### Secret Sources + +The monitor supports three types of secret sources: + +* **Plain Text**: Direct secret values (wrapped in `SecretString` for secure memory handling) +* **Environment Variables**: Secrets stored in environment variables +* **Hashicorp Cloud Vault**: Secrets stored in Hashicorp Cloud Vault + +##### Security Features + +* **Automatic Zeroization**: Secrets are automatically zeroized from memory when no longer needed +* **Type-Safe Resolution**: Secure handling of secret resolution with proper error handling +* **Configuration Support**: Serde support for configuration files + +##### Configuration + +Secrets can be configured in the JSON files using the following format: + +```json +{ + "type": "Plain", + "value": "my-secret-value" +} +``` + +```json +{ + "type": "Environment", + "value": "MY_SECRET_ENV_VAR" +} +``` + +```json +{ + "type": "HashicorpCloudVault", + "value": "my-secret-name" +} +``` + +##### Hashicorp Cloud Vault Integration + +To use Hashicorp Cloud Vault, configure the following environment variables: + +| Environment Variable | Description | +| --- | --- | +| `HCP_CLIENT_ID` | Hashicorp Cloud Vault client ID | +| `HCP_CLIENT_SECRET` | Hashicorp Cloud Vault client secret | +| `HCP_ORG_ID` | Hashicorp Cloud Vault organization ID | +| `HCP_PROJECT_ID` | Hashicorp Cloud Vault project ID | +| `HCP_APP_NAME` | Hashicorp Cloud Vault application name | + +##### Best Practices + +* Use environment variables or vault for production secrets +* Avoid storing plain text secrets in configuration files +* Use appropriate access controls for vault secrets +* Monitor vault access patterns for suspicious activity + +#### Basic Configuration + +* Set up environment variables: + +Copy the example environment file and update values according to your needs + +```bash +cp .env.example .env +``` + +This table lists the environment variables and their default values. + +| Environment Variable | Default Value | Accepted Values | Description | +| --- | --- | --- | --- | +| `RUST_LOG` | `info` | `info, debug, warn, error, trace` | Log level. | +| `LOG_MODE` | `stdout` | `stdout, file` | Write logs either to console or to file. | +| `LOG_DATA_DIR` | `logs/` | `` | Directory to write log files on host. | +| `MONITOR_DATA_DIR` | `null` | `` | Persist monitor data between container restarts. | +| `LOG_MAX_SIZE` | `1073741824` | `` | Size after which logs needs to be rolled. Accepts both raw bytes (e.g., "1073741824") or human-readable formats (e.g., "1GB", "500MB"). | +| `METRICS_ENABLED` | `false` | `true`, `false` | Enable metrics server for external tools to scrape metrics. | +| `METRICS_PORT` | `8081` | `` | Port to use for metrics server. | +| `HCP_CLIENT_ID` | - | `` | Hashicorp Cloud Vault client ID for secret management. | +| `HCP_CLIENT_SECRET` | - | `` | Hashicorp Cloud Vault client secret for secret management. | +| `HCP_ORG_ID` | - | `` | Hashicorp Cloud Vault organization ID for secret management. | +| `HCP_PROJECT_ID` | - | `` | Hashicorp Cloud Vault project ID for secret management. | +| `HCP_APP_NAME` | - | `` | Hashicorp Cloud Vault application name for secret management. | +* Copy and configure some example files: + +```bash +# EVM Configuration +cp examples/config/monitors/evm_transfer_usdc.json config/monitors/evm_transfer_usdc.json +cp examples/config/networks/ethereum_mainnet.json config/networks/ethereum_mainnet.json + +# Stellar Configuration +cp examples/config/monitors/stellar_swap_dex.json config/monitors/stellar_swap_dex.json +cp examples/config/networks/stellar_mainnet.json config/networks/stellar_mainnet.json + +# Notification Configuration +cp examples/config/triggers/slack_notifications.json config/triggers/slack_notifications.json +cp examples/config/triggers/email_notifications.json config/triggers/email_notifications.json + +# Filter Configuration +cp examples/config/filters/evm_filter_block_number.sh config/filters/evm_filter_block_number.sh +cp examples/config/filters/stellar_filter_block_number.sh config/filters/stellar_filter_block_number.sh +``` +### Command Line Options + +The monitor supports several command-line options for configuration and control: + +| **Option** | **Default** | **Description** | +| --- | --- | --- | +| `**--log-file**` | `false` | Write logs to file instead of stdout | +| `**--log-level**` | `info` | Set log level (trace, debug, info, warn, error) | +| `**--log-path**` | `logs/` | Path to store log files | +| `**--log-max-size**` | `1GB` | Maximum log file size before rolling | +| `**--metrics-address**` | `127.0.0.1:8081` | Address to start the metrics server on | +| `**--metrics**` | `false` | Enable metrics server | +| `**--monitor-path**` | - | Path to the monitor to execute (for testing) | +| `**--network**` | - | Network to execute the monitor for (for testing) | +| `**--block**` | - | Block number to execute the monitor for (for testing) | +| `**--check**` | `false` | Validate configuration files without starting the service | + +## Data Storage Configuration + +The monitor uses file-based storage by default. + +### File Storage + +When `store_blocks` is enabled in the network configuration, the monitor stores: + +* Processed blocks: `./data/_blocks_.json` +* Missed blocks: `./data/_missed_blocks.txt` (used to store missed blocks) + +The content of the `missed_blocks.txt` file may help to determine the right `max_past_blocks` value based on the network’s block time and the monitor’s cron schedule. + +Additionally, the monitor will always store: + +* Last processed block: `./data/_last_block.txt` (enables resuming from last checkpoint) + +## Configuration Files + +### Network Configuration + +A Network configuration defines connection details and operational parameters for a specific blockchain network, supporting both EVM and Stellar-based chains. + +**Example Network Configuration** + +```json +{ + "network_type": "Stellar", + "slug": "stellar_mainnet", + "name": "Stellar Mainnet", + "rpc_urls": [ + { + "type_": "rpc", + "url": { + "type": "plain", + "value": "https://soroban.stellar.org" + }, + "weight": 100 + } + ], + "network_passphrase": "Public Global Stellar Network ; September 2015", + "block_time_ms": 5000, + "confirmation_blocks": 2, + "cron_schedule": "0 */1 * * * *", + "max_past_blocks": 20, + "store_blocks": true +} +``` + +#### Available Fields + +| **Field** | **Type** | **Description** | +| --- | --- | --- | +| `**network_type**` | `String` | Type of blockchain (**"EVM"** or **"Stellar"**) | +| `**slug**` | `String` | **Required** - **_Unique_** identifier for the network | +| `**name**` | `String` | **Required** - **_Unique_** Human-readable network name | +| `**rpc_urls**` | `Array[Object]` | List of RPC endpoints with weights for load balancing | +| `**chain_id**` | `Number` | Network chain ID (**EVM only**) | +| `**network_passphrase**` | `String` | Network identifier (**Stellar only**) | +| `**block_time_ms**` | `Number` | Average block time in milliseconds | +| `**confirmation_blocks**` | `Number` | Number of blocks to wait for confirmation | +| `**cron_schedule**` | `String` | Monitor scheduling in cron format | +| `**max_past_blocks**` | `Number` | Maximum number of past blocks to process | +| `**store_blocks**` | `Boolean` | Whether to store processed blocks (defaults output to `./data/` directory) | + +#### Important Considerations + +* We strongly recommend using private RPC providers for improved reliability. + +### Trigger Configuration + +A Trigger defines actions to take when monitored conditions are met. Triggers can send notifications, make HTTP requests, or execute scripts. + +**Example Trigger Configuration** + +```json +{ + "evm_large_transfer_usdc_slack": { + "name": "Large Transfer Slack Notification", + "trigger_type": "slack", + "config": { + "slack_url": { + "type": "plain", + "value": "https://hooks.slack.com/services/A/B/C" + }, + "message": { + "title": "${monitor.name} triggered", + "body": "Large transfer of ${events.0.args.value} USDC from ${events.0.args.from} to ${events.0.args.to} | https://etherscan.io/tx/${transaction.hash}#eventlog" + } + } + }, + "stellar_large_transfer_usdc_slack": { + "name": "Large Transfer Slack Notification", + "trigger_type": "slack", + "config": { + "slack_url": { + "type": "environment", + "value": "SLACK_WEBHOOK_URL" + }, + "message": { + "title": "large_transfer_usdc_slack triggered", + "body": "${monitor.name} triggered because of a large transfer of ${functions.0.args.amount} USDC to ${functions.0.args.to} | https://stellar.expert/explorer/testnet/tx/${transaction.hash}" + } + } + } +} +``` + +#### Trigger Types + +##### Slack Notifications +```json +{ + "slack_url": { + "type": "HashicorpCloudVault", + "value": "slack-webhook-url" + }, + "message": { + "title": "Alert Title", + "body": "Alert message for ${transaction.hash}" + } +} +``` + +##### Slack Notification Fields +| **Field** | **Type** | **Description** | +| --- | --- | --- | +| `**name**` | `String` | **Required** - **_Unique_** Human-readable name for the notification | +| `**trigger_type**` | `String` | Must be **"slack"** for Slack notifications | +| `**config.slack_url.type**` | `String` | Secret type (**"Plain"**, **"Environment"**, or **"HashicorpCloudVault"**) | +| `**config.slack_url.value**` | `String` | Secret value (URL, environment variable name, or vault secret name) | +| `**config.message.title**` | `String` | Title that appears in the Slack message | +| `**config.message.body**` | `String` | Message template with variable substitution | + +##### Email Notifications +```json +{ + "host": "smtp.gmail.com", + "port": 465, + "username": { + "type": "plain", + "value": "sender@example.com" + }, + "password": { + "type": "environment", + "value": "SMTP_PASSWORD" + }, + "message": { + "title": "Alert Subject", + "body": "Alert message for ${transaction.hash}", + }, + "sender": "sender@example.com", + "recipients": ["recipient@example.com"] +} +``` + +##### Email Notification Fields +| **Field** | **Type** | **Description** | +| --- | --- | --- | +| `**name**` | `String` | **Required** - **_Unique_** Human-readable name for the notification | +| `**trigger_type**` | `String` | Must be **"email"** for email notifications | +| `**config.host**` | `String` | SMTP server hostname | +| `**config.port**` | `Number` | SMTP port (defaults to **465**) | +| `**config.username.type**` | `String` | Secret type (**"Plain"**, **"Environment"**, or **"HashicorpCloudVault"**) | +| `**config.username.value**` | `String` | Secret value (username, environment variable name, or vault secret name) | +| `**config.password.type**` | `String` | Secret type (**"Plain"**, **"Environment"**, or **"HashicorpCloudVault"**) | +| `**config.password.value**` | `String` | Secret value (password, environment variable name, or vault secret name) | +| `**config.message.title**` | `String` | Email subject line | +| `**config.message.body**` | `String` | Email body template with variable substitution | +| `**config.sender**` | `String` | Sender email address | +| `**config.recipients**` | `Array[String]` | List of recipient email addresses | + +##### Webhook Notifications +```json +{ + "url": { + "type": "HashicorpCloudVault", + "value": "webhook-url" + }, + "method": "POST", + "secret": { + "type": "environment", + "value": "WEBHOOK_SECRET" + }, + "headers": { + "Content-Type": "application/json" + }, + "message": { + "title": "Alert Title", + "body": "Alert message for ${transaction.hash}" + } +} +``` + +##### Webhook Notification Fields +| **Field** | **Type** | **Description** | +| --- | --- | --- | +| `**name**` | `String` | **Required** - **_Unique_** Human-readable name for the notification | +| `**trigger_type**` | `String` | Must be **"webhook"** for webhook notifications | +| `**config.url.type**` | `String` | Secret type (**"Plain"**, **"Environment"**, or **"HashicorpCloudVault"**) | +| `**config.url.value**` | `String` | Secret value (URL, environment variable name, or vault secret name) | +| `**config.method**` | `String` | HTTP method (POST, GET, etc.) defaults to POST | +| `**config.secret.type**` | `String` | Secret type (**"Plain"**, **"Environment"**, or **"HashicorpCloudVault"**) | +| `**config.secret.value**` | `String` | Secret value (HMAC secret, environment variable name, or vault secret name) | +| `**config.headers**` | `Object` | Headers to include in the webhook request | +| `**config.message.title**` | `String` | Title that appears in the webhook message | +| `**config.message.body**` | `String` | Message template with variable substitution | + +##### Discord Notifications +```json +{ + "discord_url": { + "type": "plain", + "value": "https://discord.com/api/webhooks/123-456-789" + }, + "message": { + "title": "Alert Title", + "body": "Alert message for ${transaction.hash}" + } +} +``` + +##### Discord Notification Fields +| **Field** | **Type** | **Description** | +| --- | --- | --- | +| `**name**` | `String` | **Required** - **_Unique_** Human-readable name for the notification | +| `**trigger_type**` | `String` | Must be **"discord"** for Discord notifications | +| `**config.discord_url.type**` | `String` | Secret type (**"Plain"**, **"Environment"**, or **"HashicorpCloudVault"**) | +| `**config.discord_url.value**` | `String` | Secret value (URL, environment variable name, or vault secret name) | +| `**config.message.title**` | `String` | Title that appears in the Discord message | +| `**config.message.body**` | `String` | Message template with variable substitution | + +##### Telegram Notifications +```json +{ + "token": { + "type": "HashicorpCloudVault", + "value": "telegram-bot-token" + }, + "chat_id": "9876543210", + "message": { + "title": "Alert Title", + "body": "Alert message for ${transaction.hash}" + } +} +``` + +##### Telegram Notification Fields +| **Field** | **Type** | **Description** | +| --- | --- | --- | +| `**name**` | `String` | **Required** - **_Unique_** Human-readable name for the notification | +| `**trigger_type**` | `String` | Must be **"telegram"** for Telegram notifications | +| `**config.token.type**` | `String` | Secret type (**"Plain"**, **"Environment"**, or **"HashicorpCloudVault"**) | +| `**config.token.value**` | `String` | Secret value (bot token, environment variable name, or vault secret name) | +| `**config.chat_id**` | `String` | Telegram chat ID | +| `**config.disable_web_preview**` | `Boolean` | Whether to disable web preview in Telegram messages (defaults to false) | +| `**config.message.title**` | `String` | Title that appears in the Telegram message | +| `**config.message.body**` | `String` | Message template with variable substitution | + +##### Custom Script Notifications +```json +{ + "language": "Bash", + "script_path": "./config/triggers/scripts/custom_notification.sh", + "arguments": ["--verbose"], + "timeout_ms": 1000 +} +``` + +##### Script Notification Fields +| **Field** | **Type** | **Description** | +| --- | --- | --- | +| `**name**` | `String` | **Required** - **_Unique_** Human-readable name for the notification | +| `**trigger_type**` | `String` | Must be **"script"** for Custom Script notifications | +| `**language**` | `String` | The language of the script | +| `**script_path**` | `String` | The path to the script | +| `**arguments**` | `Array[String]` | The arguments of the script (optional). | +| `**timeout_ms**` | `Number` | The timeout of the script is important to avoid infinite loops during the execution. If the script takes longer than the timeout, it will be killed. | + +For more information about custom scripts, see [Custom Scripts Section](/monitor/1.1.x/scripts). + + + +***Security Risk***: Only run scripts that you trust and fully understand. Malicious scripts can harm your system or expose sensitive data. Always review script contents and verify their source before execution. + + +#### Available Template Variables + +The monitor uses a structured JSON format with nested objects for template variables. The data is flattened into dot notation for template use. + +##### Common Variables +| **Variable** | **Description** | +| --- | --- | +| `**monitor.name**` | Name of the triggered monitor | +| `**transaction.hash**` | Hash of the transaction | +| `**functions**` | All functions matched and their parameters | +| `**events**` | All events matched and their parameters | + +##### Network-Specific Variables + +###### EVM Variables +| **Variable** | **Description** | +| --- | --- | +| `**transaction.from**` | Sender address | +| `**transaction.to**` | Recipient address | +| `**transaction.value**` | Transaction value | +| `**events.[index].signature**` | Event signature | +| `**events.[index].args.[param]**` | Event parameters by name | +| `**functions.[index].signature**` | Function signature | +| `**functions.[index].args.[param]**` | Function parameters by name | + +###### Stellar Variables +| **Variable** | **Description** | +| --- | --- | +| `**events.[index].args.[position]**` | Event parameters by position | +| `**events.[index].args.[param]**` | Event parameters by name (only in case the contract supports event parameters name) | +| `**functions.[index].args.[param]**` | Function parameters by name | + + + + +Transaction-related variables (`transaction.from`, `transaction.to`, `transaction.value`) are not available for Stellar networks. + + + +#### Message Formatting + +Slack, Discord, Telegram, Email and Webhook support Markdown formatting in their message bodies. You can use Markdown syntax to enhance your notifications. + +##### Example Email Notification with Markdown +```json +{ + "email_notification": { + "name": "Formatted Alert", + "trigger_type": "email", + "config": { + "host": "smtp.example.com", + "port": 465, + "username": {"type": "plain", "value": "alerts@example.com"}, + "password": {"type": "plain", "value": "password"}, + "message": { + "title": "**High Value Transfer Alert**", + "body": "### Transaction Details\n\n* **Amount:** ${events.0.args.value} USDC\n* **From:** `${events.0.args.from}`\n* **To:** `${events.0.args.to}`\n\n> Transaction Hash: ${transaction.hash}\n\n[View on Explorer](https://etherscan.io/tx/${transaction.hash})" + }, + "sender": "alerts@example.com", + "recipients": ["recipient@example.com"] + } + } +} +``` + +##### Example Slack Notification with Markdown +```json +{ + "slack_notification": { + "name": "Formatted Alert", + "trigger_type": "slack", + "config": { + "slack_url": {"type": "plain", "value": "https://hooks.slack.com/services/XXX/YYY/ZZZ"}, + "message": { + "title": "*🚨 High Value Transfer Alert*", + "body": "*Transaction Details*\n\nβ€’ *Amount:* `${events.0.args.value}` USDC\nβ€’ *From:* `${events.0.args.from}`\nβ€’ *To:* `${events.0.args.to}`\n\n>Transaction Hash: `${transaction.hash}`\n\n" + } + } + } +} +``` + +##### Example Discord Notification with Markdown +```json +{ + "discord_notification": { + "name": "Formatted Alert", + "trigger_type": "discord", + "config": { + "discord_url": {"type": "plain", "value": "https://discord.com/api/webhooks/XXX/YYY"}, + "message": { + "title": "**🚨 High Value Transfer Alert**", + "body": "# Transaction Details\n\n* **Amount:** `${events.0.args.value}` USDC\n* **From:** `${events.0.args.from}`\n* **To:** `${events.0.args.to}`\n\n>>> Transaction Hash: `${transaction.hash}`\n\n**[View on Explorer](https://etherscan.io/tx/${transaction.hash})" + } + } + } +} +``` + +##### Example Telegram Notification with Markdown +```json +{ + "telegram_notification": { + "name": "Formatted Alert", + "trigger_type": "telegram", + "config": { + "token": {"type": "plain", "value": "1234567890:ABCDEFGHIJKLMNOPQRSTUVWXYZ"}, + "chat_id": "9876543210", + "message": { + "title": "*🚨 High Value Transfer Alert*", + "body": "*Transaction Details*\n\nβ€’ *Amount:* `${events.0.args.value}` USDC\nβ€’ *From:* `${events.0.args.from}`\nβ€’ *To:* `${events.0.args.to}`\n\n`Transaction Hash: ${transaction.hash}`\n\n[View on Explorer](https://etherscan.io/tx/${transaction.hash})" + } + } + } +} +``` + +#### Important Considerations + +* Email notification port defaults to 465 if not specified. +* Template variables are context-dependent: + * Event-triggered notifications only populate event variables. + * Function-triggered notifications only populate function variables. + * Mixing contexts results in empty values. +* Credentials in configuration files should be properly secured. +* Consider using environment variables for sensitive information. + +### Monitor Configuration + +A Monitor defines what blockchain activity to watch and what actions to take when conditions are met. Each monitor combines: + +* Network targets (which chains to monitor) +* Contract addresses to watch +* Conditions to match (functions, events, transactions) +* Trigger conditions (custom scripts that act as filters for each monitor match to determine whether a trigger should be activated). +* Triggers to execute when conditions are met + +**Example Monitor Configuration** + +```json +{ + "name": "Large USDC Transfers", + "networks": ["ethereum_mainnet"], + "paused": false, + "addresses": [ + { + "address": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", + "contract_spec": [ ... ] + } + ], + "match_conditions": { + "functions": [ + { + "signature": "transfer(address,uint256)", + "expression": "value > 1000000" + } + ], + "events": [ + { + "signature": "Transfer(address,address,uint256)", + "expression": "value > 1000000" + } + ], + "transactions": [ + { + "status": "Success", + "expression": "value > 1500000000000000000" + } + ] + }, + "trigger_conditions": [ + { + "script_path": "./config/filters/evm_filter_block_number.sh", + "language": "bash", + "arguments": "--verbose", + "timeout_ms": 1000 + } + ], + "triggers": ["evm_large_transfer_usdc_slack", "evm_large_transfer_usdc_email"] +} +``` + +#### Available Fields + +| **Field** | **Type** | **Description** | +| --- | --- | --- | +| `**name**` | `String` | **Required** - **_Unique_** identifier for this monitor | +| `**networks**` | `Array[String]` | List of network slugs this monitor should watch | +| `**paused**` | `Boolean` | Whether this monitor is currently paused | +| `**addresses**` | `Array[Object]` | Contract addresses to monitor with optional ABIs | +| `**match_conditions**` | `Object` | Collection of conditions that can trigger the monitor | +| `**trigger_conditions**` | `Array[Object]` | Collection of filters to apply to monitor matches before executing triggers | +| `**triggers**` | `Array[String]` | IDs of triggers to execute when conditions match | + +#### Match Conditions + +Monitors support three types of match conditions that can be combined: + +##### Function Conditions +Match specific function calls to monitored contracts: + +```json +{ + "functions": [ + { + "signature": "transfer(address,uint256)", + "expression": "value > 1000" + } + ] +} +``` + +##### Event Conditions +Match events emitted by monitored contracts: + +```json +{ + "events": [ + { + "signature": "Transfer(address,address,uint256)", + "expression": "value > 1000000" + } + ] +} +``` + +##### Transaction Conditions +Match transaction properties. The available fields and expression syntax depend on the network type (EVM/Stellar) + +```json +{ + "transactions": [ + { + "status": "Success", // Only match successful transactions + "expression": "value > 1500000000000000000" // Match transactions with value greater than 1.5 ETH + } + ] +} +``` + +#### Available Transaction Fields (EVM) +| **Field** | **Type** | **Description** | +| --- | --- | --- | +| `**value**` | `uint256` | Transaction value in wei | +| `**from**` | `address` | Sender address (case-insensitive comparison) | +| `**to**` | `address` | Recipient address (case-insensitive comparison) | +| `**hash**` | `string` | Transaction hash | +| `**gas_price**` | `uint256` | Gas price in wei (legacy transactions) | +| `**max_fee_per_gas**` | `uint256` | EIP-1559 maximum fee per gas | +| `**max_priority_fee_per_gas**` | `uint256` | EIP-1559 priority fee | +| `**gas_limit**` | `uint256` | Gas limit for transaction | +| `**nonce**` | `uint256` | Sender nonce | +| `**input**` | `string` | Hex-encoded input data (e.g., **"0xa9059cbb..."**) | +| `**gas_used**` | `uint256` | Actual gas used (from receipt) | +| `**transaction_index**` | `uint64` | Position in block | + +#### Available Transaction Fields (Stellar) +| **Field** | **Type** | **Description** | +| --- | --- | --- | +| `**hash**` | `string` | Transaction hash | +| `**ledger**` | `i64` | Ledger sequence number where the transaction was included | +| `**value**` | `i64` | Value associated with the **first** relevant operation (e.g., payment amount). Defaults to 0 if no relevant operation or value is found. | +| `**from**` | `address` | Source account address of the **first** relevant operation (e.g., payment sender). Case-insensitive comparison. | +| `**to**` | `address` | Destination account address of the **first** relevant operation (e.g., payment recipient or invoked contract). Case-insensitive comparison. | + +#### Matching Rules + +* If no conditions are specified, all transactions match +* For multiple condition types: + * Transaction conditions are checked first + * Then either function OR event conditions must match + * Both transaction AND (function OR event) must match if both specified + +### Expressions + +Expressions allow for condition checking of function arguments, event parameters, and transaction fields. + +**Supported Parameter/Field Types and Basic Operations:** + +| Type | Description | Example Operators | Notes | +| --- | --- | --- | --- | +| `**Numeric (uint/int variants)**` | Integer values (e.g., `42`, `-100`) or decimal values (e.g., `3.14`, `-0.5`). | `>`, `>=`, `<`, `<=`, `==`, `!=` | Numbers must have digits before and after a decimal point if one is present (e.g., `.5` or `5.` are not valid standalone numbers). | +| `**Address**` | Blockchain addresses. | `==`, `!=` | Comparisons (e.g., `from == '0xABC...'`) are typically case-insensitive regarding the hex characters of the address value itself. | +| `**String**` | Text values. Can be single-quoted (e.g., ’hello'`) or, on the right-hand side of a comparison, unquoted (e.g., `active`). | `==`, `!=`, `starts_with`, `ends_with`, `contains` | Quoted strings support `\'` to escape a single quote and `\\` to escape a backslash. All string comparison operations (e.g., `name == 'Alice'`, `description contains 'error'`) are performed case-insensitively during evaluation. See the dedicated "String Operations" section for more examples and details. | +| `**Boolean**` | True or false values. | `==`, `!=` | Represented as `true` or `false`. These keywords are parsed case-insensitively (e.g., `TRUE`, `False` are also valid in expressions). | +| `**Hex String Literal**` | A string literal starting with `0x` or `0X` followed by hexadecimal characters (0-9, a-f, A-F). | `==`, `!=`, `starts_with`, `ends_with`, `contains` | Treated as a string for comparison purposes (e.g., `input_data starts_with '0xa9059cbb'`). Comparison is case-sensitive for the hex characters after `0x`. | +| `**Array (EVM/Stellar)**` | Ordered list of items. For Stellar, often a JSON string in config (e.g., ’["a", "id":1]'`). For EVM, typically decoded from ABI parameters. | `contains`, `==`, `!=`, `[index]` | Detailed operations, including indexed access and behavior of `contains`, vary by network. See "Operations on Complex Types" below. | +| `**Object/Map (Stellar)**` | Key-value pairs, typically represented as a JSON string in config (e.g., ’"key": "value", "id": 123'`). | `.key_access`, `==`, `!=` | Supports dot notation for field access (e.g., `data.id`). See "Operations on Complex Types" for details. | +| `**Vec (Stellar)**` | Ordered list, where the parameter’s value can be a CSV string (e.g., `"foo,bar"`) or a JSON array string (e.g., ’["foo","bar"]'`). | `contains`, `==`, `!=` | Behavior of `contains` and `==` differs based on whether the value is CSV or a JSON array string. See "Operations on Complex Types" for details. | +| `**Tuple (EVM)**` | Ordered list represented as a JSON array string (e.g., ’["Alice", 0x1234..., 25, true, [12,34]]'`). | `contains`, `==`, `!=` | The `contains` operation performs a case-insensitive deep search through all tuple elements. `==` and `!=` perform comparisons against the entire tuple values. See "Operations on Complex Types" for details. | + +**Logical Operators:** + +* AND - All conditions must be true +* OR - At least one condition must be true +* () - Parentheses for grouping +* AND has higher precedence than OR (i.e., AND operations are evaluated before OR operations if not grouped by parentheses) + +**Variable Naming and Access (Left-hand side of conditions):** + +The left-hand side (LHS) of a condition specifies the data field or parameter whose value you want to evaluate. + +**Base Names:** + +* These are the direct names of parameters or fields, such as `amount`, `from`, `status`, or event parameter indices like `0`, `1` (common in Stellar events). +* Base names can consist of alphanumeric characters (a-z, A-Z, 0-9) and underscores (`_`). +* They can start with a letter, an underscore, or a digit. Starting with a digit is primarily relevant for numerically indexed parameters (e.g., Stellar event parameters). +* **Important:** Variable names are case-sensitive during evaluation. The name used in the expression must exactly match the casing of the field name in the source data (e.g., from an ABI or blockchain data structure). For example, if a field is named `TotalValue` in the data, an expression using `totalvalue` will not find it. +* Variable names cannot be keywords (e.g., `true`, `AND`, `OR`, `contains`). Keywords themselves are parsed case-insensitively. + +**Path Accessors (for complex types):** + +If a base parameter is a complex type like an object, map, or array, you can access its internal data using accessors: + +**Key Access:** Use dot notation (`.`) to access properties of an object or map. + +* Examples: `transaction.value`, `user.name`, `data.0` (if `0` is a valid key name as a string). +* Keys typically consist of alphanumeric characters and underscores. They usually start with a letter or underscore, but purely numeric keys (e.g., `.0`, `.123`) are also supported for map-like structures where keys might be strings representing numbers. +* Keys cannot contain hyphens (`-`). + +**Index Access:** Use bracket notation (`[]`) to access elements of an array by their zero-based integer index. + +* Examples: `my_array[0]`, `log_entries[3]`. +* The index must be a non-negative integer. + +**Combined Access:** You can combine key and index accessors to navigate nested structures. + +* Example: `event.data_array[0].property` (accesses the `property` field of the first object in `data_array`, which is part of `event`). +* Example: `map.numeric_key_as_string_0[1].name` (accesses the `name` property of the second element of an array stored under the key `0` in `map`). + +**String Operations:** + +Several operators are available for matching patterns and comparing string values. These are particularly useful for EVM transaction `input` data, Stellar parameters defined with `kind: "string"`, or any other field that contains text. + +* `string_param starts_with 'prefix'`:: + Checks if the string parameter’s value begins with the specified `prefix`. + Example: `transaction.input starts_with '0xa9059cbb'` (checks for ERC20 transfer function selector). +* `string_param ends_with 'suffix'`:: + Checks if the string parameter’s value ends with the specified `suffix`. + Example: `file_name ends_with '.txt'` +* `string_param contains 'substring'`:: + Checks if the string parameter’s value contains the specified `substring` anywhere within it. + Example: `message contains 'error'` +* `string_param == 'exact_string'`:: + Checks if the string parameter’s value is exactly equal to `exact_string`. +* `string_param != 'different_string'`:: + Checks if the string parameter’s value is not equal to `different_string`. + +**Important Notes on String Operations:** + +* **Operator Keywords:** The operator keywords themselves (`starts_with`, `ends_with`, `contains`, `AND`, `OR`, `true`, `false`, comparison symbols like `==`, `>`) are parsed case-insensitively. For example, `CONTAINS` is treated the same as `contains`, and `TRUE` is the same as `true`. +* **Case-Insensitive Evaluation for String Comparisons:** When comparing string data (e.g., from event parameters, transaction fields, or function arguments) with literal string values in your expression, all standard string operations perform a ***case-insensitive*** comparison during evaluation. + * Equality (`==`) and Inequality (`!=`) + * Pattern matching (`starts_with`, `ends_with`, `contains`) +* **Variable Name Case Sensitivity:** It is important to distinguish this from variable names (the left-hand side of your condition, e.g., `status`). Variable names **are** case-sensitive and must exactly match the field names in your source data (ABI, etc.). + +**Whitespace Handling:** +Flexible whitespace is generally allowed around operators, parentheses, and keywords for readability. However, whitespace within quoted string literals is significant and preserved. + +#### Operations on Complex Types + +Beyond simple primitive types, expressions can also interact with more complex data structures like arrays, objects, and vectors. + +##### EVM Specifics + +**Array Operations (`kind: "array"`)** + +When an EVM parameter is an array (often represented internally or configured with `kind: "array"` and its value being a JSON string representation if manually configured), the following operations are supported: + +* `array_param contains 'value'` checks if the string ’value'` exists within the array. +* `array_param == '["raw_json_array_string"]'` string comparison of the array’s entire JSON string representation against the provided string +* `array_param != '["raw_json_array_string"]'` the negation of the above +* `array_param[0]` indexed access + +**Tuple Operations (`kind: "tuple"`)** + +* `tuple_param contains 'value'` checks if the string ’value'` exists within the tuple. +* `tuple_param == (12, "hello", "testing", 34)` checks if the tuple is equal. +* `tuple_param != (12, "hello", "testing", 34)` checks if the tuple is not equal. + +Where `tuple_param` is the name of tuple param (we should have only one param for tuples). + +**Note on Solidity Structs:** When working with Solidity smart contracts, struct types are automatically converted to tuples during ABI encoding/decoding. For example, a Solidity struct like: + +```solidity +struct User { + uint256 id; + string name; + string email; + uint256 age; +} +``` + +Will be represented as a tuple `**(12, "user_name", "user_email", 34)**` where the values correspond to the struct fields in their declaration order. This conversion is handled transparently by the Solidity compiler and Web3 libraries, allowing you to use the tuple operations above to work with struct data returned from smart contract calls. + +##### Stellar Specifics + +**Object (`kind: "object"`) / Map (`kind: "Map"`) Operations** + +* `object_param.key == 'value'` checks if the object or map has a key named `key` with the value ’value'`. +* `object_param.nested_key.another_key > 100` checks if the nested key `another_key` within `nested_key` has a value greater than 100. +* `object_param == '"raw_json_object_string"'` checks if the object or map matches the provided JSON string representation. +* `object_param != '"raw_json_object_string"'` the negation of the above + +**Array (`kind: "array"`) Operations** + +* `array_param[index]` accesses the element at the specified `index` in the array. +* `array_param[0] == 'value'` checks if the first element in the array is equal to ’value'`. +* `array_param[1].property == 'value'` checks if the second element in the array has a property named `property` with the value ’value'`. +* `array_param contains 'value'` checks if the array contains the string ’value'`. +* `array_param == '["raw_json_array_string"]'` checks if the array matches the provided JSON string representation. +* `array_param != '["raw_json_array_string"]'` the negation of the above + +**Vector (`kind: "vec"`) Operations** +When a Stellar parameter has `kind: "vec"`, its value can be either a CSV string or a JSON array string. + +* `vec_param contains 'item'` checks if the vector contains the string ’item'`. This works for both CSV and JSON array strings. +* `vec_param == 'raw_string_value'` checks if the vector matches the provided raw string value. This works for both CSV and JSON array strings. +* `vec_param != 'raw_string_value'` the negation of the above + +**Event Parameter Access (Stellar)** + +Starting with Stellar Protocol 23, Soroban contracts can include event definitions in their contract specifications. This enables two ways to access event parameters: + +**Access by Name (Protocol 23+):** +When a contract specification includes event definitions, you can access event parameters by their defined names: + +* If an event has a parameter named `recipient` (kind: "Address"): + * `recipient == 'GBBD...ABCD'` +* If an event has a parameter named `amount` (kind: "U128"): + * `amount > 1000000` +* If an event has a parameter named `metadata` (kind: "Map") containing ’"id": 123, "name": "Test"'`: + * `metadata.id == 123` + * `metadata.name contains 'test'` (case-insensitive) +* If an event has a parameter named `items` (kind: "array") containing ’["alpha", "beta"]'`: + * `items contains 'beta'` (case-insensitive deep search) + +**Access by Index (Legacy):** +For contracts without event definitions in their specification, or when working with older contracts, event parameters can be accessed by their numeric index (e.g., `0`, `1`, `2`): + +* If event parameter `0` (kind: "Map") is ’"id": 123, "name": "Test"'`: + * `0.id == 123` + * `0.name contains 'est'` (case-insensitive) +* If event parameter `1` (kind: "array") is ’["alpha", "val": "beta"]'`: + * `1[0] == 'ALPHA'` (case-insensitive) + * `1[1].val == 'Beta'` (case-insensitive) + * `1 contains 'beta'` (case-insensitive deep search) + + + +Named access is recommended when available as it makes expressions more readable and maintainable. The monitor will automatically use named parameters if they’re available in the contract specification, otherwise it falls back to indexed access. + + +##### EVM Examples + +These examples assume common EVM event parameters or transaction fields. + +**Basic Comparisons** + +```json +// Numeric +"transaction.value > 1000000000000000000" // Value greater than 1 ETH +"event.amount <= 500" +"block.number == 12345678" + +// String (case-insensitive evaluation for '==' and 'contains') +"transaction.to == '0xdeadbeef...'" // Address check (address value comparison itself is case-insensitive) +"event.token_name == 'mytoken'" +"transaction.input contains 'a9059cbb'" // Checks for ERC20 transfer selector + +// Boolean +"receipt.status == true" // or simply "receipt.status" if boolean field can be evaluated directly +"event.isFinalized == false" +``` + +**Logical Operators** + +```json +"transaction.value > 1000 AND event.type == 'Deposit'" +"(receipt.status == true OR event.fallback_triggered == true) AND user.is_whitelisted == false" +``` + +**String Operations** + +```json +"transaction.input starts_with '0xa9059cbb'" // Case-insensitive for the operation +"event.message ends_with 'failed'" +"event.details contains 'critical alert'" +``` + +**Array Operations** + +Assume `event.ids` is `[10, 20, 30]` and `event.participants` is `["user": "Alice", "role": "admin", "user": "Bob", "role": "editor"]`. +```json +"event.ids[0] == 10" +"event.ids contains '20'" // Checks for string '20' (case-insensitive) + +"event.participants contains 'Alice'" // True (deep search, case-insensitive) +"event.participants contains 'editor'" // True (deep search, case-insensitive) +"event.participants == '[{\"user\": \"Alice\", \"role\": \"admin\"}, {\"user\": \"Bob\", \"role\": \"editor\"}]'" // Raw JSON match (case-sensitive for structure and keys) +``` + +##### Stellar Examples + +**Basic Comparisons** + +```json +// Numeric +"event.params.amount > 10000000" // Accessing 'amount' field in an object 'params' +"ledger.sequence >= 123456" + +// String (case-insensitive evaluation for '==' and 'contains') +"event.params.recipient == 'GBD22...'" // Address check +"event.type == 'payment_processed'" + +// Boolean +"transaction.successful == true" +"event.data.is_verified == false" +``` + +**Logical Operators** + +```json +"event.data.value > 500 AND event.source_account == 'GCA7Z...'" +"(event.type == 'TRANSFER' OR event.type == 'PAYMENT') AND event.params.asset_code == 'XLM'" +``` + +**String Operations** + +```json +"event.contract_id starts_with 'CA23...'" +"event.memo ends_with '_TEST'" +"event.params.description contains 'urgent'" +``` + +**Object (`kind: "object"`) / Map (`kind: "Map"`) Operations** + +Assume `event.details` (kind: "Map") is ’"id": 123, "user": "name": "CHarlie", "status": "Active", "tags": ["new"]'`. +```json +"event.details.id == 123" +"event.details.user.name == 'charlie'" // Case-insensitive string comparison +"event.details.user.status contains 'act'" // Case-insensitive contains +"event.details.tags == '[\"new\"]'" // Raw JSON string match for the 'tags' field +``` + +**Array (`kind: "array"`) Operations** + +Assume `event.items` (kind: "array") is ’["sku": "A1", "qty": 10, "sku": "B2", "qty": 5, "notes":"Rush order"]'`. +```json +"event.items[0].sku == 'a1'" +"event.items[1].qty < 10" +"event.items contains 'A1'" // Deep search (case-insensitive) +"event.items contains 'rush order'" // Deep search (case-insensitive) +``` + +**Vector (`kind: "vec"`) Operations** + +Assume `csv_data` (kind: "vec") is `"ALPHA,Bravo,Charlie"` and `json_array_data` (kind: "vec") is ’["Delta", "id": "ECHO", "Foxtrot"]'`. +```json +"csv_data contains 'bravo'" // Case-insensitive CSV element match +"csv_data == 'ALPHA,Bravo,Charlie'" // Raw string match + +"json_array_data contains 'delta'" // Case-insensitive deep search (like array) +"json_array_data contains 'ECHO'" // Case-insensitive deep search (like array) +``` + +**Event Parameter Access (Numerically Indexed)** + +Assume event parameter `0` is `12345` (u64), `1` (kind: "array") is ’["Val1", "VAL2"]'`, and `2` (kind: "Map") is ’"keyA": "dataX", "keyB": 789'`. +```json +"0 > 10000" +"1[0] == 'val1'" +"1 contains 'val2'" +"2.keyA == 'DATAX'" +"2.keyB < 1000" +``` + +Now, after Stellar Protocol 23 we can access to Event parameters by name (first, make sure the contract supports the feature) + +``` +"0 > 10000" +"param_name[0] == 'val1'" +"param_name contains 'val2'" +"param_name.keyA == 'DATAX'" +"param_name.keyB < 1000" +``` + + + + +With SEP-48 support, Stellar functions can now reference parameters by name (e.g., `amount > 1000`) instead of position (e.g., `2 > 1000`). Events still use indexed parameters until SEP-48 support is added for events. + +You can find the contract specification through Stellar contract explorer tool. For example: +[Stellar DEX Contract Interface](https://lab.stellar.org/smart-contracts/contract-explorer?$=network$id=mainnet&label=Mainnet&horizonUrl=https:////horizon.stellar.org&rpcUrl=https:////mainnet.sorobanrpc.com&passphrase=Public%20Global%20Stellar%20Network%20/;%20September%202015;&smartContracts$explorer$contractId=CA6PUJLBYKZKUEKLZJMKBZLEKP2OTHANDEOWSFF44FTSYLKQPIICCJBE;;) + + + +#### Trigger Conditions (Custom filters) + +Custom filters allow you to create sophisticated filtering logic for processing monitor matches. These filters act as additional validation layers that determine whether a match should trigger the execution of a trigger or not. + +For more information about custom scripts, see [Custom Scripts Section](/monitor/1.1.x/scripts). + + + +***Security Risk***: Only run scripts that you trust and fully understand. Malicious scripts can harm your system or expose sensitive data. Always review script contents and verify their source before execution. + + +**Example Trigger Conditions Configuration** + +```json +{ + "script_path": "./config/filters/evm_filter_block_number.sh", + "language": "Bash", + "arguments": ["--verbose"], + "timeout_ms": 1000 +} +``` + +#### Available Fields + +##### Trigger Conditions Fields +| Field | Type | Description | +| --- | --- | --- | +| `**script_path**` | String | The path to the script | +| `**language**` | String | The language of the script | +| `**arguments**` | Array[String] | The arguments of the script (optional). | +| `**timeout_ms**` | Number | The timeout of the script is important to avoid infinite loops during the execution. If the script takes longer than the timeout, it will be killed and the match will be included by default. | + +#### Important Considerations + +* Network slugs in the monitor must match valid network configurations. +* Trigger IDs must match configured triggers. +* Expression syntax and available variables differ between EVM and Stellar networks. +* ABIs can be provided in two ways: + * For EVM networks: Through the monitor configuration using standard Ethereum ABI format + * For Stellar networks: Through the monitor configuration using SEP-48 format, or automatically fetched from the chain if not provided +* The monitoring frequency is controlled by the network’s `cron_schedule`. +* Each monitor can watch multiple networks and addresses simultaneously. +* Monitors can be paused without removing their configuration. + +## Running the Monitor + +### Local Execution + +1. ***Basic startup:*** + + ```bash + ./openzeppelin-monitor + ``` +2. ***With logging to file:*** + + ```bash + ./openzeppelin-monitor --log-file + ``` +3. ***With metrics enabled:*** + + ```bash + ./openzeppelin-monitor --metrics + ``` +4. ***Validate configuration without starting:*** + + ```bash + ./openzeppelin-monitor --check + ``` + +### Docker Execution + +1. ***Start all services:*** + + ```bash + cargo make docker-compose-up + ``` +2. ***With metrics and monitoring (Prometheus + Grafana):*** + + ```bash + # Set METRICS_ENABLED=true in .env file, then: + docker compose --profile metrics up -d + ``` +3. ***View logs:*** + + ```bash + docker compose logs -f monitor + ``` +4. ***Stop services:*** + + ```bash + cargo make docker-compose-down + ``` + +### Command Line Options + +| | | | +| --- | --- | --- | +| Option | Default | Description | +| `--log-file` | `false` | Write logs to file instead of stdout | +| `--log-level` | `info` | Set log level (trace, debug, info, warn, error) | +| `--metrics` | `false` | Enable metrics server on port 8081 | +| `--check` | `false` | Validate configuration files only | +| `--help` | - | Show all available options | + +### Testing your configuration + +#### Network Configuration +The `validate_network_config.sh` script helps ensure your network configuration is properly set up and operational. The script: + +* Tests the health of all configured RPC endpoints +* Validates connectivity using network-specific methods +* Provides clear visual feedback for each endpoint + +```bash +# Test default networks directory (/config/networks/) +./scripts/validate_network_config.sh + +# Test a specific configuration directory +./scripts/validate_network_config.sh -f /path/to/configs +``` + + +Run this script when setting up new networks, before deploying configuration changes, or when troubleshooting connectivity issues. + + +#### Validating Configuration Files + +Before starting the monitor service, you can validate your configuration files using the `--check` option: + +```bash +./openzeppelin-monitor --check +``` + +This command will: + +* Parse and validate all configuration files +* Check for syntax errors +* Verify references between monitors, networks, and triggers +* Report any issues without starting the service + +It’s recommended to run this check after making changes to any configuration files. + +#### Monitor Configuration +The monitor can be tested in two modes: + +#### 1. Latest Block Mode + +This mode processes the most recent blocks across all configured networks. + +```bash +./openzeppelin-monitor --monitor-path="config/monitors/evm_transfer_usdc.json" +``` + +What this does: + +* Runs the "Large Transfer of USDC Token" monitor +* Targets all networks specified in the configuration +* Processes only the latest block for each network +* Sends a notification to all associated channels for every match that is found + +#### 2. Specific Block Mode + +This mode allows you to analyze a particular block on a specific network, which is useful for debugging specific transactions, verifying monitor behavior on known events, and testing monitor performance on historical data. + +```bash +./openzeppelin-monitor \ + --monitor-path="config/monitors/evm_transfer_usdc.json" \ + --network=ethereum_mainnet \ + --block=12345678 +``` + +What this does: + +* Runs the "Large Transfer of USDC Token" monitor +* Targets only the specified network (`ethereum_mainnet`) +* Processes only the specified block (`12345678`) +* Sends a notification to all associated channels for every match that is found + + + + +Specific Block Mode requires both parameters: + +* `--network`: The network to analyze +* `--block`: The block number to process + + + +#### Data Persistence (Optional) + +* Set `LOG_MODE` as file will persist the log data in `logs/` on host. To change it to a different directory use `LOG_DATA_DIR`. +* Set `MONITOR_DATA_DIR` to specific dir on your host system which will persist data between container restarts. + +## Error Handling + +The monitor implements a comprehensive error handling system with rich context and tracing capabilities. For detailed information about error handling, see [Error Handling Guide](/monitor/1.1.x/error). + +## Important Considerations + +### Performance Considerations + +* Monitor performance depends on network congestion and RPC endpoint reliability. + * View the [list of RPC calls](/monitor/1.1.x/rpc#list_of_rpc_calls) made by the monitor. +* The `max_past_blocks` configuration is critical: + * Calculate as: `(cron_interval_ms/block_time_ms) + confirmation_blocks + 1` (defaults to this calculation if not specified). + * Example for 1-minute Ethereum cron: `(60000/12000) + 12 + 1 = 18 blocks`. + * Too low settings may result in missed blocks. +* Trigger conditions are executed sequentially based on their position in the trigger conditions array. Proper execution also depends on the number of available file descriptors on your system. To ensure optimal performance, it is recommended to increase the limit for open file descriptors to at least 2048 or higher. On Unix-based systems you can check the current limit by running `ulimit -n` and _***temporarily***_ increase it with `ulimit -n 2048`. +* Since scripts are loaded at startup, any modifications to script files require restarting the monitor to take effect. +* See performance considerations about custom scripts [here](/monitor/1.1.x/scripts#performance_considerations). + +### Notification Considerations + +* Template variables are context-dependent: + * Event-triggered notifications only populate event variables. + * Function-triggered notifications only populate function variables. + * Mixing contexts results in empty values. +* Custom script notifications have additional considerations: + * Scripts receive monitor match data and arguments as JSON input + * Scripts must complete within their configured timeout_ms or they will be terminated + * Script modifications require monitor restart to take effect + * Supported languages are limited to Python, JavaScript, and Bash + +## Support + +For support or inquiries, contact us on [Telegram](https://t.me/openzeppelin_tg/4). + +Have feature requests or want to contribute? Join our community on [GitHub](https://github.com/OpenZeppelin/openzeppelin-monitor/) + +## License +This project is licensed under the GNU Affero General Public License v3.0 - see the LICENSE file for details. + +## Security +For security concerns, please refer to our [Security Policy](https://github.com/OpenZeppelin/openzeppelin-monitor/blob/main/SECURITY.md). diff --git a/content/monitor/1.1.x/project-structure.mdx b/content/monitor/1.1.x/project-structure.mdx new file mode 100644 index 00000000..6e4238f3 --- /dev/null +++ b/content/monitor/1.1.x/project-structure.mdx @@ -0,0 +1,208 @@ +--- +title: Project Structure +--- + +This document describes the project structure and organization of the OpenZeppelin Monitor codebase, including the source code layout, configuration files, and development resources. + +## Project Layout + +The project follows a standard Rust project layout with additional directories for configuration, documentation, and operational resources: + +``` +openzeppelin-monitor/ +β”œβ”€β”€ src/ # Source code +β”‚ β”œβ”€β”€ bootstrap/ # Bootstrap functions for the application +β”‚ β”œβ”€β”€ models/ # Data structures and types +β”‚ β”œβ”€β”€ repositories/ # Configuration storage +β”‚ β”œβ”€β”€ services/ # Core business logic +β”‚ β”œβ”€β”€ utils/ # Helper functions +β”‚ +β”œβ”€β”€ config/ # Configuration files +β”œβ”€β”€ tests/ # Integration and property-based tests +β”œβ”€β”€ data/ # Runtime data storage +β”œβ”€β”€ docs/ # Documentation +β”œβ”€β”€ scripts/ # Utility scripts +β”œβ”€β”€ cmd/ # Metrics and monitoring +β”œβ”€β”€ examples/ # Example configuration files +└── ... other root files (Cargo.toml, README.md, etc.) +``` + +## Source Code Organization + +### `src/` Directory + +The main source code directory contains the core implementation files organized into several modules: + +#### `bootstrap/` +Application initialization and setup for `main.rs`: + +* Handles service initialization and dependency injection +* Manages the startup sequence and service lifecycle + +#### `models/` +Core data structures and types: + +* `blockchain/`: Platform-specific implementations + * `evm/`: Ethereum Virtual Machine specific types + * `stellar/`: Stellar blockchain specific types +* `config/`: Configuration loading and validation +* `core/`: Core domain models +* `security/`: Security and secret management + +#### `repositories/` +Configuration storage: + +* Handles loading and validating configuration files +* Provides storage interfaces for monitors, networks, and triggers +* Implements validation of configuration references + +#### `services/` +Core business logic: + +* `blockchain/`: Blockchain client interfaces + * `transports/`: Transport clients + * `evm/`: Ethereum Virtual Machine transport client + * `stellar/`: Stellar transport client + * `clients/`: Client implementations + * `evm/`: Ethereum Virtual Machine client + * `stellar/`: Stellar client +* `blockwatcher/`: Block monitoring and processing +* `filter/`: Transaction and event filtering + * `filters/`: Filter implementations + * `evm/`: Ethereum Virtual Machine filter + * `stellar/`: Stellar filter +* `notification/`: Alert handling +* `trigger/`: Trigger evaluation and execution + * `script/`: Script execution utilities + +#### `utils/` +Helper functions: + +* `cron_utils`: Cron schedule utilities +* `expression`: Expression evaluation +* `logging/`: Logging utilities +* `macros/`: Macros for common functionality +* `metrics/`: Metrics utilities +* `monitor/`: Monitor configuration test utilities +* `tests/`: Contains test utilities and helper functions + * `builders/`: Test builder patterns implementing fluent interfaces for creating test fixtures + * `evm/`: Builder implementations specific to Ethereum Virtual Machine (EVM) testing + * `stellar/`: Builder implementations specific to Stellar blockchain testing + +## Configuration and Data + +### `config/` Directory + +Contains JSON configuration files for: + +* ***Network configurations*** (`networks/`) + * Connection details for blockchain networks + * RPC endpoints and network parameters +* ***Monitor configurations*** (`monitors/`) + * Monitoring rules and conditions + * Network and trigger references +* ***Trigger configurations*** (`triggers/`) + * Notification settings + * Script definitions +* ***Filter configurations*** (`filters/`) + * Match filter scripts + + + +The `examples/config/` directory contains example JSON configuration files for each (network, monitor, trigger and filters). + + +### `data/` Directory + +Runtime data storage: + +* Block processing state +* Operational data +* Temporary files + + + + +The `data/`, `logs/` and `config/` directories are gitignored except for example files. These directories are mounted to persist the configs and runtime data. + + + +## Examples and Resources + +### `examples/` Directory + +Provides practical examples and sample configurations to help users get started: + +* Demonstrates typical service configurations for various networks +* Acts as a quick-start guide for customizing the monitor +* Serves as a reference for best practices in configuration + +## Metrics and Monitoring + +### `cmd/prometheus/` Directory + +Prometheus exporters and monitoring infrastructure: + +* `dashboards/`: Grafana dashboards +* `datasources/`: Prometheus datasources +* `prometheus.yml`: Prometheus configuration +* `grafana.ini`: Grafana configuration + +## Testing and Documentation + +### `tests/` Directory + +Contains comprehensive test suites: + +* Integration tests +* Property-based tests +* Mock implementations +* Test utilities and helpers + +### `docs/` Directory + +Project documentation: + +* User guides +* API documentation +* Configuration examples +* Architecture diagrams + +### `scripts/` Directory + +Utility scripts for: + +* Development workflows +* Documentation generation +* Build processes +* Deployment helpers + +## Development Tools + +### Pre-commit Hooks + +Located in the project root: + +* Code formatting checks +* Linting rules +* Commit message validation + +### Build Configuration + +Core build files: + +* `Cargo.toml`: Project dependencies and metadata +* `rustfmt.toml`: Code formatting rules +* `rust-toolchain.toml`: Rust version and components + +## Docker Support + +The project includes Docker configurations for different environments: + +* `Dockerfile.development`: Development container setup +* `Dockerfile.production`: Production-ready container +* Before running the docker compose set your env variables in `.env` according to your needs + + + +For detailed information about running the monitor in containers, see the Docker deployment [section](/monitor/1.1.x#docker_installation) in the user documentation. diff --git a/content/monitor/1.1.x/quickstart.mdx b/content/monitor/1.1.x/quickstart.mdx new file mode 100644 index 00000000..9bf7b5b9 --- /dev/null +++ b/content/monitor/1.1.x/quickstart.mdx @@ -0,0 +1,654 @@ +--- +title: Quick Start Guide +--- + +OpenZeppelin Monitor is a powerful tool for monitoring blockchain events and transactions. This guide will help you get up and running quickly with practical examples for both EVM and Stellar networks. + +## What You'll Learn + +* How to set up OpenZeppelin Monitor locally or with Docker +* How to configure monitoring for USDC transfers on Ethereum +* How to monitor DEX swaps on Stellar +* How to set up notifications via Slack and email + +## Prerequisites + +Before you begin, ensure you have the following installed: + +* ***Rust 2021 edition*** - Required for building from source +* ***Docker*** - Optional, for containerized deployment +* ***Git*** - For cloning the repository + + + +If you don’t have Rust installed, visit https://rustup.rs/ to install it. + + +### System Dependencies (Linux) + +For Ubuntu 22.04+ or Debian-based systems (both x86 and ARM64 architectures), install required packages: + +***Note:*** Python 3.9+ is required for pre-commit hooks compatibility. + +```bash +# Install required packages directly +sudo apt update +sudo apt install -y \ + build-essential \ + curl \ + git \ + pkg-config \ + libssl-dev \ + libffi-dev \ + libyaml-dev \ +``` + +Or use the provided system packages script: + +```bash +chmod +x ./scripts/linux/sys_pkgs_core.sh +./scripts/linux/sys_pkgs_core.sh // For runtime dependencies only +``` + +## Quick Setup Options + +We provide two setup paths to get you started: + +### Option 1: Automated Setup (Recommended) + +For the fastest setup experience, use our automated script that handles everything for you. + +#### What the Automated Setup Does + +The `setup_and_run.sh` script provides a complete solution that: + +* ***Builds the monitor application*** from source +* ***Copies example configurations*** from `examples/` to `config/` + * Network configurations for major blockchains + * Pre-configured monitor examples (USDC transfers, Stellar DEX swaps) + * Required filter scripts and basic trigger notifications +* ***Validates all configurations*** to ensure proper setup +* ***Optionally runs the monitor*** to verify everything works + +#### Running the Automated Setup + +1. ***Clone the repository:*** + + ```bash + git clone https://github.com/openzeppelin/openzeppelin-monitor + cd openzeppelin-monitor + ``` +2. ***Make the script executable:*** + + ```bash + chmod +x setup_and_run.sh + ``` +3. ***Run the automated setup:*** + + ```bash + ./setup_and_run.sh + ``` + +The script provides colored output and clear guidance throughout the process. + +#### After Automated Setup + +Once complete, you’ll have: + +* A fully built OpenZeppelin Monitor +* Example configurations ready for customization +* Clear guidance on next steps + +***Next Steps:*** +. Customize the copied configurations in `config/` directories +. Update RPC URLs and notification credentials +. Run the monitor with `./openzeppelin-monitor` + + + +The setup script creates working configurations with placeholder values. ***Remember to update your files with actual RPC endpoints and notification credentials*** before starting real monitoring. + + +### Option 2: Manual Setup + +For users who prefer more control over the setup process. + +#### Building from Source + +1. ***Clone and build:*** + + ```bash + git clone https://github.com/openzeppelin/openzeppelin-monitor + cd openzeppelin-monitor + cargo build --release + ``` +2. ***Move the binary to project root:*** + + ```bash + mv ./target/release/openzeppelin-monitor . + ``` + +#### Docker Setup + +For containerized deployment: + +1. ***Start services:*** + + ```bash + docker compose up + ``` + + + + +By default, Docker Compose uses `Dockerfile.development`. For production, set: +`DOCKERFILE=Dockerfile.production` before running the command. + + + +#### Docker Management Commands + +| Command | Description | +| --- | --- | +| `docker ps -a` | Verify container status | +| `docker compose down` | Stop services (without metrics) | +| `docker compose --profile metrics down` | Stop services (with metrics) | +| `docker compose logs -f` | View logs (follow mode) | + +## Environment Configuration + +### Logging Configuration + +Configure logging verbosity by setting the `RUST_LOG` environment variable: + +| Level | Description | +| --- | --- | +| `error` | Only error messages | +| `warn` | Warnings and errors | +| `info` | General information (recommended) | +| `debug` | Detailed debugging information | +| `trace` | Very detailed trace information | + +```bash +export RUST_LOG=info +``` + +### Local Configuration + +Copy the example environment file and customize it: + +```bash +cp .env.example .env +``` + +For detailed configuration options, see [Basic Configuration](/monitor/1.1.x#basic_configuration). + +## Practical Examples + +Now let’s set up real monitoring scenarios. Choose the example that matches your needs: + +### Example 1: Monitor USDC Transfers (Ethereum) + +This example monitors large USDC transfers on Ethereum mainnet and sends notifications when transfers exceed 10,000 USDC. + +#### Step 1: Network Configuration + +Create the Ethereum mainnet configuration: + +```bash +# Only necessary if you haven't already run the automated setup script (Option 1: Automated Setup) +cp examples/config/networks/ethereum_mainnet.json config/networks/ethereum_mainnet.json +``` + +***Key Configuration Details:*** + +```json +{ + "network_type": "EVM", + "slug": "ethereum_mainnet", + "name": "Ethereum Mainnet", + "rpc_urls": [ + { + "type_": "rpc", + "url": { + "type": "plain", + "value": "YOUR_RPC_URL_HERE" + }, + "weight": 100 + } + ], + "chain_id": 1, + "block_time_ms": 12000, + "confirmation_blocks": 12, + "cron_schedule": "0 */1 * * * *", + "max_past_blocks": 18, + "store_blocks": false +} +``` + + + + +***Important:*** Replace `YOUR_RPC_URL_HERE` with your actual Ethereum RPC endpoint. You can use providers like Infura, Alchemy, or run your own node. + + + +#### Step 2: Monitor Configuration + +Set up the USDC transfer monitor: + +```bash +# Only necessary if you haven't already run the automated setup script (Option 1: Automated Setup) +cp examples/config/monitors/evm_transfer_usdc.json config/monitors/evm_transfer_usdc.json +cp examples/config/filters/evm_filter_block_number.sh config/filters/evm_filter_block_number.sh +``` + +***Monitor Configuration Overview:*** + +```json +{ + "name": "Large Transfer of USDC Token", + "paused": false, + "networks": ["ethereum_mainnet"], + "addresses": [ + { + "address": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", + "contract_spec": [ + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event" + } + ] + } + ], + "match_conditions": { + "functions": [], + "events": [ + { + "signature": "Transfer(address,address,uint256)", + "expression": "value > 10000000000" + } + ], + "transactions": [ + { + "status": "Success", + "expression": null + } + ] + }, + "trigger_conditions": [ + { + "script_path": "./config/filters/evm_filter_block_number.sh", + "language": "bash", + "arguments": ["--verbose"], + "timeout_ms": 1000 + } + ], + "triggers": ["evm_large_transfer_usdc_slack", "evm_large_transfer_usdc_email"] +} +``` + + + + +* The `expression: "value > 10000000000"` monitors transfers over 10,000 USDC (USDC has 6 decimals) +* Remove the `trigger_conditions` array to disable additional filtering +* The USDC contract address `0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48` is the official USDC contract on Ethereum mainnet + + + +#### Step 3: Notification Setup + +##### Slack Notifications + +```bash +# Only necessary if you haven't already run the automated setup script (Option 1: Automated Setup) +cp examples/config/triggers/slack_notifications.json config/triggers/slack_notifications.json +``` + +***Slack Configuration:*** + +```json +{ + "evm_large_transfer_usdc_slack": { + "name": "Large Transfer Slack Notification", + "trigger_type": "slack", + "config": { + "slack_url": { + "type": "plain", + "value": "SLACK_WEBHOOK_URL" + }, + "message": { + "title": "large_transfer_slack triggered", + "body": "Large transfer of ${events.0.args.value} USDC from ${events.0.args.from} to ${events.0.args.to} | https://etherscan.io/tx/${transaction.hash}#eventlog" + } + } + } +} +``` + + + +To get a Slack webhook URL: + +1. Go to https://api.slack.com/apps +2. Create a new app or select existing one +3. Enable "Incoming Webhooks" +4. Create a webhook for your channel + + +##### Email Notifications + +```bash +# Only necessary if you haven't already run the automated setup script (Option 1: Automated Setup) +cp examples/config/triggers/email_notifications.json config/triggers/email_notifications.json +``` + +***Email Configuration:*** + +```json +{ + "evm_large_transfer_usdc_email": { + "name": "Large Transfer Email Notification", + "trigger_type": "email", + "config": { + "host": "smtp.gmail.com", + "port": 465, + "username": { + "type": "plain", + "value": "your_email@gmail.com" + }, + "password": { + "type": "plain", + "value": "SMTP_PASSWORD" + }, + "message": { + "title": "large_transfer_usdc_email triggered", + "body": "Large transfer of ${events.0.args.value} USDC from ${events.0.args.from} to ${events.0.args.to} | https://etherscan.io/tx/${transaction.hash}#eventlog" + }, + "sender": "your_email@gmail.com", + "recipients": [ + "recipient1@example.com", + "recipient2@example.com" + ] + } + } +} +``` + + + +For Gmail, you’ll need to use an "App Password" instead of your regular password. Enable 2FA and generate an app password in your Google Account settings. + + +#### Step 4: Run the Monitor + +***Local Deployment:*** + +```bash +./openzeppelin-monitor +``` + +***Docker Deployment:*** + +```bash +cargo make docker-compose-up +``` + +#### What Happens Next + +Once running, the monitor will: + +1. Check for new Ethereum blocks every minute +2. Watch for USDC transfers over 10,000 USDC +3. Send notifications via Slack and email when large transfers occur + +#### Customization Options + +* ***Adjust threshold:*** Modify `"value > 10000000000"` to change the minimum transfer amount +* ***Monitor other tokens:*** Create new monitor configurations for different ERC20 tokens +* ***Add more networks:*** Configure additional EVM networks (Polygon, BSC, etc.) + +### Example 2: Monitor DEX Swaps (Stellar) + +This example monitors large DEX swaps on Stellar mainnet. + +#### Step 1: Network Configuration + +Create the Stellar mainnet configuration: + +```bash +# Only necessary if you haven't already run the automated setup script (Option 1: Automated Setup) +cp examples/config/networks/stellar_mainnet.json config/networks/stellar_mainnet.json +``` + +***Key Configuration Details:*** + +```json +{ + "network_type": "Stellar", + "slug": "stellar_mainnet", + "name": "Stellar Mainnet", + "rpc_urls": [ + { + "type_": "rpc", + "url": { + "type": "plain", + "value": "YOUR_RPC_URL_HERE" + }, + "weight": 100 + } + ], + "network_passphrase": "Public Global Stellar Network ; September 2015", + "block_time_ms": 5000, + "confirmation_blocks": 2, + "cron_schedule": "0 */1 * * * *", + "max_past_blocks": 20, + "store_blocks": true +} +``` + +#### Step 2: Monitor Configuration + +Set up the DEX swap monitor: + +```bash +# Only necessary if you haven't already run the automated setup script (Option 1: Automated Setup) +cp examples/config/monitors/stellar_swap_dex.json config/monitors/stellar_swap_dex.json +cp examples/config/filters/stellar_filter_block_number.sh config/filters/stellar_filter_block_number.sh +``` + +***Monitor Configuration Overview:*** + +```json +{ + "name": "Large Swap By Dex", + "paused": false, + "networks": ["stellar_mainnet"], + "addresses": [ + { + "address": "CA6PUJLBYKZKUEKLZJMKBZLEKP2OTHANDEOWSFF44FTSYLKQPIICCJBE", + "contract_spec": [ + { + "function_v0": { + "doc": "", + "name": "swap", + "inputs": [ + { + "doc": "", + "name": "user", + "type_": "address" + }, + { + "doc": "", + "name": "in_idx", + "type_": "u32" + }, + { + "doc": "", + "name": "out_idx", + "type_": "u32" + }, + { + "doc": "", + "name": "in_amount", + "type_": "u128" + }, + { + "doc": "", + "name": "out_min", + "type_": "u128" + } + ], + "outputs": ["u128"] + } + } + ] + } + ], + "match_conditions": { + "functions": [ + { + "signature": "swap(Address,U32,U32,U128,U128)", + "expression": "out_min > 1000000000" + } + ], + "events": [], + "transactions": [ + { + "status": "Success", + "expression": null + } + ] + }, + "trigger_conditions": [ + { + "script_path": "./config/filters/stellar_filter_block_number.sh", + "language": "bash", + "arguments": ["--verbose"], + "timeout_ms": 1000 + } + ], + "triggers": ["stellar_large_swap_by_dex_slack"] +} +``` + + + + +* The `contract_spec` field is optional for Stellar contracts. If not provided, the monitor automatically fetches the contract’s SEP-48 interface from the chain +* You can explore Stellar contract interfaces using the [Stellar Contract Explorer](https://lab.stellar.org/smart-contracts/contract-explorer) +* The expression `"out_min > 1000000000"` monitors swaps with minimum output over 1 billion tokens +* Now, you can also filter by parameters event’s name (Stellar Protocol 23 has introduced this new feature). See this [section](/monitor/1.1.x#stellar_specifics) for more details + + + +#### Step 3: Notification Setup + +Set up Slack notifications for Stellar swaps: + +```bash +# Only necessary if you haven't already run the automated setup script (Option 1: Automated Setup) +cp examples/config/triggers/slack_notifications.json config/triggers/slack_notifications.json +``` + +***Slack Configuration:*** + +```json +{ + "stellar_large_swap_by_dex_slack": { + "name": "Large Swap By Dex Slack Notification", + "trigger_type": "slack", + "config": { + "slack_url": { + "type": "plain", + "value": "slack-webhook-url" + }, + "message": { + "title": "large_swap_by_dex_slack triggered", + "body": "${monitor.name} triggered because of a large swap of ${functions.0.args.out_min} tokens | https://stellar.expert/explorer/public/tx/${transaction.hash}" + } + } + } +} +``` + +* If you want to include event details in the notification message body, you can also access event parameters by name. Here’s an example: +```bash +"body": "${monitor.name} triggered because of a large swap from ${events.0.args.from} tokens | https://stellar.expert/explorer/public/tx/${transaction.hash}" +``` + +#### Step 4: Run the Monitor + +***Local Deployment:*** + +```bash +./openzeppelin-monitor +``` + +***Docker Deployment:*** + +```bash +cargo make docker-compose-up +``` + +#### What Happens Next + +Once running, the monitor will: + +1. Check for new Stellar blocks every minute +2. Watch for large DEX swaps +3. Send notifications via Slack when large swaps occur + +## Next Steps + +Now that you have OpenZeppelin Monitor running, here are some suggestions for what to do next: + +### Testing and Validation + +* [Test your configuration](/monitor/1.1.x#testing_your_configuration) against specific block numbers +* Verify your RPC endpoints are working correctly +* Test notification channels with small transactions + +### Security and Best Practices + +* [Configure secure secret management](/monitor/1.1.x#secret_management) for sensitive data +* Use environment variables or Hashicorp Cloud Vault for credentials +* Regularly update your RPC endpoints and monitor configurations + +### Advanced Configuration + +* Explore additional examples in the [`examples/config/monitors` directory](https://github.com/OpenZeppelin/openzeppelin-monitor/tree/main/examples/config/monitors) +* Set up monitoring for multiple networks simultaneously +* Configure custom filter scripts for complex conditions + +### Getting Help + +* Check the [GitHub Issues](https://github.com/OpenZeppelin/openzeppelin-monitor/issues) for known problems +* Review the [User Documentation](/monitor/1.1.x) for detailed configuration options +* Join the OpenZeppelin community for support + + + +Start with simple monitoring scenarios and gradually add complexity. This helps you understand how the system works and makes troubleshooting easier. diff --git a/content/monitor/1.1.x/rpc.mdx b/content/monitor/1.1.x/rpc.mdx new file mode 100644 index 00000000..9b1cdf4f --- /dev/null +++ b/content/monitor/1.1.x/rpc.mdx @@ -0,0 +1,307 @@ +--- +title: RPC Client +--- + +## Overview + +The OpenZeppelin Monitor includes a robust RPC client implementation with automatic endpoint rotation and fallback capabilities. This ensures reliable blockchain monitoring even when individual RPC endpoints experience issues. + +* Multiple RPC endpoint support with weighted load balancing +* Automatic fallback on endpoint failures +* Rate limit handling (429 responses) +* Connection health checks +* Thread-safe endpoint rotation + +## Configuration + +### RPC URLs + +RPC endpoints are configured in the network configuration files with weights for load balancing: + +```json +{ + "rpc_urls": [ + { + "type_": "rpc", + "url": {"type": "plain", "value": "https://primary-endpoint.example.com"}, + "weight": 100 + }, + { + "type_": "rpc", + "url": {"type": "plain", "value": "https://backup-endpoint.example.com"}, + "weight": 50 + } + ] +} +``` + + + +For high-availability setups, configure at least 3 (private) RPC endpoints with appropriate weights to ensure continuous operation even if multiple endpoints fail. + + +### Configuration Fields + +| Field | Type | Description | +| --- | --- | --- | +| `**type_**` | `String` | Type of endpoint (currently only "rpc" is supported) | +| `**url.type**` | `String` | Secret type ("Plain", "Environment", or "HashicorpCloudVault") | +| `**url.value**` | `String` | The RPC endpoint URL | +| `**weight**` | `Number` | Load balancing weight (0-100) | + +## Endpoint Management + +The endpoint manager handles + +* Initial endpoint selection based on weights +* Automatic rotation on failures +* Connection health checks +* Thread-safe endpoint updates + +Each blockchain network type has its own specialized transport client that wraps the base `HttpTransportClient`. +The transport clients are implemented as: + +1. **Core HTTP Transport**: `HttpTransportClient` provides core HTTP functionality, including the integrated retryable client. +2. **Network-Specific Transports**: + * `EVMTransportClient` for EVM networks + * `StellarTransportClient` for Stellar networks + +### Rotation Strategy + +The RPC client includes an automatic rotation strategy for handling specific types of failures: + +* For 429 (Too Many Requests) responses: + * Immediately rotates to a fallback URL + * Retries the request with the new endpoint + * Continues this process until successful or all endpoints are exhausted + +#### Configuration Options + +The error codes that trigger RPC endpoint rotation can be customized in the `src/services/blockchain/transports/mod.rs` file. + +```rust +pub const ROTATE_ON_ERROR_CODES: [u16; 1] = [429]; +``` + +### Retry Strategy + +The transport layer uses a combination of same-endpoint retries and endpoint rotation to handle transient failures and maintain service availability. + +#### Same-Endpoint Retry (via `reqwest-retry`) + +The `HttpTransportClient` (and by extension, EVM and Stellar clients) utilizes a `reqwest_middleware::ClientWithMiddleware`. This client is configured during initialization using the `utils::http::create_retryable_http_client` utility. This utility layers `reqwest_retry::RetryTransientMiddleware` on top of a shared base `reqwest::Client`. + +This middleware handles: + +* Automatic retries for transient HTTP errors (e.g., 5xx server errors, network timeouts) for requests made to the **currently active RPC URL**. +* An exponential backoff policy between these retry attempts. +* Parameters like the number of retries, backoff durations, and jitter are defined in an `RetryConfig` struct (see [Configuration Options](#configuration-options)). +* This same-endpoint retry mechanism is independent of, and operates before, the endpoint rotation logic. If all same-endpoint retries fail for the current URL, the error is then processed by the `EndpointManager`. + +#### Endpoint Rotation (via `EndpointManager`) + +If all same-endpoint retries fail for the currently active RPC URL, or if certain HTTP status codes (e.g., 429 Too Many Requests, as defined in `ROTATE_ON_ERROR_CODES`) are received, the `EndpointManager` (used by `HttpTransportClient`) will attempt to rotate to a healthy fallback URL. This ensures that if one endpoint becomes persistently unavailable, the system can switch to an alternative. The health check for a fallback URL also benefits from the same-endpoint retry mechanism. + +#### Configuration Options + +The same-endpoint retry behavior is configured via the `RetryConfig` struct, which is used by `create_retryable_http_client` to set up the `ExponentialBackoff` policy for `reqwest-retry`. + +The default settings for `RetryConfig` result in an `ExponentialBackoff` policy approximately equivalent to: +```rust +// This illustrates the default policy created by RetryConfig::default() +// and create_retryable_http_client. +let http_retry_config = RetryConfig::default(); +let retry_policy = ExponentialBackoff::builder() + .base(http_retry_config.base_for_backoff) + .retry_bounds(http_retry_config.initial_backoff, http_retry_config.max_backoff) + .jitter(http_retry_config.jitter) + .build_with_max_retries(http_retry_config.max_retries); +``` + +The configurable options are defined in the `RetryConfig` struct: +```rust +// In utils::http +pub struct RetryConfig { + /// Maximum number of retries for transient errors (after the initial attempt). + pub max_retries: u32, + /// Initial backoff duration before the first retry. + pub initial_backoff: Duration, + /// Maximum backoff duration for retries. + pub max_backoff: Duration, + /// Base for the exponential backoff calculation (e.g., 2). + pub base_for_backoff: u64, + /// Jitter to apply to the backoff duration. + pub jitter: Jitter, +} +``` + +The client architecture ensures efficient resource use and consistent retry behavior: + +1. A single base `reqwest::Client` is created by `HttpTransportClient` with optimized connection pool settings. This base client is shared. +2. The `create_retryable_http_client` utility takes this base client and an `RetryConfig` to produce a `ClientWithMiddleware`. +3. This `ClientWithMiddleware` (the "retryable client") is then used for all HTTP operations within `HttpTransportClient`, including initial health checks, requests sent via `EndpointManager`, and `try_connect` calls during rotation. This ensures all operations benefit from the configured retry policy and the shared connection pool. + +Each transport client may define its own retry policy: + +```rust +// src/services/transports/http.rs +pub struct HttpTransportClient { + pub client: ClientWithMiddleware, + endpoint_manager: EndpointManager, + test_connection_payload: Option, +} + +// Example of client creation with retry mechanism +// Use default retry policy +let http_retry_config = RetryConfig::default(); + +// Create the base HTTP client +let base_http_client = reqwest::ClientBuilder::new() + .pool_idle_timeout(Duration::from_secs(90)) + .pool_max_idle_per_host(32) + .timeout(Duration::from_secs(30)) + .connect_timeout(Duration::from_secs(20)) + .build() + .context("Failed to create base HTTP client")?; + +// Create a retryable HTTP client with the base client and retry policy +let retryable_client = create_retryable_http_client( + &http_retry_config, + base_http_client, + Some(TransientErrorRetryStrategy), // Use custom or default retry strategy +); + +``` + +### Implementation Details +The `EndpointManager` uses the retry-enabled `ClientWithMiddleware` provided by `HttpTransportClient` for its attempts on the primary URL. If these attempts (including internal `reqwest-retry` retries) ultimately fail with an error that warrants rotation (e.g., a 429 status code, or persistent network errors), then `EndpointManager` initiates the URL rotation sequence. + +```mermaid +sequenceDiagram + participant User as User/Application + participant HTC as HttpTransportClient + participant EM as EndpointManager + participant RetryClient as ClientWithMiddleware (reqwest-retry) + participant RPC_Primary as Primary RPC + participant RPC_Fallback as Fallback RPC + + User->>HTC: send_raw_request() + HTC->>EM: send_raw_request(self, ...) + EM->>RetryClient: POST to RPC_Primary + Note over RetryClient, RPC_Primary: RetryClient handles same-endpoint retries internally (e.g., for 5xx) + alt Retries on RPC_Primary succeed + RPC_Primary-->>RetryClient: Success + RetryClient-->>EM: Success + EM-->>HTC: Success + HTC-->>User: Response + else All retries on RPC_Primary fail (e.g. network error or 429) + RPC_Primary-->>RetryClient: Final Error (e.g. 429 or network error) + RetryClient-->>EM: Final Error from RPC_Primary + EM->>EM: Decide to Rotate (based on error type) + EM->>HTC: try_connect(Fallback_URL) (HTC uses its RetryClient for this) + HTC->>RetryClient: POST to RPC_Fallback (health check) + alt Fallback health check succeeds + RPC_Fallback-->>RetryClient: Success (health check) + RetryClient-->>HTC: Success (health check) + HTC-->>EM: Success (health check) + EM->>EM: Update active URL to RPC_Fallback + EM->>RetryClient: POST to RPC_Fallback (actual request) + RPC_Fallback-->>RetryClient: Success + RetryClient-->>EM: Success + EM-->>HTC: Success + HTC-->>User: Response + else Fallback health check fails + RPC_Fallback-->>RetryClient: Error (health check) + RetryClient-->>HTC: Error (health check) + HTC-->>EM: Error (health check) + EM-->>HTC: Final Error (all URLs failed) + HTC-->>User: Error Response + end + end +``` + +## List of RPC Calls + +Below is a list of RPC calls made by the monitor for each network type for each iteration of the cron schedule. +As the number of blocks being processed increases, the number of RPC calls grows, potentially leading to rate limiting issues or increased costs if not properly managed. + +```mermaid +graph TD + subgraph Common Operations + A[Main] --> D[Process New Blocks] + end + + subgraph EVM Network Calls + B[Network Init] -->|net_version| D + D -->|eth_blockNumber| E[For every block in range] + E -->|eth_getBlockByNumber| G1[Process Block] + G1 -->|eth_getLogs| H[Get Block Logs] + H -->|Only when needed| J[Get Transaction Receipt] + J -->|eth_getTransactionReceipt| I[Complete] + end + + subgraph Stellar Network Calls + C[Network Init] -->|getNetwork| D + D -->|getLatestLedger| F[In batches of 200 blocks] + F -->|getLedgers| G2[Process Block] + G2 -->|For each monitored contract without ABI| M[Fetch Contract Spec] + M -->|getLedgerEntries| N[Get WASM Hash] + N -->|getLedgerEntries| O[Get WASM Code] + O --> G2 + G2 -->|In batches of 200| P[Fetch Block Data] + P -->|getTransactions| L1[Get Transactions] + P -->|getEvents| L2[Get Events] + L1 --> Q[Complete] + L2 --> Q + end +``` + +**EVM** + +* RPC Client initialization (per active network): `net_version` +* Fetching the latest block number (per cron iteration): `eth_blockNumber` +* Fetching block data (per block): `eth_getBlockByNumber` +* Fetching block logs (per block): `eth_getLogs` +* Fetching transaction receipt (only when needed): + * When monitor condition requires receipt-specific fields (e.g., `gas_used`) + * When monitoring transaction status and no logs are present to validate status + +**Stellar** + +* RPC Client initialization (per active network): `getNetwork` +* Fetching the latest ledger (per cron iteration): `getLatestLedger` +* Fetching ledger data (batched up to 200 in a single request): `getLedgers` +* During block filtering, for each monitored contract without an ABI in config: + * Fetching contract instance data: `getLedgerEntries` + * Fetching contract WASM code: `getLedgerEntries` +* Fetching transactions (batched up to 200 in a single request): `getTransactions` +* Fetching events (batched up to 200 in a single request): `getEvents` + +## Best Practices + +* Configure multiple private endpoints with appropriate weights +* Use geographically distributed endpoints when possible +* Monitor endpoint health and adjust weights as needed +* Set appropriate retry policies based on network characteristics + +## Troubleshooting + +### Common Issues + +* **429 Too Many Requests**: Increase the number of fallback URLs, adjust weights or reduce monitoring frequency +* **Connection Timeouts**: Check endpoint health and network connectivity +* **Invalid Responses**: Verify endpoint compatibility with your network type + +### Logging + +Enable debug logging for detailed transport information: + +```bash +RUST_LOG=debug +``` + +This will show: + +* Endpoint rotations +* Connection attempts +* Request/response details diff --git a/content/monitor/1.1.x/scripts.mdx b/content/monitor/1.1.x/scripts.mdx new file mode 100644 index 00000000..53b14e8e --- /dev/null +++ b/content/monitor/1.1.x/scripts.mdx @@ -0,0 +1,617 @@ +--- +title: Custom Scripts +--- + +OpenZeppelin Monitor allows you to implement custom scripts for additional filtering of monitor matches and custom notification handling. + + + +***Security Risk:*** Only run scripts that you trust and fully understand. Malicious scripts can harm your system or expose sensitive data. Always review script contents and verify their source before execution. + + +## Custom Filter Scripts + +Custom filter scripts allow you to apply additional conditions to matches detected by the monitor. This helps you refine the alerts you receive based on criteria specific to your use case. + +### Implementation Guide + +1. Create a script in one of the supported languages: + * Bash + * Python + * JavaScript +2. Your script will receive a JSON object with the following structure: + * EVM + + ```json + { + "args": ["--verbose"], + "monitor_match": { + "EVM": { + "matched_on": { + "events": [], + "functions": [ + { + "expression": null, + "signature": "transfer(address,uint256)" + } + ], + "transactions": [ + { + "expression": null, + "status": "Success" + } + ] + }, + "matched_on_args": { + "events": null, + "functions": [ + { + "args": [ + { + "indexed": false, + "kind": "address", + "name": "to", + "value": "0x94d953b148d4d7143028f397de3a65a1800f97b3" + }, + { + "indexed": false, + "kind": "uint256", + "name": "value", + "value": "434924400" + } + ], + "hex_signature": "a9059cbb", + "signature": "transfer(address,uint256)" + } + ] + }, + "monitor": { + "addresses": [ + { + "contract_spec": null, + "address": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48" + } + ], + "match_conditions": { + "events": [ + { + "expression": "value > 10000000000", + "signature": "Transfer(address,address,uint256)" + } + ], + "functions": [ + { + "expression": null, + "signature": "transfer(address,uint256)" + } + ], + "transactions": [ + { + "expression": null, + "status": "Success" + } + ] + }, + "name": "Large Transfer of USDC Token", + "networks": ["ethereum_mainnet"], + "paused": false, + "trigger_conditions": [ + { + "arguments": ["--verbose"], + "language": "Bash", + "script_path": "./config/filters/evm_filter_block_number.sh", + "timeout_ms": 1000 + } + ], + "triggers": ["evm_large_transfer_usdc_script"] + }, + "receipt": { + "blockHash": "0x...", + "blockNumber": "0x...", + "contractAddress": null, + "cumulativeGasUsed": "0x...", + "effectiveGasPrice": "0x...", + "from": "0x...", + "gasUsed": "0xb068", + "status": "0x1", + "to": "0x...", + "transactionHash": "0x...", + "transactionIndex": "0x1fc", + "type": "0x2" + }, + "logs": [ + { + "address": "0xd1f2586790a5bd6da1e443441df53af6ec213d83", + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x00000000000000000000000060af8cf92e5aa9ead4a592d657cd6debecfbc616", + "0x000000000000000000000000d1f2586790a5bd6da1e443441df53af6ec213d83" + ], + "data": "0x00000000000000000000000000000000000000000000106015728793d21f77ac", + "blockNumber": "0x1451aca", + "transactionHash": "0xa39d1b9b3edda74414bd6ffaf6596f8ea12cf0012fd9a930f71ed69df6ff34d0", + "transactionIndex": "0x0", + "blockHash": "0x9432868b7fc57e85f0435ca3047f6a76add86f804b3c1af85647520061e30f80", + "logIndex": "0x2", + "removed": false + }, + ], + "transaction": { + "accessList": [], + "blockHash": "0x...", + "blockNumber": "0x1506545", + "chainId": "0x1", + "from": "0x...", + "gas": "0x7a120", + "gasPrice": "0x...", + "hash": "0x...", + "maxFeePerGas": "0x...", + "maxPriorityFeePerGas": "0x...", + "nonce": "0x14779f", + "to": "0x...", + "transactionIndex": "0x...", + "type": "0x2", + "value": "0x0" + } + } + } + } + ``` + * Stellar + + ```json + { + "args": ["--verbose"], + "monitor_match": { + "Stellar": { + "monitor": { + "name": "Large Swap By Dex", + "networks": ["stellar_mainnet"], + "paused": false, + "addresses": [ + { + "address": "GCXYK...", + "contract_spec": null + } + ], + "match_conditions": { + "functions": [ + { + "signature": "swap(Address,U32,U32,U128,U128)", + "expression": "out_min > 1000000000" + } + ], + "events": [], + "transactions": [] + }, + "trigger_conditions": [ + { + "arguments": ["--verbose"], + "language": "Bash", + "script_path": "./config/filters/stellar_filter_block_number.sh", + "timeout_ms": 1000 + } + ], + "triggers": ["stellar_large_transfer_usdc_script"] + }, + "transaction": { + "status": "SUCCESS", + "txHash": "2b5a0c...", + "applicationOrder": 3, + "feeBump": false, + "envelopeXdr": "AAAAAA...", + "envelopeJson": { + "type": "ENVELOPE_TYPE_TX", + "tx": {/* transaction details */} + }, + "resultXdr": "AAAAAA...", + "resultJson": {/* result details */}, + "resultMetaXdr": "AAAAAA...", + "resultMetaJson": {/* metadata details */}, + "diagnosticEventsXdr": ["AAAAAA..."], + "diagnosticEventsJson": [{/* event details */}], + "ledger": 123456, + "createdAt": 1679644800, + "decoded": { + "envelope": {/* decoded envelope */}, + "result": {/* decoded result */}, + "meta": {/* decoded metadata */} + } + }, + "ledger": { + "hash": "abc1...", + "sequence": 123456, + "ledgerCloseTime": "2024-03-20T10:00:00Z", + "headerXdr": "AAAAAA...", + "headerJson": {/* header details */}, + "metadataXdr": "AAAAAA...", + "metadataJSON": {/* metadata details */} + }, + "matched_on": { + "functions": [ + { + "signature": "swap(Address,U32,U32,U128,U128)", + "expression": "out_min > 1000000000" + } + ], + "events": [], + "transactions": [] + }, + "matched_on_args": { + "functions": [], + "events": null + } + } + } + } + ``` + +### Script Output Requirements + +* Your script should print a boolean value indicating whether the match should be filtered. +* Print `true` if the match should be filtered out (not trigger an alert). +* Print `false` if the match should be processed (trigger an alert). +* Only the **last** printed line will be considered for evaluation. + +### Example Filter Script (Bash) + +```bash +#!/bin/bash + +main() { + # Read JSON input from stdin + input_json=$(cat) + + # Parse arguments from the input JSON and initialize verbose flag + verbose=false + args=$(echo "$input_json" | jq -r '.args[]? // empty') + if [ ! -z "$args" ]; then + while IFS= read -r arg; do + if [ "$arg" = "--verbose" ]; then + verbose=true + echo "Verbose mode enabled" + fi + done <<< "$args" + fi + + # Extract the monitor match data from the input + monitor_data=$(echo "$input_json" | jq -r '.monitor_match') + + if [ "$verbose" = true ]; then + echo "Input JSON received:" + fi + + # Extract blockNumber from the EVM receipt or transaction + block_number_hex=$(echo "$monitor_data" | jq -r '.EVM.transaction.blockNumber' || echo "") + + # Validate that block_number_hex is not empty + if [ -z "$block_number_hex" ]; then + echo "Invalid JSON or missing blockNumber" + echo "false" + exit 1 + fi + + # Remove 0x prefix if present and clean the string + block_number_hex=$(echo "$block_number_hex" | tr -d '\n' | tr -d ' ') + block_number_hex=${block_number_hex#0x} + + if [ "$verbose" = true ]; then + echo "Extracted block number (hex): $block_number_hex" + fi + + # Convert hex to decimal with error checking + if ! block_number=$(printf "%d" $((16#${block_number_hex})) 2>/dev/null); then + echo "Failed to convert hex to decimal" + echo "false" + exit 1 + fi + + if [ "$verbose" = true ]; then + echo "Converted block number (decimal): $block_number" + fi + + # Check if even or odd using modulo + is_even=$((block_number % 2)) + + if [ $is_even -eq 0 ]; then + echo "Block number $block_number is even" + echo "Verbose mode: $verbose" + echo "true" + exit 0 + else + echo "Block number $block_number is odd" + echo "Verbose mode: $verbose" + echo "false" + exit 0 + fi +} + +# Call main function +main +``` + +### Example Filter Script (JavaScript) + +```bash +#!/bin/bash + +try { + let inputData = ''; + // Read from stdin + process.stdin.on('data', chunk => { + inputData += chunk; + }); + + process.stdin.on('end', () => { + const data = JSON.parse(inputData); + const monitorMatch = data.monitor_match; + const args = data.args; + + // Extract block_number + let blockNumber = null; + if (monitorMatch.EVM) { + const hexBlock = monitorMatch.EVM.transaction?.blockNumber; + if (hexBlock) { + // Convert hex string to integer + blockNumber = parseInt(hexBlock, 16); + } + } + + if (blockNumber === null) { + console.log('false'); + return; + } + + const result = blockNumber % 2 === 0; + console.log(`Block number ${blockNumber} is ${result ? 'even' : 'odd'}`); + console.log(result.toString()); + }); +} catch (e) { + console.log(`Error processing input: ${e}`); + console.log('false'); +} + +``` + +### Example Filter Script (Python) + +```bash +#!/bin/bash + +import sys +import json + +def main(): + try: + # Read input from stdin + input_data = sys.stdin.read() + if not input_data: + print("No input JSON provided", flush=True) + return False + + # Parse input JSON + try: + data = json.loads(input_data) + monitor_match = data['monitor_match'] + args = data['args'] + except json.JSONDecodeError as e: + print(f"Invalid JSON input: {e}", flush=True) + return False + + # Extract block_number + block_number = None + if "EVM" in monitor_match: + hex_block = monitor_match['EVM']['transaction'].get('blockNumber') + if hex_block: + # Convert hex string to integer + block_number = int(hex_block, 16) + + if block_number is None: + print("Block number is None") + return False + + result = block_number % 2 == 0 + print(f"Block number {block_number} is {'even' if result else 'odd'}", flush=True) + return result + + except Exception as e: + print(f"Error processing input: {e}", flush=True) + return False + +if __name__ == "__main__": + result = main() + # Print the final boolean result + print(str(result).lower(), flush=True) + +``` + +This examples script filters EVM transactions based on their block number: + +* Returns `true` (filter out) for transactions in even-numbered blocks +* Returns `false` (allow) for transactions in odd-numbered blocks +* Accepts a `--verbose` flag for detailed logging +* Explore other examples in the [`examples/config/filters` directory](https://github.com/OpenZeppelin/openzeppelin-monitor/tree/main/examples/config/filters). + +### Integration + +Integrate your custom filter script with the monitor by following the [configuration guidelines](/monitor/1.1.x#trigger_conditions_custom_filters). + + + + +Trigger conditions are executed sequentially based on their position in the trigger conditions array. Every filter must return `false` for the match to be included and are only considered if they were executed successfully. + + + +## Custom Notification Scripts + +Custom notification scripts allow you to define how alerts are delivered when specific conditions are met. This can include sending alerts to different channels or formatting notifications in a particular way. + +### Implementation Guide + +1. Create a script in one of the supported languages: + * Bash + * Python + * JavaScript +2. Your script will receive the same JSON input format as [filter scripts](#implementation_guide) + +### Script Output Requirements + +* A non-zero exit code indicates an error occurred +* Error messages should be written to `stderr` +* A zero exit code indicates successful execution + +### Example Notification Script (Bash) + +```bash +#!/bin/bash + +main() { + # Read JSON input from stdin + input_json=$(cat) + + # Parse arguments from the input JSON and initialize verbose flag + verbose=false + args=$(echo "$input_json" | jq -r '.args[]? // empty') + if [ ! -z "$args" ]; then + while IFS= read -r arg; do + if [ "$arg" = "--verbose" ]; then + verbose=true + echo "Verbose mode enabled" + fi + done <<< "$args" + fi + + # Extract the monitor match data from the input + monitor_data=$(echo "$input_json" | jq -r '.monitor_match') + + # Validate input + if [ -z "$input_json" ]; then + echo "No input JSON provided" + exit 1 + fi + + # Validate JSON structure + if ! echo "$input_json" | jq . >/dev/null 2>&1; then + echo "Invalid JSON input" + exit 1 + fi + + if [ "$verbose" = true ]; then + echo "Input JSON received:" + echo "$input_json" | jq '.' + echo "Monitor match data:" + echo "$monitor_data" | jq '.' + fi + + # Process args if they exist + args_data=$(echo "$input_json" | jq -r '.args') + if [ "$args_data" != "null" ]; then + echo "Args: $args_data" + fi + + # If we made it here, everything worked + echo "Verbose mode: $verbose" + # return a non zero exit code and an error message + echo "Error: This is a test error" >&2 + exit 1 +} + +# Call main function +main +``` + +### Example Notification Script (JavaScript) + +```bash +#!/bin/bash + +try { + let inputData = ''; + // Read from stdin + process.stdin.on('data', chunk => { + inputData += chunk; + }); + + process.stdin.on('end', () => { + // Parse input JSON + const data = JSON.parse(inputData); + const monitorMatch = data.monitor_match; + const args = data.args; + + // Log args if they exist + if (args && args.length > 0) { + console.log(`Args: ${JSON.stringify(args)}`); + } + + // Validate monitor match data + if (!monitorMatch) { + console.log("No monitor match data provided"); + return; + } + }); +} catch (e) { + console.log(`Error processing input: ${e}`); +} + +``` + +### Example Notification Script (Python) + +```bash +#!/bin/bash + +import sys +import json + +def main(): + try: + # Read input from stdin + input_data = sys.stdin.read() + if not input_data: + print("No input JSON provided", flush=True) + + # Parse input JSON + try: + data = json.loads(input_data) + monitor_match = data['monitor_match'] + args = data['args'] + if args: + print(f"Args: {args}") + except json.JSONDecodeError as e: + print(f"Invalid JSON input: {e}", flush=True) + + + except Exception as e: + print(f"Error processing input: {e}", flush=True) + +if __name__ == "__main__": + main() + +``` + +This examples demonstrates how to: + +* Process the input JSON data +* Handle verbose mode for debugging +* Return error messages via `stderr` +* Set appropriate exit codes +* Explore other examples in the [`examples/config/triggers/scripts` directory](https://github.com/OpenZeppelin/openzeppelin-monitor/tree/main/examples/config/triggers/scripts). + +### Integration + +Integrate your custom notification script with the triggers by following the [configuration guidelines](/monitor/1.1.x#custom_script_notifications). + +## Performance Considerations + +* **File descriptor limits**: Each script execution requires file descriptors for `stdin`, `stdout`, and `stderr` + * Ensure your system allows at least 2,048 open file descriptors + * Check your current limit on Unix-based systems with `ulimit -n` + * Temporarily increase the limit with `ulimit -n 2048` + * For permanent changes, modify `/etc/security/limits.conf` or equivalent for your system +* **Script timeout**: Configure appropriate timeout values in your trigger conditions to prevent long-running scripts from blocking the pipeline + * The `timeout_ms` parameter controls how long a script can run before being terminated +* **Resource usage**: Complex scripts may consume significant CPU or memory resources + * Consider optimizing resource-intensive operations in your scripts + * Monitor system performance during high-volume periods +* **Script reloading**: Since scripts are loaded at startup, any modifications to script files require restarting the monitor to take effect diff --git a/content/monitor/1.1.x/testing.mdx b/content/monitor/1.1.x/testing.mdx new file mode 100644 index 00000000..7f822d16 --- /dev/null +++ b/content/monitor/1.1.x/testing.mdx @@ -0,0 +1,127 @@ +--- +title: Testing Guide +--- + +This document provides information about testing OpenZeppelin Monitor, including running tests, generating coverage reports, and understanding the test structure. + +## Test Organization + +The project includes comprehensive test suites organized into different categories: + +### Test Types + +* ***Unit Tests***: Located within `src/` modules alongside the code they test +* ***Integration Tests***: Located in `tests/integration/` directory +* ***Property-based Tests***: Located in `tests/properties/` directory +* ***Mock Implementations***: Located in `tests/integration/mocks/` + +### Test Structure + +``` +tests/ +β”œβ”€β”€ integration/ # Integration tests +β”‚ β”œβ”€β”€ blockchain/ # Blockchain client tests +β”‚ β”œβ”€β”€ blockwatcher/ # Block monitoring tests +β”‚ β”œβ”€β”€ filters/ # Filter logic tests +β”‚ β”œβ”€β”€ fixtures/ # Test data and configurations +β”‚ β”œβ”€β”€ mocks/ # Mock implementations +β”‚ └── ... +β”œβ”€β”€ properties/ # Property-based tests +β”‚ β”œβ”€β”€ filters/ # Filter property tests +β”‚ β”œβ”€β”€ notifications/ # Notification property tests +β”‚ └── ... +└── integration.rs # Integration test entry point +``` + +## Running Tests + +### All Tests + +Run the complete test suite: + +```bash +RUST_TEST_THREADS=1 cargo test +``` + + + + +`RUST_TEST_THREADS=1` is required to prevent test conflicts when accessing shared resources like configuration files or network connections. + + + +### Specific Test Categories + +***Property-based Tests:*** +```bash +RUST_TEST_THREADS=1 cargo test properties +``` + +***Integration Tests:*** +```bash +RUST_TEST_THREADS=1 cargo test integration +``` + +***Unit Tests Only:*** +```bash +RUST_TEST_THREADS=1 cargo test --lib +``` + +## Coverage Reports + +### Prerequisites + +Install the coverage tool: +```bash +rustup component add llvm-tools-preview +cargo install cargo-llvm-cov +``` + +### Generating Coverage + +***HTML Coverage Report:*** +```bash +RUST_TEST_THREADS=1 cargo +stable llvm-cov --html --open +``` + +This generates an HTML report in `target/llvm-cov/html/` and opens it in your browser. + +***Terminal Coverage Report:*** +```bash +RUST_TEST_THREADS=1 cargo +stable llvm-cov +``` + +## Troubleshooting + +### Common Issues + +***Tests hanging or timing out:*** +- Ensure `RUST_TEST_THREADS=1` is set +- Verify mock setups are correct + +***Coverage tool not found:*** +- Install with `cargo install cargo-llvm-cov` +- Add component with `rustup component add llvm-tools-preview` + +***Permission errors:*** +- Ensure test directories are writable +- Check file permissions on test fixtures + +### Debug Output + +Enable debug logging for tests: +```bash +RUST_LOG=debug RUST_TEST_THREADS=1 cargo test -- --nocapture +``` + +## Contributing Tests + +When contributing new features: + +1. ***Add comprehensive tests*** for new functionality +2. ***Ensure all tests pass*** locally before submitting +3. ***Include both unit and integration tests*** where appropriate +4. ***Update test documentation*** if adding new test patterns +5. ***Maintain or improve code coverage*** + +For more information about contributing, see the project’s contributing guidelines. diff --git a/content/monitor/architecture.mdx b/content/monitor/architecture.mdx index 8dd1aec0..65e5aa3b 100644 --- a/content/monitor/architecture.mdx +++ b/content/monitor/architecture.mdx @@ -13,6 +13,14 @@ OpenZeppelin Monitor is organized as a data processing pipeline that spans from The diagram below shows the core processing pipeline of OpenZeppelin Monitor, from blockchain networks and configuration through to notification channels: ```mermaid +%%{init: { + 'theme': 'base', + 'themeVariables': { + 'background': '#ffffff', + 'mainBkg': '#ffffff', + 'primaryBorderColor': '#cccccc' + } +}}%% flowchart LR subgraph "Blockchain Networks" EVMN["EVM Networks"] @@ -72,6 +80,14 @@ The system consists of several core services that are initialized at startup and ### Service Initialization Flow ```mermaid +%%{init: { + 'theme': 'base', + 'themeVariables': { + 'background': '#ffffff', + 'mainBkg': '#ffffff', + 'primaryBorderColor': '#cccccc' + } +}}%% graph TD subgraph Entry Point MAIN[main.rs] @@ -195,6 +211,14 @@ The following table describes the key responsibilities of each service in the Op The following _runtime flow_ illustrates how data moves through the system, from blockchain networks to notification channels. This sequence represents the core monitoring loop that executes for each configured network. ```mermaid +%%{init: { + 'theme': 'base', + 'themeVariables': { + 'background': '#ffffff', + 'mainBkg': '#ffffff', + 'primaryBorderColor': '#cccccc' + } +}}%% sequenceDiagram participant BWS as BlockWatcherService participant BS as BlockStorage @@ -316,7 +340,7 @@ The system implements comprehensive validation: -For configuration examples and best practices, see the [Configuration Guidelines](/monitor#configuration-guidelines) section in the user documentation. +For configuration examples and best practices, see the [Configuration Guidelines](#configuration-guidelines) section in the user documentation. ## Extensibility Points @@ -359,4 +383,4 @@ For detailed information about the project structure, source code organization, For information about RPC logic and network communication, see the [RPC section](/monitor/rpc). -For configuration examples and best practices, see the [Configuration Guidelines](/monitor#configuration-guidelines) section in the user documentation. +For configuration examples and best practices, see the [Configuration Guidelines](#configuration-guidelines) section in the user documentation. diff --git a/content/monitor/changelog.mdx b/content/monitor/changelog.mdx index 24825b59..276fa8ad 100644 --- a/content/monitor/changelog.mdx +++ b/content/monitor/changelog.mdx @@ -2,6 +2,89 @@ title: Changelog --- + +# [v1.1.0](https://github.com/OpenZeppelin/openzeppelin-monitor/releases/tag/v1.1.0) - 2025-10-22 + +## [1.1.0](https://github.com/OpenZeppelin/openzeppelin-monitor/compare/v1.0.0...v1.1.0) (2025-10-22) + + +### πŸš€ Features + +* add block tracker ([#11](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/11)) ([1d4d117](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/1d4d117aab56e2c31c0747d6bf681fe60b2d8b10)) +* Add CLA assistant bot ([#107](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/107)) ([47e490e](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/47e490e4a5657a48bc60f85c38d72aca16334ac0)) +* Add client rpc pool ([#75](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/75)) ([28cd940](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/28cd940a8aea5c97fb15a4ca0d415debaa2864b1)) +* add email support ([#7](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/7)) ([decb56d](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/decb56d45d3f1000346c24e137d1a5d952c4a9dd)) +* Add endpoint rotation manager ([#69](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/69)) ([454a630](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/454a630cf92c305ea5d9254b211a7b60abf8804d)) +* Add environment vars and Hashicorp cloud vault support (breaking) ([#199](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/199)) ([558304f](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/558304f335a645c1de2d348a041337ccba2c2a06)) +* Add events and functions summary in notifications ([#339](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/339)) ([000ae24](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/000ae24e896cd0867c6252111a71151942d820bc)) +* Add new error context ([#77](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/77)) ([612bb76](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/612bb76b9c8e9a470fc68685c2f06481663a9474)) +* Add rc workflow file ([#156](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/156)) ([8907591](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/890759186570a64a9d0b0ef4dc9e512d0110d7a0)) +* Add support for webhook, telegram, discord notifications ([#65](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/65)) ([829967d](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/829967da45062dc22ffb0cb3376e68101a46b3e9)) +* Enhance filter expression parsing and evaluation ([#222](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/222)) ([3cb0849](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/3cb084919b3d477f329a85fbafce1ce6d696b16d)) +* Extend support for EVM transaction properties ([#187](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/187)) ([f20086b](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/f20086b0431a787dd55aa8928a09aece80b9a731)) +* Handle Stellar JSON-RPC outside of retention window error for `getTransactions` and `getEvents` ([#270](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/270)) ([ae116ff](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/ae116ff10f393a04c19d3b845df656027c6be4b9)) +* Implement client pooling for Webhook-based notifiers ([#281](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/281)) ([4f480c6](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/4f480c6a05aeb949cfd8e227c5c08f19a5e60180)) +* Introduce `TransportError` ([#259](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/259)) ([0e04cfb](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/0e04cfb57109251095ef8ee526fb5e05f5792792)) +* Introduce centralized retryable HTTP client creation ([#273](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/273)) ([5f6edaf](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/5f6edaf5deb77a5d9dfead52a162e923aad6a2ab)) +* Introduce retry mechanism for Email notifier ([#282](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/282)) ([b6301aa](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/b6301aaac963ae904d93e07674d9d01543ecfcd0)) +* Leverage contract spec (SEP-48) for Stellar functions (breaking) ([#208](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/208)) ([5ebc2a4](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/5ebc2a441b9ac6ed66a0807cac2795af2ae5b1c8)) +* Markdown for telegram, discord, slack and email ([#197](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/197)) ([791bf4b](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/791bf4b347d8cfe03ccd53e9797f179c15629a33)) +* Plat 6187 write metrics to prometheus ([#95](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/95)) ([2dc08d5](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/2dc08d51670834f453498299937debfca67fa1b7)) +* PLAT-6148 Adding post filter to monitor model ([#58](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/58)) ([920a0bf](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/920a0bf27953b67eb722d17d5ebf50b51237d4d4)) +* PLAT-6151 Integrate custom script execution with notification service ([#79](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/79)) ([bd5f218](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/bd5f218507dfc30bd4b2182077e2997cf04b8877)) +* PLAT-6477 Adding rust toolchain file ([#117](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/117)) ([ea6fb1e](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/ea6fb1ee6bba46cfa66a0c81665e17930bbbed93)) +* Separate code test coverage into different categories of tests ([#84](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/84)) ([a3ad89c](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/a3ad89cdcf0bab5883af7ec36b854fedc2f060cd)) +* spawn block-watcher per network ([#4](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/4)) ([d7a19ec](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/d7a19ec57344e4fb28dffc6f2025e809d0f5d946)) +* Test execute the monitor against specific block ([#133](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/133)) ([563c34f](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/563c34fde3c0f334a7c5884de5510bf27e4fca48)) +* Update payload builder to support formatted titles ([#336](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/336)) ([12213b3](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/12213b32d609bf6a1ba69ce548f70809971f9fb3)) +* Upgrade stellar crates and read events from specs ([#371](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/371)) ([7273a3f](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/7273a3f8d9249692db6b6ca53f4d8b28b21670f4)) + + +### πŸ› Bug Fixes + +* Add thread flag when running tests in CI ([#41](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/41)) ([4312669](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/4312669d8da84f5cf7e7817b10c377fe3a6992af)) +* Adding validation for unknown field names ([#223](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/223)) ([cadf4da](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/cadf4dac293e2c24a02a2eb188540e1eb312b75f)) +* Adjust netlify toml settings ([#47](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/47)) ([af9fe55](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/af9fe553a92cfc47a306a7dcfc43be0b2257f835)) +* Bump MSRV ([#291](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/291)) ([f2d7953](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/f2d795310cd1417ad2fac854ea5f80cf6296b761)) +* CLA labels and assistant ([#176](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/176)) ([b14f060](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/b14f0600dc4cac5a5f00d3772328abe123114b2a)) +* correct env var value in semgrep.yml ([#317](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/317)) ([7a8253f](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/7a8253fd23ae27c73b3971e2a688c39051c08a84)) +* Deprecate Stellar `paging_token` in `GetEvents` response ([#344](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/344)) ([68d20f9](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/68d20f91b643ef3a7c85ee897308d4f92d43698b)) +* Docs link ([#106](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/106)) ([f12d95d](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/f12d95d85ad9230bece0342c39cb5c3c1cd62832)) +* Docs pipeline ([#167](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/167)) ([1e78ec4](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/1e78ec4f98f70ac12dea353c1605ac4ac2c5734b)) +* Documentation name for antora ([#105](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/105)) ([5a8c4bd](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/5a8c4bd8315e62bb2dedb066f6b6bfcaa09c2d37)) +* Duplicate name in triggers config ([#274](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/274)) ([00f58f4](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/00f58f4be3f9452792f9fdcf5dd8696947a274cb)) +* Environment adjustments and cargo lock file improvements ([#219](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/219)) ([1b4d5d8](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/1b4d5d8dbe8cba26fbb84a8f847fc22b1a1dc096)) +* Event and function signatures from matched_on ([#198](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/198)) ([cdd9f1d](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/cdd9f1d7333ee2f3ef9c476a08e918388b3c35f0)) +* Fix cargo lock ([#110](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/110)) ([c440ca4](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/c440ca43542e919cd473a7d533b0820cf5474d3e)) +* Fix cargo lock file ([#116](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/116)) ([1bd3658](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/1bd3658ab507c2dde90a2132b6eaec6d849e0e3c)) +* Fix the codecov yaml syntax ([#97](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/97)) ([fcafcbf](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/fcafcbf5765014a65c3f2c8718ee0f24a4531ebe)) +* fixed check ([1d36aaa](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/1d36aaa63ca12b4a660ec7e7bfcb18f722d8adf2)) +* Generate SBOM step in release pipeline ([#294](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/294)) ([327269d](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/327269d1ce2a16e9c8419e872ca02503c318c480)) +* Linter ([b0e27ca](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/b0e27ca21f8e39b3a3c16d356df00dfcd0a868e5)) +* Monitor match template var signature collission (breaking) ([#203](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/203)) ([283b724](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/283b724a88f45f82c3c5fc81742a564b70909d45)) +* Multi arch. docker images and binary mismatch ([#382](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/382)) ([a61701e](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/a61701e11a13af03cdf86689b58e670b7d984a38)) +* Pagination logic in stellar getEvents relies only on cursor data ([#265](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/265)) ([fca4057](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/fca4057ff5847e04981e5903eebe6ccf3931726c)) +* PLAT-6301 Remove logic for checking file descriptors open and fixing readme ([#90](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/90)) ([71dbd24](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/71dbd24a9ba5ab4c37cf4be432a4614c2e68166b)) +* Reduce USDC ABI and fix trailing comma ([#62](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/62)) ([92e343c](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/92e343c09dc2da565912b6cd5bc83fbdc591cdb5)) +* Release binaries and enable nightly workflows to create binary artifacts and images ([#313](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/313)) ([43a0091](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/43a0091ed7b57a4ca33ca25a73423a73929802f7)) +* Remove deprecated reviewers field from dependabot.yml ([#316](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/316)) ([152843d](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/152843df396b089e1c6054221206097339502f1b)) +* remove the create-github-app-token action from the scorecard workflow ([#174](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/174)) ([48ca0b1](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/48ca0b106dbee225b5d4824013c2a28b773b23b3)) +* rename docker binaries ([#2](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/2)) ([78d438a](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/78d438a1ca4931651d3ca106c5dbda1ea1357574)) +* rename import ([#6](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/6)) ([745e591](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/745e591faba06f557b2f6a091434250ed559df6e)) +* Replace automatic minor version bumps ([#285](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/285)) ([0c9e14a](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/0c9e14a542cae2d2c7ff580ff7de28b0d9aab22a)) +* Risk of key collision for monitor custom scripts ([#258](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/258)) ([2aa4cd7](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/2aa4cd730dbcbbd1cf0892394cedc4ea06332375)) +* Running duplicate tests ([#181](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/181)) ([ad0f741](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/ad0f741608b2719a1db16dd22bf8c457e5814f86)) +* Semgrep CI integration ([#315](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/315)) ([a2bc23b](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/a2bc23baa27630ba914fca12ac40b191cbbad525)) +* Stellar ledgers are deterministic ([#257](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/257)) ([56a9f9e](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/56a9f9e10e533ea96c01cb1f0f67024600ad89df)) +* syntax error in codeql.yml ([#322](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/322)) ([7068e9e](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/7068e9ee3845a007ed9d6c80157cbe86555ad14e)) +* trigger execution order ([#24](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/24)) ([26581fe](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/26581fec9ec1078ea4284fd6b43509616c66ad64)) +* Update the Semgrep config ([#306](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/306)) ([d4ed740](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/d4ed7405e790098a0b1a0df3701feccb1908c56c)) +* Use unicode character for emoji ([#295](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/295)) ([bdccda5](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/bdccda5f2ca72612a4455a293c30647618476f95)) +* Variable resolving ([#49](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/49)) ([e26d173](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/e26d17314e9b2e78c0772a46f3139da70c6ca144)) + +[Changes][v1.1.0] + + # [v1.0.0](https://github.com/OpenZeppelin/openzeppelin-monitor/releases/tag/v1.0.0) - 2025-06-30 @@ -106,7 +189,7 @@ title: Changelog } ] ``` - + * Webhook URLs: ``` @@ -211,6 +294,7 @@ title: Changelog [Changes][v0.1.0] +[v1.1.0]: https://github.com/OpenZeppelin/openzeppelin-monitor/compare/v1.0.0...v1.1.0 [v1.0.0]: https://github.com/OpenZeppelin/openzeppelin-monitor/compare/v0.2.0...v1.0.0 [v0.2.0]: https://github.com/OpenZeppelin/openzeppelin-monitor/compare/v0.1.0...v0.2.0 [v0.1.0]: https://github.com/OpenZeppelin/openzeppelin-monitor/tree/v0.1.0 diff --git a/content/monitor/contribution.mdx b/content/monitor/contribution.mdx index 6cf79cb0..08416ea1 100644 --- a/content/monitor/contribution.mdx +++ b/content/monitor/contribution.mdx @@ -41,6 +41,38 @@ Before contributing, ensure you have: * ***Git*** - For version control * ***Python/pip*** - For pre-commit hooks +### System Dependencies (Linux) + +For Ubuntu 22.04+ or Debian-based systems (both x86 and ARM64 architectures), install required packages: + +***Note:*** Python 3.9+ is required for pre-commit hooks compatibility. + +```bash +# Install required packages directly +sudo apt update +sudo apt install -y \ + build-essential \ + curl \ + git \ + pkg-config \ + libssl-dev \ + libffi-dev \ + libyaml-dev \ + python3 \ + python3-venv \ + python3-pip +``` + +Or use the provided system package script (automatically ensures Python 3.9+ compatibility): + +```bash +chmod +x ./scripts/linux/sys_pkgs_core.sh +chmod +x ./scripts/linux/sys_pkgs_dev.sh +# Installs required packages and ensures compatible Python version +./scripts/linux/sys_pkgs_core.sh // For runtime dependencies only +./scripts/linux/sys_pkgs_dev.sh // For Python/dev dependencies (calls core script) +``` + ### Initial Setup ```bash @@ -110,7 +142,7 @@ The pre-commit hooks will automatically run on every commit and push, checking f ```bash # Set up your working directory -export working_dir="$HOME/repos" +export working_dir="${HOME}/repos" export user= # Clone your fork diff --git a/content/monitor/error.mdx b/content/monitor/error.mdx index 3b9c1dab..0bc23a81 100644 --- a/content/monitor/error.mdx +++ b/content/monitor/error.mdx @@ -14,13 +14,13 @@ Let’s follow how an error propagates through our blockchain monitoring system: ```rust // Creates basic errors with specific context -async fn send_raw_request(...) -> Result +async fn send_raw_request(...) -> Result { let response = client.post(...) .await - .map_err(|e| anyhow::anyhow!("Failed to send request: {", e))?; + .map_err(|e| anyhow::anyhow!("Failed to send request: {}", e))?; - if !status.is_success() - return Err(anyhow::anyhow!("HTTP error {: {}", status, error_body)); + if !status.is_success() { + return Err(anyhow::anyhow!("HTTP error {}: {}", status, error_body)); } } ``` @@ -29,15 +29,15 @@ async fn send_raw_request(...) -> Result ```rust // Adds business context to low-level errors -async fn get_transaction_receipt(...) -> Result +async fn get_transaction_receipt(...) -> Result { let response = self.alloy_client .send_raw_request(...) .await - .with_context(|| format!("Failed to get transaction receipt: {", tx_hash))?; + .with_context(|| format!("Failed to get transaction receipt: {}", tx_hash))?; - if receipt_data.is_null() + if receipt_data.is_null() { return Err(anyhow::anyhow!("Transaction receipt not found")); - + } } ``` @@ -45,12 +45,12 @@ async fn get_transaction_receipt(...) -> Result Result, FilterError> +async fn filter_block(...) -> Result, FilterError> { let receipts = match futures::future::join_all(receipt_futures).await { Ok(receipts) => receipts, Err(e) => { return Err(FilterError::network_error( - format!("Failed to get transaction receipts for block {", block_num), + format!("Failed to get transaction receipts for block {}", block_num), Some(e.into()), None, )); @@ -67,7 +67,7 @@ ERROR filter_block: openzeppelin_monitor::utils::error: Error occurred, error.trace_id: a464d73c-5992-4cb5-a002-c8d705bfef8d, error.timestamp: 2025-03-14T09:42:03.412341+00:00, error.chain: Failed to get receipt for transaction 0x7722194b65953085fe1e9ec01003f1d7bdd6258a0ea5c91a59da80419513d95d - Caused by: HTTP error 429 Too Many Requests: "code":-32007,"message":"[Exceeded request limit per second]" + Caused by: HTTP error 429 Too Many Requests: {"code":-32007,"message":"[Exceeded request limit per second]"} network: ethereum_mainnet ``` @@ -77,7 +77,7 @@ ERROR filter_block: openzeppelin_monitor::utils::error: Error occurred, Every error in our system includes detailed context information: ```rust -pub struct ErrorContext +pub struct ErrorContext { /// The error message pub message: String, /// The source error (if any) @@ -88,7 +88,7 @@ pub struct ErrorContext pub timestamp: DateTime, /// Optional key-value metadata pub metadata: HashMap, - +} ``` ### Domain-Specific Error Types @@ -154,8 +154,8 @@ async fn filter_block( _network: &Network, block: &BlockType, monitors: &[Monitor], -) -> Result, FilterError> - tracing::debug!("Processing block {", block_number); +) -> Result, FilterError> { + tracing::debug!("Processing block {}", block_number); // ... } ``` diff --git a/content/monitor/index.mdx b/content/monitor/index.mdx index cee8fe97..9078ae07 100644 --- a/content/monitor/index.mdx +++ b/content/monitor/index.mdx @@ -29,10 +29,12 @@ In the rapidly evolving world of blockchain technology, effective monitoring is * ***Webhooks*** - Send HTTP requests to custom endpoints * ***Custom Scripts*** - Execute Python, JavaScript, or Bash scripts + To get started immediately, see [Quickstart](/monitor/quickstart). + ## Installation @@ -41,6 +43,38 @@ To get started immediately, see [Quickstart](/monitor/quickstart). * Use ***Rust 2021 edition***, version `1.86` or later. * ***Docker*** (optional, for containerized deployment) +#### System Dependencies (Linux) + +For Ubuntu 22.04+ or Debian-based systems (both x86 and ARM64 architectures), install required packages: + +***Note:*** Python 3.9+ is required for pre-commit hooks compatibility. + +```bash +# Install required packages directly +sudo apt update +sudo apt install -y \ + build-essential \ + curl \ + git \ + pkg-config \ + libssl-dev \ + libffi-dev \ + libyaml-dev \ + python3 \ + python3-venv \ + python3-pip +``` + +Or use the provided system package script (automatically ensures Python 3.9+ compatibility): + +```bash +chmod +x ./scripts/linux/sys_pkgs_core.sh +chmod +x ./scripts/linux/sys_pkgs_dev.sh +# Installs required packages and ensures compatible Python version +./scripts/linux/sys_pkgs_core.sh // For runtime dependencies only +./scripts/linux/sys_pkgs_dev.sh // For Python/dev dependencies (calls core script) +``` + ### Local Installation 1. ***Clone the repository:*** @@ -160,6 +194,7 @@ By default, predefined metrics within a dashboard is populated in grafana. "triggers": ["large_transfer_slack"], ... } + ``` @@ -465,8 +500,8 @@ A Trigger defines actions to take when monitored conditions are met. Triggers ca "value": "https://hooks.slack.com/services/A/B/C" }, "message": { - "title": "large_transfer_slack triggered", - "body": "Large transfer of ${events.0.args.value} USDC from $events.0.args.from to $events.0.args.to | https://etherscan.io/tx/$transaction.hash#eventlog" + "title": "${monitor.name} triggered", + "body": "Large transfer of ${events.0.args.value} USDC from ${events.0.args.from} to ${events.0.args.to} | https://etherscan.io/tx/${transaction.hash}#eventlog" } } }, @@ -480,7 +515,7 @@ A Trigger defines actions to take when monitored conditions are met. Triggers ca }, "message": { "title": "large_transfer_usdc_slack triggered", - "body": "${monitor.name} triggered because of a large transfer of $functions.0.args.amount USDC to $functions.0.args.to | https://stellar.expert/explorer/testnet/tx/$transaction.hash" + "body": "${monitor.name} triggered because of a large transfer of ${functions.0.args.amount} USDC to ${functions.0.args.to} | https://stellar.expert/explorer/testnet/tx/${transaction.hash}" } } } @@ -528,7 +563,7 @@ A Trigger defines actions to take when monitored conditions are met. Triggers ca }, "message": { "title": "Alert Subject", - "body": "Alert message for ${transaction.hash}" + "body": "Alert message for ${transaction.hash}", }, "sender": "sender@example.com", "recipients": ["recipient@example.com"] @@ -674,8 +709,8 @@ The monitor uses a structured JSON format with nested objects for template varia | --- | --- | | `**monitor.name**` | Name of the triggered monitor | | `**transaction.hash**` | Hash of the transaction | -| `**functions.[index].signature**` | Function signature | -| `**events.[index].signature**` | Event signature | +| `**functions**` | All functions matched and their parameters | +| `**events**` | All events matched and their parameters | ##### Network-Specific Variables @@ -685,19 +720,24 @@ The monitor uses a structured JSON format with nested objects for template varia | `**transaction.from**` | Sender address | | `**transaction.to**` | Recipient address | | `**transaction.value**` | Transaction value | +| `**events.[index].signature**` | Event signature | | `**events.[index].args.[param]**` | Event parameters by name | +| `**functions.[index].signature**` | Function signature | | `**functions.[index].args.[param]**` | Function parameters by name | ###### Stellar Variables | **Variable** | **Description** | | --- | --- | | `**events.[index].args.[position]**` | Event parameters by position | +| `**events.[index].args.[param]**` | Event parameters by name (only in case the contract supports event parameters name) | | `**functions.[index].args.[param]**` | Function parameters by name | + Transaction-related variables (`transaction.from`, `transaction.to`, `transaction.value`) are not available for Stellar networks. + #### Message Formatting @@ -716,7 +756,7 @@ Slack, Discord, Telegram, Email and Webhook support Markdown formatting in their "password": {"type": "plain", "value": "password"}, "message": { "title": "**High Value Transfer Alert**", - "body": "### Transaction Details\n\n* **Amount:** ${events.0.args.value} USDC\n* **From:** `$events.0.args.from`\n* **To:** `$events.0.args.to`\n\n> Transaction Hash: $transaction.hash\n\n[View on Explorer](https://etherscan.io/tx/$transaction.hash)" + "body": "### Transaction Details\n\n* **Amount:** ${events.0.args.value} USDC\n* **From:** `${events.0.args.from}`\n* **To:** `${events.0.args.to}`\n\n> Transaction Hash: ${transaction.hash}\n\n[View on Explorer](https://etherscan.io/tx/${transaction.hash})" }, "sender": "alerts@example.com", "recipients": ["recipient@example.com"] @@ -735,7 +775,7 @@ Slack, Discord, Telegram, Email and Webhook support Markdown formatting in their "slack_url": {"type": "plain", "value": "https://hooks.slack.com/services/XXX/YYY/ZZZ"}, "message": { "title": "*🚨 High Value Transfer Alert*", - "body": "*Transaction Details*\n\nβ€’ *Amount:* `${events.0.args.value}` USDC\nβ€’ *From:* `$events.0.args.from`\nβ€’ *To:* `$events.0.args.to`\n\n>Transaction Hash: `$transaction.hash`\n\n" + "body": "*Transaction Details*\n\nβ€’ *Amount:* `${events.0.args.value}` USDC\nβ€’ *From:* `${events.0.args.from}`\nβ€’ *To:* `${events.0.args.to}`\n\n>Transaction Hash: `${transaction.hash}`\n\n" } } } @@ -752,7 +792,7 @@ Slack, Discord, Telegram, Email and Webhook support Markdown formatting in their "discord_url": {"type": "plain", "value": "https://discord.com/api/webhooks/XXX/YYY"}, "message": { "title": "**🚨 High Value Transfer Alert**", - "body": "# Transaction Details\n\n* **Amount:** `${events.0.args.value}` USDC\n* **From:** `$events.0.args.from`\n* **To:** `$events.0.args.to`\n\n>>> Transaction Hash: `$transaction.hash`\n\n**[View on Explorer](https://etherscan.io/tx/$transaction.hash)" + "body": "# Transaction Details\n\n* **Amount:** `${events.0.args.value}` USDC\n* **From:** `${events.0.args.from}`\n* **To:** `${events.0.args.to}`\n\n>>> Transaction Hash: `${transaction.hash}`\n\n**[View on Explorer](https://etherscan.io/tx/${transaction.hash})" } } } @@ -770,7 +810,7 @@ Slack, Discord, Telegram, Email and Webhook support Markdown formatting in their "chat_id": "9876543210", "message": { "title": "*🚨 High Value Transfer Alert*", - "body": "*Transaction Details*\n\nβ€’ *Amount:* `${events.0.args.value}` USDC\nβ€’ *From:* `$events.0.args.from`\nβ€’ *To:* `$events.0.args.to`\n\n`Transaction Hash: $transaction.hash`\n\n[View on Explorer](https://etherscan.io/tx/$transaction.hash)" + "body": "*Transaction Details*\n\nβ€’ *Amount:* `${events.0.args.value}` USDC\nβ€’ *From:* `${events.0.args.from}`\nβ€’ *To:* `${events.0.args.to}`\n\n`Transaction Hash: ${transaction.hash}`\n\n[View on Explorer](https://etherscan.io/tx/${transaction.hash})" } } } @@ -834,7 +874,7 @@ A Monitor defines what blockchain activity to watch and what actions to take whe { "script_path": "./config/filters/evm_filter_block_number.sh", "language": "bash", - "arguments": ["--verbose"], + "arguments": "--verbose", "timeout_ms": 1000 } ], @@ -949,6 +989,7 @@ Expressions allow for condition checking of function arguments, event parameters | `**Array (EVM/Stellar)**` | Ordered list of items. For Stellar, often a JSON string in config (e.g., ’["a", "id":1]'`). For EVM, typically decoded from ABI parameters. | `contains`, `==`, `!=`, `[index]` | Detailed operations, including indexed access and behavior of `contains`, vary by network. See "Operations on Complex Types" below. | | `**Object/Map (Stellar)**` | Key-value pairs, typically represented as a JSON string in config (e.g., ’"key": "value", "id": 123'`). | `.key_access`, `==`, `!=` | Supports dot notation for field access (e.g., `data.id`). See "Operations on Complex Types" for details. | | `**Vec (Stellar)**` | Ordered list, where the parameter’s value can be a CSV string (e.g., `"foo,bar"`) or a JSON array string (e.g., ’["foo","bar"]'`). | `contains`, `==`, `!=` | Behavior of `contains` and `==` differs based on whether the value is CSV or a JSON array string. See "Operations on Complex Types" for details. | +| `**Tuple (EVM)**` | Ordered list represented as a JSON array string (e.g., ’["Alice", 0x1234..., 25, true, [12,34]]'`). | `contains`, `==`, `!=` | The `contains` operation performs a case-insensitive deep search through all tuple elements. `==` and `!=` perform comparisons against the entire tuple values. See "Operations on Complex Types" for details. | **Logical Operators:** @@ -1033,6 +1074,27 @@ When an EVM parameter is an array (often represented internally or configured wi * `array_param != '["raw_json_array_string"]'` the negation of the above * `array_param[0]` indexed access +**Tuple Operations (`kind: "tuple"`)** + +* `tuple_param contains 'value'` checks if the string ’value'` exists within the tuple. +* `tuple_param == (12, "hello", "testing", 34)` checks if the tuple is equal. +* `tuple_param != (12, "hello", "testing", 34)` checks if the tuple is not equal. + +Where `tuple_param` is the name of tuple param (we should have only one param for tuples). + +**Note on Solidity Structs:** When working with Solidity smart contracts, struct types are automatically converted to tuples during ABI encoding/decoding. For example, a Solidity struct like: + +```solidity +struct User { + uint256 id; + string name; + string email; + uint256 age; +} +``` + +Will be represented as a tuple `**(12, "user_name", "user_email", 34)**` where the values correspond to the struct fields in their declaration order. This conversion is handled transparently by the Solidity compiler and Web3 libraries, allowing you to use the tuple operations above to work with struct data returned from smart contract calls. + ##### Stellar Specifics **Object (`kind: "object"`) / Map (`kind: "Map"`) Operations** @@ -1060,7 +1122,23 @@ When a Stellar parameter has `kind: "vec"`, its value can be either a CSV string **Event Parameter Access (Stellar)** -Stellar event parameters are typically accessed by their numeric index as the base variable name (e.g., `0`, `1`, `2`). If an indexed event parameter is itself a complex type (like an array or map, represented as a JSON string), you can then apply the respective access methods: +Starting with Stellar Protocol 23, Soroban contracts can include event definitions in their contract specifications. This enables two ways to access event parameters: + +**Access by Name (Protocol 23+):** +When a contract specification includes event definitions, you can access event parameters by their defined names: + +* If an event has a parameter named `recipient` (kind: "Address"): + * `recipient == 'GBBD...ABCD'` +* If an event has a parameter named `amount` (kind: "U128"): + * `amount > 1000000` +* If an event has a parameter named `metadata` (kind: "Map") containing ’"id": 123, "name": "Test"'`: + * `metadata.id == 123` + * `metadata.name contains 'test'` (case-insensitive) +* If an event has a parameter named `items` (kind: "array") containing ’["alpha", "beta"]'`: + * `items contains 'beta'` (case-insensitive deep search) + +**Access by Index (Legacy):** +For contracts without event definitions in their specification, or when working with older contracts, event parameters can be accessed by their numeric index (e.g., `0`, `1`, `2`): * If event parameter `0` (kind: "Map") is ’"id": 123, "name": "Test"'`: * `0.id == 123` @@ -1070,6 +1148,11 @@ Stellar event parameters are typically accessed by their numeric index as the ba * `1[1].val == 'Beta'` (case-insensitive) * `1 contains 'beta'` (case-insensitive deep search) + + +Named access is recommended when available as it makes expressions more readable and maintainable. The monitor will automatically use named parameters if they’re available in the contract specification, otherwise it falls back to indexed access. + + ##### EVM Examples These examples assume common EVM event parameters or transaction fields. @@ -1116,7 +1199,7 @@ Assume `event.ids` is `[10, 20, 30]` and `event.participants` is `["user": "Alic "event.participants contains 'Alice'" // True (deep search, case-insensitive) "event.participants contains 'editor'" // True (deep search, case-insensitive) -"event.participants == '[\"user\": \"Alice\", \"role\": \"admin\", \"user\": \"Bob\", \"role\": \"editor\"]'" // Raw JSON match (case-sensitive for structure and keys) +"event.participants == '[{\"user\": \"Alice\", \"role\": \"admin\"}, {\"user\": \"Bob\", \"role\": \"editor\"}]'" // Raw JSON match (case-sensitive for structure and keys) ``` ##### Stellar Examples @@ -1194,6 +1277,17 @@ Assume event parameter `0` is `12345` (u64), `1` (kind: "array") is ’["Val1", "2.keyB < 1000" ``` +Now, after Stellar Protocol 23 we can access to Event parameters by name (first, make sure the contract supports the feature) + +``` +"0 > 10000" +"param_name[0] == 'val1'" +"param_name contains 'val2'" +"param_name.keyA == 'DATAX'" +"param_name.keyB < 1000" +``` + + With SEP-48 support, Stellar functions can now reference parameters by name (e.g., `amount > 1000`) instead of position (e.g., `2 > 1000`). Events still use indexed parameters until SEP-48 support is added for events. @@ -1201,6 +1295,7 @@ With SEP-48 support, Stellar functions can now reference parameters by name (e.g You can find the contract specification through Stellar contract explorer tool. For example: [Stellar DEX Contract Interface](https://lab.stellar.org/smart-contracts/contract-explorer?$=network$id=mainnet&label=Mainnet&horizonUrl=https:////horizon.stellar.org&rpcUrl=https:////mainnet.sorobanrpc.com&passphrase=Public%20Global%20Stellar%20Network%20/;%20September%202015;&smartContracts$explorer$contractId=CA6PUJLBYKZKUEKLZJMKBZLEKP2OTHANDEOWSFF44FTSYLKQPIICCJBE;;) + #### Trigger Conditions (Custom filters) diff --git a/content/monitor/latest-versions.js b/content/monitor/latest-versions.js new file mode 100644 index 00000000..faf19278 --- /dev/null +++ b/content/monitor/latest-versions.js @@ -0,0 +1,31 @@ +/** + * @typedef {Object} VersionConfig + * @property {string} label - Display label for the version + * @property {string} value - Internal value identifier + * @property {string} path - URL path for the version + * @property {boolean} isStable - Whether this is a stable release + */ + +export const latestStable = "1.1.x"; + +/** @type {VersionConfig[]} */ +export const allVersions = [ + { + label: "Development", + value: "development", + path: "/monitor", + isStable: false, + }, + { + label: "v1.1.x (latest stable)", + value: "1.1.x", + path: "/monitor/1.1.x", + isStable: true, + }, + { + label: "v1.0.x", + value: "1.0.x", + path: "/monitor/1.0.x", + isStable: true, + }, +]; diff --git a/content/monitor/project-structure.mdx b/content/monitor/project-structure.mdx index fc33ecb9..e3c160dd 100644 --- a/content/monitor/project-structure.mdx +++ b/content/monitor/project-structure.mdx @@ -120,10 +120,12 @@ Runtime data storage: * Operational data * Temporary files + The `data/`, `logs/` and `config/` directories are gitignored except for example files. These directories are mounted to persist the configs and runtime data. + ## Examples and Resources diff --git a/content/monitor/quickstart.mdx b/content/monitor/quickstart.mdx index be054f75..2f4631aa 100644 --- a/content/monitor/quickstart.mdx +++ b/content/monitor/quickstart.mdx @@ -24,6 +24,32 @@ Before you begin, ensure you have the following installed: If you don’t have Rust installed, visit https://rustup.rs/ to install it. +### System Dependencies (Linux) + +For Ubuntu 22.04+ or Debian-based systems (both x86 and ARM64 architectures), install required packages: + +***Note:*** Python 3.9+ is required for pre-commit hooks compatibility. + +```bash +# Install required packages directly +sudo apt update +sudo apt install -y \ + build-essential \ + curl \ + git \ + pkg-config \ + libssl-dev \ + libffi-dev \ + libyaml-dev \ +``` + +Or use the provided system packages script: + +```bash +chmod +x ./scripts/linux/sys_pkgs_core.sh +./scripts/linux/sys_pkgs_core.sh // For runtime dependencies only +``` + ## Quick Setup Options We provide two setup paths to get you started: @@ -112,11 +138,13 @@ For containerized deployment: docker compose up ``` + By default, Docker Compose uses `Dockerfile.development`. For production, set: `DOCKERFILE=Dockerfile.production` before running the command. + #### Docker Management Commands @@ -153,7 +181,7 @@ Copy the example environment file and customize it: cp .env.example .env ``` -For detailed configuration options, see [Basic Configuration](/monitor#basic-configuration). +For detailed configuration options, see [Basic Configuration](/monitor#basic_configuration). ## Practical Examples @@ -175,7 +203,7 @@ cp examples/config/networks/ethereum_mainnet.json config/networks/ethereum_mainn ***Key Configuration Details:*** ```json - +{ "network_type": "EVM", "slug": "ethereum_mainnet", "name": "Ethereum Mainnet", @@ -185,7 +213,7 @@ cp examples/config/networks/ethereum_mainnet.json config/networks/ethereum_mainn "url": { "type": "plain", "value": "YOUR_RPC_URL_HERE" - , + }, "weight": 100 } ], @@ -198,10 +226,12 @@ cp examples/config/networks/ethereum_mainnet.json config/networks/ethereum_mainn } ``` + ***Important:*** Replace `YOUR_RPC_URL_HERE` with your actual Ethereum RPC endpoint. You can use providers like Infura, Alchemy, or run your own node. + #### Step 2: Monitor Configuration @@ -216,7 +246,7 @@ cp examples/config/filters/evm_filter_block_number.sh config/filters/evm_filter_ ***Monitor Configuration Overview:*** ```json - +{ "name": "Large Transfer of USDC Token", "paused": false, "networks": ["ethereum_mainnet"], @@ -232,19 +262,19 @@ cp examples/config/filters/evm_filter_block_number.sh config/filters/evm_filter_ "internalType": "address", "name": "from", "type": "address" - , - + }, + { "indexed": true, "internalType": "address", "name": "to", "type": "address" - , - + }, + { "indexed": false, "internalType": "uint256", "name": "value", "type": "uint256" - + } ], "name": "Transfer", "type": "event" @@ -252,39 +282,41 @@ cp examples/config/filters/evm_filter_block_number.sh config/filters/evm_filter_ ] } ], - "match_conditions": + "match_conditions": { "functions": [], "events": [ { "signature": "Transfer(address,address,uint256)", "expression": "value > 10000000000" - + } ], "transactions": [ - + { "status": "Success", "expression": null - + } ] }, "trigger_conditions": [ - + { "script_path": "./config/filters/evm_filter_block_number.sh", "language": "bash", "arguments": ["--verbose"], "timeout_ms": 1000 - + } ], "triggers": ["evm_large_transfer_usdc_slack", "evm_large_transfer_usdc_email"] } ``` + * The `expression: "value > 10000000000"` monitors transfers over 10,000 USDC (USDC has 6 decimals) * Remove the `trigger_conditions` array to disable additional filtering * The USDC contract address `0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48` is the official USDC contract on Ethereum mainnet + #### Step 3: Notification Setup @@ -298,7 +330,7 @@ cp examples/config/triggers/slack_notifications.json config/triggers/slack_notif ***Slack Configuration:*** ```json - +{ "evm_large_transfer_usdc_slack": { "name": "Large Transfer Slack Notification", "trigger_type": "slack", @@ -306,10 +338,10 @@ cp examples/config/triggers/slack_notifications.json config/triggers/slack_notif "slack_url": { "type": "plain", "value": "SLACK_WEBHOOK_URL" - , - "message": + }, + "message": { "title": "large_transfer_slack triggered", - "body": "Large transfer of ${events.0.args.value USDC from $events.0.args.from to $events.0.args.to | https://etherscan.io/tx/$transaction.hash#eventlog" + "body": "Large transfer of ${events.0.args.value} USDC from ${events.0.args.from} to ${events.0.args.to} | https://etherscan.io/tx/${transaction.hash}#eventlog" } } } @@ -336,7 +368,7 @@ cp examples/config/triggers/email_notifications.json config/triggers/email_notif ***Email Configuration:*** ```json - +{ "evm_large_transfer_usdc_email": { "name": "Large Transfer Email Notification", "trigger_type": "email", @@ -346,14 +378,14 @@ cp examples/config/triggers/email_notifications.json config/triggers/email_notif "username": { "type": "plain", "value": "your_email@gmail.com" - , - "password": + }, + "password": { "type": "plain", "value": "SMTP_PASSWORD" - , - "message": + }, + "message": { "title": "large_transfer_usdc_email triggered", - "body": "Large transfer of ${events.0.args.value USDC from $events.0.args.from to $events.0.args.to | https://etherscan.io/tx/$transaction.hash#eventlog" + "body": "Large transfer of ${events.0.args.value} USDC from ${events.0.args.from} to ${events.0.args.to} | https://etherscan.io/tx/${transaction.hash}#eventlog" }, "sender": "your_email@gmail.com", "recipients": [ @@ -414,7 +446,7 @@ cp examples/config/networks/stellar_mainnet.json config/networks/stellar_mainnet ***Key Configuration Details:*** ```json - +{ "network_type": "Stellar", "slug": "stellar_mainnet", "name": "Stellar Mainnet", @@ -424,7 +456,7 @@ cp examples/config/networks/stellar_mainnet.json config/networks/stellar_mainnet "url": { "type": "plain", "value": "YOUR_RPC_URL_HERE" - , + }, "weight": 100 } ], @@ -450,7 +482,7 @@ cp examples/config/filters/stellar_filter_block_number.sh config/filters/stellar ***Monitor Configuration Overview:*** ```json - +{ "name": "Large Swap By Dex", "paused": false, "networks": ["stellar_mainnet"], @@ -467,27 +499,27 @@ cp examples/config/filters/stellar_filter_block_number.sh config/filters/stellar "doc": "", "name": "user", "type_": "address" - , - + }, + { "doc": "", "name": "in_idx", "type_": "u32" - , - + }, + { "doc": "", "name": "out_idx", "type_": "u32" - , - + }, + { "doc": "", "name": "in_amount", "type_": "u128" - , - + }, + { "doc": "", "name": "out_min", "type_": "u128" - + } ], "outputs": ["u128"] } @@ -495,39 +527,42 @@ cp examples/config/filters/stellar_filter_block_number.sh config/filters/stellar ] } ], - "match_conditions": + "match_conditions": { "functions": [ { "signature": "swap(Address,U32,U32,U128,U128)", "expression": "out_min > 1000000000" - + } ], "events": [], "transactions": [ - + { "status": "Success", "expression": null - + } ] }, "trigger_conditions": [ - + { "script_path": "./config/filters/stellar_filter_block_number.sh", "language": "bash", "arguments": ["--verbose"], "timeout_ms": 1000 - + } ], "triggers": ["stellar_large_swap_by_dex_slack"] } ``` + * The `contract_spec` field is optional for Stellar contracts. If not provided, the monitor automatically fetches the contract’s SEP-48 interface from the chain * You can explore Stellar contract interfaces using the [Stellar Contract Explorer](https://lab.stellar.org/smart-contracts/contract-explorer) * The expression `"out_min > 1000000000"` monitors swaps with minimum output over 1 billion tokens +* Now, you can also filter by parameters event’s name (Stellar Protocol 23 has introduced this new feature). See this [section](/monitor#stellar_specifics) for more details + #### Step 3: Notification Setup @@ -541,7 +576,7 @@ cp examples/config/triggers/slack_notifications.json config/triggers/slack_notif ***Slack Configuration:*** ```json - +{ "stellar_large_swap_by_dex_slack": { "name": "Large Swap By Dex Slack Notification", "trigger_type": "slack", @@ -549,16 +584,21 @@ cp examples/config/triggers/slack_notifications.json config/triggers/slack_notif "slack_url": { "type": "plain", "value": "slack-webhook-url" - , - "message": + }, + "message": { "title": "large_swap_by_dex_slack triggered", - "body": "${monitor.name triggered because of a large swap of $functions.0.args.out_min tokens | https://stellar.expert/explorer/public/tx/$transaction.hash" + "body": "${monitor.name} triggered because of a large swap of ${functions.0.args.out_min} tokens | https://stellar.expert/explorer/public/tx/${transaction.hash}" } } } } ``` +* If you want to include event details in the notification message body, you can also access event parameters by name. Here’s an example: +```bash +"body": "${monitor.name} triggered because of a large swap from ${events.0.args.from} tokens | https://stellar.expert/explorer/public/tx/${transaction.hash}" +``` + #### Step 4: Run the Monitor ***Local Deployment:*** @@ -587,13 +627,13 @@ Now that you have OpenZeppelin Monitor running, here are some suggestions for wh ### Testing and Validation -* [Test your configuration](/monitor#testing-your-configuration) against specific block numbers +* [Test your configuration](/monitor#testing_your_configuration) against specific block numbers * Verify your RPC endpoints are working correctly * Test notification channels with small transactions ### Security and Best Practices -* [Configure secure secret management](/monitor#secret-management) for sensitive data +* [Configure secure secret management](/monitor#secret_management) for sensitive data * Use environment variables or Hashicorp Cloud Vault for credentials * Regularly update your RPC endpoints and monitor configurations diff --git a/content/monitor/rpc.mdx b/content/monitor/rpc.mdx index 3655be8e..9b1cdf4f 100644 --- a/content/monitor/rpc.mdx +++ b/content/monitor/rpc.mdx @@ -17,6 +17,7 @@ The OpenZeppelin Monitor includes a robust RPC client implementation with automa ### RPC URLs RPC endpoints are configured in the network configuration files with weights for load balancing: + ```json { "rpc_urls": [ @@ -34,6 +35,8 @@ RPC endpoints are configured in the network configuration files with weights for } ``` + + For high-availability setups, configure at least 3 (private) RPC endpoints with appropriate weights to ensure continuous operation even if multiple endpoints fail. @@ -41,14 +44,14 @@ For high-availability setups, configure at least 3 (private) RPC endpoints with | Field | Type | Description | | --- | --- | --- | -| `type_` | `String` | Type of endpoint (currently only "rpc" is supported) | -| `url.type` | `String` | Secret type ("Plain", "Environment", or "HashicorpCloudVault") | -| `url.value` | `String` | The RPC endpoint URL | -| `weight` | `Number` | Load balancing weight (0-100) | +| `**type_**` | `String` | Type of endpoint (currently only "rpc" is supported) | +| `**url.type**` | `String` | Secret type ("Plain", "Environment", or "HashicorpCloudVault") | +| `**url.value**` | `String` | The RPC endpoint URL | +| `**weight**` | `Number` | Load balancing weight (0-100) | ## Endpoint Management -The endpoint manager handles: +The endpoint manager handles * Initial endpoint selection based on weights * Automatic rotation on failures @@ -167,6 +170,7 @@ let retryable_client = create_retryable_http_client( base_http_client, Some(TransientErrorRetryStrategy), // Use custom or default retry strategy ); + ``` ### Implementation Details diff --git a/content/monitor/scripts.mdx b/content/monitor/scripts.mdx index 73d844d6..60d9dbb6 100644 --- a/content/monitor/scripts.mdx +++ b/content/monitor/scripts.mdx @@ -120,7 +120,7 @@ Custom filter scripts allow you to apply additional conditions to matches detect "type": "0x2" }, "logs": [ - { + { "address": "0xd1f2586790a5bd6da1e443441df53af6ec213d83", "topics": [ "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", @@ -134,7 +134,7 @@ Custom filter scripts allow you to apply additional conditions to matches detect "blockHash": "0x9432868b7fc57e85f0435ca3047f6a76add86f804b3c1af85647520061e30f80", "logIndex": "0x2", "removed": false - } + }, ], "transaction": { "accessList": [], @@ -205,17 +205,17 @@ Custom filter scripts allow you to apply additional conditions to matches detect "tx": {/* transaction details */} }, "resultXdr": "AAAAAA...", - "resultJson": /* result details */, + "resultJson": {/* result details */}, "resultMetaXdr": "AAAAAA...", - "resultMetaJson": /* metadata details */, + "resultMetaJson": {/* metadata details */}, "diagnosticEventsXdr": ["AAAAAA..."], - "diagnosticEventsJson": [/* event details */], + "diagnosticEventsJson": [{/* event details */}], "ledger": 123456, "createdAt": 1679644800, "decoded": { "envelope": {/* decoded envelope */}, - "result": /* decoded result */, - "meta": /* decoded metadata */ + "result": {/* decoded result */}, + "meta": {/* decoded metadata */} } }, "ledger": { @@ -225,7 +225,7 @@ Custom filter scripts allow you to apply additional conditions to matches detect "headerXdr": "AAAAAA...", "headerJson": {/* header details */}, "metadataXdr": "AAAAAA...", - "metadataJSON": /* metadata details */ + "metadataJSON": {/* metadata details */} }, "matched_on": { "functions": [ @@ -300,7 +300,7 @@ main() { fi # Convert hex to decimal with error checking - if ! block_number=$(printf "%d" $((16#$block_number_hex)) 2>/dev/null); then + if ! block_number=$(printf "%d" $((16#${block_number_hex})) 2>/dev/null); then echo "Failed to convert hex to decimal" echo "false" exit 1 @@ -332,8 +332,8 @@ main ### Example Filter Script (JavaScript) -```javascript -#!/usr/bin/env node +```bash +#!/bin/bash try { let inputData = ''; @@ -375,8 +375,8 @@ try { ### Example Filter Script (Python) -```python -#!/usr/bin/env python3 +```bash +#!/bin/bash import sys import json @@ -434,12 +434,14 @@ This examples script filters EVM transactions based on their block number: ### Integration -Integrate your custom filter script with the monitor by following the [configuration guidelines](/monitor#trigger-conditions-custom-filters). +Integrate your custom filter script with the monitor by following the [configuration guidelines](/monitor#trigger_conditions_custom_filters). + Trigger conditions are executed sequentially based on their position in the trigger conditions array. Every filter must return `false` for the match to be included and are only considered if they were executed successfully. + ## Custom Notification Scripts @@ -451,7 +453,7 @@ Custom notification scripts allow you to define how alerts are delivered when sp * Bash * Python * JavaScript -2. Your script will receive the same JSON input format as [filter scripts](#implementation-guide) +2. Your script will receive the same JSON input format as [filter scripts](#implementation_guide) ### Script Output Requirements @@ -521,8 +523,8 @@ main ### Example Notification Script (JavaScript) -```javascript -#!/usr/bin/env node +```bash +#!/bin/bash try { let inputData = ''; @@ -556,8 +558,8 @@ try { ### Example Notification Script (Python) -```python -#!/usr/bin/env python3 +```bash +#!/bin/bash import sys import json @@ -568,7 +570,6 @@ def main(): input_data = sys.stdin.read() if not input_data: print("No input JSON provided", flush=True) - return # Parse input JSON try: @@ -579,7 +580,7 @@ def main(): print(f"Args: {args}") except json.JSONDecodeError as e: print(f"Invalid JSON input: {e}", flush=True) - return + except Exception as e: print(f"Error processing input: {e}", flush=True) @@ -599,7 +600,7 @@ This examples demonstrates how to: ### Integration -Integrate your custom notification script with the triggers by following the [configuration guidelines](/monitor#custom-script-notifications). +Integrate your custom notification script with the triggers by following the [configuration guidelines](/monitor#custom_script_notifications). ## Performance Considerations diff --git a/content/monitor/testing.mdx b/content/monitor/testing.mdx index 7f9c5e27..7f822d16 100644 --- a/content/monitor/testing.mdx +++ b/content/monitor/testing.mdx @@ -43,10 +43,12 @@ Run the complete test suite: RUST_TEST_THREADS=1 cargo test ``` + `RUST_TEST_THREADS=1` is required to prevent test conflicts when accessing shared resources like configuration files or network connections. + ### Specific Test Categories diff --git a/content/relayer/1.0.x/api_reference.mdx b/content/relayer/1.0.x/api_reference.mdx new file mode 100644 index 00000000..7d235ad1 --- /dev/null +++ b/content/relayer/1.0.x/api_reference.mdx @@ -0,0 +1,995 @@ +--- +title: API Reference +--- + +This document provides information on the implemented API, along with usage examples. + +## Pre-requisites +1. API key +This key is essential for most API calls. It can be set in `.env` file, under the `API_KEY` variable. +In case of a change on the key, there is no need to rebuild docker images, as `docker compose` will pick up the changes the next time the container is started. + +This key should be sent as a header for most of the API calls: + +```json +Authorization: Bearer +``` + +## Request format +By default, the container listens on port `8080`. Calls should follow call the URL: +`http://:8080/api/v1/relayers//rpc` + + +`relayer_id` is the name given to a relayer configuration in `./config/config.json` file. + + +## Environments +* Solana +* EVM +* Stellar + +## API Reference +* [Common Actions](#common-actions) +* [Solana](#solana) +* [EVM](#evm) +* [Stellar](#stellar) + +### Common actions +These are a set of REST calls common to both Solana and EVM relayers. + + +We are assuming a base url of `http://localhost:8080/` for these examples. + + +#### List relayers + +Request: `GET http://localhost:8080/api/v1/relayers/` + +Example request: +```bash +curl --location --request GET 'http://localhost:8080/api/v1/relayers/' \ +--header 'Authorization: Bearer ' +``` + +Example response: +```json +{ + "success": true, + "data": [ + { + "id": "sepolia-example", + "name": "Sepolia Example", + "network": "sepolia", + "paused": false, + "network_type": "evm", + "signer_id": "local-signer", + "policies": { + "eip1559_pricing": false, + "private_transactions": false, + "min_balance": 1 + }, + "address": "0xc834dcdc9a074dbbadcc71584789ae4b463db116", + "notification_id": "notification-example", + "system_disabled": false + } + ], + "error": null, + "pagination": { + "current_page": 1, + "per_page": 10, + "total_items": 1 + } +} +``` + +#### Get relayer details + +Request: `GET http://localhost:8080/api/v1/relayers/` + +* `relayer_id` can be found by listing relayers or checking the config file (`./config/config.json`) + +Example request: +```bash +curl --location --request GET 'http://localhost:8080/api/v1/relayers/' \ +--header 'Authorization: Bearer ' +``` + +Example response: +```json +{ + "success": true, + "data": { + "id": "sepolia-example", + "name": "Sepolia Example", + "network": "sepolia", + "network_type": "evm", + "paused": false, + "policies": { + "eip1559_pricing": false, + "private_transactions": false, + "min_balance": 1 + }, + "address": "0xc834dcdc9a074dbbadcc71584789ae4b463db116", + "system_disabled": false + }, + "error": null +} +``` + +#### Update Relayer + +Request: `PATCH http://localhost:8080/api/v1/relayers/` + +Example request to pause a relayer: +```bash +curl --location --request PATCH 'http://localhost:8080/api/v1/relayers/' \ +--header 'Authorization: Bearer ' \ +--header 'Content-Type: application/json' \ +--data-raw '{ + "paused": true +}' +``` + +Example response: +```json +{ + "success": true, + "data": { + "id": "sepolia-example", + "name": "Sepolia Example", + "network": "sepolia", + "paused": true, + "network_type": "evm", + "signer_id": "local-signer", + "policies": { + "eip1559_pricing": false, + "private_transactions": false, + "min_balance": 1 + }, + "address": "0xc834dcdc9a074dbbadcc71584789ae4b463db116", + "notification_id": "notification-example", + "system_disabled": false + }, + "error": null +} +``` + +#### Get relayer balance +Request: `GET http://localhost:8080/api/v1/relayers//balance` + +Example request to pause a relayer: +```bash +curl --location --request GET 'http://localhost:8080/api/v1/relayers/sepolia-example/balance' \ +--header 'Authorization: Bearer ' +``` + +Example response: +```json +{ + "success": true, + "data": { + "balance": 1000000000000000, + "unit": "wei" + }, + "error": null +} +``` + +#### Get relayer status +Request: `GET http://localhost:8080/api/v1/relayers//status` + +Example request: +```bash +curl --location --request GET 'http://localhost:8080/api/v1/relayers/sepolia-example/status' \ +--header 'Authorization: Bearer ' +``` + +Example response for EVM relayer: +```json +{ + "success": true, + "data": { + "balance": "1000000000000000000", + "pending_transactions_count": 2, + "last_confirmed_transaction_timestamp": "2025-02-26T13:28:55.838812+00:00", + "system_disabled": false, + "paused": false, + "nonce": "42" + }, + "error": null +} +``` + +Example response for Stellar relayer: +```json +{ + "success": true, + "data": { + "balance": "100000000", + "pending_transactions_count": 0, + "last_confirmed_transaction_timestamp": null, + "system_disabled": false, + "paused": false, + "sequence_number": "12345678901234567890" + }, + "error": null +} +``` + +Response fields: +| Field | Type | Description | +| --- | --- | --- | +| `balance` | String | Current relayer balance in the smallest unit (wei for EVM, lamports for Solana, stroops for Stellar) | +| `pending_transactions_count` | Number | Number of transactions that are pending, submitted, or mined but not yet confirmed | +| `last_confirmed_transaction_timestamp` | String (optional) | ISO 8601 timestamp of the most recent confirmed transaction, or `null` if no transactions have been confirmed | +| `system_disabled` | Boolean | Whether the relayer has been disabled by the system due to errors or configuration issues | +| `paused` | Boolean | Whether the relayer has been manually paused | +| `nonce` | String (EVM only) | Current transaction nonce for EVM relayers | +| `sequence_number` | String (Stellar only) | Current sequence number for Stellar relayers | + + + + +* For Solana relayers, this endpoint is currently not supported and will return an error +* Network-specific fields (`nonce` for EVM, `sequence_number` for Stellar) are included directly in the response using JSON flattening +* The `balance` field represents the raw balance value as a string to avoid precision loss with large numbers + + + +### Solana + +The Solana API implementation conforms to the [Paymaster Spec, window="_blank"](https://docs.google.com/document/d/1lweO5WH12QJaSAu5RG_wUistyk_nFeT6gy1CdvyCEHg/edit?tab=t.0#heading=h.4yldgprkuvav). + +Solana API + +| Method Name | Required Parameters | Result | Description | +| --- | --- | --- | --- | +| feeEstimate | `transaction`, `fee_token` | `estimated_fee`, `conversion_rate` | Estimate the fee for an arbitrary transaction using a specified token. | +| transferTransaction | `amount`, `token`, `source`, `destination` | `transaction`, `fee_in_spl`, `token`, `fee_in_lamports`, `valid_until_blockheight` | Create a transfer transaction for a specified token, sender, and recipient. The token supplied will be assumed to be the token to also be used for fees. Returns a partially signed transaction. | +| prepareTransaction | `transaction`, `fee_token` | `transaction`, `fee_in_spl`, `fee_token`, `fee_in_lamports`, `valid_until_blockheight` | Prepare a transaction by adding relayer-specific instructions. Returns a partially signed transaction. | +| signTransaction | `transaction` | `transaction`, `signature` | Sign a prepared transaction without submitting it to the blockchain. | +| signAndSendTransaction | `transaction` | `transaction`, `signature` | Sign and submit a transaction to the blockchain. | +| getSupportedTokens | (none) | `tokens[]` (list of token metadata) | Retrieve a list of tokens supported by the relayer for fee payments. | +| getFeaturesEnabled | (none) | `features[]` (list of enabled features) | Retrieve a list of features supported by the relayer. | + +Key terminology +| Key | Description | +| --- | --- | +| `transaction` | Base64-encoded serialized Solana transaction. This could be a signed or unsigned transaction. | +| `signature` | Unique "transaction hash" that can be used to look up transaction status on-chain. | +| `source` | Source wallet address. The relayer is responsible for deriving and the TA. | +| `destination` | Destination wallet address. The relayer is responsible for deriving and creating the TA if necessary. | +| `fee_token` | Token mint address for the fee payment. | +| `fee_in_spl` | Fee amount the end user will pay to the relayer to process the transaction in spl tokens in the smallest unit of the spl token (no decimals) | +| `fee_in_lamports` | Fee amount in Lamports the Relayer estimates it will pay for the transaction. | +| `valid_until_block_height` | Expiration block height for time-sensitive operations. | +| `tokens[]` | Array of supported token metadata (e.g., symbol, mint, decimals). | +| `features[]` | Array of features enabled by the relayer (e.g., bundle support, sponsorship). | + + +We are assuming a base url of `http://localhost:8080/` for these examples. + + +#### Get supported tokens + +Request: +```bash +curl --location --request POST 'http://localhost:8080/api/v1/relayers//rpc' \ +--header 'Authorization: Bearer ' \ +--header 'Content-Type: application/json' \ +--data-raw '{ + "jsonrpc": "2.0", + "method": "getSupportedTokens", + "params": {}, + "id": 2 +}' +``` + +Result: +```json +{ + "jsonrpc": "2.0", + "result": { + "tokens": [ + { + "decimals": 6, + "max_allowed_fee": 100000000, + "mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", + "symbol": "USDC" + }, + { + "decimals": 9, + "max_allowed_fee": null, + "mint": "So11111111111111111111111111111111111111112", + "symbol": "SOL" + } + ] + }, + "id": 2 +} +``` + +#### Fee estimate + + +The fee estimation method returns mocked values on devnet and testnet because the Jupiter service is available only on mainnet-beta. + + +Request: +```bash +curl --location --request POST 'http://localhost:8080/api/v1/relayers//rpc' \ +--header 'Authorization: Bearer ' \ +--header 'Content-Type: application/json' \ +--data-raw ' +{ + "jsonrpc": "2.0", + "method": "feeEstimate", + "params": { + "transaction": "AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAEDpNhTBS0w2fqEkg0sAghld4KIZNFW3kt5Co2TA75icpEAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAZzDKeiaRTZZ3ipAtgJOOmqCGhz1iUHo8A9xynrbleugBAgIAAQwCAAAAQEIPAAAAAAA=", + "fee_token": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" + }, + "id": 3 +}' +``` + +Result: +```json +{ + "jsonrpc": "2.0", + "result": { + "conversion_rate": "142.6", + "estimated_fee": "0.000713" + }, + "id": 3 +} +``` + +#### Sign transaction + +Request: +```bash +curl --location --request POST 'http://localhost:8080/api/v1/relayers//rpc' \ +--header 'Authorization: Bearer ' \ +--header 'Content-Type: application/json' \ +--data-raw '{ + "jsonrpc": "2.0", + "method": "signTransaction", + "params": { + "transaction": "AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAEDpNhTBS0w2fqEkg0sAghld4KIZNFW3kt5Co2TA75icpEAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/bKmYrYtPWWI7zwiXWqAC5iFnkAkRL2D8s6lPkoJJokBAgIAAQwCAAAAQEIPAAAAAAA=" + + }, + "id": 4 +}' +``` + +Result: +```json +{ + "jsonrpc": "2.0", + "result": { + "signature": "2jg9xbGLtZRsiJBrDWQnz33JuLjDkiKSZuxZPdjJ3qrJbMeTEerXFAKynkPW63J88nq63cvosDNRsg9VqHtGixvP", + "transaction": "AVbRgFoUlj0XdlLP4gJJ2zwmr/2g2LOdeNqGPYTl4VFzY7lrX+nKNXUEU0DLJEA+2BW3uHvudQSXz5YBqd5d9gwBAAEDpNhTBS0w2fqEkg0sAghld4KIZNFW3kt5Co2TA75icpEAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/bKmYrYtPWWI7zwiXWqAC5iFnkAkRL2D8s6lPkoJJokBAgIAAQwCAAAAQEIPAAAAAAA=" + }, + "id": 4 +} +``` + +#### Sign and send transaction +```bash +curl --location --request POST 'http://localhost:8080/api/v1/relayers//rpc' \ +--header 'Authorization: Bearer ' \ +--header 'Content-Type: application/json' \ +--data-raw '{ + "jsonrpc": "2.0", + "method": "signAndSendTransaction", + "params": { + "transaction": "AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAEDpNhTBS0w2fqEkg0sAghld4KIZNFW3kt5Co2TA75icpEAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/bKmYrYtPWWI7zwiXWqAC5iFnkAkRL2D8s6lPkoJJokBAgIAAQwCAAAAQEIPAAAAAAA=" + }, + "id": 5 +}' +``` + +Result: +```json +{ + "jsonrpc": "2.0", + "result": { + "signature": "2jg9xbGLtZRsiJBrDWQnz33JuLjDkiKSZuxZPdjJ3qrJbMeTEerXFAKynkPW63J88nq63cvosDNRsg9VqHtGixvP", + "transaction": "AVbRgFoUlj0XdlLP4gJJ2zwmr/2g2LOdeNqGPYTl4VFzY7lrX+nKNXUEU0DLJEA+2BW3uHvudQSXz5YBqd5d9gwBAAEDpNhTBS0w2fqEkg0sAghld4KIZNFW3kt5Co2TA75icpEAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/bKmYrYtPWWI7zwiXWqAC5iFnkAkRL2D8s6lPkoJJokBAgIAAQwCAAAAQEIPAAAAAAA=" + }, + "id": 5 +} +``` + +#### Prepare Transaction + + +The prepare transaction method returns a mocked value for the fee_in_spl response field on devnet and testnet, because the Jupiter service is available only on mainnet-beta. + + +```bash +curl --location --request POST 'http://localhost:8080/api/v1/relayers/solana-example/rpc' \ +--header 'Authorization: Bearer ' \ +--header 'Content-Type: application/json' \ +--data-raw '{ + "jsonrpc": "2.0", + "method": "prepareTransaction", + "params": { + "transaction": "AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAEDpNhTBS0w2fqEkg0sAghld4KIZNFW3kt5Co2TA75icpEAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/bKmYrYtPWWI7zwiXWqAC5iFnkAkRL2D8s6lPkoJJokBAgIAAQwCAAAAQEIPAAAAAAA=", + "fee_token": "Gh9ZwEmdLJ8DscKNTkTqPbNwLNNBjuSzaG9Vp2KGtKJr" + + }, + "id": 6 +}' +``` + +Result: +```json +{ + "jsonrpc": "2.0", + "result": { + "fee_in_lamports": "5000", + "fee_in_spl": "5000", + "fee_token": "Gh9ZwEmdLJ8DscKNTkTqPbNwLNNBjuSzaG9Vp2KGtKJr", + "transaction": "Ae7kEB+DOH8vhFDlV6SqTCcaf0mJI/Yrn1Zr/WFh8kEfdD0c99wJ1bYV3FDjt/qtwxRa5LxuVDlHR2CT+M5BIgYBAAEDpNhTBS0w2fqEkg0sAghld4KIZNFW3kt5Co2TA75icpEAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAuTJfv3pxOOfvB3SHRW0ArtL0kkx6rVqN+d+tGrRgLIMBAgIAAQwCAAAAQEIPAAAAAAA=", + "valid_until_blockheight": 351723643 + }, + "id": 6 +} +``` + +#### Transfer Transaction + + +The transfer transaction method returns a mocked value for the fee_in_spl response field on devnet and testnet, because the Jupiter service is available only on mainnet-beta. + + +```bash +curl --location --request POST 'http://localhost:8080/api/v1/relayers/solana-example/rpc' \ +--header 'Authorization: Bearer ' \ +--header 'Content-Type: application/json' \ +--data-raw '{ + "jsonrpc": "2.0", + "method": "transferTransaction", + "params": { + "token": "Gh9ZwEmdLJ8DscKNTkTqPbNwLNNBjuSzaG9Vp2KGtKJr", + "amount": 1, + "source": "C6VBV1EK2Jx7kFgCkCD5wuDeQtEH8ct2hHGUPzEhUSc8", + "destination": "D6VBV1EK2Jx7kFgCkCD5wuDeQtEH8ct2hHGUPzEhUSc8" + + }, + "id": 7 +}' +``` + +Result: +```json +{ + "jsonrpc": "2.0", + "result": { + "fee_in_lamports": "5000", + "fee_in_spl": "5000", + "fee_token": "Gh9ZwEmdLJ8DscKNTkTqPbNwLNNBjuSzaG9Vp2KGtKJr", + "transaction": "AaQ8y7r1eIuwrmhuIWSJ7iWVJ5gAhZaZ9vd2I9wQ0PFs79GPYejdVrsVgMLm3t1c7g/WsoYhoPdt83ST1xcwdggBAAIEpNhTBS0w2fqEkg0sAghld4KIZNFW3kt5Co2TA75icpEMsnnyKbZZ5yUtDsJ/8r0KO7Li3BEwZoWs+nOJzoXwvgbd9uHXZaGT2cvhRs7reawctIXtX1s3kTqM9YV+/wCp6Sg5VQll/9TWSsqvRtRd9zGOW09XyQxIfWBiXYKbg3tDrlnF1KFvUS/T47LoVLV2lUyLS2zrfs8g57jdLLGvWwECBAEDAQAKDAEAAAAAAAAABg==", + "valid_until_blockheight": 351724045 + }, + "id": 7 +} +``` + +### EVM + +| Method | Required Parameters | Result | Description | +| --- | --- | --- | --- | +| send transaction | `value`, `data`, `to`, `gas_limit` | | Submit transaction to blockchain. | +| list transactions | (none) | | List relayer transactions. | +| get transaction by id | `id` | | Retrieve transaction by id. | +| get transaction by nonce | `nonce` | | Retrieve transaction by nonce. | + +#### Send transaction +Request: `POST http://localhost:8080/api/v1/relayers//transactions` + +Example request to send transaction: +```bash + curl --location --request POST 'http://localhost:8080/api/v1/relayers/sepolia-example/transactions' \ +--header 'Authorization: Bearer ' \ +--header 'Content-Type: application/json' \ +--data-raw '{ + "value": 1, + "data": "0x", + "to": "0xd9b55a2ba539031e3c18c9528b0dc3a7f603a93b", + "gas_limit": 21000, + "speed": "average" +}' +``` + +Example response: +```json +{ + "success": true, + "data": { + "id": "47f440b3-f4ce-4441-9489-55fc83be12cf", + "hash": null, + "status": "pending", + "created_at": "2025-02-26T13:24:35.560593+00:00", + "sent_at": null, + "confirmed_at": null, + "gas_price": null, + "gas_limit": 21000, + "nonce": 0, + "value": "0x1", + "from": "0xc834dcdc9a074dbbadcc71584789ae4b463db116", + "to": "0x5e87fD270D40C47266B7E3c822f4a9d21043012D", + "relayer_id": "sepolia-example" + }, + "error": null +} +``` + +#### List Transactions +Request: `GET http://localhost:8080/api/v1/relayers//transactions` + +Example request to list relayer transactions: +```bash +curl --location --request GET 'http://localhost:8080/api/v1/relayers/sepolia-example/transactions' \ +--header 'Authorization: Bearer ' +``` + +Example response: +```json +{ + "success": true, + "data": [ + { + "id": "bfa362dc-a84a-4466-93d0-b8487bfd40cc", + "hash": "0xca349b67fad7b64239f4682a231c5398b0b52a93b626d1d67cb9ec037cdd290c", + "status": "confirmed", + "created_at": "2025-02-26T13:28:46.838812+00:00", + "sent_at": "2025-02-26T13:28:48.838812+00:00", + "confirmed_at": "2025-02-26T13:28:55.838812+00:00", + "gas_price": 12312313123, + "gas_limit": 21000, + "nonce": 8, + "value": "0x1", + "from": "0xc834dcdc9a074dbbadcc71584789ae4b463db116", + "to": "0x5e87fD270D40C47266B7E3c822f4a9d21043012D", + "relayer_id": "sepolia-example" + }, + ], + "error": null, + "pagination": { + "current_page": 1, + "per_page": 10, + "total_items": 0 + } +} +``` + +#### Get transaction by id +Request: `GET http://localhost:8080/api/v1/relayers//transactions/id` + +Example request fetch relayer transaction by id: +```bash +curl --location --request GET 'http://localhost:8080/api/v1/relayers/sepolia-example/transactions/47f440b3-f4ce-4441-9489-55fc83be12cf' \ +--header 'Authorization: Bearer ' +``` + +Example response: +```json +{ + "success": true, + "data": { + "id": "47f440b3-f4ce-4441-9489-55fc83be12cf", + "hash": "0xa5759c99e99a1fc3b6e66bca75688659d583ee2556c7d185862dc8fcdaa4d5d7", + "status": "confirmed", + "created_at": "2025-02-26T13:28:46.838812+00:00", + "sent_at": "2025-02-26T13:28:48.838812+00:00", + "confirmed_at": "2025-02-26T13:28:55.838812+00:00", + "gas_price": 35843464006, + "gas_limit": 21000, + "nonce": 0, + "value": "0x1", + "from": "0xc834dcdc9a074dbbadcc71584789ae4b463db116", + "to": "0x5e87fD270D40C47266B7E3c822f4a9d21043012D", + "relayer_id": "sepolia-example" + }, + "error": null +} +``` + +#### Get transaction by nonce +Request: `GET http://localhost:8080/api/v1/relayers//transactions/by-nonce/0` + +Example request fetch relayer transaction by nonce: +```bash +curl --location --request GET 'http://localhost:8080/api/v1/relayers/sepolia-example/transactions/by-nonce/0' \ +--header 'Authorization: Bearer ' +``` + +Example response: +```json +{ + "success": true, + "data": { + "id": "47f440b3-f4ce-4441-9489-55fc83be12cf", + "hash": "0xa5759c99e99a1fc3b6e66bca75688659d583ee2556c7d185862dc8fcdaa4d5d7", + "status": "confirmed", + "created_at": "2025-02-26T13:28:46.838812+00:00", + "sent_at": "2025-02-26T13:28:48.838812+00:00", + "confirmed_at": "2025-02-26T13:28:55.838812+00:00", + "gas_price": 35843464006, + "gas_limit": 21000, + "nonce": 0, + "value": "0x1", + "from": "0xc834dcdc9a074dbbadcc71584789ae4b463db116", + "to": "0x5e87fD270D40C47266B7E3c822f4a9d21043012D", + "relayer_id": "sepolia-example" + }, + "error": null +} +``` + +### Stellar + + +Basic support for Stellar; it is currently under active development. The API interactions and specifics described below may evolve. + + +This section outlines how to interact with the Stellar network via the Relayer API. The relayer supports Soroban smart contract operations, including contract invocation, deployment, and WASM uploads. + +| Method Name | Required Parameters | Description | +| --- | --- | --- | +| Send Transaction | `network`, `operations` (or `transaction_xdr`) | Submit a transaction to the Stellar network. Supports payment and InvokeHostFunction operations, pre-built XDR transactions, and fee bump transactions. | +| Get Transaction Details | `transaction_id` | Retrieve a specific transaction by its ID. | +| List Transactions | (none) | List transactions for the relayer. | + +#### Supported Operation Types + +| Operation Type | Description | +| --- | --- | +| `payment` | Transfer native XLM or other assets between accounts | +| `invoke_contract` | Call a deployed Soroban smart contract function | +| `create_contract` | Deploy a new Soroban smart contract from WASM hash | +| `upload_wasm` | Upload WASM contract code to the Stellar ledger | + +#### Send Transaction +Submit a transaction to the Stellar network. + +Request: `POST http://localhost:8080/api/v1/relayers//transactions` + +##### Transaction Input Methods + +The relayer supports three ways to submit transactions: + +1. ***Operations-based***: Build a transaction by specifying the `operations` array (recommended for most use cases) +2. ***Transaction XDR (unsigned)***: Submit a pre-built unsigned transaction using `transaction_xdr` field (advanced use case) +3. ***Transaction XDR (signed) with fee bump***: Submit a signed transaction using `transaction_xdr` with `fee_bump: true` to wrap it in a fee bump transaction +===== Transaction Structure + +***Required fields:*** +- `network`: The Stellar network ("testnet", "mainnet", etc.) +- Either `operations` (array of operations) OR `transaction_xdr` (base64-encoded XDR) - but not both + +***Optional fields:*** +- `source_account`: The Stellar account that will be the source of the transaction (defaults to relayer’s address) +- `memo`: Transaction memo (see Memo Types below) +- `valid_until`: Transaction expiration time (ISO 8601 format) +- `transaction_xdr`: Pre-built transaction XDR (base64 encoded, signed or unsigned) - mutually exclusive with `operations` +- `fee_bump`: Boolean flag to request fee-bump wrapper (only valid with signed `transaction_xdr`) +- `max_fee`: Maximum fee for fee bump transactions in stroops (defaults to 1,000,000 = 0.1 XLM) + +##### Asset Types + +Assets in Stellar operations must be specified with a type field: + +***Native XLM:*** +```json +{"type": "native"} +``` + +***Credit Asset (4 characters or less):*** +```json +{ + "type": "credit_alphanum4", + "code": "USDC", + "issuer": "GA5ZSEJYB37JRC5AVCIA5MOP4RHTM335X2KGX3IHOJAPP5RE34K4KZVN" +} +``` + +***Credit Asset (5-12 characters):*** +```json +{ + "type": "credit_alphanum12", + "code": "LONGASSET", + "issuer": "GA5ZSEJYB37JRC5AVCIA5MOP4RHTM335X2KGX3IHOJAPP5RE34K4KZVN" +} +``` + +##### Memo Types + +Transactions can include optional memos: + +***No Memo:*** +```json +{"type": "none"} +``` + +***Text Memo (max 28 UTF-8 bytes):*** +```json +{"type": "text", "value": "Payment for services"} +``` + +***ID Memo:*** +```json +{"type": "id", "value": "12345"} +``` + +***Hash Memo (32 bytes hex):*** +```json +{"type": "hash", "value": "deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef"} +``` + +***Return Memo (32 bytes hex):*** +```json +{"type": "return", "value": "deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef"} +``` + +Example requests (cURL): + +***1. Payment Operation:*** +```bash +curl --location --request POST 'http://localhost:8080/api/v1/relayers//transactions' \ +--header 'Authorization: Bearer ' \ +--header 'Content-Type: application/json' \ +--data-raw '{ + "network": "testnet", + "operations": [ + { + "type": "payment", + "destination": "GD77B6LYQ5XDCW6CND7CQMA23FSV7MZQGLBAU5OMEOXQM6XFTCMWQQCJ", + "asset": {"type": "native"}, + "amount": 1000000 + } + ], + "memo": {"type": "text", "value": "Payment for services"} +}' +``` + +***2. Invoke Contract:*** +```bash +curl --location --request POST 'http://localhost:8080/api/v1/relayers//transactions' \ +--header 'Authorization: Bearer ' \ +--header 'Content-Type: application/json' \ +--data-raw '{ + "network": "testnet", + "operations": [ + { + "type": "invoke_contract", + "contract_address": "CA7QYNF7SOWQ3GLR2BGMZEHXAVIRZA4KVWLTJJFC7MGXUA74P7UJUWDA", + "function_name": "transfer", + "args": [ + {"address": "GCRID3RFJXOBEB73FWRYJJ4II5E5UQ413F7LTM4W5KI54NBHQDRUXVLY"}, + {"address": "GD77B6LYQ5XDCW6CND7CQMA23FSV7MZQGLBAU5OMEOXQM6XFTCMWQQCJ"}, + {"u64": "1000000"} + ], + "auth": {"type": "source_account"} + } + ] +}' +``` + +***3. Create Contract:*** +```bash +curl --location --request POST 'http://localhost:8080/api/v1/relayers//transactions' \ +--header 'Authorization: Bearer ' \ +--header 'Content-Type: application/json' \ +--data-raw '{ + "network": "testnet", + "operations": [ + { + "type": "create_contract", + "source": { + "from": "address", + "address": "GCRID3RFJXOBEB73FWRYJJ4II5E5UQ413F7LTM4W5KI54NBHQDRUXVLY" + }, + "wasm_hash": "d3b2f6f8a1c5e9b4a7d8c2e1f5a9b3c6e8d4f7a2b5c8e1d4f7a0b3c6e9d2f5a8", + "salt": "0000000000000000000000000000000000000000000000000000000000000001" + } + ] +}' +``` + + +For create_contract, you can also include optional `constructor_args` array and use `"from": "contract"` for factory pattern deployments. + + +***4. Upload WASM:*** +```bash +curl --location --request POST 'http://localhost:8080/api/v1/relayers//transactions' \ +--header 'Authorization: Bearer ' \ +--header 'Content-Type: application/json' \ +--data-raw '{ + "network": "testnet", + "operations": [ + { + "type": "upload_wasm", + "wasm": { + "type": "base64", + "base64": "AGFzbQEAAAABBgFgAX8BfwMCAQAFAwEAAQcPAgVoZWxsbwAACG1lbW9yeTIDCgQAAAAL" + } + } + ] +}' +``` + + +WASM can be provided as either `"type": "base64"` or `"type": "hex"` encoding. + + +***5. Submit Pre-built Unsigned Transaction (XDR):*** + +For advanced use cases, you can submit a pre-built unsigned transaction as base64-encoded XDR: + +```bash +curl --location --request POST 'http://localhost:8080/api/v1/relayers//transactions' \ +--header 'Authorization: Bearer ' \ +--header 'Content-Type: application/json' \ +--data-raw '{ + "network": "testnet", + "transaction_xdr": "AAAAAgAAAAC0V9YG9Ks6MEexw5yB+FDD8VJwmtv5OU2BwgPN6PpZcwAAAGQCeO4pAAAAAgAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAACgAAAAAAAAAAAAAAAAAAAAA=", + "source_account": "GCRID3RFJXOBEB73FWRYJJ4II5E5UQ413F7LTM4W5KI54NBHQDRUXVLY" +}' +``` + + +When submitting XDR transactions, the `operations` field is not required. The relayer will parse the transaction from the XDR + + +***6. Fee Bump Transaction:*** + +To submit a fee bump transaction for an existing signed transaction: + +```bash +curl --location --request POST 'http://localhost:8080/api/v1/relayers//transactions' \ +--header 'Authorization: Bearer ' \ +--header 'Content-Type: application/json' \ +--data-raw '{ + "network": "testnet", + "transaction_xdr": "AAAAAgAAAAC0V9YG9Ks6MEexw5yB+FDD8VJwmtv5OU2BwgPN6PpZcwAAAGQCeO4pAAAAAgAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAACgAAAAAAAAAAAAAAAAAAAADN6PpZcwAAAEDtHqNhqC0V8mEZX9xXd4Gw3amGyg/aNTPKUQIH2nipnRps7H3HQTPhPiSzxwvzfXcGAz9H3hXXIkWegqJlEAoN", + "fee_bump": true, + "max_fee": 1000000 +}' +``` + + +When `fee_bump` is true, the `transaction_xdr` should contain a fully signed transaction (not a fee bump envelope). The relayer will create a fee bump transaction wrapper around it, paying the additional fees up to `max_fee` (in stroops). + + +Example response: +```json +{ + "success": true, + "data": { + "id": "5431b88c-183b-41c7-9bbb-841d38ddd866", + "hash": null, + "status": "pending", + "created_at": "2025-05-19T11:26:55.188781+00:00", + "sent_at": null, + "confirmed_at": null, + "source_account": "GCRID3RFJXOBEB73FWRYJJ4II5E5UQ413F7LTM4W5KI54NBHQDRUXVLY", + "fee": 0, + "sequence_number": 0 + }, + "error": null +} +``` + +#### Get Transaction Details +Retrieve details for a specific Stellar transaction submitted via the relayer. + +Request: `GET http://localhost:8080/api/v1/relayers//transactions/` + +* ``: The ID of your Stellar relayer configuration. +* ``: The ID of the transaction (returned from Send Transaction or from List Transactions). + +Example request (cURL): +```bash +curl --location --request GET 'http://localhost:8080/api/v1/relayers//transactions/' \ +--header 'Authorization: Bearer ' +``` + +Example response: +```json +{ + "success": true, + "data": { + "id": "5431b88c-183b-41c7-9bbb-841d38ddd866", + "hash": "f22e5d9a36cbedee20de01d5bf89d2e80682c102e844d72f567da1acd1944cb0", + "status": "submitted", + "created_at": "2025-05-19T11:26:55.188781+00:00", + "sent_at": "2025-05-19T11:26:56.136646+00:00", + "confirmed_at": null, + "source_account": "GCRID3RFJXOBEB73FWRYJJ4II5E5UQ413F7LTM4W5KI54NBHQDRUXVLY", + "fee": 0, + "sequence_number": 3700719915892739 + }, + "error": null +} +``` + +#### List Transactions +List transactions associated with a Stellar relayer, with support for pagination. + +Request: `GET http://localhost:8080/api/v1/relayers//transactions` + +Example request (cURL): +```bash +curl --location --request GET 'http://localhost:8080/api/v1/relayers//transactions' \ +--header 'Authorization: Bearer ' +``` + +Example response: +```json +{ + "success": true, + "data": [ + { + "id": "5431b88c-183b-41c7-9bbb-841d38ddd866", + "hash": "f22e5d9a36cbedee20de01d5bf89d2e80682c102e844d72f567da1acd1944cb0", + "status": "submitted", + "created_at": "2025-05-19T11:26:55.188781+00:00", + "sent_at": "2025-05-19T11:26:56.136646+00:00", + "confirmed_at": null, + "source_account": "GCRID3RFJXOBEB73FWRYJJ4II5E5UQ413F7LTM4W5KI54NBHQDRUXVLY", + "fee": 0, + "sequence_number": 3700719915892739 + } + ], + "error": null, + "pagination": { + "current_page": 1, + "per_page": 10, + "total_items": 1 + } +} +``` + +#### ScVal Argument Format + +When invoking contract functions, arguments must be provided as ScVal values in JSON format. The relayer uses the stellar-xdr JSON serialization format. + +Here are the supported ScVal types and their formats: + +| Type | Format | Description | +| --- | --- | --- | +| U64 | `"u64": "1000000"` | Unsigned 64-bit integer | +| I64 | `"i64": "-500"` | Signed 64-bit integer | +| U32 | `"u32": 42` | Unsigned 32-bit integer | +| I32 | `"i32": -42` | Signed 32-bit integer | +| Boolean | `"bool": true` | Boolean value | +| String | `"string": "hello world"` | UTF-8 string | +| Symbol | `"symbol": "transfer"` | Symbol (used for function names and identifiers) | +| Address | `"address": "GCRID3RFJXOBEB73FWRYJJ4II5E5UQ413F7LTM4W5KI54NBHQDRUXVLY"` | Stellar account or contract address | +| Bytes | `"bytes": "deadbeef"` | Hex-encoded byte array | +| Vector | `"vec": ["u32": 1, "u32": 2, "u32": 3]` | Array of ScVal values | +| Map | `"map": ["key": "symbol": "name", "val": "string": "MyToken"]` | Key-value pairs of ScVal values | +| U128 | `"u128": "hi": "100", "lo": "200"` | Unsigned 128-bit integer (as high/low parts) | +| I128 | `"i128": "hi": "-100", "lo": "200"` | Signed 128-bit integer (as high/low parts) | +| U256 | `"u256": "hi_hi": "1", "hi_lo": "2", "lo_hi": "3", "lo_lo": "4"` | Unsigned 256-bit integer (as four 64-bit parts) | +| I256 | `"i256": "hi_hi": "-1", "hi_lo": "2", "lo_hi": "3", "lo_lo": "4"` | Signed 256-bit integer (as four 64-bit parts) | + +***Address Format Notes:*** +- Account addresses start with 'G' +- Contract addresses start with 'C' +- All addresses use SEP-23 Strkey encoding + +#### Authorization Modes + +Soroban operations support different authorization modes: + +| Type | Description | Example Usage | +| --- | --- | --- | +| `none` | No authorization required | `"auth": "type": "none"` | +| `source_account` | Use the transaction source account (default) | `"auth": "type": "source_account"` | +| `addresses` | Use specific addresses (future feature) | `"auth": "type": "addresses", "signers": ["GABC..."]` | +| `xdr` | Advanced: provide base64-encoded XDR entries | `"auth": "type": "xdr", "entries": [""]` | diff --git a/content/relayer/1.0.x/changelog.mdx b/content/relayer/1.0.x/changelog.mdx new file mode 100644 index 00000000..38c7b004 --- /dev/null +++ b/content/relayer/1.0.x/changelog.mdx @@ -0,0 +1,505 @@ +--- +title: Changelog +--- + + +# [v1.1.0](https://github.com/OpenZeppelin/openzeppelin-relayer/releases/tag/v1.1.0) - 2025-08-11 + +## [1.1.0](https://github.com/OpenZeppelin/openzeppelin-relayer/compare/v1.0.0...v1.1.0) (2025-08-11) + + +### πŸš€ Features + +* Add Arbitrum support ([#373](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/373)) ([7b5372b](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/7b5372bf54fe26756ca5db6cb393e0d9d79ae621)) +* add base models ([#5](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/5)) ([55db42b](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/55db42b16d88e95ca8f6927e3b4d07c939e677c8)) +* Add CLA assistant bot ([#130](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/130)) ([4ad5733](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/4ad5733daadefe5e52bd617eaa47039677443745)) +* add directory structure and example ([d946c10](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/d946c10fd96ee2d1ce2e373ba4ccfced31f985f9)) +* add evm intristic gas_limit validation ([dd1b2d6](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/dd1b2d6768d09f051791d0db68c912a38d273715)) +* Add get_status method for EVM and Stellar ([#229](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/229)) ([e84217e](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/e84217e0fa941fcd580ad6b84ab6bfac939dd5f4)) +* Add Launctube plugin example ([#414](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/414)) ([5bda763](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/5bda7635f304923fcd4031f855009228eeefee4b)) +* Add logging improvements ([#28](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/28)) ([bb6751a](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/bb6751a4f868eb82787e7763a7995d3974ecfd49)) +* Add logic to resubmit transaction ([#102](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/102)) ([6c258b6](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/6c258b625dc7edb1d028b771647ff25b12c2b07d)) +* Add node support to environment ([#236](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/236)) ([3ab46f8](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/3ab46f848e7e4c6dee2545d62dc646b33623d63d)) +* Add noop support and refactor status ([#134](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/134)) ([f0e3a17](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/f0e3a177a536c53fe8eff834243d417bb673b744)) +* add optimism extra cost calculation ([#146](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/146)) ([b85e070](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/b85e070074ecc0aa4fbd7d5dc3af6ca0d600220b)) +* Add plugin invoker service ([#290](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/290)) ([489ce02](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/489ce0285cd88a18b1616af94bfc970a4a674228)) +* Add plugins call endpoint ([#279](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/279)) ([c278589](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/c278589f4c6bf88be86788fdd9b68c2f166f5f33)) +* Add queue processing support ([#6](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/6)) ([3ebbac2](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/3ebbac25f1ecb403dec7d090d39882a85227d883)) +* Add release workflow ([#148](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/148)) ([bd9a7e9](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/bd9a7e91a300e6650b08f799aecea4478bb4b974)) +* Add sign tx for evm local signer ([#65](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/65)) ([b17fb36](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/b17fb3625677f1dbcf1ddf3963db13b9b88ca25e)) +* Add status_reason field to transaction responses ([#369](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/369)) ([c489e5d](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/c489e5d39e3cec555caf92ac93266016c547b2bb)) +* Add stellar launchtube plugin ([#401](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/401)) ([801e2f7](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/801e2f7efc8f0cb7eb54f545ce398e6ee24cf6b9)) +* Add support for feebumped tx ([#309](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/309)) ([b4efd2e](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/b4efd2e894fb6534b61a10c5f8872a73d923410c)) +* add support for relayer paused and system disabled state ([#13](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/13)) ([44968a2](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/44968a29ec4f1cf1166c2ad726f2c9a1bac246c3)) +* Add support for stellar InvokeHostFunction transactions ([#284](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/284)) ([32ba63e](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/32ba63e58e3dfc1359b7a5c9f61f9ff2a8b6c317)) +* Add support to plugin list endpoint ([#358](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/358)) ([6517af0](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/6517af0a753db41638b006fa2b896a3ccec0d4ef)) +* add timeout_seconds to EVM relayer configuration ([#169](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/169)) ([6fd59bc](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/6fd59bc0e5993d63608d47e7ba7825a027e26b99)) +* Add transaction status handling for stellar ([#223](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/223)) ([9496eb6](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/9496eb63514afb0bd29c731bebe86ffdcf393362)) +* Add wait API for plugin transactions ([#345](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/345)) ([6069af2](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/6069af256e6cfe8470244731d4bb444b87bd175f)) +* Add worldchain testnet support ([#137](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/137)) ([25751ef](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/25751ef97b7b9fbe0c4b53fab5b762d1696f8c93)) +* Added resolve_plugin_path for script_path ([#340](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/340)) ([0b30739](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/0b30739e51f5ef6c0b97c1da585d403496b2bbac)) +* Adding job tests ([#110](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/110)) ([4d2dd98](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/4d2dd98efedacaded8d4ace118c43dbe25907278)) +* Create initial js plugins library ([#302](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/302)) ([98238e9](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/98238e9a6a30de8dba3bf8d308a82658e29de46f)) +* enabling it to listen on all interfaces - allows for easy docker config ([74a59da](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/74a59da79b314160baf35ec9750e372fbad0f360)) +* enabling it to listen on all interfaces - allows for easy docker config ([23f94c0](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/23f94c07ce46254f7b80df77ce8c4fc59fb4eef6)) +* Enhance Stellar tx handling with fee updates ([#368](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/368)) ([05617d7](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/05617d7cb06ab378c2c2207f9d0a2e11a04cc472)) +* **evm:** Add AWS KMS signer support ([#287](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/287)) ([723a9a8](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/723a9a8d7e625dd3f52b2d678d0e1cd842053e06)) +* **evm:** Implement delete pending txs ([#289](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/289)) ([bc6f829](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/bc6f829e580d42359adebceeddaf38002390e10b)) +* **evm:** Implement json rpc endpoint ([#286](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/286)) ([91528aa](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/91528aab82e3fa3cba08f63feb4ac9879aa8940e)) +* extract networks to json files ([#238](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/238)) ([5ac07b3](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/5ac07b3c570485d7cdbc419a23f373867d7ebe81)) +* handle non-retriable errors and provider health errors ([#233](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/233)) ([7add348](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/7add348da4d06af5ebebcce78d856485e9894ac3)) +* implement balance validation in EVM ([#168](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/168)) ([27fe333](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/27fe333806c28c268af981f5377e188160c845b9)) +* Implement get_balance method for StellarRelayer ([#228](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/228)) ([d92c75f](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/d92c75fe7da1b02ddb7a38df32f98082474e4cd9)) +* implement network config deserializing ([#235](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/235)) ([6d537f9](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/6d537f9298626fefc0d5a45c311a95208e1c8ef5)) +* improve examples ([#119](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/119)) ([7e59aa6](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/7e59aa64f75f3470807396b293e71cd68d3292d1)) +* Improve Redis startup logic ([#120](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/120)) ([8618ecf](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/8618ecf00b4739891fe4ce98caf14f729face896)) +* Improve Redis startup logic ([#120](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/120)) ([8618ecf](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/8618ecf00b4739891fe4ce98caf14f729face896)) +* initial repo setup ([d8815b6](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/d8815b6752931003536aa427370ca8fb1c57231c)) +* Integrate Netlify with antora ([#74](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/74)) ([09e3d48](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/09e3d4894b54c58754b373da239e9d564df69aa9)) +* Local signing for stellar ([#178](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/178)) ([f69270a](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/f69270ade4c9a9239bba874ac74858c8e7375298)) +* Pass arbitrary payloads to script exectution ([#312](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/312)) ([adecaf5](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/adecaf5d73c3df9083c6a3fcf62ed669bc90b25c)) +* Plat 5744 implement an api key authentication mechanism ([#11](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/11)) ([8891887](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/88918872d51ab10632ec6d590689d52e59dfd640)) +* Plat 5768 setup metrics endpoint ([#50](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/50)) ([7c292a5](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/7c292a572a7aef8213969fc72cadca74f9016fe8)) +* Plat 6434 improve authorization header validation ([#122](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/122)) ([eed7c31](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/eed7c31e938c7b6ecaa82774ca5d3a508bb89281)) +* Plat-5749 implement basic webhook notifications service ([#12](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/12)) ([1b47b64](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/1b47b64c318208eb7dc2ec6d62020fab30ccafbb)) +* Plat-5802 openapi sdk client ([#109](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/109)) ([1b4b681](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/1b4b681a3755f60e2934548a9666c60a4465dabb)) +* PLAT-6026 Imp cancel transaction ([#101](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/101)) ([1e5cc47](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/1e5cc47bdc54acafeeefb60489db410b42722b0f)) +* PLAT-6026 Imp cancel transaction ([#101](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/101)) ([1e5cc47](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/1e5cc47bdc54acafeeefb60489db410b42722b0f)) +* Plat-6118 implement logic for syncing relayer state upon service start ([#19](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/19)) ([2ba3629](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/2ba36292a0b8d0d67ddab42d2845a6a0d5f31e3a)) +* Plat-6153 add network definitions for Solana networks ([#26](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/26)) ([ff453d5](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/ff453d59724eeaa194ccf7f83993ce8d649f7432)) +* Plat-6154 add support for solana local signer ([#29](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/29)) ([40caead](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/40caeadde5f08200410912b98943346971084163)) +* plat-6158 implement Solana rpc service ([#36](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/36)) ([8fb50a8](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/8fb50a833e7f9b1773dbe4ca1d77a9609a5d5ec1)) +* Plat-6159 extend relayer config file solana policies ([#38](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/38)) ([4f4602b](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/4f4602b754e71539937447c1743a7f069317598b)) +* Plat-6164 implement feeestimate rpc method ([#61](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/61)) ([43b016c](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/43b016c4e5faa5ee1fedcdadccf3bc768962178e)) +* Plat-6165 implement transfertransaction rpc method ([#63](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/63)) ([c59a3b8](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/c59a3b8894c32470adf10770f4804e272aa829d3)) +* Plat-6167 implement signtransaction rpc method ([#57](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/57)) ([ad7a1ff](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/ad7a1ffe41eb868f54737c1f1b44a52c6d02d172)) +* Plat-6169 implement getsupportedtokens rpc method ([#45](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/45)) ([3f91199](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/3f9119981acd7f92618ba6ec12c3039563368202)) +* Plat-6170 add vault hosted signer support ([#99](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/99)) ([7a9491d](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/7a9491d4094fc21bc87551c68687b4f44f3edd18)) +* Plat-6207 implement trait abstraction relayer ([#43](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/43)) ([abeb7cf](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/abeb7cfccc9e70b26ddd0d41d736352d57d6ade9)) +* plat-6215 add support for rpc failovers and retries ([#231](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/231)) ([ca6d24f](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/ca6d24f1bcdbb912795dcb1496519b49b5e81bf1)) +* Plat-6216 adding network symbol support ([#37](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/37)) ([21f798f](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/21f798fc114de47ae0ed7e127e496bb50ca081a8)) +* Plat-6236 adding validation payload ([#42](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/42)) ([a5ff165](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/a5ff165df14f48d47adee03e8e2c8ef5a899ff57)) +* Plat-6236 adding validation payload ([#42](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/42)) ([a5ff165](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/a5ff165df14f48d47adee03e8e2c8ef5a899ff57)) +* Plat-6239 whitelist policy validation ([#44](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/44)) ([3adb45e](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/3adb45e17b8b23c70e09e422cfca051ebab266f1)) +* Plat-6239 whitelist policy validation ([#44](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/44)) ([3adb45e](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/3adb45e17b8b23c70e09e422cfca051ebab266f1)) +* Plat-6248 implementation dummy of legacy price ([#49](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/49)) ([6319d64](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/6319d64bf27fd75f5192165df885156ca91ea9f0)) +* Plat-6248 implementation dummy of legacy price ([#49](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/49)) ([6319d64](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/6319d64bf27fd75f5192165df885156ca91ea9f0)) +* Plat-6267 add utility script for generating local keystore files ([#69](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/69)) ([b5df7f6](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/b5df7f6b0450118c9123de46689fa115efcdec94)) +* Plat-6291 add webhook notifications for rpc methods ([#72](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/72)) ([2f35d81](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/2f35d81b3711cf2f87dbc6df31b9e0f90432164e)) +* Plat-6299 clean transaction response ([#76](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/76)) ([fc5dd05](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/fc5dd05154bca4a1d740cef058bb797cd3f513a0)) +* Plat-6300 returning the balance of the relayer ([#78](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/78)) ([e0ce8e0](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/e0ce8e04f3950c094c9af3e3413d61cd7162c8e7)) +* Plat-6300 returning the balance of the relayer ([#78](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/78)) ([e0ce8e0](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/e0ce8e04f3950c094c9af3e3413d61cd7162c8e7)) +* Plat-6303 store solana submitted transactions to db and run status check logic ([#398](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/398)) ([e8420bc](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/e8420bca02c20a53b02d9bedc8da1b7a784716dc)) +* Plat-6304 use Authorization header instead of x api key ([#94](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/94)) ([34e8a81](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/34e8a813234ee6aaf2a6956f6dd45f82e47e7861)) +* Plat-6309 Fetching eip1559 prices ([#83](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/83)) ([68d574f](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/68d574fcb159ae3b6502167a9bcf34bb1a56ea7e)) +* Plat-6309 Fetching eip1559 prices ([#83](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/83)) ([68d574f](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/68d574fcb159ae3b6502167a9bcf34bb1a56ea7e)) +* plat-6340 store private keys securely in memory ([#104](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/104)) ([28c2fab](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/28c2fab84f3db6b9d971126cf917263da395c421)) +* PLAT-6350 - Sign EIP-1559 ([#98](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/98)) ([673e420](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/673e4202f9d98bfd02512090fa3daacfa40831fe)) +* PLAT-6350 - Sign EIP-1559 ([#98](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/98)) ([673e420](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/673e4202f9d98bfd02512090fa3daacfa40831fe)) +* PLAT-6374 EIP-1559 default if network support it and not explicit false ([#100](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/100)) ([c982dde](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/c982ddefeba93381ac7d2c5e09f616a60820b8b8)) +* PLAT-6374 EIP-1559 default if network support it and not explicit false ([#100](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/100)) ([c982dde](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/c982ddefeba93381ac7d2c5e09f616a60820b8b8)) +* PLAT-6416 Use generics transaction factory ([#105](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/105)) ([7b94662](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/7b946625af77c6aabd336d34646e9ae62ece3b6a)) +* plat-6433 add minimum length validations for config sensitive values ([#125](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/125)) ([31453c5](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/31453c5586ca4fef70e7ea0e2dcd0260a8a721a6)) +* Plat-6441 document upcoming work ([#131](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/131)) ([377a8bb](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/377a8bb57ff5b3b23abb58d1c3378489c40218cf)) +* PLAT-6442 - Abstraction and unit tests relayer domain ([#117](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/117)) ([643194a](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/643194acd9079ac3ac157e909f0b30199af8b0c9)) +* PLAT-6442 - Abstraction and unit tests relayer domain ([#117](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/117)) ([643194a](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/643194acd9079ac3ac157e909f0b30199af8b0c9)) +* Plat-6457 Ignore utoipa ([#127](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/127)) ([234854a](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/234854afbf30a9a94fa3365f60f035e53e068938)) +* Plat-6457 Ignore utoipa ([#127](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/127)) ([234854a](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/234854afbf30a9a94fa3365f60f035e53e068938)) +* Plat-6459 create mermaid architecture diagram ([#126](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/126)) ([3de147b](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/3de147b907c28d3e9a8a38a2d6b8cd665253c423)) +* plat-6471 add Solana Token 2022 extensions support ([#166](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/166)) ([d35c506](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/d35c506ea298a86897ede5702481403f839f2451)) +* plat-6476 Add support to collect transaction fee ([#135](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/135)) ([4f4a07b](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/4f4a07b2846d2980bbf09734602315702ded9dbe)) +* Plat-6479 added support for rpc custom endpoints ([#138](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/138)) ([3df3d49](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/3df3d49ec6a662698a90630811d717920b7cdf3b)) +* Plat-6521 add turnkey hosted signer support (evm, solana) ([#174](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/174)) ([b24688e](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/b24688ead4fe3015ca3b7c74e56f1906085a5aa3)) +* plat-6522 allow for the use of on chain defi to automatically swap spl ([#198](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/198)) ([dc9e2e2](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/dc9e2e2dd1d46830bc6479c1928a2e7ef7f91fb3)) +* plat-6571 add support for gcp signer ([#221](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/221)) ([0170fa1](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/0170fa12c3ecc64d1c48ed3a726358ed74d4596b)) +* Plat-6677 implement redis repositories for existing collections ([#350](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/350)) ([5fee731](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/5fee731c5f19013f41a12a5b93af79d65bdf777e)) +* Plat-6679 implement startup logic to populate redis from config file ([#359](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/359)) ([5e1c0c8](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/5e1c0c825d3c1185a5c59360a2c857d79b46abba)) +* Plat-6681 expose crud api endpoints ([#365](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/365)) ([f3c3426](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/f3c34266f3f035cd240105833ef4e67711cb0356)) +* Plat-6684 add support for transaction entries expiration ([#394](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/394)) ([6f6f765](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/6f6f765556b2fc16764f8afe02ceedf268c26c13)) +* plat-6817 EVM add support for gas limit calculation ([#355](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/355)) ([dd1b2d6](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/dd1b2d6768d09f051791d0db68c912a38d273715)) +* plat-6873 add storage documentation ([#395](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/395)) ([ffd4ed5](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/ffd4ed58d322bad63be500a084a0b082ac7b59d9)) +* Plugins improvements ([#410](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/410)) ([648a0f1](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/648a0f121a6308e8bde0e09010d2e0c83de5c6ec)) +* Pricing validation on receiving payload EVM ([#59](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/59)) ([1206d42](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/1206d4241dbda84bc861f501d322f6bd33234f0b)) +* Pricing validation on receiving payload EVM ([#59](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/59)) ([1206d42](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/1206d4241dbda84bc861f501d322f6bd33234f0b)) +* Relayer plugins - add support to plugins in configs ([#253](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/253)) ([6a14239](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/6a14239486900b2ef121b5de9e87410c412b65fe)) +* **replace_tx:** Implement replace tx for evm ([#272](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/272)) ([b48e71f](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/b48e71f55fda03bea83e90255b0d180db704cb52)) +* Set default network folder ([#313](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/313)) ([b28c99c](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/b28c99c43bedd921a55660622d845e63890e0d74)) +* Signer service ([#8](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/8)) ([4f85b7b](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/4f85b7bf5b6aa83903ed8febdfe244d54e803642)) +* **signer:** Add GCP Signer to EVM ([#305](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/305)) ([a8817b6](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/a8817b6c87c65731232d0a141338f3996aef2510)) +* Speed support transaction ([#62](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/62)) ([a572af6](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/a572af65ca4f664dce13e705eac37b56dee306fa)) +* Stellar RPC config ([#213](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/213)) ([6fd75ea](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/6fd75ea65bf1a945ba891f99d83b0cdacdf30014)) +* Stellar RPC service ([#183](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/183)) ([9943ffd](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/9943ffd67a709df487264f50eccd03b06cc817d4)) +* Stellar transaction submission ([#199](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/199)) ([c6b72bf](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/c6b72bfba82c7fb9288c07e49bef04cf527d1245)) +* support for multiple custom RPCs with weighted configuration ([#182](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/182)) ([92ea5ad](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/92ea5ad324323b957fcbdce85c37517ec6f963ba)) +* support for retries and failovers in EVM Provider ([#197](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/197)) ([542f21a](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/542f21a9346def9b7fe47e0a29a2bbd5ab2af349)) +* Support plugin timeouts ([#348](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/348)) ([0a1c51e](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/0a1c51e9fe540ba570af25146538992a26b9a8a0)) +* Tx submissions and status mgmt ([#81](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/81)) ([9f829f1](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/9f829f1c59c4221c9cf38c6cb1ff36351a348cd1)) +* Types introduced for plugin params and result ([#351](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/351)) ([dda83a2](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/dda83a296fd5bd5bfca7f7902f4ca035e1bd8796)) +* Update Stellar network config and docs ([#380](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/380)) ([a4e1a0f](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/a4e1a0f38590f21c6d5e917a02fee4f6bef4f075)) +* Update transaction status to mined/expired ([#85](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/85)) ([8f5ee53](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/8f5ee53bbe64d55ccf8015a1c8d203cf5e391f08)) + + +### πŸ› Bug Fixes + +* Add memo validation for InvokeHostFunction ([#294](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/294)) ([6bb4ffa](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/6bb4ffaf9ceb4a8daef29ec5878595cca7041300)) +* change the ampersand to and, as as the shell interpret it ([#206](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/206)) ([d164d6a](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/d164d6a4d63fbf0acdfe1330cf25147e86280af8)) +* Changing base image to wolfi, added node and npm ([#266](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/266)) ([1181996](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/1181996dac6da52f96e164b1c937828a3940d5b8)) +* CLA assistant ([#171](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/171)) ([b326a56](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/b326a5680722e812263aab949003c214795fd2c0)) +* CLA labels ([#173](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/173)) ([e31405b](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/e31405b8cba9ffd2ff991d56444320ff3d069ad0)) +* Codecov changes and adjustments ([#113](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/113)) ([6e62dcf](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/6e62dcf212a917421c7559566136c018e17c38f5)) +* Config example file ([#285](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/285)) ([a020c6f](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/a020c6fcd6f9b638d955d5f2c99aa0e199d8bf6e)) +* Correct env var value in semgrep.yml ([#375](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/375)) ([2e98e21](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/2e98e2149135b97a62b90c302675379642fdf7b3)) +* Docker Compose ([#156](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/156)) ([6ca012f](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/6ca012fb9b50d5c2159c498679673cb27530fc3c)) +* Docker readme file ([#339](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/339)) ([2db9933](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/2db9933def061046cc3585a07249107a236ef98c)) +* docker-scan - chainguard issue ([#255](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/255)) ([c9ab94b](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/c9ab94bcee7b386a33b063504b3e6d2cf188d8b5)) +* Docs link ([#128](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/128)) ([8263828](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/82638284cf13a4da376624362f5353b57365302a)) +* Docs path for crate ([#129](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/129)) ([51cf556](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/51cf556411c9c1f79dbee7f4c3aa25df7fe2af49)) +* **docs:** replaced Monitor for Relayer ([2ff196b](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/2ff196bf772668556210a895d4f83315e579577f)) +* Documentation name for antora ([#121](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/121)) ([63c36f5](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/63c36f5393b1369a169c8617b20952bca30aef0c)) +* Environment variables ([#124](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/124)) ([8d31131](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/8d31131c087a6d0a64ae2dadecb5ae395ad1b575)) +* Fix the codecov yaml syntax ([#108](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/108)) ([ab9ab5b](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/ab9ab5b0c9313d083cd47c71d7faade867c58deb)) +* Flaky logging tests ([#89](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/89)) ([bc909cc](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/bc909cc336613bb5a191c562632278bd3c270b09)) +* Implement stellar sequence sync and tx reset ([#367](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/367)) ([60b5deb](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/60b5deb4915041d60a064cfac1a066406c339517)) +* Inheritance validation ([#374](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/374)) ([f8b921b](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/f8b921b4d6d85b8068428f1e34de121183a02179)) +* Make plugins entry in configs optional ([#300](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/300)) ([f299779](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/f299779318429677fd672d4a2433828971a1b62e)) +* Minor fixes in Plugin docs ([#325](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/325)) ([33bb6a1](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/33bb6a1841f2e84723e49cc81258a930241dc735)) +* Missing libssl and workflow ([#155](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/155)) ([9de7133](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/9de7133c2ba1768f4d989158f19c27444e522f9e)) +* Plat 6286 write tests for metrics and middleware functions ([#70](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/70)) ([18124fb](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/18124fbbfbc26f300648a7a4050ebf9be72465ac)) +* PLAT-6426 Increase test coverage ([#118](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/118)) ([1fa41f0](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/1fa41f0f225c9d515690738e960073396dce66ce)) +* PLAT-6478 create unit test for use of on relayers dotenv ([#139](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/139)) ([509e166](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/509e1664518823ef3844e52e818707f3371ddbff)) +* plat-6480 allow transfering wrapped sol tokens ([#132](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/132)) ([f04e66a](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/f04e66a568c877c2a4c5c5378fb6017c2e41d2c6)) +* Plat-6815 resubmission bug ([#353](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/353)) ([72ac174](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/72ac17471e3a0a6ac35e9a9bb9ff8fe5e8b94bf2)) +* plat-6888 aws kms signer issue ([#411](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/411)) ([3c12c88](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/3c12c88703c92526fe975eabba6ba0ffa9ca9c79)) +* Plugin result + adds tests for plugin ts lib ([#336](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/336)) ([b30246e](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/b30246e8922d3cb5bd3c5b92a7678f7591db5b97)) +* Relayer plugins format output ([#307](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/307)) ([8f25e5f](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/8f25e5f55812e3d346c8bc0ff063cf07e2f0b753)) +* Release merge conflicts ([#163](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/163)) ([4cac422](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/4cac4221817373a1ae7eff92db187dbae2f1665b)) +* remove the ci job dependant from the test job ([#222](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/222)) ([4056610](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/40566108b66c701323145c2889ce0141b84714b8)) +* Replace automatic minor version bumps ([#315](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/315)) ([85784b4](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/85784b486a9508429ae94373a7f3db13d78b39d6)) +* Replace tx request body ([#326](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/326)) ([a20c916](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/a20c916b592891b7a2afafd2e62b32723fc05dc2)) +* SBOM upload error ([#342](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/342)) ([1f9318e](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/1f9318e22cbe59ca03bc617b0986379574e5f770)) +* Semgrep CI integration ([#371](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/371)) ([6b9a6d2](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/6b9a6d24e22b78743f16c566026b34f9912669ad)) +* Semgrep send metrics value ([#381](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/381)) ([315ccbc](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/315ccbca9a48816fc6e0c8133301aa3e3186ff93)) +* Skip releases ([ccafcbe](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/ccafcbe11bc6ea46dacb9c59be578abd45112ad3)) +* Solve issues with new solana_sdk version ([#324](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/324)) ([ab97253](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/ab972533259506bb21e22ec7f899a45d2fc97db5)) +* Switch Redocly build to use standalone html file ([#291](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/291)) ([97a8698](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/97a86980bec6260920a469018fee0d3541d1a063)) +* syntax error in codeql.yml ([#385](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/385)) ([987fd33](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/987fd33566b66b2821490d0769a3c863a778c271)) +* Update configs and dockerfiles in examples ([#298](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/298)) ([2e505ad](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/2e505ad827ab7544f7c6a3fdf4018b1e9428f1d6)) +* Update semgrep.yml ([#347](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/347)) ([5ffb803](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/5ffb8036ca6d3fb5a8cdb34fa5484e7732c842a1)) +* Update Stellar API docs to match implementation ([#292](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/292)) ([96d95e3](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/96d95e35784c25f39afe626b56f11477fd213196)) +* Use unicode character for emoji ([#343](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/343)) ([784e89f](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/784e89fae4ad2ddad037ddbbd0bec6df160e9a6a)) + +[Changes][v1.1.0] + + + +# [v1.0.0](https://github.com/OpenZeppelin/openzeppelin-relayer/releases/tag/v1.0.0) - 2025-06-30 + +## [1.0.0](https://github.com/OpenZeppelin/openzeppelin-relayer/compare/v0.2.0...v1.0.0) (2025-06-30) + + +### πŸš€ Features + +* add base models ([#5](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/5)) ([55db42b](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/55db42b16d88e95ca8f6927e3b4d07c939e677c8)) +* Add CLA assistant bot ([#130](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/130)) ([4ad5733](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/4ad5733daadefe5e52bd617eaa47039677443745)) +* add directory structure and example ([d946c10](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/d946c10fd96ee2d1ce2e373ba4ccfced31f985f9)) +* Add get_status method for EVM and Stellar ([#229](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/229)) ([e84217e](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/e84217e0fa941fcd580ad6b84ab6bfac939dd5f4)) +* Add logging improvements ([#28](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/28)) ([bb6751a](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/bb6751a4f868eb82787e7763a7995d3974ecfd49)) +* Add logic to resubmit transaction ([#102](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/102)) ([6c258b6](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/6c258b625dc7edb1d028b771647ff25b12c2b07d)) +* Add node support to environment ([#236](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/236)) ([3ab46f8](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/3ab46f848e7e4c6dee2545d62dc646b33623d63d)) +* Add noop support and refactor status ([#134](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/134)) ([f0e3a17](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/f0e3a177a536c53fe8eff834243d417bb673b744)) +* add optimism extra cost calculation ([#146](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/146)) ([b85e070](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/b85e070074ecc0aa4fbd7d5dc3af6ca0d600220b)) +* Add plugin invoker service ([#290](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/290)) ([489ce02](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/489ce0285cd88a18b1616af94bfc970a4a674228)) +* Add plugins call endpoint ([#279](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/279)) ([c278589](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/c278589f4c6bf88be86788fdd9b68c2f166f5f33)) +* Add queue processing support ([#6](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/6)) ([3ebbac2](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/3ebbac25f1ecb403dec7d090d39882a85227d883)) +* Add release workflow ([#148](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/148)) ([bd9a7e9](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/bd9a7e91a300e6650b08f799aecea4478bb4b974)) +* Add sign tx for evm local signer ([#65](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/65)) ([b17fb36](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/b17fb3625677f1dbcf1ddf3963db13b9b88ca25e)) +* Add support for feebumped tx ([#309](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/309)) ([b4efd2e](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/b4efd2e894fb6534b61a10c5f8872a73d923410c)) +* add support for relayer paused and system disabled state ([#13](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/13)) ([44968a2](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/44968a29ec4f1cf1166c2ad726f2c9a1bac246c3)) +* Add support for stellar InvokeHostFunction transactions ([#284](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/284)) ([32ba63e](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/32ba63e58e3dfc1359b7a5c9f61f9ff2a8b6c317)) +* add timeout_seconds to EVM relayer configuration ([#169](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/169)) ([6fd59bc](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/6fd59bc0e5993d63608d47e7ba7825a027e26b99)) +* Add transaction status handling for stellar ([#223](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/223)) ([9496eb6](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/9496eb63514afb0bd29c731bebe86ffdcf393362)) +* Add worldchain testnet support ([#137](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/137)) ([25751ef](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/25751ef97b7b9fbe0c4b53fab5b762d1696f8c93)) +* Adding job tests ([#110](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/110)) ([4d2dd98](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/4d2dd98efedacaded8d4ace118c43dbe25907278)) +* Create initial js plugins library ([#302](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/302)) ([98238e9](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/98238e9a6a30de8dba3bf8d308a82658e29de46f)) +* enabling it to listen on all interfaces - allows for easy docker config ([74a59da](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/74a59da79b314160baf35ec9750e372fbad0f360)) +* enabling it to listen on all interfaces - allows for easy docker config ([23f94c0](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/23f94c07ce46254f7b80df77ce8c4fc59fb4eef6)) +* **evm:** Add AWS KMS signer support ([#287](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/287)) ([723a9a8](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/723a9a8d7e625dd3f52b2d678d0e1cd842053e06)) +* **evm:** Implement delete pending txs ([#289](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/289)) ([bc6f829](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/bc6f829e580d42359adebceeddaf38002390e10b)) +* **evm:** Implement json rpc endpoint ([#286](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/286)) ([91528aa](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/91528aab82e3fa3cba08f63feb4ac9879aa8940e)) +* extract networks to json files ([#238](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/238)) ([5ac07b3](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/5ac07b3c570485d7cdbc419a23f373867d7ebe81)) +* handle non-retriable errors and provider health errors ([#233](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/233)) ([7add348](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/7add348da4d06af5ebebcce78d856485e9894ac3)) +* implement balance validation in EVM ([#168](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/168)) ([27fe333](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/27fe333806c28c268af981f5377e188160c845b9)) +* Implement get_balance method for StellarRelayer ([#228](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/228)) ([d92c75f](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/d92c75fe7da1b02ddb7a38df32f98082474e4cd9)) +* implement network config deserializing ([#235](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/235)) ([6d537f9](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/6d537f9298626fefc0d5a45c311a95208e1c8ef5)) +* improve examples ([#119](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/119)) ([7e59aa6](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/7e59aa64f75f3470807396b293e71cd68d3292d1)) +* Improve Redis startup logic ([#120](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/120)) ([8618ecf](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/8618ecf00b4739891fe4ce98caf14f729face896)) +* initial repo setup ([d8815b6](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/d8815b6752931003536aa427370ca8fb1c57231c)) +* Integrate Netlify with antora ([#74](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/74)) ([09e3d48](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/09e3d4894b54c58754b373da239e9d564df69aa9)) +* Local signing for stellar ([#178](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/178)) ([f69270a](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/f69270ade4c9a9239bba874ac74858c8e7375298)) +* Pass arbitrary payloads to script exectution ([#312](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/312)) ([adecaf5](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/adecaf5d73c3df9083c6a3fcf62ed669bc90b25c)) +* Plat 5744 implement an api key authentication mechanism ([#11](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/11)) ([8891887](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/88918872d51ab10632ec6d590689d52e59dfd640)) +* Plat 5768 setup metrics endpoint ([#50](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/50)) ([7c292a5](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/7c292a572a7aef8213969fc72cadca74f9016fe8)) +* Plat 6434 improve authorization header validation ([#122](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/122)) ([eed7c31](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/eed7c31e938c7b6ecaa82774ca5d3a508bb89281)) +* Plat-5749 implement basic webhook notifications service ([#12](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/12)) ([1b47b64](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/1b47b64c318208eb7dc2ec6d62020fab30ccafbb)) +* Plat-5802 openapi sdk client ([#109](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/109)) ([1b4b681](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/1b4b681a3755f60e2934548a9666c60a4465dabb)) +* PLAT-6026 Imp cancel transaction ([#101](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/101)) ([1e5cc47](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/1e5cc47bdc54acafeeefb60489db410b42722b0f)) +* Plat-6118 implement logic for syncing relayer state upon service start ([#19](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/19)) ([2ba3629](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/2ba36292a0b8d0d67ddab42d2845a6a0d5f31e3a)) +* Plat-6153 add network definitions for Solana networks ([#26](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/26)) ([ff453d5](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/ff453d59724eeaa194ccf7f83993ce8d649f7432)) +* Plat-6154 add support for solana local signer ([#29](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/29)) ([40caead](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/40caeadde5f08200410912b98943346971084163)) +* plat-6158 implement Solana rpc service ([#36](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/36)) ([8fb50a8](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/8fb50a833e7f9b1773dbe4ca1d77a9609a5d5ec1)) +* Plat-6159 extend relayer config file solana policies ([#38](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/38)) ([4f4602b](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/4f4602b754e71539937447c1743a7f069317598b)) +* Plat-6164 implement feeestimate rpc method ([#61](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/61)) ([43b016c](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/43b016c4e5faa5ee1fedcdadccf3bc768962178e)) +* Plat-6165 implement transfertransaction rpc method ([#63](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/63)) ([c59a3b8](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/c59a3b8894c32470adf10770f4804e272aa829d3)) +* Plat-6167 implement signtransaction rpc method ([#57](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/57)) ([ad7a1ff](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/ad7a1ffe41eb868f54737c1f1b44a52c6d02d172)) +* Plat-6169 implement getsupportedtokens rpc method ([#45](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/45)) ([3f91199](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/3f9119981acd7f92618ba6ec12c3039563368202)) +* Plat-6170 add vault hosted signer support ([#99](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/99)) ([7a9491d](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/7a9491d4094fc21bc87551c68687b4f44f3edd18)) +* Plat-6207 implement trait abstraction relayer ([#43](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/43)) ([abeb7cf](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/abeb7cfccc9e70b26ddd0d41d736352d57d6ade9)) +* plat-6215 add support for rpc failovers and retries ([#231](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/231)) ([ca6d24f](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/ca6d24f1bcdbb912795dcb1496519b49b5e81bf1)) +* Plat-6216 adding network symbol support ([#37](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/37)) ([21f798f](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/21f798fc114de47ae0ed7e127e496bb50ca081a8)) +* Plat-6236 adding validation payload ([#42](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/42)) ([a5ff165](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/a5ff165df14f48d47adee03e8e2c8ef5a899ff57)) +* Plat-6239 whitelist policy validation ([#44](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/44)) ([3adb45e](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/3adb45e17b8b23c70e09e422cfca051ebab266f1)) +* Plat-6248 implementation dummy of legacy price ([#49](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/49)) ([6319d64](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/6319d64bf27fd75f5192165df885156ca91ea9f0)) +* Plat-6267 add utility script for generating local keystore files ([#69](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/69)) ([b5df7f6](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/b5df7f6b0450118c9123de46689fa115efcdec94)) +* Plat-6291 add webhook notifications for rpc methods ([#72](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/72)) ([2f35d81](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/2f35d81b3711cf2f87dbc6df31b9e0f90432164e)) +* Plat-6299 clean transaction response ([#76](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/76)) ([fc5dd05](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/fc5dd05154bca4a1d740cef058bb797cd3f513a0)) +* Plat-6300 returning the balance of the relayer ([#78](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/78)) ([e0ce8e0](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/e0ce8e04f3950c094c9af3e3413d61cd7162c8e7)) +* Plat-6304 use Authorization header instead of x api key ([#94](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/94)) ([34e8a81](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/34e8a813234ee6aaf2a6956f6dd45f82e47e7861)) +* Plat-6309 Fetching eip1559 prices ([#83](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/83)) ([68d574f](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/68d574fcb159ae3b6502167a9bcf34bb1a56ea7e)) +* plat-6340 store private keys securely in memory ([#104](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/104)) ([28c2fab](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/28c2fab84f3db6b9d971126cf917263da395c421)) +* PLAT-6350 - Sign EIP-1559 ([#98](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/98)) ([673e420](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/673e4202f9d98bfd02512090fa3daacfa40831fe)) +* PLAT-6374 EIP-1559 default if network support it and not explicit false ([#100](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/100)) ([c982dde](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/c982ddefeba93381ac7d2c5e09f616a60820b8b8)) +* PLAT-6416 Use generics transaction factory ([#105](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/105)) ([7b94662](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/7b946625af77c6aabd336d34646e9ae62ece3b6a)) +* plat-6433 add minimum length validations for config sensitive values ([#125](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/125)) ([31453c5](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/31453c5586ca4fef70e7ea0e2dcd0260a8a721a6)) +* Plat-6441 document upcoming work ([#131](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/131)) ([377a8bb](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/377a8bb57ff5b3b23abb58d1c3378489c40218cf)) +* PLAT-6442 - Abstraction and unit tests relayer domain ([#117](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/117)) ([643194a](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/643194acd9079ac3ac157e909f0b30199af8b0c9)) +* Plat-6457 Ignore utoipa ([#127](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/127)) ([234854a](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/234854afbf30a9a94fa3365f60f035e53e068938)) +* Plat-6459 create mermaid architecture diagram ([#126](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/126)) ([3de147b](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/3de147b907c28d3e9a8a38a2d6b8cd665253c423)) +* plat-6471 add Solana Token 2022 extensions support ([#166](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/166)) ([d35c506](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/d35c506ea298a86897ede5702481403f839f2451)) +* plat-6476 Add support to collect transaction fee ([#135](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/135)) ([4f4a07b](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/4f4a07b2846d2980bbf09734602315702ded9dbe)) +* Plat-6479 added support for rpc custom endpoints ([#138](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/138)) ([3df3d49](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/3df3d49ec6a662698a90630811d717920b7cdf3b)) +* Plat-6521 add turnkey hosted signer support (evm, solana) ([#174](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/174)) ([b24688e](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/b24688ead4fe3015ca3b7c74e56f1906085a5aa3)) +* plat-6522 allow for the use of on chain defi to automatically swap spl ([#198](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/198)) ([dc9e2e2](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/dc9e2e2dd1d46830bc6479c1928a2e7ef7f91fb3)) +* plat-6571 add support for gcp signer ([#221](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/221)) ([0170fa1](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/0170fa12c3ecc64d1c48ed3a726358ed74d4596b)) +* Pricing validation on receiving payload EVM ([#59](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/59)) ([1206d42](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/1206d4241dbda84bc861f501d322f6bd33234f0b)) +* Pricing validation on receiving payload EVM ([#59](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/59)) ([1206d42](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/1206d4241dbda84bc861f501d322f6bd33234f0b)) +* Relayer plugins - add support to plugins in configs ([#253](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/253)) ([6a14239](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/6a14239486900b2ef121b5de9e87410c412b65fe)) +* **replace_tx:** Implement replace tx for evm ([#272](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/272)) ([b48e71f](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/b48e71f55fda03bea83e90255b0d180db704cb52)) +* Set default network folder ([#313](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/313)) ([b28c99c](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/b28c99c43bedd921a55660622d845e63890e0d74)) +* Signer service ([#8](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/8)) ([4f85b7b](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/4f85b7bf5b6aa83903ed8febdfe244d54e803642)) +* **signer:** Add GCP Signer to EVM ([#305](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/305)) ([a8817b6](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/a8817b6c87c65731232d0a141338f3996aef2510)) +* Speed support transaction ([#62](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/62)) ([a572af6](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/a572af65ca4f664dce13e705eac37b56dee306fa)) +* Stellar RPC config ([#213](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/213)) ([6fd75ea](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/6fd75ea65bf1a945ba891f99d83b0cdacdf30014)) +* Stellar RPC service ([#183](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/183)) ([9943ffd](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/9943ffd67a709df487264f50eccd03b06cc817d4)) +* Stellar transaction submission ([#199](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/199)) ([c6b72bf](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/c6b72bfba82c7fb9288c07e49bef04cf527d1245)) +* support for multiple custom RPCs with weighted configuration ([#182](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/182)) ([92ea5ad](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/92ea5ad324323b957fcbdce85c37517ec6f963ba)) +* support for retries and failovers in EVM Provider ([#197](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/197)) ([542f21a](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/542f21a9346def9b7fe47e0a29a2bbd5ab2af349)) +* Tx submissions and status mgmt ([#81](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/81)) ([9f829f1](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/9f829f1c59c4221c9cf38c6cb1ff36351a348cd1)) +* Update transaction status to mined/expired ([#85](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/85)) ([8f5ee53](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/8f5ee53bbe64d55ccf8015a1c8d203cf5e391f08)) + + +### πŸ› Bug Fixes + +* Add memo validation for InvokeHostFunction ([#294](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/294)) ([6bb4ffa](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/6bb4ffaf9ceb4a8daef29ec5878595cca7041300)) +* change the ampersand to and, as as the shell interpret it ([#206](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/206)) ([d164d6a](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/d164d6a4d63fbf0acdfe1330cf25147e86280af8)) +* Changing base image to wolfi, added node and npm ([#266](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/266)) ([1181996](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/1181996dac6da52f96e164b1c937828a3940d5b8)) +* CLA assistant ([#171](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/171)) ([b326a56](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/b326a5680722e812263aab949003c214795fd2c0)) +* CLA labels ([#173](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/173)) ([e31405b](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/e31405b8cba9ffd2ff991d56444320ff3d069ad0)) +* Codecov changes and adjustments ([#113](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/113)) ([6e62dcf](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/6e62dcf212a917421c7559566136c018e17c38f5)) +* Config example file ([#285](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/285)) ([a020c6f](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/a020c6fcd6f9b638d955d5f2c99aa0e199d8bf6e)) +* Docker Compose ([#156](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/156)) ([6ca012f](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/6ca012fb9b50d5c2159c498679673cb27530fc3c)) +* docker-scan - chainguard issue ([#255](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/255)) ([c9ab94b](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/c9ab94bcee7b386a33b063504b3e6d2cf188d8b5)) +* Docs link ([#128](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/128)) ([8263828](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/82638284cf13a4da376624362f5353b57365302a)) +* Docs path for crate ([#129](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/129)) ([51cf556](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/51cf556411c9c1f79dbee7f4c3aa25df7fe2af49)) +* **docs:** replaced Monitor for Relayer ([2ff196b](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/2ff196bf772668556210a895d4f83315e579577f)) +* Documentation name for antora ([#121](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/121)) ([63c36f5](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/63c36f5393b1369a169c8617b20952bca30aef0c)) +* Environment variables ([#124](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/124)) ([8d31131](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/8d31131c087a6d0a64ae2dadecb5ae395ad1b575)) +* Fix the codecov yaml syntax ([#108](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/108)) ([ab9ab5b](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/ab9ab5b0c9313d083cd47c71d7faade867c58deb)) +* Flaky logging tests ([#89](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/89)) ([bc909cc](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/bc909cc336613bb5a191c562632278bd3c270b09)) +* Make plugins entry in configs optional ([#300](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/300)) ([f299779](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/f299779318429677fd672d4a2433828971a1b62e)) +* Missing libssl and workflow ([#155](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/155)) ([9de7133](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/9de7133c2ba1768f4d989158f19c27444e522f9e)) +* Plat 6286 write tests for metrics and middleware functions ([#70](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/70)) ([18124fb](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/18124fbbfbc26f300648a7a4050ebf9be72465ac)) +* PLAT-6426 Increase test coverage ([#118](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/118)) ([1fa41f0](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/1fa41f0f225c9d515690738e960073396dce66ce)) +* PLAT-6478 create unit test for use of on relayers dotenv ([#139](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/139)) ([509e166](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/509e1664518823ef3844e52e818707f3371ddbff)) +* plat-6480 allow transfering wrapped sol tokens ([#132](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/132)) ([f04e66a](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/f04e66a568c877c2a4c5c5378fb6017c2e41d2c6)) +* Relayer plugins format output ([#307](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/307)) ([8f25e5f](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/8f25e5f55812e3d346c8bc0ff063cf07e2f0b753)) +* Release merge conflicts ([#163](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/163)) ([4cac422](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/4cac4221817373a1ae7eff92db187dbae2f1665b)) +* remove the ci job dependant from the test job ([#222](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/222)) ([4056610](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/40566108b66c701323145c2889ce0141b84714b8)) +* Replace automatic minor version bumps ([#315](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/315)) ([85784b4](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/85784b486a9508429ae94373a7f3db13d78b39d6)) +* Skip releases ([ccafcbe](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/ccafcbe11bc6ea46dacb9c59be578abd45112ad3)) +* Update configs and dockerfiles in examples ([#298](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/298)) ([2e505ad](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/2e505ad827ab7544f7c6a3fdf4018b1e9428f1d6)) +* Update Stellar API docs to match implementation ([#292](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/292)) ([96d95e3](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/96d95e35784c25f39afe626b56f11477fd213196)) + +[Changes][v1.0.0] + + + +# [v0.2.0](https://github.com/OpenZeppelin/openzeppelin-relayer/releases/tag/v0.2.0) - 2025-05-14 + +## [0.2.0](https://github.com/OpenZeppelin/openzeppelin-relayer/compare/v0.1.1...v0.2.0) (2025-05-14) + + +### πŸš€ Features + +* add optimism extra cost calculation ([#146](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/146)) ([b85e070](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/b85e070074ecc0aa4fbd7d5dc3af6ca0d600220b)) +* add timeout_seconds to EVM relayer configuration ([#169](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/169)) ([6fd59bc](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/6fd59bc0e5993d63608d47e7ba7825a027e26b99)) +* implement balance validation in EVM ([#168](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/168)) ([27fe333](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/27fe333806c28c268af981f5377e188160c845b9)) +* Local signing for stellar ([#178](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/178)) ([f69270a](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/f69270ade4c9a9239bba874ac74858c8e7375298)) +* plat-6471 add Solana Token 2022 extensions support ([#166](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/166)) ([d35c506](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/d35c506ea298a86897ede5702481403f839f2451)) +* Plat-6521 add turnkey hosted signer support (evm, solana) ([#174](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/174)) ([b24688e](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/b24688ead4fe3015ca3b7c74e56f1906085a5aa3)) +* Stellar RPC service ([#183](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/183)) ([9943ffd](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/9943ffd67a709df487264f50eccd03b06cc817d4)) +* Stellar transaction submission ([#199](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/199)) ([c6b72bf](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/c6b72bfba82c7fb9288c07e49bef04cf527d1245)) +* support for multiple custom RPCs with weighted configuration ([#182](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/182)) ([92ea5ad](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/92ea5ad324323b957fcbdce85c37517ec6f963ba)) + + +### πŸ› Bug Fixes + +* CLA assistant ([#171](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/171)) ([b326a56](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/b326a5680722e812263aab949003c214795fd2c0)) +* CLA labels ([#173](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/173)) ([e31405b](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/e31405b8cba9ffd2ff991d56444320ff3d069ad0)) +* Docker Compose ([#156](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/156)) ([6ca012f](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/6ca012fb9b50d5c2159c498679673cb27530fc3c)) +* Missing libssl and workflow ([#155](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/155)) ([9de7133](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/9de7133c2ba1768f4d989158f19c27444e522f9e)) +* Release merge conflicts ([#163](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/163)) ([4cac422](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/4cac4221817373a1ae7eff92db187dbae2f1665b)) +* Skip releases ([ccafcbe](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/ccafcbe11bc6ea46dacb9c59be578abd45112ad3)) + +[Changes][v0.2.0] + + + +# [v0.1.1](https://github.com/OpenZeppelin/openzeppelin-relayer/releases/tag/v0.1.1) - 2025-04-08 + +## [0.1.1](https://github.com/OpenZeppelin/openzeppelin-relayer/compare/v0.1.0...v0.1.1) (2025-04-08) + + +### πŸ› Bug Fixes + +* Skip releases ([e79b2e9](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/e79b2e963439721dd8e151fa0827654e4019df5f)) +* Skip releases with release please ([#158](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/158)) ([e79b2e9](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/e79b2e963439721dd8e151fa0827654e4019df5f)) + + +### βš™οΈ Miscellaneous Chores + +* Fix workflow and missing libs in docker file ([#157](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/157)) ([c7a681d](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/c7a681dea154b06b675a286e936606e2f9ce087b)) +* plat-7575 Docs fixes ([#153](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/153)) ([#154](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/154)) ([44257e8](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/44257e8ea3e658adbf40f69ad809e4e3503e9af4)) + +[Changes][v0.1.1] + + + +# [v0.1.0](https://github.com/OpenZeppelin/openzeppelin-relayer/releases/tag/v0.1.0) - 2025-04-07 + +## 0.1.0 (2025-04-07) + + +### πŸš€ Features + +* add base models ([#5](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/5)) ([55db42b](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/55db42b16d88e95ca8f6927e3b4d07c939e677c8)) +* Add CLA assistant bot ([#130](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/130)) ([4ad5733](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/4ad5733daadefe5e52bd617eaa47039677443745)) +* add directory structure and example ([d946c10](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/d946c10fd96ee2d1ce2e373ba4ccfced31f985f9)) +* Add logging improvements ([#28](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/28)) ([bb6751a](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/bb6751a4f868eb82787e7763a7995d3974ecfd49)) +* Add logic to resubmit transaction ([#102](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/102)) ([6c258b6](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/6c258b625dc7edb1d028b771647ff25b12c2b07d)) +* Add noop support and refactor status ([#134](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/134)) ([f0e3a17](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/f0e3a177a536c53fe8eff834243d417bb673b744)) +* Add queue processing support ([#6](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/6)) ([3ebbac2](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/3ebbac25f1ecb403dec7d090d39882a85227d883)) +* Add release workflow ([#148](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/148)) ([bd9a7e9](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/bd9a7e91a300e6650b08f799aecea4478bb4b974)) +* Add sign tx for evm local signer ([#65](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/65)) ([b17fb36](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/b17fb3625677f1dbcf1ddf3963db13b9b88ca25e)) +* add support for relayer paused and system disabled state ([#13](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/13)) ([44968a2](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/44968a29ec4f1cf1166c2ad726f2c9a1bac246c3)) +* Add worldchain testnet support ([#137](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/137)) ([25751ef](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/25751ef97b7b9fbe0c4b53fab5b762d1696f8c93)) +* Adding job tests ([#110](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/110)) ([4d2dd98](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/4d2dd98efedacaded8d4ace118c43dbe25907278)) +* enabling it to listen on all interfaces - allows for easy docker config ([74a59da](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/74a59da79b314160baf35ec9750e372fbad0f360)) +* enabling it to listen on all interfaces - allows for easy docker config ([23f94c0](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/23f94c07ce46254f7b80df77ce8c4fc59fb4eef6)) +* improve examples ([#119](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/119)) ([7e59aa6](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/7e59aa64f75f3470807396b293e71cd68d3292d1)) +* Improve Redis startup logic ([#120](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/120)) ([8618ecf](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/8618ecf00b4739891fe4ce98caf14f729face896)) +* Improve Redis startup logic ([#120](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/120)) ([8618ecf](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/8618ecf00b4739891fe4ce98caf14f729face896)) +* initial repo setup ([d8815b6](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/d8815b6752931003536aa427370ca8fb1c57231c)) +* Integrate Netlify with antora ([#74](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/74)) ([09e3d48](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/09e3d4894b54c58754b373da239e9d564df69aa9)) +* Plat 5744 implement an api key authentication mechanism ([#11](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/11)) ([8891887](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/88918872d51ab10632ec6d590689d52e59dfd640)) +* Plat 5768 setup metrics endpoint ([#50](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/50)) ([7c292a5](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/7c292a572a7aef8213969fc72cadca74f9016fe8)) +* Plat 6434 improve authorization header validation ([#122](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/122)) ([eed7c31](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/eed7c31e938c7b6ecaa82774ca5d3a508bb89281)) +* Plat-5749 implement basic webhook notifications service ([#12](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/12)) ([1b47b64](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/1b47b64c318208eb7dc2ec6d62020fab30ccafbb)) +* Plat-5802 openapi sdk client ([#109](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/109)) ([1b4b681](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/1b4b681a3755f60e2934548a9666c60a4465dabb)) +* PLAT-6026 Imp cancel transaction ([#101](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/101)) ([1e5cc47](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/1e5cc47bdc54acafeeefb60489db410b42722b0f)) +* PLAT-6026 Imp cancel transaction ([#101](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/101)) ([1e5cc47](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/1e5cc47bdc54acafeeefb60489db410b42722b0f)) +* Plat-6118 implement logic for syncing relayer state upon service start ([#19](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/19)) ([2ba3629](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/2ba36292a0b8d0d67ddab42d2845a6a0d5f31e3a)) +* Plat-6153 add network definitions for Solana networks ([#26](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/26)) ([ff453d5](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/ff453d59724eeaa194ccf7f83993ce8d649f7432)) +* Plat-6154 add support for solana local signer ([#29](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/29)) ([40caead](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/40caeadde5f08200410912b98943346971084163)) +* plat-6158 implement Solana rpc service ([#36](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/36)) ([8fb50a8](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/8fb50a833e7f9b1773dbe4ca1d77a9609a5d5ec1)) +* Plat-6159 extend relayer config file solana policies ([#38](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/38)) ([4f4602b](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/4f4602b754e71539937447c1743a7f069317598b)) +* Plat-6164 implement feeestimate rpc method ([#61](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/61)) ([43b016c](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/43b016c4e5faa5ee1fedcdadccf3bc768962178e)) +* Plat-6165 implement transfertransaction rpc method ([#63](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/63)) ([c59a3b8](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/c59a3b8894c32470adf10770f4804e272aa829d3)) +* Plat-6167 implement signtransaction rpc method ([#57](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/57)) ([ad7a1ff](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/ad7a1ffe41eb868f54737c1f1b44a52c6d02d172)) +* Plat-6169 implement getsupportedtokens rpc method ([#45](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/45)) ([3f91199](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/3f9119981acd7f92618ba6ec12c3039563368202)) +* Plat-6170 add vault hosted signer support ([#99](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/99)) ([7a9491d](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/7a9491d4094fc21bc87551c68687b4f44f3edd18)) +* Plat-6207 implement trait abstraction relayer ([#43](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/43)) ([abeb7cf](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/abeb7cfccc9e70b26ddd0d41d736352d57d6ade9)) +* Plat-6216 adding network symbol support ([#37](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/37)) ([21f798f](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/21f798fc114de47ae0ed7e127e496bb50ca081a8)) +* Plat-6236 adding validation payload ([#42](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/42)) ([a5ff165](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/a5ff165df14f48d47adee03e8e2c8ef5a899ff57)) +* Plat-6236 adding validation payload ([#42](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/42)) ([a5ff165](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/a5ff165df14f48d47adee03e8e2c8ef5a899ff57)) +* Plat-6239 whitelist policy validation ([#44](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/44)) ([3adb45e](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/3adb45e17b8b23c70e09e422cfca051ebab266f1)) +* Plat-6239 whitelist policy validation ([#44](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/44)) ([3adb45e](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/3adb45e17b8b23c70e09e422cfca051ebab266f1)) +* Plat-6248 implementation dummy of legacy price ([#49](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/49)) ([6319d64](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/6319d64bf27fd75f5192165df885156ca91ea9f0)) +* Plat-6248 implementation dummy of legacy price ([#49](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/49)) ([6319d64](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/6319d64bf27fd75f5192165df885156ca91ea9f0)) +* Plat-6267 add utility script for generating local keystore files ([#69](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/69)) ([b5df7f6](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/b5df7f6b0450118c9123de46689fa115efcdec94)) +* Plat-6291 add webhook notifications for rpc methods ([#72](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/72)) ([2f35d81](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/2f35d81b3711cf2f87dbc6df31b9e0f90432164e)) +* Plat-6299 clean transaction response ([#76](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/76)) ([fc5dd05](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/fc5dd05154bca4a1d740cef058bb797cd3f513a0)) +* Plat-6300 returning the balance of the relayer ([#78](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/78)) ([e0ce8e0](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/e0ce8e04f3950c094c9af3e3413d61cd7162c8e7)) +* Plat-6300 returning the balance of the relayer ([#78](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/78)) ([e0ce8e0](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/e0ce8e04f3950c094c9af3e3413d61cd7162c8e7)) +* Plat-6304 use Authorization header instead of x api key ([#94](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/94)) ([34e8a81](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/34e8a813234ee6aaf2a6956f6dd45f82e47e7861)) +* Plat-6309 Fetching eip1559 prices ([#83](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/83)) ([68d574f](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/68d574fcb159ae3b6502167a9bcf34bb1a56ea7e)) +* Plat-6309 Fetching eip1559 prices ([#83](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/83)) ([68d574f](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/68d574fcb159ae3b6502167a9bcf34bb1a56ea7e)) +* plat-6340 store private keys securely in memory ([#104](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/104)) ([28c2fab](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/28c2fab84f3db6b9d971126cf917263da395c421)) +* PLAT-6350 - Sign EIP-1559 ([#98](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/98)) ([673e420](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/673e4202f9d98bfd02512090fa3daacfa40831fe)) +* PLAT-6350 - Sign EIP-1559 ([#98](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/98)) ([673e420](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/673e4202f9d98bfd02512090fa3daacfa40831fe)) +* PLAT-6374 EIP-1559 default if network support it and not explicit false ([#100](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/100)) ([c982dde](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/c982ddefeba93381ac7d2c5e09f616a60820b8b8)) +* PLAT-6374 EIP-1559 default if network support it and not explicit false ([#100](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/100)) ([c982dde](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/c982ddefeba93381ac7d2c5e09f616a60820b8b8)) +* PLAT-6416 Use generics transaction factory ([#105](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/105)) ([7b94662](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/7b946625af77c6aabd336d34646e9ae62ece3b6a)) +* plat-6433 add minimum length validations for config sensitive values ([#125](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/125)) ([31453c5](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/31453c5586ca4fef70e7ea0e2dcd0260a8a721a6)) +* Plat-6441 document upcoming work ([#131](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/131)) ([377a8bb](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/377a8bb57ff5b3b23abb58d1c3378489c40218cf)) +* PLAT-6442 - Abstraction and unit tests relayer domain ([#117](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/117)) ([643194a](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/643194acd9079ac3ac157e909f0b30199af8b0c9)) +* PLAT-6442 - Abstraction and unit tests relayer domain ([#117](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/117)) ([643194a](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/643194acd9079ac3ac157e909f0b30199af8b0c9)) +* Plat-6457 Ignore utoipa ([#127](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/127)) ([234854a](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/234854afbf30a9a94fa3365f60f035e53e068938)) +* Plat-6457 Ignore utoipa ([#127](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/127)) ([234854a](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/234854afbf30a9a94fa3365f60f035e53e068938)) +* Plat-6459 create mermaid architecture diagram ([#126](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/126)) ([3de147b](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/3de147b907c28d3e9a8a38a2d6b8cd665253c423)) +* plat-6476 Add support to collect transaction fee ([#135](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/135)) ([4f4a07b](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/4f4a07b2846d2980bbf09734602315702ded9dbe)) +* Plat-6479 added support for rpc custom endpoints ([#138](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/138)) ([3df3d49](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/3df3d49ec6a662698a90630811d717920b7cdf3b)) +* Pricing validation on receiving payload EVM ([#59](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/59)) ([1206d42](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/1206d4241dbda84bc861f501d322f6bd33234f0b)) +* Pricing validation on receiving payload EVM ([#59](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/59)) ([1206d42](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/1206d4241dbda84bc861f501d322f6bd33234f0b)) +* Signer service ([#8](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/8)) ([4f85b7b](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/4f85b7bf5b6aa83903ed8febdfe244d54e803642)) +* Speed support transaction ([#62](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/62)) ([a572af6](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/a572af65ca4f664dce13e705eac37b56dee306fa)) +* Tx submissions and status mgmt ([#81](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/81)) ([9f829f1](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/9f829f1c59c4221c9cf38c6cb1ff36351a348cd1)) +* Update transaction status to mined/expired ([#85](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/85)) ([8f5ee53](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/8f5ee53bbe64d55ccf8015a1c8d203cf5e391f08)) + + +### πŸ› Bug Fixes + +* Codecov changes and adjustments ([#113](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/113)) ([6e62dcf](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/6e62dcf212a917421c7559566136c018e17c38f5)) +* Docs link ([#128](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/128)) ([8263828](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/82638284cf13a4da376624362f5353b57365302a)) +* Docs path for crate ([#129](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/129)) ([51cf556](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/51cf556411c9c1f79dbee7f4c3aa25df7fe2af49)) +* **docs:** replaced Monitor for Relayer ([2ff196b](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/2ff196bf772668556210a895d4f83315e579577f)) +* Documentation name for antora ([#121](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/121)) ([63c36f5](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/63c36f5393b1369a169c8617b20952bca30aef0c)) +* Environment variables ([#124](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/124)) ([8d31131](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/8d31131c087a6d0a64ae2dadecb5ae395ad1b575)) +* Fix the codecov yaml syntax ([#108](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/108)) ([ab9ab5b](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/ab9ab5b0c9313d083cd47c71d7faade867c58deb)) +* Flaky logging tests ([#89](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/89)) ([bc909cc](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/bc909cc336613bb5a191c562632278bd3c270b09)) +* Plat 6286 write tests for metrics and middleware functions ([#70](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/70)) ([18124fb](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/18124fbbfbc26f300648a7a4050ebf9be72465ac)) +* PLAT-6426 Increase test coverage ([#118](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/118)) ([1fa41f0](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/1fa41f0f225c9d515690738e960073396dce66ce)) +* PLAT-6478 create unit test for use of on relayers dotenv ([#139](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/139)) ([509e166](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/509e1664518823ef3844e52e818707f3371ddbff)) +* plat-6480 allow transfering wrapped sol tokens ([#132](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/132)) ([f04e66a](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/f04e66a568c877c2a4c5c5378fb6017c2e41d2c6)) + + +### πŸ“š Documentation + +* add cargo docs ([#75](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/75)) ([c4dd8e3](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/c4dd8e30525ccaeb563560bc2ef87cdcec5b1790)) +* Add testing instructions ([#107](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/107)) ([c7c2ed7](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/c7c2ed7772d99b4b68ced9fbf8835fa9e46da5e1)) +* Adding configuration documentation ([#48](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/48)) ([929cc1b](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/929cc1bf1e0c6b3be872daf6654abe24eb79b907)) +* Fixing formatting and location of files ([#41](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/41)) ([4d4f153](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/4d4f1530f466a5bd597d0338559ccb33815286f0)) +* Move README to a similar format to Monitor ([#39](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/39)) ([5985339](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/59853396b3786a972ce7bbc793d4dbacc62fe6c0)) +* Readability improvements ([#133](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/133)) ([9220727](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/9220727cc2b4349052c2d96a48c5d9c3012b38b9)) +* Small doc updates - policy field descriptions ([#51](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/51)) ([cc83c49](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/cc83c496bbe2593018b03c414a864691c967ff41)) +* Small fixes and Antora docs improvements ([#40](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/40)) ([655d16d](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/655d16dc658a74b7413ce785dee5b8e33cfb40f7)) +* TG link and other minor doc updates ([#116](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/116)) ([fc68b6a](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/fc68b6afa844d2c2638d031fce44fcc514d59a7d)) +* Update API docs. Fix Dockerfiles ([#77](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/77)) ([0bd6bfe](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/0bd6bfea69d60c1a7e9d6b8a690ba1a2d0e44b74)) + +[Changes][v0.1.0] + + +[v1.1.0]: https://github.com/OpenZeppelin/openzeppelin-relayer/compare/v1.0.0...v1.1.0 +[v1.0.0]: https://github.com/OpenZeppelin/openzeppelin-relayer/compare/v0.2.0...v1.0.0 +[v0.2.0]: https://github.com/OpenZeppelin/openzeppelin-relayer/compare/v0.1.1...v0.2.0 +[v0.1.1]: https://github.com/OpenZeppelin/openzeppelin-relayer/compare/v0.1.0...v0.1.1 +[v0.1.0]: https://github.com/OpenZeppelin/openzeppelin-relayer/tree/v0.1.0 diff --git a/content/relayer/1.0.x/configuration/index.mdx b/content/relayer/1.0.x/configuration/index.mdx new file mode 100644 index 00000000..3e40155a --- /dev/null +++ b/content/relayer/1.0.x/configuration/index.mdx @@ -0,0 +1,469 @@ +--- +title: Configuration +--- + +## Overview + +Most configuration files should live under `./config`, including the signer configurations, under `./config/keys`. +Please ensure appropriate access permissions on all configuration files (for `./config/keys/*`, we recommend `0500`. + + + + +The configuration system consists of two main components: + +1. ***`config.json`***: Contains relayer definitions, signer configurations, and network policies +2. ***`.env`*** file: Contains environment variables like API keys and connection strings + +Both files must be properly configured before starting the application. Changes to either file require restarting the container to take effect. + +For quick setup examples with pre-configured files, see the [examples directory](https://github.com/OpenZeppelin/openzeppelin-relayer/tree/main/examples) in our GitHub repository. + + + +## Environment configuration (.env) + +This defines some base configurations for the Relayer application: + +Copy the example environment file and update values according to your needs + +```bash +cp .env.example .env +``` + +This table lists the environment variables and their default values. + +| Environment Variable | Default Value | Accepted Values | Description | +| --- | --- | --- | --- | +| `RUST_LOG` | `info` | `info, debug, warn, error, trace` | Log level. | +| `CONFIG_DIR` | `./config` | `` | Relative path of directory where config files reside | +| `CONFIG_FILE_NAME` | `config.json` | `` | File Name of the configuration file. | +| `RATE_LIMIT_RPS` | `100` | `` | Rate limit for the API in requests per second. | +| `RATE_LIMIT_BURST_SIZE` | `300` | `` | Rate limit burst size. | +| `API_KEY` | `` | `string`, | API key to use for authentication to the relayer server. Minimum length 32 characters. | +| `WEBHOOK_SIGNING_KEY` | `` | `string` | Signing key to use for webhook notifications. Minimum length 32 characters. | +| `LOG_MODE` | `stdout` | `stdout, file` | Write logs either to console or to file. | +| `LOG_DATA_DIR` | `./logs` | `` | Directory to persist log files on host. | +| `LOG_MAX_SIZE (in bytes)` | `1073741824` | `` | Size after which logs needs to be rolled. | +| `METRICS_ENABLED` | `false` | `bool` | Enable metrics server for external tools to scrape metrics. | +| `METRICS_PORT` | `8081` | `` | Port to use for metrics server. | +| `REDIS_URL` | `redis://localhost:6379` | `` | Redis connection URL for the relayer. | +| `REDIS_CONNECTION_TIMEOUT_MS` | `10000` | `` | Connection timeout for Redis in milliseconds. | +| `RPC_TIMEOUT_MS` | `10000` | `` | Sets the maximum time to wait for RPC connections before timing out. | +| `PROVIDER_MAX_RETRIES` | `3` | `` | Maximum number of retry attempts for provider operations. | +| `PROVIDER_RETRY_BASE_DELAY_MS` | `100` | `` | Base delay between retry attempts in milliseconds. | +| `PROVIDER_RETRY_MAX_DELAY_MS` | `2000` | `` | Maximum delay between retry attempts in milliseconds. | +| `PROVIDER_MAX_FAILOVERS` | `3` | `` | Maximum number of failovers (switching to different providers). | +| `ENABLE_SWAGGER` | `false` | `true, false` | Enable or disable Swagger UI for API documentation. | +| `KEYSTORE_PASSPHRASE` | `` | `` | Passphrase for the keystore file used for signing transactions. | + +### Environment configuration example + +`.env` file config example: + +``` +RUST_LOG=DEBUG +CONFIG_DIR=./config +CONFIG_FILE_NAME=config.json +WEBHOOK_SIGNING_KEY=e1d42480-6f74-4d0b-85f4-b7f0bb690fae +API_KEY=5eefd216-0e44-4ca7-b421-2925f90d30d5 +RATE_LIMIT_RPS=100 +RATE_LIMIT_BURST_SIZE=300 +METRICS_ENABLED=true +METRICS_PORT=8081 +REDIS_URL=redis://localhost:6379 +REDIS_CONNECTION_TIMEOUT_MS=10000 +RPC_TIMEOUT_MS=10000 +PROVIDER_MAX_RETRIES=3 +PROVIDER_RETRY_BASE_DELAY_MS=100 +PROVIDER_RETRY_MAX_DELAY_MS=2000 +PROVIDER_MAX_FAILOVERS=3 +ENABLE_SWAGGER=false +KEYSTORE_PASSPHRASE=your_keystore_passphrase +``` + +## Main configuration file (config.json) + +This file can exist in any directory, but the default location is `./config/config.json`. + +Copy the example config file and update values according to your needs + +```bash +cp config/config.example.json config/config.json +``` + +Key sections in this file include: + +* Signers: Defines transaction signing methods. +* Notifications: Sets up status alerts +* Relayers: Configures networks, notifications channels, policies & singers. +* Networks: Defines blockchain network configurations. +* Plugins: Configures plugins. + +### 1. Signers + +Transaction signers are responsible for cryptographically signing transactions before they are submitted to blockchain networks. The `signers` array must contain at least one valid signer configuration. + +For comprehensive details on configuring all supported signer types including: + +* Local keystore file signers +* HashiCorp Vault (secret, cloud, and transit) +* Cloud KMS providers (Google Cloud, AWS) +* Turnkey signers +* Security best practices and troubleshooting + +See the dedicated [Signers Configuration](/relayer/1.0.x/configuration/signers) guide. + +### 2. Notifications + +* `notifications` array, which should contain, at least, one valid configuration: + +```json +"notifications": [ + { + "id": "notification-test", + "type": "webhook", + "url": "https://webhook.site/f95cf78d-742d-4b21-88b7-d683e6fd147b", + "signing_key": { + "type": "env", + "value": "WEBHOOK_SIGNING_KEY" + } + } +] +``` +Available configuration fields +| Field | Type | Description | +| --- | --- | --- | +| id | String | Unique id for the notification | +| type | String | Type of notification (only `webhook` available, for now) | +| url | String | Notification URL | +| signing_key.type | String | Type of key used in signing the notification (`env` or `plain`) | +| signing_key.value | String | Signing key value, env variable name, ... | + +### 3. Relayers + +* `relayers` array, containing at least one valid relayer configuration: + +```json +"relayers": [ + { + "id": "solana-testnet", + "name": "Solana Testnet", + "paused": false, + "notification_id": "notification-test", + "signer_id": "local-signer", + "network_type": "solana", + "network": "testnet", + "custom_rpc_urls": [ + { + "url": "https://primary-rpc.example.com", + "weight": 2 // Higher weight routes more requests to this endpoint. The value must be an integer between 0 and 100 (inclusive). + }, + { + "url": "https://backup-rpc.example.com", + "weight": 1 + } + ], + "policies": { + "allowed_programs": [ + "11111111111111111111111111111111", + "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", + "BPFLoaderUpgradeab1e11111111111111111111111" + ] + } + } +] +``` + +Available configuration fields +| Field | Type | Description | +| --- | --- | --- | +| id | String | Unique id for the relayer | +| name | String | Human readable name for the relayer | +| paused | Boolean | Whether or not the relayer is paused (`true`, `false`) | +| notification_id | String | ID of a configured notification object | +| signer_id | String | ID of a configured signer | +| network_type | String | Type of network the relayer will connect to (`evm`, `solana`) | +| network | String | Network the relayer will connect to. Must match a network identifier defined in your network configuration files. See [Network Configuration](/relayer/1.0.x/network_configuration) for details on defining networks. | +| custom_rpc_urls | list | Optional custom RPC URLs for the network. If provided, this will be used instead of the public RPC URLs. This is useful for using your own RPC node or a paid service provider. The first url of the list is going to be used as the default | +| policies | list | Overrides default policies. Please refer to the [`Policies`](/relayer/1.0.x/configuration#network-policies) table | + +Policies +| Network type | Policy | Type | Description | +| --- | --- | --- | --- | +| solana, evm | min_balance | `unsigned 128` | Minimum balance (in lamports or wei) required for the relayer to operate. Optional. | +| solana | fee_payment_strategy | `enum(user,relayer)` | Specifies who pays the fee. "user" (default) means the sender pays; "relayer" means the relayer pays. For "user", RPC methods add an instruction to transfer SPL tokens (calculated from the current SOL price plus a configurable margin) from the user to the relayer, ensuring fees are sustainably covered in tokens rather than SOL. | +| solana | swap_config | `SwapConfig` | Optional object configuring automated token‐swaps on Solana. | +| solana | fee_margin_percentage | `f32` | Additional margin percentage added to estimated transaction fees to account for price fluctuations. For example, a value of 10 will add 10% to estimated fees. Optional. | +| solana | max_allowed_fee_lamports | `unsigned 64` | Maximum allowed fee (in lamports) for a transaction. Optional. | +| solana | allowed_tokens | `Vector` | List of allowed tokens. Only these tokens are supported if provided. Optional. | +| solana | allowed_programs | `Vector` | List of allowed programs by their identifiers. Only these programs are supported if provided. | +| solana | allowed_accounts | `Vector` | List of allowed accounts by their public keys. The relayer will only operate with these accounts if provided. | +| solana | disallowed_accounts | `Vector` | List of disallowed accounts by their public keys. These accounts will be explicitly blocked. | +| solana | max_tx_data_size | `unsigned 16` | Maximum transaction size. Optional. | +| solana | max_signatures | `unsigned 8` | Maximum supported signatures. Optional. | +| evm | gas_price_cap | `unsigned 128` | Specify a maximum gas price for every transaction sent with the Relayer. When enabled, any transaction exceeding the cap will have its gasPrice or maxFeePerGas overwritten. (Optional) | +| evm | whitelist_receivers | `Vector` | A list of authorized contracts for each transaction sent using the Relayer. Transactions will be rejected if the destination address is not on the list. (Optional) | + +#### RPC URL Configuration + +The relayer supports two ways to configure RPC URLs: + +1. ***Public RPC URLs***: These are the default RPC endpoints provided by the network. They are automatically selected based on the network configuration. +2. ***Custom RPC URLs***: You can specify custom RPC URLs using the `custom_rpc_urls` field in the relayer configuration. Each URL can be configured with an optional weight for high availability: + +```json +"custom_rpc_urls": [ + { + "url": "https://primary-rpc.example.com", + "weight": 2 // Higher weight routes more requests to this endpoint. The value must be an integer between 0 and 100 (inclusive). + }, + { + "url": "https://secondary-rpc.example.com", + "weight": 100, // Max allowed weight + }, + { + "url": "https://backup-rpc.example.com" // No weight specified, defaults to 100 + }, + { + "url": "https://backup2-rpc.example.com", + "weight": 0, // A value of 0 disables the endpoint. + } +] +``` + +This is useful when you want to: + * Use your own RPC nodes with load balancing + * Use a paid service provider for better reliability and performance + * Override the default public RPC URLs + * Access custom network endpoints + * Configure primary and backup endpoints with different weights + +When both are available, the relayer will: +1. First attempt to use the `custom_rpc_urls` if configured. +2. Fall back to the public RPC URLs if no custom URL is configured. + +For backward compatibility, string arrays are still supported: + +```json +"custom_rpc_urls": ["https://your-rpc.example.com"] +``` + + + + +When using custom RPC URLs: + +* Ensure the URLs are secure (HTTPS) when accessing over public networks +* Keep your API keys and authentication tokens secure +* Test the RPC endpoints' reliability and performance before using it in production +* Configure weights to prioritize endpoints, assigning higher values to more reliable or performant ones. +* The weight must be an integer between 0 and 100 (inclusive). +* A weight of 0 disables the endpoint. +* If a weight is not specified for an endpoint, it defaults to 100. + + + +### 4. Plugins + +For more information on how to write a plugin, please refer to the [Plugins](/relayer/1.0.x/plugins) page. + +* `plugins` array, containing plugin configurations: + +```json +"plugins": [ + { + "id": "my-plugin", + "path": "my-plugin.ts" + } +] +``` + +Available configuration fields +| Field | Type | Description | +| --- | --- | --- | +| id | String | Unique id for the plugin | +| path | String | Path to the plugin file | + +### 5. Networks + +You can configure networks either: + +* In separate JSON files (recommended for better organization) +* Directly in your main `config.json` + +For comprehensive network configuration details, including: + +* Network field reference +* Configuration examples for all network types +* Network inheritance +* Special tags and their behavior +* Best practices and troubleshooting + +See the dedicated [Network Configuration](/relayer/1.0.x/network_configuration) guide. + +## Configuration File Example + +Full `config/config.json` example with evm and solana relayers definitions using keystore signer: + +```json +{ + "relayers": [ + { + "id": "sepolia-example", + "name": "Sepolia Example", + "network": "sepolia", + "paused": false, + "notification_id": "notification-example", + "signer_id": "local-signer", + "network_type": "evm", + "custom_rpc_urls": [ + { + "url": "https://primary-rpc.example.com", + "weight": 2 + }, + { + "url": "https://backup-rpc.example.com", + "weight": 1 + } + ], + "policies": { + "gas_price_cap": 30000000000000, + "eip1559_pricing": true + } + }, + { + "id": "solana-example", + "name": "Solana Example", + "network": "devnet", + "paused": false, + "notification_id": "notification-example", + "signer_id": "local-signer", + "network_type": "solana", + "custom_rpc_urls": [ + { + "url": "https://primary-solana-rpc.example.com", + "weight": 2 + }, + { + "url": "https://backup-solana-rpc.example.com", + "weight": 1 + } + ], + "policies": { + "fee_payment_strategy": "user", + "min_balance": 0, + "allowed_tokens": [ + { + "mint": "Gh9ZwEmdLJ8DscKNTkTqPbNwLNNBjuSzaG9Vp2KGtKJr", + "max_allowed_fee": 100000000 + }, + { + "mint": "So11111111111111111111111111111111111111112" + } + ] + } + }, + { + "id": "solana-mainnet-example", + "name": "Solana Mainnet Example", + "network": "mainnet-beta", + "paused": false, + "notification_id": "notification-example", + "signer_id": "local-signer", + "network_type": "solana", + "custom_rpc_urls": ["https://your-private-solana-rpc.example.com"], + "policies": { + "fee_payment_strategy": "user", + "min_balance": 0, + "swap_config": { + "cron_schedule": "0 0 * * * *", + "min_balance_threshold": 0, + "strategy": "jupiter-ultra" + }, + "allowed_tokens": [ + { + "mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", + "max_allowed_fee": 100000000, + "swap_config": { + "min_amount": 0, + "max_amount": 0, + "retain_min_amount": 0 + } + }, + { + "mint": "So11111111111111111111111111111111111111112" + } + ] + } + } + ], + "notifications": [ + { + "id": "notification-example", + "type": "webhook", + "url": "https://webhook.site/1384d4d9-21b1-40a0-bcd1-d3f3b66be955", + "signing_key": { + "type": "env", + "value": "WEBHOOK_SIGNING_KEY" + } + } + ], + "signers": [ + { + "id": "local-signer", + "type": "local", + "config": { + "path": "config/keys/local-signer.json", + "passphrase": { + "type": "env", + "value": "KEYSTORE_PASSPHRASE" + } + } + } + ], + "networks": [ + { + "average_blocktime_ms": 12000, + "chain_id": 11155111, + "explorer_urls": [ + "https://api-sepolia.etherscan.io/api", + "https://sepolia.etherscan.io" + ], + "features": [ + "eip1559" + ], + "is_testnet": true, + "network": "sepolia", + "required_confirmations": 6, + "rpc_urls": [ + "https://sepolia.drpc.org", + "https://1rpc.io/sepolia", + "https://ethereum-sepolia-rpc.publicnode.com", + "https://ethereum-sepolia-public.nodies.app" + ], + "symbol": "ETH", + "tags": [ + "deprecated" + ], + "type": "evm" + }, + { + "type": "solana", + "network": "devnet", + "rpc_urls": ["https://api.devnet.solana.com"], + "explorer_urls": ["https://explorer.solana.com?cluster=devnet"], + "average_blocktime_ms": 400, + "is_testnet": true + }, + { + "type": "solana", + "network": "mainnet-beta", + "rpc_urls": ["https://api.mainnet-beta.solana.com"], + "explorer_urls": ["https://explorer.solana.com"], + "average_blocktime_ms": 400, + "is_testnet": false + } + ] +} +``` diff --git a/content/relayer/1.0.x/configuration/signers.mdx b/content/relayer/1.0.x/configuration/signers.mdx new file mode 100644 index 00000000..efe9f74b --- /dev/null +++ b/content/relayer/1.0.x/configuration/signers.mdx @@ -0,0 +1,369 @@ +--- +title: Signers Configuration +--- + +## Overview + +Signers are responsible for cryptographically signing transactions before they are submitted to blockchain networks. OpenZeppelin Relayer supports multiple signer types to accommodate different security requirements and infrastructure setups. + +The `signers` array in your configuration must contain at least one valid signer configuration. Each signer is referenced by its `id` in relayer configurations. + +## Configuration Structure + +Example signer configuration: +```json +"signers": [ + { + "id": "my_id", + "type": "local", + "config": { + "path": "config/keys/local-signer.json", + "passphrase": { + "type": "env", + "value": "KEYSTORE_PASSPHRASE" + } + } + } +] +``` + +## Supported Signer Types + +OpenZeppelin Relayer supports the following signer types: + +* `local`: Keystore file signer +* `vault`: HashiCorp Vault secret signer +* `vault_cloud`: Hosted HashiCorp Vault secret signer +* `vault_transit`: HashiCorp Vault Transit signer +* `turnkey`: Turnkey signer +* `google_cloud_kms`: Google Cloud KMS signer +* `aws_kms`: Amazon AWS KMS signer + +## Network Compatibility Matrix + +The following table shows which signer types are compatible with each network type: + +| Signer Type | EVM Networks | Solana Networks | Stellar Networks | +| --- | --- | --- | --- | +| `local` | βœ… Supported | βœ… Supported | βœ… Supported | +| `vault` | βœ… Supported | βœ… Supported | ❌ Not supported | +| `vault_cloud` | βœ… Supported | βœ… Supported | ❌ Not supported | +| `vault_transit` | ❌ Not supported | βœ… Supported | ❌ Not supported | +| `turnkey` | βœ… Supported | βœ… Supported | ❌ Not supported | +| `google_cloud_kms` | βœ… Supported | βœ… Supported | ❌ Not supported | +| `aws_kms` | βœ… Supported | ❌ Not supported | ❌ Not supported | + + + + +***Network-specific considerations:*** + +* ***EVM Networks***: Use secp256k1 cryptography. Most signers support EVM networks with proper key generation. +* ***Solana Networks***: Use ed25519 cryptography. Ensure your signer supports ed25519 key generation and signing. +* ***Stellar Networks***: Use ed25519 cryptography with specific Stellar requirements. Limited signer support due to network-specific implementation requirements. +* ***AWS KMS***: Currently optimized for EVM networks with secp256k1 support. +* ***Google Cloud KMS***: Supports both secp256k1 (EVM) and ed25519 (Solana) key types. +* ***Turnkey***: Supports EVM and Solana networks with appropriate key management. + + + +## Common Configuration Fields + +All signer types share these common configuration fields: + +| Field | Type | Description | +| --- | --- | --- | +| id | String | Unique identifier for the signer (used to reference this signer in relayer configurations) | +| type | String | Type of signer (see supported signer types above) | +| config | Map | Signer type-specific configuration object | + +## Local Signer Configuration + +The local signer uses encrypted keystore files stored on the filesystem. + +```json +{ + "id": "local-signer", + "type": "local", + "config": { + "path": "config/keys/local-signer.json", + "passphrase": { + "type": "env", + "value": "KEYSTORE_PASSPHRASE" + } + } +} +``` + +Configuration fields: +| Field | Type | Description | +| --- | --- | --- | +| path | String | Path to the signer JSON file. Should be under the `./config` directory | +| passphrase.type | String | Type of passphrase source (`env` or `plain`) | +| passphrase.value | String | Passphrase value or environment variable name | + +## HashiCorp Vault Signer Configuration + +### Vault Secret Signer + +Uses HashiCorp Vault’s secret engine to store private keys. + +```json +{ + "id": "vault-signer", + "type": "vault", + "config": { + "address": "https://vault.example.com", + "role_id": { + "type": "env", + "value": "VAULT_ROLE_ID" + }, + "secret_id": { + "type": "env", + "value": "VAULT_SECRET_ID" + }, + "key_name": "relayer-key", + "mount_point": "secret" + } +} +``` + +Configuration fields: +| Field | Type | Description | +| --- | --- | --- | +| address | String | Specifies the Vault API endpoint | +| role_id.type | String | Type of value source (`env` or `plain`) | +| role_id.value | String | The Vault AppRole role identifier value, or the environment variable name where the AppRole role identifier is stored | +| secret_id.type | String | Type of value source (`env` or `plain`) | +| secret_id.value | String | The Vault AppRole role secret value, or the environment variable name where the AppRole secret value is stored | +| key_name | String | The name of the cryptographic key within Vault’s Secret engine that is used for signing operations | +| mount_point | String | The mount point for the Secrets engine in Vault. Defaults to `secret` if not explicitly specified. Optional. | + +### Vault Cloud Signer + +Uses HashiCorp Vault Cloud (HCP Vault) for key management. + +```json +{ + "id": "vault-cloud-signer", + "type": "vault_cloud", + "config": { + "client_id": "your-client-id", + "client_secret": { + "type": "env", + "value": "VAULT_CLOUD_CLIENT_SECRET" + }, + "org_id": "your-org-id", + "project_id": "your-project-id", + "app_name": "relayer-app", + "key_name": "signing-key" + } +} +``` + +Configuration fields: +| Field | Type | Description | +| --- | --- | --- | +| client_id | String | The client identifier used to authenticate with Vault Cloud | +| client_secret.type | String | Type of value source (`env` or `plain`) | +| client_secret.value | String | The Vault secret value, or the environment variable name where the secret value is stored | +| org_id | String | The organization ID for your Vault Cloud account | +| project_id | String | The project ID that uniquely identifies your Vault Cloud project | +| app_name | String | The name of the application integrating with Vault Cloud | +| key_name | String | The name of the cryptographic key used for signing or encryption operations in Vault Cloud | + +### Vault Transit Signer + +Uses HashiCorp Vault’s Transit secrets engine for cryptographic operations. + +```json +{ + "id": "vault-transit-signer", + "type": "vault_transit", + "config": { + "address": "https://vault.example.com", + "role_id": { + "type": "env", + "value": "VAULT_ROLE_ID" + }, + "secret_id": { + "type": "env", + "value": "VAULT_SECRET_ID" + }, + "key_name": "relayer-transit-key", + "mount_point": "transit", + "namespace": "production", + "pubkey": "your-public-key-here" + } +} +``` + +Configuration fields: +| Field | Type | Description | +| --- | --- | --- | +| address | String | Specifies the Vault API endpoint | +| role_id.type | String | Type of value source (`env` or `plain`) | +| role_id.value | String | The Vault AppRole role identifier value, or the environment variable name where the AppRole role identifier is stored | +| secret_id.type | String | Type of value source (`env` or `plain`) | +| secret_id.value | String | The Vault AppRole role secret value, or the environment variable name where the AppRole secret value is stored | +| key_name | String | The name of the cryptographic key within Vault’s Transit engine that is used for signing operations | +| mount_point | String | The mount point for the Transit secrets engine in Vault. Defaults to `transit` if not explicitly specified. Optional. | +| namespace | String | The Vault namespace for API calls. This is used only in Vault Enterprise environments. Optional. | +| pubkey | String | Public key of the cryptographic key within Vault’s Transit engine that is used for signing operations | + +## Turnkey Signer Configuration + +Uses Turnkey’s secure key management infrastructure. + +```json +{ + "id": "turnkey-signer", + "type": "turnkey", + "config": { + "api_public_key": "your-api-public-key", + "api_private_key": { + "type": "env", + "value": "TURNKEY_API_PRIVATE_KEY" + }, + "organization_id": "your-org-id", + "private_key_id": "your-private-key-id", + "public_key": "your-public-key" + } +} +``` + +Configuration fields: +| Field | Type | Description | +| --- | --- | --- | +| api_public_key | String | The public key associated with your Turnkey API access credentials. Used for authentication to the Turnkey signing service | +| api_private_key.type | String | Type of value source (`env` or `plain`) | +| api_private_key.value | String | The Turnkey API private key or environment variable name containing it. Used with the public key to authenticate API requests | +| organization_id | String | Your unique Turnkey organization identifier. Required to access resources within your specific organization | +| private_key_id | String | The unique identifier of the private key in your Turnkey account that will be used for signing operations | +| public_key | String | The public key corresponding to the private key identified by private_key_id. Used for address derivation and signature verification | + +## Google Cloud KMS Signer Configuration + +Uses Google Cloud Key Management Service for secure key operations. + + + + +For EVM transaction signing, ensure your Google Cloud KMS key is created with: +- Protection level: HSM +- Purpose: Asymmetric sign +- Algorithm: "Elliptic Curve secp256k1 - SHA256 Digest" + +This provides secp256k1 compatibility required for Ethereum transactions. + + + +```json +{ + "id": "gcp-kms-signer", + "type": "google_cloud_kms", + "config": { + "service_account": { + "project_id": "your-gcp-project", + "private_key_id": { + "type": "env", + "value": "GCP_PRIVATE_KEY_ID" + }, + "private_key": { + "type": "env", + "value": "GCP_PRIVATE_KEY" + }, + "client_email": { + "type": "env", + "value": "GCP_CLIENT_EMAIL" + }, + "client_id": "your-client-id" + }, + "key": { + "location": "us-west2", + "key_ring_id": "relayer-keyring", + "key_id": "relayer-key", + "key_version": 1 + } + } +} +``` + +Configuration fields: +| Field | Type | Description | +| --- | --- | --- | +| service_account.project_id | String | The Google Cloud project ID where your KMS resources are located | +| service_account.private_key_id.type | String | Type of value source for the private key ID (`env` or `plain`) | +| service_account.private_key_id.value | String | The private key ID value or the environment variable name containing it | +| service_account.private_key.type | String | Type of value source for the private key (`env` or `plain`) | +| service_account.private_key.value | String | The Google Cloud service account private key (PEM format) or the environment variable name containing it | +| service_account.client_email.type | String | Type of value source for the client email (`env` or `plain`) | +| service_account.client_email.value | String | The Google Cloud service account client email or the environment variable name containing it | +| service_account.client_id | String | The Google Cloud service account client ID | +| key.location | String | The Google Cloud location (region) where your KMS key ring is located (e.g., "us-west2", "global") | +| key.key_ring_id | String | The KMS key ring ID containing your cryptographic key | +| key.key_id | String | The KMS key ID used for signing operations | +| key.key_version | Integer | The version of the KMS key to use for signing operations. Defaults to 1 | + +## AWS KMS Signer Configuration + +Uses Amazon Web Services Key Management Service for cryptographic operations. + +```json +{ + "id": "aws-kms-signer", + "type": "aws_kms", + "config": { + "region": "us-west-2", + "key_id": "arn:aws:kms:us-west-2:123456789012:key/12345678-1234-1234-1234-123456789012" + } +} +``` + +Configuration fields: +| Field | Type | Description | +| --- | --- | --- | +| region | String | AWS region. If the key is non-replicated across regions, this must match the key’s original region. Optional. If not specified, the default region from shared credentials is used | +| key_id | String | ID of the key in AWS KMS (can be key ID, key ARN, alias name, or alias ARN) | + +## Security Best Practices + +### File Permissions +* Set restrictive permissions on keystore files: `chmod 0500 config/keys/*` +* Ensure configuration directories are properly secured +* Use environment variables for sensitive data like passphrases and API keys + +### Key Management +* Use HSM-backed keys for production environments when available +* Implement proper key rotation policies +* Never commit private keys or sensitive configuration to version control +* Use dedicated service accounts with minimal required permissions + +### Environment Separation +* Use different signers for different environments (development, staging, production) +* Implement proper secrets management in production deployments +* Consider using cloud-native key management services for enhanced security + +## Troubleshooting + +### Common Issues + +***Invalid keystore passphrase*** + +* Verify the passphrase environment variable is correctly set +* Check that the keystore file is not corrupted +* Ensure the keystore format is compatible + +***Cloud KMS authentication failures*** + +* Verify service account credentials are valid and properly formatted +* Check that the service account has necessary permissions for KMS operations +* Ensure the KMS key exists and is in the correct region/project + +***Vault connection issues*** + +* Verify Vault server address and network connectivity +* Check AppRole credentials and permissions +* Ensure the secret/transit engine is properly mounted and configured + +For additional troubleshooting help, check the application logs and refer to the specific cloud provider or service documentation. diff --git a/content/relayer/1.0.x/index.mdx b/content/relayer/1.0.x/index.mdx new file mode 100644 index 00000000..d3cb442a --- /dev/null +++ b/content/relayer/1.0.x/index.mdx @@ -0,0 +1,336 @@ +--- +title: OpenZeppelin Relayer +--- + +## Overview + +OpenZeppelin Relayer is a service that provides infrastructure to relay transactions to the EVM & Non-EVM networks. It is designed to be used as a backend for dApps that need to interact with these networks. + +## Features + +* ***Multi-Chain Support***: Interact with multiple blockchain networks, including Solana and EVM-based chains. +* ***Transaction Relaying***: Submit transactions to supported blockchain networks efficiently. +* ***Transaction Signing***: Securely sign transactions using configurable key management. +* ***Transaction Fee Estimation***: Estimate transaction fees for better cost management. +* ***Solana Gasless Transactions***: Support for gasless transactions on Solana, enabling users to interact without transaction fees. +* ***Transaction Nonce Management***: Handle nonce management to ensure transaction order. +* ***Transaction Status Monitoring***: Track the status of submitted transactions. +* ***SDK Integration***: Easily interact with the relayer through our companion JavaScript/TypeScript SDK. +* ***Extensible Architecture***: Easily add support for new blockchain networks. +* ***Configurable Network Policies***: Define and enforce network-specific policies for transaction processing. +* ***Metrics and Observability***: Monitor application performance using Prometheus and Grafana. +* ***Docker Support***: Deploy the relayer using Docker for both development and production environments. +* ***Plugins***: Extend the functionality of the relayer with custom logic using TypeScript functions. + +## Supported Networks + +OpenZeppelin Relayer supports multiple blockchain networks through a flexible JSON-based configuration system. Networks are defined in configuration files, allowing you to configure: + +* ***Any EVM-compatible network*** (Ethereum, Polygon, BSC, Arbitrum, Optimism, etc.) +* ***Solana networks*** (mainnet-beta, devnet, testnet, custom RPC endpoints) +* ***Stellar networks*** (Pubnet, Testnet, custom networks) +* ***Create custom network configurations*** with specific RPC endpoints, chain IDs, and network parameters +* ***Use inheritance*** to create network variants that inherit from base configurations + +### Network Types + +| Network Type | Description | +| --- | --- | +| `evm` | Ethereum Virtual Machine compatible networks. Supports any EVM chain by configuring chain ID, RPC URLs, and network-specific parameters. | +| `solana` | Solana blockchain networks. Supports all Solana clusters and custom RPC endpoints. | +| `stellar` | Stellar blockchain networks (Partial support). Supports Stellar Public Network and Testnet. | + +Networks can be loaded from: + +* ***JSON arrays***: Direct network definitions in configuration files +* ***Directory of files***: Multiple JSON files each containing network definitions + +For detailed network configuration options and examples, see the [Network Configuration](/relayer/1.0.x/network_configuration) page. + + + + +For information about our development plans and upcoming features, see [Project Roadmap](/relayer/1.0.x/roadmap). + + + + + + +To get started immediately, see [Quickstart](/relayer/1.0.x/quickstart). + + + +## Technical Overview + +```mermaid +%%{init: { + 'theme': 'base', + 'themeVariables': { + 'background': '#ffffff', + 'mainBkg': '#ffffff', + 'primaryBorderColor': '#cccccc' + } +}}%% +flowchart TB + subgraph "Clients" + client[API/SDK] + end + + subgraph "OpenZeppelin Relayer" + subgraph "API Layer" + api[API Routes & Controllers] + middleware[Middleware] + plugins[Plugins] + end + + subgraph "Domain Layer" + domain[Domain Logic] + relayer[Relayer Services] + policies[Policy Enforcement] + end + + subgraph "Infrastructure" + repositories[Repositories] + jobs[Job Queue System] + signer[Signer Services] + provider[Network Providers] + end + + subgraph "Services Layer" + transaction[Transaction Services] + vault[Vault Services] + webhook[Webhook Notifications] + monitoring[Monitoring & Metrics] + end + + subgraph "Configuration" + config_files[Config Files] + env_vars[Environment Variables] + end + end + + subgraph "External Systems" + blockchain[Blockchain Networks] + redis[Redis] + vault_ext[HashiCorp Vault] + metrics[Prometheus/Grafana] + notification[Notification Services] + end + + %% Client connections + client -- "HTTP Requests" --> api + + %% API Layer connections + api -- "Processes requests" --> middleware + middleware -- "Validates & routes" --> domain + middleware -- "Invokes" --> plugins + + %% Domain Layer connections + domain -- "Uses" --> relayer + domain -- "Enforces" --> policies + relayer -- "Processes" --> transaction + plugins -- "Interacts with" --> relayer + + %% Services Layer connections + transaction -- "Signs with" --> signer + transaction -- "Connects via" --> provider + transaction -- "Queues jobs" --> jobs + webhook -- "Notifies" --> notification + monitoring -- "Collects" --> metrics + signer -- "May use" --> vault + + %% Infrastructure connections + repositories -- "Stores data" --> redis + jobs -- "Processes async" --> redis + vault -- "Secrets management" --> vault_ext + provider -- "Interacts with" --> blockchain + + %% Configuration connections + config_files -- "Configures" --> domain + env_vars -- "Configures" --> domain + + %% Styling + classDef apiClass fill:#f9f,stroke:#333,stroke-width:2px + classDef domainClass fill:#bbf,stroke:#333,stroke-width:2px + classDef infraClass fill:#bfb,stroke:#333,stroke-width:2px + classDef serviceClass fill:#fbf,stroke:#333,stroke-width:2px + classDef configClass fill:#fbb,stroke:#333,stroke-width:2px + classDef externalClass fill:#ddd,stroke:#333,stroke-width:1px + + class api,middleware,plugins apiClass + class domain,relayer,policies domainClass + class repositories,jobs,signer,provider infraClass + class transaction,vault,webhook,monitoring serviceClass + class config_files,env_vars configClass + class blockchain,redis,vault_ext,metrics,notification externalClass +``` + +## Project Structure + +The project follows a standard Rust project layout: + +``` +openzeppelin-relayer/ +β”œβ”€β”€ src/ +β”‚ β”œβ”€β”€ api/ # Route and controllers logic +β”‚ β”œβ”€β”€ bootstrap/ # Service initialization logic +β”‚ β”œβ”€β”€ config/ # Configuration logic +β”‚ β”œβ”€β”€ constants/ # Constant values used in the system +β”‚ β”œβ”€β”€ domain/ # Domain logic +β”‚ β”œβ”€β”€ jobs/ # Asynchronous processing logic (queueing) +β”‚ β”œβ”€β”€ logging/ # Logs File rotation logic +β”‚ β”œβ”€β”€ metrics/ # Metrics logic +β”‚ β”œβ”€β”€ models/ # Data structures and types +β”‚ β”œβ”€β”€ repositories/ # Configuration storage +β”‚ β”œβ”€β”€ services/ # Services logic +β”‚ └── utils/ # Helper functions +β”‚ +β”œβ”€β”€ config/ # Configuration files +β”œβ”€β”€ tests/ # Integration tests +β”œβ”€β”€ docs/ # Documentation +β”œβ”€β”€ scripts/ # Utility scripts +β”œβ”€β”€ examples/ # Configuration examples +β”œβ”€β”€ helpers/ # Rust helper scripts +β”œβ”€β”€ plugins/ # Plugins directory +└── ... other root files (Cargo.toml, README.md, etc.) +``` + +For detailed information about each directory and its contents, see [Project Structure Details](/relayer/1.0.x/structure). + +## Getting Started + +### Prerequisites + +* Rust 2021 edition, version `1.85` or later +* Docker (optional, for containerized deployment) +* Node.js, typescript and ts-node (optional, for plugins) + + + +**Ready-to-Use Example Configurations** + +For quick setup with various configurations, check the [examples directory](https://github.com/OpenZeppelin/openzeppelin-relayer/tree/main/examples) in our GitHub repository: + +* `basic-example`: Simple setup with Redis +* `basic-example-logging`: Configuration with file-based logging +* `basic-example-metrics`: Setup with Prometheus and Grafana metrics +* `vault-secret-signer`: Using HashiCorp Vault for key management +* `vault-transit-signer`: Using Vault Transit for secure signing +* `evm-gcp-kms-signer`: Using Google Cloud KMS for EVM secure signing +* `evm-turnkey-signer`: Using Turnkey for EVM secure signing +* `solana-turnkey-signer`: Using Turnkey for Solana secure signing + +Each example includes a README with step-by-step instructions and Docker Compose configuration. + + +### Install Locally + +1. Clone the repository: + + ```bash + git clone https://github.com/openzeppelin/openzeppelin-relayer + cd openzeppelin-relayer + ``` +2. Verify you have sodium libs installed. If not, follow these instructions: + + * Install a stable libsodium version from [here](https://download.libsodium.org/libsodium/releases/). + * Follow the steps in the [libsodium installation guide](https://doc.libsodium.org/installation). +3. Install dependencies: + + ```bash + cargo build + ``` + +## Running the Relayer + +### Option 1: Run Locally + +```bash +cargo run +``` + + +Before executing the command, ensure that the `.env` and `config.json` files are configured as detailed in the [Configuration References](#configuration_references) section. + + +### Option 2: Run with Docker + +The Relayer can be run as either a development or production container using the corresponding Dockerfile (`Dockerfile.development` or `Dockerfile.production`). + +#### Step 1: Configure Environment + +* Edit `.env` at the root of the repository to adjust environment variables +* The appropriate .env file will be included during image build + +#### Step 2: Build the Image + +You can build using Docker Compose (v2). + +```bash +# Default build +docker compose build + +# Or, for a leaner image (and using Dockerfile.production) +DOCKERFILE=Dockerfile.production docker compose build +``` + +#### Step 3: Run the Container + +Use Docker Compose to run the container: + +```bash +docker compose up -d +``` + +For production runs, you can use: + +```bash +DOCKERFILE=Dockerfile.production docker compose up -d +``` + +## Configuration + +OpenZeppelin Relayer requires proper configuration before starting. The configuration system uses two main files: + +* ***`config.json`***: Contains relayer definitions, signer configurations, and network policies +* ***`.env`***: Contains environment variables like API keys and connection strings + + + + +Both configuration files must be properly set up before starting the application. Changes to either file require restarting the container to take effect. + +For quick setup examples with pre-configured files, see the [examples directory](https://github.com/OpenZeppelin/openzeppelin-relayer/tree/main/examples) in our GitHub repository. + + + +For comprehensive configuration details, including: + +* Environment variables and their settings +* Main configuration file structure +* Signer configurations (local, vault, cloud KMS, etc.) +* Notification setup +* Relayer policies and network settings +* Plugin configuration +* Complete configuration examples + +See the dedicated [Configuration Guide](/relayer/1.0.x/configuration). + +## Important Considerations + +## Deployment Considerations + + +The OpenZeppelin Relayer is designed to function as a backend service and is not meant to be directly exposed to the public internet. To protect the service from unauthorized access, deploy it behind your own secure backend infrastructureβ€”such as a reverse proxy or firewallβ€”and restrict access to trusted internal components only. Direct exposure can increase the risk of exploitation and security breaches. + + +## Support + +For support or inquiries, contact us on [Telegram](https://t.me/openzeppelin_tg/2). + +## License +This project is licensed under the GNU Affero General Public License v3.0 - see the LICENSE file for details. + +## Security +For security concerns, please refer to our [Security Policy](https://github.com/OpenZeppelin/openzeppelin-relayer/blob/main/SECURITY.md). diff --git a/content/relayer/1.0.x/network_configuration.mdx b/content/relayer/1.0.x/network_configuration.mdx new file mode 100644 index 00000000..76857d0a --- /dev/null +++ b/content/relayer/1.0.x/network_configuration.mdx @@ -0,0 +1,381 @@ +--- +title: Network Configuration +--- + +The OpenZeppelin Relayer supports multiple blockchain networks through a flexible JSON-based configuration system. This guide covers everything you need to know about configuring networks for your relayer instances. + +## Overview + +Networks are defined in JSON configuration files, allowing you to: + +* Configure ***any EVM-compatible network*** (Ethereum, Polygon, BSC, Arbitrum, Optimism, etc.) +* Set up ***Solana networks*** (mainnet-beta, devnet, testnet, custom RPC endpoints) +* Configure ***Stellar networks*** (Pubnet, Testnet, custom networks) +* Create ***custom network configurations*** with specific RPC endpoints, chain IDs, and network parameters +* Use ***inheritance*** to create network variants without duplicating configuration + +## Network Types + +| Network Type | Description | +| --- | --- | +| `evm` | Ethereum Virtual Machine compatible networks. Supports any EVM chain by configuring chain ID, RPC URLs, and network-specific parameters. | +| `solana` | Solana blockchain networks. Supports all Solana clusters and custom RPC endpoints. | +| `stellar` | Stellar blockchain networks. Supports Stellar Public Network and Testnet. | + +## Configuration Methods + +### Default Network Configuration + +If no `networks` field is specified in your `config.json`, the relayer will automatically load network configurations from the `./config/networks` directory. This is the default behavior. + +```json +{ + "relayers": [...], + "notifications": [...], + "signers": [...] + // No "networks" field - defaults to "./config/networks" +} +``` + + +Once you specify a `networks` field in your configuration, the default `./config/networks` directory will ***not*** be loaded automatically. If you want to use files from that directory, you must explicitly specify the path `"./config/networks"`. + + +You can configure networks in two ways: + +### Method 1: Separate JSON Files + +Specify the path to network configuration files in your main `config.json`: + +```json +{ + "relayers": [...], + "notifications": [...], + "signers": [...], + "networks": "./config/networks" // Path to directory or file +} +``` + + +This is the same as the default behavior, but explicitly specified. You can also point to a different directory or file path. + + +Each JSON file ***must*** contain a top-level `networks` array: + +```json +{ + "networks": [ + // ... network definitions ... + ] +} +``` + +When using a directory structure: +``` +networks/ +β”œβ”€β”€ evm.json # {"networks": [...]} +β”œβ”€β”€ solana.json # {"networks": [...]} +└── stellar.json # {"networks": [...]} +``` + +### Method 2: Direct Configuration + +Define networks directly in your main `config.json` instead of using separate files: + +```json +{ + "relayers": [...], + "notifications": [...], + "signers": [...], + "networks": [ + { + "type": "evm", + "network": "ethereum-mainnet", + "chain_id": 1, + // ... other fields + } + ] +} +``` + +When using this method, the default `./config/networks` directory is ignored, and only the networks defined in this array will be available. + +## Network Field Reference + +### Common Fields + +All network types support these configuration fields: + +| Field | Type | Required | Description | +| --- | --- | --- | --- | +| `type` | string | Yes | Network type: `"evm"`, `"solana"`, or `"stellar"` | +| `network` | string | Yes | Unique network identifier (e.g., "ethereum-mainnet", "polygon-mumbai") | +| `from` | string | No | Name of parent network to inherit from (same type only) | +| `rpc_urls` | array[string] | Yes* | List of RPC endpoint URLs (*Required for base networks, optional for inherited) | +| `explorer_urls` | array[string] | No | List of blockchain explorer URLs | +| `average_blocktime_ms` | number | No | Estimated average time between blocks in milliseconds | +| `is_testnet` | boolean | No | Whether this is a testnet (affects behavior and validation) | +| `tags` | array[string] | No | Arbitrary tags for categorization and filtering | + +### Special Network Tags + +Some tags have special meaning and affect relayer behavior: + +| Tag | Description and Behavior | +| --- | --- | +| `rollup` | Identifies Layer 2 rollup networks (e.g., Arbitrum, Optimism, Base) | +| `optimism` | Identifies Optimism-based networks using the OP Stack (e.g., Optimism, Base, World Chain) | +| `no-mempool` | Indicates networks that lack a traditional mempool (e.g., Arbitrum) | +| `deprecated` | Marks networks that are deprecated and may be removed in future versions | + +#### Example: Using Special Tags + +Here’s an example showing how special tags are used in practice: + +```json +{ + "type": "evm", + "network": "arbitrum-one", + "chain_id": 42161, + "required_confirmations": 1, + "symbol": "ETH", + "rpc_urls": ["https://arb1.arbitrum.io/rpc"], + "tags": ["rollup", "no-mempool"], // Arbitrum is a rollup without mempool + "is_testnet": false +} +``` + +These tags help the relayer: + +* Apply specific transaction handling for rollups +* Use optimized fee calculation for OP Stack chains +* Skip mempool-related operations for networks without mempools +* Warn users about deprecated networks + +### EVM-Specific Fields + +| Field | Type | Required | Description | +| --- | --- | --- | --- | +| `chain_id` | number | Yes* | Unique chain identifier (e.g., 1 for Ethereum mainnet, 137 for Polygon) (*Required for base networks, optional for inherited) | +| `required_confirmations` | number | Yes* | Number of block confirmations before considering a transaction final (*Required for base networks, optional for inherited) | +| `symbol` | string | Yes* | Native currency symbol (e.g., "ETH", "MATIC", "BNB") (*Required for base networks, optional for inherited) | +| `features` | array[string] | No | Supported features (e.g., ["eip1559", "london"]) | + +#### Example: EVM Network Configuration + +Here’s an example showing an EVM network configuration: + +```json +{ + "type": "evm", + "network": "ethereum-mainnet", + "chain_id": 1, // Ethereum mainnet chain ID + "required_confirmations": 12, // High security: 12 confirmations + "symbol": "ETH", // Native currency symbol + "features": ["eip1559"], // Supports EIP-1559 fee market + "rpc_urls": ["https://mainnet.infura.io/v3/YOUR_KEY"], + "is_testnet": false +} +``` + +### Solana-Specific Fields + +Currently, Solana networks use only the common fields. Additional Solana-specific configuration options may be added in future versions. + +### Stellar-Specific Fields + +| Field | Type | Required | Description | +| --- | --- | --- | --- | +| `passphrase` | string | No | Network passphrase for transaction signing and network identification (optional for all networks, including base networks) | + +#### Example: Stellar Network Configuration + +Here’s an example showing a Stellar network configuration with passphrase: + +```json +{ + "type": "stellar", + "network": "pubnet", + "rpc_urls": ["https://horizon.stellar.org"], + "explorer_urls": ["https://stellar.expert/explorer/public"], + "passphrase": "Public Global Stellar Network ; September 2015", // Official mainnet passphrase + "average_blocktime_ms": 5000, + "is_testnet": false +} +``` + +## Configuration Examples + +### Basic EVM Network + +```json +{ + "type": "evm", + "network": "ethereum-mainnet", + "chain_id": 1, + "required_confirmations": 12, + "symbol": "ETH", + "rpc_urls": ["https://mainnet.infura.io/v3/YOUR_KEY"], + "explorer_urls": ["https://etherscan.io"], + "average_blocktime_ms": 12000, + "is_testnet": false, + "tags": ["mainnet", "ethereum"] +} +``` + +### Layer 2 EVM Network with Tags + +```json +{ + "type": "evm", + "network": "optimism", + "chain_id": 10, + "required_confirmations": 1, + "symbol": "ETH", + "rpc_urls": [ + "https://mainnet.optimism.io", + "https://optimism.drpc.org" + ], + "features": ["eip1559"], + "tags": ["rollup", "optimism"], + "average_blocktime_ms": 2000, + "is_testnet": false +} +``` + +### Solana Network + +```json +{ + "type": "solana", + "network": "mainnet-beta", + "rpc_urls": ["https://api.mainnet-beta.solana.com"], + "explorer_urls": ["https://explorer.solana.com"], + "average_blocktime_ms": 400, + "is_testnet": false, + "tags": ["mainnet", "solana"] +} +``` + +### Stellar Network + +```json +{ + "type": "stellar", + "network": "pubnet", + "rpc_urls": ["https://horizon.stellar.org"], + "passphrase": "Public Global Stellar Network ; September 2015", + "explorer_urls": ["https://stellar.expert/explorer/public"], + "average_blocktime_ms": 5000, + "is_testnet": false, + "tags": ["mainnet", "stellar"] +} +``` + +## Network Inheritance + +Networks can inherit from other networks of the same type, allowing you to create variants without duplicating configuration: + +```json +{ + "networks": [ + { + "type": "evm", + "network": "ethereum-base", + "chain_id": 1, + "required_confirmations": 12, + "symbol": "ETH", + "rpc_urls": ["https://mainnet.infura.io/v3/YOUR_KEY"] + }, + { + "from": "ethereum-base", + "type": "evm", + "network": "ethereum-sepolia", + "chain_id": 11155111, + "required_confirmations": 3, + "rpc_urls": ["https://sepolia.infura.io/v3/YOUR_KEY"], + "is_testnet": true + } + ] +} +``` + +When using inheritance: + +* The child network inherits all fields from the parent +* Fields specified in the child override parent values +* The `from` field must reference a network of the same type + +## Using Networks in Relayer Configuration + +Once networks are defined, reference them in your relayer configurations: + +```json +{ + "relayers": [ + { + "id": "my-evm-relayer", + "name": "My EVM Relayer", + "network": "ethereum-mainnet", // References network ID + "network_type": "evm", + "signer_id": "my-signer" + } + ] +} +``` + +## Best Practices + +### 1. Network Organization +* Group related networks in separate files (e.g., `ethereum.json`, `polygon.json`) +* Use consistent naming conventions for network identifiers +* Include both mainnet and testnet configurations + +### 2. RPC URLs +* Always configure multiple RPC URLs for redundancy +* Use private/dedicated RPC endpoints for production +* Ensure URLs are secure (HTTPS) when accessing over public networks + +### 3. Confirmation Requirements +* Set appropriate `required_confirmations` based on network security +* Higher values for mainnet, lower for testnets +* Consider network-specific finality characteristics + +### 4. Tags and Features +* Use tags to categorize networks (e.g., "mainnet", "testnet", "rollup") +* Enable appropriate features (e.g., "eip1559" for supported networks) +* Document custom tags used in your organization + +### 5. Inheritance +* Create base configurations for common settings +* Use inheritance to reduce duplication +* Override only necessary fields in child networks + +## Troubleshooting + +### Common Issues + +***Network not found:*** + +* Ensure the network identifier in relayer config matches exactly +* Check that network configuration files are in the correct location +* Verify JSON syntax is valid + +***RPC connection failures:*** + +* Test RPC URLs independently before configuring +* Ensure firewall/network allows outbound HTTPS connections +* Check API keys are included in RPC URLs where required + +***Invalid configuration:*** + +* Validate required fields are present for network type +* Ensure numeric fields (chain_id, confirmations) are numbers, not strings +* Check that inherited networks reference existing parent networks + +## See Also + +* [Relayer Configuration](/relayer/1.0.x#relayer_configuration) +* [Quickstart Guide](/relayer/1.0.x/quickstart) +* [Solana Integration](/relayer/1.0.x/solana) +* [API Reference](https://openzeppelin-relayer.netlify.app/api_docs.html) diff --git a/content/relayer/1.0.x/plugins.mdx b/content/relayer/1.0.x/plugins.mdx new file mode 100644 index 00000000..b38323a5 --- /dev/null +++ b/content/relayer/1.0.x/plugins.mdx @@ -0,0 +1,180 @@ +--- +title: Plugins +--- + +## Overview + +OpenZeppelin Relayer supports plugins to extend the functionality of the relayer. + +Plugins are `TypeScript` functions running in the Relayer server that can include any arbitrary logic defined by the Relayer operator. + +It also includes a simple `Plugin` library to interact with the Relayer, allowing to send transactions, and +is extensible to support new features in the future. + +## Configuration + +### Writing a Plugin + +Plugins are declared under `plugins` directory, and are expected to be TypeScript files (`.ts` extension). + +```bash +openzeppelin-relayer/ +β”œβ”€β”€ plugins/ +β”‚ └── my-plugin.ts # Plugin code +└── config/ + └── config.json # Plugins in configuration file +``` + +The plugin code must include the following structure: + +```typescript +/// Required imports. +import { runPlugin, Plugin } from "./lib/plugin"; + +/// Here you can define custom params that will be included as part +/// of the request when the plugin is invoked. +type MyCustomParams = { + foo: string, + bar: number +} + +/// The plugin function body. +async function myPlugin(api: Plugin, params: MyCustomParams) { + // You can use the `params` to access the custom params passed to the plugin. + console.log(params.foo); + console.log(params.bar); + + // Api usage to send a transaction: + let relayer = api.relayer('my-relayer'); + const tx = await relayer.sendTransaction({ + to: "0x1234567890123456789012345678901234567890", + value: ethers.parseEther("1"), + }); +} + +/// `runPlugin` is the entry point for the plugin. +runPlugin(myPlugin); +``` + +### Declaring in config file + +Plugins are configured in the `./config/config.json` file, under the `plugins` key. + +The file contains a list of plugins, each with an id and path. + + +The plugin path is relative to the `/plugins` directory + + +Example: + +```json + +"plugins": [ + { + "id": "my-plugin", + "path": "my-plugin.ts" + } +] +``` + +## Invocation + +Plugins are invoked by hitting the `api/v1/plugins/plugin-id/call` endpoint. + +The endpoint accepts a `POST` request with the following body: + +```json +{ + "params": { + "foo": "bar", + "bar": 1 + } +} +``` + +Then the plugin will be invoked passing the `params` as the second argument of the plugin function. + +## Debugging + +When invoking a plugin, the response will include: + +* `logs`: The logs from the plugin execution. +* `return_value`: The returned value of the plugin execution. +* `error`: An error message if the plugin execution failed. +* `traces`: A list of messages sent between the plugin and the Relayer instance. This includes all the payloads passed through the `api` object. + +### Example + +1. Example Plugin code: + +```typescript +import { runPlugin, Plugin } from "./lib/plugin"; +import { ethers } from "ethers"; + +type MyCustomParams = { + foo: string, +} + +async function myPlugin(api: Plugin, params: MyCustomParams) { + console.log("Hello, world!"); + + // For example, to send a transaction: + let relayer = api.relayer('my-relayer'); + const tx = await relayer.sendTransaction({ + to: "0x1234567890123456789012345678901234567890", + value: ethers.parseEther("1"), + }); + + console.log("Foo ", params.foo); + + return `Successfully sent transaction with id: ${tx.id}`; +} + +runPlugin(myPlugin); +``` + +1. Example Invocation: + +```bash +curl -X POST http://localhost:3000/api/v1/plugins/my-plugin/call \ +-H "Content-Type: application/json" \ +-d '{"params": {"foo": "bar"}}' +``` + +1. Example Response: + +```json +{ + "success": true, + "message": "Plugin called successfully", + "logs": [ + { + "level": "log", + "message": "Hello, world!" + }, + { + "level": "log", + "message": "Foo bar" + } + ], + "return_value": "Successfully sent transaction with id: 1234567890", + "error": "", + "traces": [ + { + "relayer_id": "my-relayer", + "method": "sendTransaction", + "payload": { + "to": "0x1234567890123456789012345678901234567890", + "value": "1000000000000000000" + } + } + ] +} +``` + +Where: +- `logs` indicates the terminal logs (console.log, console.error, etc.) of the plugin. +- `traces` are the messages sent between the plugin and the Relayer instance. +- `error` will include the error message if the plugin fails. +- `return_value` will include the returned value of the plugin execution. diff --git a/content/relayer/1.0.x/quickstart.mdx b/content/relayer/1.0.x/quickstart.mdx new file mode 100644 index 00000000..d2496bae --- /dev/null +++ b/content/relayer/1.0.x/quickstart.mdx @@ -0,0 +1,167 @@ +--- +title: Quick Start Guide +--- + +This guide provides step-by-step instructions for setting up OpenZeppelin Relayer. It includes prerequisites, installation, and configuration examples. + +## Prerequisites + +* Rust 2021, version `1.85` or later. +* Redis +* Docker (optional, for containerized deployment) +* Node.js, typescript and ts-node (optional, for plugins) + +## Configuration + +### Step 1: Clone the Repository + +Clone the repository and navigate to the project directory: + +```bash +git clone https://github.com/OpenZeppelin/openzeppelin-relayer +cd openzeppelin-relayer +``` + +### Step 2: Create Configuration Files + +Create environment configuration: + +```bash +cp .env.example .env +``` + +These files are already partially configured. We will add missing data in next steps. + +Ready-to-Use Example Configurations + +For quick setup with various configurations, check the [examples directory](https://github.com/OpenZeppelin/openzeppelin-relayer/tree/main/examples) in our GitHub repository: + +### Step 3: Create a Signer + +Generate a new signer keystore for the basic example: + +```bash +cargo run --example create_key -- \ + --password \ + --output-dir examples/basic-example/config/keys \ + --filename local-signer.json +``` +Replace `` with a strong password. + + + + +Your password must contain at least: + +* 12 characters +* One uppercase letter +* One lowercase letter +* One number +* One special character + + + +Next, update the `KEYSTORE_PASSPHRASE` in `.env` with the password you used above. + +### Step 4: Configure Notifications + +#### Configure Webhook URL + +Edit the file `config/config.json` and update the `notifications[0].url` field with your webhook URL. For a quick test, you can use a temporary URL from [Webhook.site](https://webhook.site). + +#### Configure Webhook Signing Key + +Generate a webhook signing key: + +```bash +cargo run --example generate_uuid +``` + + + + +Alternatively, you can use any online UUID generator tool if you don’t want to run the included command. + + + +Copy the generated UUID and update the `WEBHOOK_SIGNING_KEY` entry in `.env`. + +### Step 5: Configure API Key + +Generate an API key signing key for development: + +```bash +cargo run --example generate_uuid +``` + + + + +You can also use UUID generator with a simple command on your terminal. + +```bash +uuidgen +``` + +Alternatively, you can use any online UUID generator tool. + + + +Copy the generated UUID and update the `API_KEY` entry in `.env`. + +### Step 6: Run the Service + +#### Local + +Run Redis container: + +```sh +docker run --name openzeppelin-redis \ + -p 6379:6379 \ + -d redis:latest +``` + +Run Relayer service: + +```bash +cargo run +``` + +#### Docker + +Building and Running the docker image: + +```bash +docker compose up -d +``` + +By default docker compose command uses `Dockerfile.development` to build the image. If you want to use `Dockerfile.production`, you can use the following command: + +```bash +DOCKERFILE=Dockerfile.production docker compose up -d +``` + +### Step 7: Test the Relayer + +Verify the service by sending a GET request: + +```bash +curl -X GET http://localhost:8080/api/v1/relayers \ + -H "Content-Type: application/json" \ + -H "AUTHORIZATION: Bearer YOUR_API_KEY" +``` +Replace `YOUR_API_KEY` with the API key you configured in your `.env` file. + +Expected Result: A successful request should return an HTTP 200 status code along with the list of relayers. + +## Using the relayer through the API + +For detailed API usage, refer to the [API guide](/relayer/1.0.x/api_reference). The guide provides endpoint descriptions, usage examples, and best practices for integrating with the relayer service. + +## Using the relayer through the SDK + +For documentation and examples on how to consume Relayer service via SDK check [SDK documentation](https://github.com/OpenZeppelin/openzeppelin-relayer-sdk). + +## Additional Resources and Troubleshooting + +Troubleshooting: If you encounter issues during setup or deployment, verify your environment variables, check container logs, and review your configuration files for syntax errors. diff --git a/content/relayer/1.0.x/roadmap.mdx b/content/relayer/1.0.x/roadmap.mdx new file mode 100644 index 00000000..0fbfbfbf --- /dev/null +++ b/content/relayer/1.0.x/roadmap.mdx @@ -0,0 +1,113 @@ +--- +title: OpenZeppelin Relayer Roadmap +--- + +This document outlines the planned development roadmap for the OpenZeppelin Relayer project. Please note that priorities and timelines may shift based on community feedback, security considerations, and emerging blockchain ecosystem needs. + + + + +This roadmap represents our current plans and is subject to change. We will update this document regularly to reflect our progress and any changes in direction. + + + +## General Roadmap + +* **Stability Improvements** + * Enhanced error handling and recovery mechanisms: Implement robust exception management and failover processes to minimize downtime. + * Improved background job processing: Optimize task scheduling and queuing systems to ensure smooth and reliable asynchronous operations. + * Comprehensive test coverage: Extend unit, integration, and regression tests across all components. + * End-to-End (E2E) testing: Simulate real-world scenarios to verify complete system functionality. + * Performance optimizations: Enhance throughput and reduce latency for high-demand scenarios. + * Stress and load testing: Identify and address performance bottlenecks under extreme conditions. +* **Security Enhancements** + * External security audit: Engage third-party experts to identify and remediate vulnerabilities. + * Continuous security monitoring: Implement ongoing surveillance and incident response protocols to swiftly address threats. +* **Developer Experience** + * SDK improvements: Expand SDK capabilities, add multi-language support, and simplify integration processes. + * Enhanced documentation: Develop interactive guides, detailed API references, and comprehensive troubleshooting tips. + * Additional examples and best practices: Provide real-world usage scenarios and community-contributed tutorials to ease onboarding. +* **Features** + * Redis storage integration: Leverage Redis for fast, scalable data storage across all system components. + * Enhanced relayer balance management: Implement real-time monitoring and alerts to maintain optimal balance status. + * Dynamic gas price updates: Regularly fetch and update gas prices from multiple reliable sources to ensure accurate fee estimations. +* **Scaling Improvements** + * Horizontal scaling capabilities: Design the system architecture to seamlessly distribute workloads across multiple instances. + +## Network-Specific Roadmap + +### EVM Networks (πŸ—οΈ In Progress) + +#### Current Status +* Basic Transaction Submission +* Fee Estimation +* Transaction Status Tracking +* Flexible Network Configuration System (any EVM-compatible network via JSON configuration) +* Hosted signers support (AWS KMS, GCP, Turnkey) +* Custom RPC Endpoints +* RPC Retries and Failover Mechanisms + +#### Upcoming Features +* L2 improvements +* SDK client improvements +* Full CRUD API support + +### Solana (πŸ—οΈ In Progress) + +#### Current Status +* Solana Paymaster Specification Support +* Fee estimation +* Gasless transactions +* Hosted Signer Integrations (Vault, GCP, Turnkey) +* Custom RPC Endpoints +* RPC Retries and Failover Mechanisms + +#### Upcoming Features +* Extended RPC Methods +* Improved Transaction Status Checks +* Full CRUD API support + +### Stellar (πŸ—οΈ In Progress) + +#### Current Status +* Supports payment and InvokeHostFunction operations, pre-built XDR transactions, and fee bump transactions, +* Advanced transaction status logic +* Stellar-specific endpoints +* Expanded signer support +* Transaction lifecycle management logic +* Custom RPC Endpoints +* RPC Retries and Failover Mechanisms + +#### Upcoming Features +* Relayer security policies: Transaction amount limits, destination whitelisting, time bound and limit operations +* Hosted signers +* Full CRUD API support + +## Community and Documentation + +### Continuous +* **Documentation** + * Comprehensive API reference + * Tutorials and guides + * Integration examples +* **Community Engagement** + * Contributing guidelines + * Support for community-driven improvements + +## Notes on Prioritization + + + + +Our development priorities are influenced by several factors: + +1. **Security**: Security enhancements always take precedence +2. **Stability**: Ensuring reliable operation across all supported networks +3. **Community Feedback**: Features requested by the community +4. **Ecosystem Developments**: Adapting to changes in blockchain protocols + + + +This roadmap is a living document and will be updated regularly to reflect changing priorities and completed milestones. We welcome community input on our direction and priorities. + +To contribute to discussions about the roadmap, please join our community channels or open an issue on our GitHub repository with your suggestions. diff --git a/content/relayer/1.0.x/solana.mdx b/content/relayer/1.0.x/solana.mdx new file mode 100644 index 00000000..dc84d013 --- /dev/null +++ b/content/relayer/1.0.x/solana.mdx @@ -0,0 +1,214 @@ +--- +title: Solana Integration +--- + +## Overview + +OpenZeppelin Relayer provides robust support for Solana networks, enabling secure transaction relaying, automated token swaps, gasless transactions, and advanced fee management. This page covers everything you need to get started and make the most of Solana-specific features. + +## Features + +* Automated token swaps via Jupiter DEX (mainnet-beta only) +* Gasless transactions (user or relayer pays fees) +* Secure transaction signing with multiple signer backends +* Transaction status monitoring and nonce management +* Custom RPC endpoints and network policies +* Metrics and observability + +## Supported Networks + +Solana networks are defined via JSON configuration files, providing flexibility to: + +* Configure standard Solana clusters: `mainnet-beta`, `devnet`, `testnet` +* Set up custom Solana-compatible networks with specific RPC endpoints +* Create network variants using inheritance from base configurations + +Example Solana network configurations: + +```json +{ + "networks": [ + { + "type": "solana", + "network": "solana-mainnet", + "rpc_urls": ["https://api.mainnet-beta.solana.com"], + "explorer_urls": ["https://explorer.solana.com"], + "is_testnet": false, + "tags": ["mainnet", "solana"] + }, + { + "type": "solana", + "network": "solana-devnet", + "rpc_urls": ["https://api.devnet.solana.com"], + "explorer_urls": ["https://explorer.solana.com?cluster=devnet"], + "is_testnet": true, + "tags": ["devnet", "solana"] + }, + { + "type": "solana", + "network": "solana-custom", + "rpc_urls": ["https://your-custom-solana-rpc.example.com"], + "tags": ["custom", "solana"] + } + ] +} +``` + +For detailed network configuration options, see the [Network Configuration](/relayer/1.0.x/network_configuration) guide. + +## Supported Signers + +* `vault_transit` (hosted) +* `turnkey` (hosted) +* `google_cloud_kms` (hosted) +* `local` (local) +* `vault` (local) +* `vault_cloud` (local) + + + + +In production systems, hosted signers are recommended for the best security model. + + + +## Quickstart + +For a step-by-step setup, see [Quick Start Guide](/relayer/1.0.x/quickstart). +Key prerequisites: + +* Rust 2021, version `1.85` or later +* Redis +* Docker (optional) + +Example configuration for a Solana relayer: +```json +{ + "id": "solana-example", + "name": "Solana Example", + "network": "devnet", + "paused": false, + "notification_id": "notification-example", + "signer_id": "local-signer", + "network_type": "solana", + "custom_rpc_urls": [ + { "url": "https://primary-solana-rpc.example.com", "weight": 100 }, + { "url": "https://backup-solana-rpc.example.com", "weight": 100 } + ], + "policies": { + "fee_payment_strategy": "user", + "min_balance": 0, + "allowed_tokens": [ + { "mint": "So111...", "max_allowed_fee": 100000000 } + ], + "swap_config": { + "strategy": "jupiter-swap", + "cron_schedule": "0 0 * * * *", + "min_balance_threshold": 1000000, + "jupiter_swap_options": { + "dynamic_compute_unit_limit": true, + "priority_level": "high", + "priority_fee_max_lamports": 1000000000 + } + } + } +} +``` + +For more configuration examples, visit the [OpenZeppelin Relayer examples repository, window=_blank](https://github.com/OpenZeppelin/openzeppelin-relayer/tree/main/examples). + +## Configuration + +### Relayer Policies + +In addition to standard relayer configuration and policies, Solana relayers support additional options: + +* `fee_payment_strategy`: `"user"` or `"relayer"` (who pays transaction fees) +* `allowed_tokens`: List of SPL tokens supported for swaps and fee payments +* `allowed_programs`, `allowed_accounts`, `disallowed_accounts`: Restrict relayer operations to specific programs/accounts +* `swap_config`: Automated token swap settings (see below) + +You can check all options in [User Documentation - Relayers](/relayer/1.0.x#3_relayers). + +### Automated token swap configuration options: + +* `strategy`: The swap engine to use. Supported values: `"jupiter-swap"` (Jupiter Swap API), `"jupiter-ultra"` (Jupiter Ultra API). +* `cron_schedule`: Cron expression defining how often scheduled swaps should run (e.g., `"0 0 * * * *"` for every hour). +* `min_balance_threshold`: Minimum token balance (in lamports) that triggers a swap. If the relayer’s balance drops below this, a swap is attempted. +* `jupiter_swap_options`: Advanced options for Jupiter swaps, such as: + * `dynamic_compute_unit_limit`: If `true`, dynamically adjusts compute units for swap transactions. + * `priority_level`: Priority for the swap transaction. Supported values: `"medium"`, `"high"`, `"veryHigh"`. + * `priority_fee_max_lamports`: Maximum priority fee (in lamports) to pay for a swap transaction. +* Per-token swap limits: + * `min_amount`: Minimum amount of a token to swap in a single operation. + * `max_amount`: Maximum amount of a token to swap in a single operation. + * `retain_min_amount`: Minimum amount of a token to retain in the relayer account after a swap (prevents swapping the entire balance). + +## Automated Token Swaps + +The relayer can perform automated token swaps on Solana when user fee_payment_strategy is used for relayer using: + +* ***jupiter-swap*** – via the Jupiter Swap API +* ***jupiter-ultra*** – via the Jupiter Ultra API + +Swaps can be set to work as: + +* ***Scheduled Swaps***: Background jobs run swaps based on your cron schedule. +* ***On-Demand Swaps***: If a transaction fails due to insufficient funds, the relayer attempts a swap before returning an error. + +## API Reference + +The Solana API conforms to the [Paymaster spec, window=_blank](https://docs.google.com/document/d/1lweO5WH12QJaSAu5RG_wUistyk_nFeT6gy1CdvyCEHg/edit?tab=t.0#heading=h.4yldgprkuvav). + +Common endpoints: +- `POST /api/v1/relayers//rpc` + Methods: + +* `feeEstimate`, +* `prepareTransaction`, +* `transferTransaction`, +* `signTransaction`, +* `signAndSendTransaction`, +* `getSupportedTokens` +* `getSupportedFeatures` + +Example: Estimate fee for a transaction +```bash +curl --location --request POST 'http://localhost:8080/api/v1/relayers/solana-example/rpc' \ +--header 'Authorization: Bearer ' \ +--header 'Content-Type: application/json' \ +--data-raw '{ + "jsonrpc": "2.0", + "method": "feeEstimate", + "params": { + "transaction": "", + "fee_token": "" + }, + "id": 1 +}' +``` + +See [API Reference](/relayer/1.0.x/api_reference) and [SDK examples, window=_blank](https://github.com/OpenZeppelin/openzeppelin-relayer-sdk/tree/main/examples/solana) for full details and examples. + +## Security + +* Do not expose the relayer directly to the public internet. +* Deploy behind a secure backend (reverse proxy, firewall). +* Use hosted signers in production systems. + +## Troubleshooting + +* Check environment variables and configuration files for errors +* Review container logs for issues + +## Roadmap + +* See [Project Roadmap](/relayer/1.0.x/roadmap) for upcoming features + +## Support + +For help, join our [Telegram](https://t.me/openzeppelin_tg/2) or open an issue on GitHub. + +## License + +This project is licensed under the GNU Affero General Public License v3.0. diff --git a/content/relayer/1.0.x/structure.mdx b/content/relayer/1.0.x/structure.mdx new file mode 100644 index 00000000..0704bb4a --- /dev/null +++ b/content/relayer/1.0.x/structure.mdx @@ -0,0 +1,106 @@ +--- +title: Project Structure +--- + +This document provides detailed information about each directory in the OpenZeppelin Relayer project. + +## Source Code Organization + +### `src/` Directory +The main source code directory contains the core implementation files organized into several modules: + +* `api/`: Route and controllers logic + * Manages HTTP routing and delegates incoming requests to controllers +* `bootstrap/`: Service initialization + * Bootstraps and initializes application services +* `config/`: Configuration management + * Handles system configuration and environment settings +* `constants/`: Global constants + * Provides static values used across the application +* `domain/`: Business domain logic + * Encapsulates core business rules and domain-specific functionality +* `jobs/`: Asynchronous job processing + * Manages background task queueing and execution +* `logging/`: Logging and file rotation + * Implements logging functionalities and log file management +* `metrics/`: Metrics collection + * Collects and reports application performance and usage metrics +* `models/`: Core data models and types + * Defines data structures and type definitions for the system +* `repositories/`: Configuration storage + * Provides interfaces for storing and retrieving configuration data +* `services/`: Business service logic + * Implements core business functionalities and service operations +* `utils/`: Utility functions + * Offers helper functions and common utilities for the application + +## Documentation + +### `docs/` Directory +Project documentation: + +* User guides +* API documentation +* Configuration examples +* Architecture diagrams + +## Configuration + +### `config/` Directory + +Houses system configuration file and keys: + +* `config.json` configuration file +* keystore files referenced from config.json file + +## Tests + +### `test/` Directory + +Includes comprehensive testing suites to ensure system reliability: + +* End-to-end tests that simulate real-world user scenarios + +## Scripts + +### `scripts/` Directory + +Utility scripts. + +## Examples + +### `examples/` Directory + +Provides practical examples and sample configurations to help users get started: + +* Demonstrates typical service configurations for various environments +* Acts as a quick-start guide for customizing and deploying the relayer +* Serves as a reference for best practices in configuration and deployment + +## Development Tools + +### Pre-commit Hooks +Located in the project root: + +* Code formatting checks +* Linting rules +* Commit message validation + +### Build Configuration +Core build files: + +* `Cargo.toml`: Project dependencies and metadata +* `rustfmt.toml`: Code formatting rules +* `rust-toolchain.toml`: Rust version and components + +## Docker Support + +The project includes Docker configurations for different environments: + +* `Dockerfile.development`: Development container setup +* `Dockerfile.production`: Production-ready container + + + +For detailed information about running the relayers in containers, see the Docker deployment section in the main documentation. + diff --git a/content/relayer/1.1.x/api/callPlugin.mdx b/content/relayer/1.1.x/api/callPlugin.mdx new file mode 100644 index 00000000..fe557873 --- /dev/null +++ b/content/relayer/1.1.x/api/callPlugin.mdx @@ -0,0 +1,15 @@ +--- +title: Calls a plugin method. +full: true +_openapi: + method: POST + route: /api/v1/plugins/{plugin_id}/call + toc: [] + structuredData: + headings: [] + contents: [] +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + + \ No newline at end of file diff --git a/content/relayer/1.1.x/api/cancelTransaction.mdx b/content/relayer/1.1.x/api/cancelTransaction.mdx new file mode 100644 index 00000000..5e048adf --- /dev/null +++ b/content/relayer/1.1.x/api/cancelTransaction.mdx @@ -0,0 +1,15 @@ +--- +title: Cancels a specific transaction by its ID. +full: true +_openapi: + method: DELETE + route: /api/v1/relayers/{relayer_id}/transactions/{transaction_id} + toc: [] + structuredData: + headings: [] + contents: [] +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + + \ No newline at end of file diff --git a/content/relayer/1.1.x/api/createNotification.mdx b/content/relayer/1.1.x/api/createNotification.mdx new file mode 100644 index 00000000..9b979508 --- /dev/null +++ b/content/relayer/1.1.x/api/createNotification.mdx @@ -0,0 +1,15 @@ +--- +title: Creates a new notification. +full: true +_openapi: + method: POST + route: /api/v1/notifications + toc: [] + structuredData: + headings: [] + contents: [] +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + + \ No newline at end of file diff --git a/content/relayer/1.1.x/api/createRelayer.mdx b/content/relayer/1.1.x/api/createRelayer.mdx new file mode 100644 index 00000000..a6f15a08 --- /dev/null +++ b/content/relayer/1.1.x/api/createRelayer.mdx @@ -0,0 +1,15 @@ +--- +title: Creates a new relayer. +full: true +_openapi: + method: POST + route: /api/v1/relayers + toc: [] + structuredData: + headings: [] + contents: [] +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + + \ No newline at end of file diff --git a/content/relayer/1.1.x/api/createSigner.mdx b/content/relayer/1.1.x/api/createSigner.mdx new file mode 100644 index 00000000..8ef67359 --- /dev/null +++ b/content/relayer/1.1.x/api/createSigner.mdx @@ -0,0 +1,15 @@ +--- +title: Creates a new signer. +full: true +_openapi: + method: POST + route: /api/v1/signers + toc: [] + structuredData: + headings: [] + contents: [] +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + + \ No newline at end of file diff --git a/content/relayer/1.1.x/api/deleteNotification.mdx b/content/relayer/1.1.x/api/deleteNotification.mdx new file mode 100644 index 00000000..e79a94a6 --- /dev/null +++ b/content/relayer/1.1.x/api/deleteNotification.mdx @@ -0,0 +1,15 @@ +--- +title: Deletes a notification by ID. +full: true +_openapi: + method: DELETE + route: /api/v1/notifications/{notification_id} + toc: [] + structuredData: + headings: [] + contents: [] +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + + \ No newline at end of file diff --git a/content/relayer/1.1.x/api/deletePendingTransactions.mdx b/content/relayer/1.1.x/api/deletePendingTransactions.mdx new file mode 100644 index 00000000..629f7246 --- /dev/null +++ b/content/relayer/1.1.x/api/deletePendingTransactions.mdx @@ -0,0 +1,15 @@ +--- +title: Deletes all pending transactions for a specific relayer. +full: true +_openapi: + method: DELETE + route: /api/v1/relayers/{relayer_id}/transactions/pending + toc: [] + structuredData: + headings: [] + contents: [] +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + + \ No newline at end of file diff --git a/content/relayer/1.1.x/api/deleteRelayer.mdx b/content/relayer/1.1.x/api/deleteRelayer.mdx new file mode 100644 index 00000000..108df063 --- /dev/null +++ b/content/relayer/1.1.x/api/deleteRelayer.mdx @@ -0,0 +1,15 @@ +--- +title: Deletes a relayer by ID. +full: true +_openapi: + method: DELETE + route: /api/v1/relayers/{relayer_id} + toc: [] + structuredData: + headings: [] + contents: [] +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + + \ No newline at end of file diff --git a/content/relayer/1.1.x/api/deleteSigner.mdx b/content/relayer/1.1.x/api/deleteSigner.mdx new file mode 100644 index 00000000..1eac45c0 --- /dev/null +++ b/content/relayer/1.1.x/api/deleteSigner.mdx @@ -0,0 +1,15 @@ +--- +title: Deletes a signer by ID. +full: true +_openapi: + method: DELETE + route: /api/v1/signers/{signer_id} + toc: [] + structuredData: + headings: [] + contents: [] +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + + \ No newline at end of file diff --git a/content/relayer/1.1.x/api/getNotification.mdx b/content/relayer/1.1.x/api/getNotification.mdx new file mode 100644 index 00000000..fb83d496 --- /dev/null +++ b/content/relayer/1.1.x/api/getNotification.mdx @@ -0,0 +1,15 @@ +--- +title: Retrieves details of a specific notification by ID. +full: true +_openapi: + method: GET + route: /api/v1/notifications/{notification_id} + toc: [] + structuredData: + headings: [] + contents: [] +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + + \ No newline at end of file diff --git a/content/relayer/1.1.x/api/getRelayer.mdx b/content/relayer/1.1.x/api/getRelayer.mdx new file mode 100644 index 00000000..a587175d --- /dev/null +++ b/content/relayer/1.1.x/api/getRelayer.mdx @@ -0,0 +1,15 @@ +--- +title: Retrieves details of a specific relayer by ID. +full: true +_openapi: + method: GET + route: /api/v1/relayers/{relayer_id} + toc: [] + structuredData: + headings: [] + contents: [] +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + + \ No newline at end of file diff --git a/content/relayer/1.1.x/api/getRelayerBalance.mdx b/content/relayer/1.1.x/api/getRelayerBalance.mdx new file mode 100644 index 00000000..78808265 --- /dev/null +++ b/content/relayer/1.1.x/api/getRelayerBalance.mdx @@ -0,0 +1,15 @@ +--- +title: Retrieves the balance of a specific relayer. +full: true +_openapi: + method: GET + route: /api/v1/relayers/{relayer_id}/balance + toc: [] + structuredData: + headings: [] + contents: [] +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + + \ No newline at end of file diff --git a/content/relayer/1.1.x/api/getRelayerStatus.mdx b/content/relayer/1.1.x/api/getRelayerStatus.mdx new file mode 100644 index 00000000..158e831f --- /dev/null +++ b/content/relayer/1.1.x/api/getRelayerStatus.mdx @@ -0,0 +1,15 @@ +--- +title: Fetches the current status of a specific relayer. +full: true +_openapi: + method: GET + route: /api/v1/relayers/{relayer_id}/status + toc: [] + structuredData: + headings: [] + contents: [] +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + + \ No newline at end of file diff --git a/content/relayer/1.1.x/api/getSigner.mdx b/content/relayer/1.1.x/api/getSigner.mdx new file mode 100644 index 00000000..cef67a33 --- /dev/null +++ b/content/relayer/1.1.x/api/getSigner.mdx @@ -0,0 +1,15 @@ +--- +title: Retrieves details of a specific signer by ID. +full: true +_openapi: + method: GET + route: /api/v1/signers/{signer_id} + toc: [] + structuredData: + headings: [] + contents: [] +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + + \ No newline at end of file diff --git a/content/relayer/1.1.x/api/getTransactionById.mdx b/content/relayer/1.1.x/api/getTransactionById.mdx new file mode 100644 index 00000000..f2672ef9 --- /dev/null +++ b/content/relayer/1.1.x/api/getTransactionById.mdx @@ -0,0 +1,15 @@ +--- +title: Retrieves a specific transaction by its ID. +full: true +_openapi: + method: GET + route: /api/v1/relayers/{relayer_id}/transactions/{transaction_id} + toc: [] + structuredData: + headings: [] + contents: [] +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + + \ No newline at end of file diff --git a/content/relayer/1.1.x/api/getTransactionByNonce.mdx b/content/relayer/1.1.x/api/getTransactionByNonce.mdx new file mode 100644 index 00000000..c3565b0c --- /dev/null +++ b/content/relayer/1.1.x/api/getTransactionByNonce.mdx @@ -0,0 +1,15 @@ +--- +title: Retrieves a transaction by its nonce value. +full: true +_openapi: + method: GET + route: /api/v1/relayers/{relayer_id}/transactions/by-nonce/{nonce} + toc: [] + structuredData: + headings: [] + contents: [] +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + + \ No newline at end of file diff --git a/content/relayer/1.1.x/api/health.mdx b/content/relayer/1.1.x/api/health.mdx new file mode 100644 index 00000000..75a5d483 --- /dev/null +++ b/content/relayer/1.1.x/api/health.mdx @@ -0,0 +1,29 @@ +--- +title: Health routes implementation +full: true +_openapi: + method: GET + route: /v1/health + toc: [] + structuredData: + headings: [] + contents: + - content: >- + Note: OpenAPI documentation for these endpoints can be found in the + `openapi.rs` file + + Handles the `/health` endpoint. + + + Returns an `HttpResponse` with a status of `200 OK` and a body of + `"OK"`. +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + +Note: OpenAPI documentation for these endpoints can be found in the `openapi.rs` file +Handles the `/health` endpoint. + +Returns an `HttpResponse` with a status of `200 OK` and a body of `"OK"`. + + \ No newline at end of file diff --git a/content/relayer/1.1.x/api/index.mdx b/content/relayer/1.1.x/api/index.mdx new file mode 100644 index 00000000..89580fb1 --- /dev/null +++ b/content/relayer/1.1.x/api/index.mdx @@ -0,0 +1,114 @@ +--- +title: Relayer API Reference +--- + +## Relayers + +### [List Relayers](./api/listRelayers) +Lists all relayers with pagination support + +### [Create Relayer](./api/createRelayer) +Creates a new relayer + +### [Get Relayer](./api/getRelayer) +Retrieves details of a specific relayer by ID + +### [Delete Relayer](./api/deleteRelayer) +Deletes a relayer by ID + +### [Update Relayer](./api/updateRelayer) +Updates a relayer's information + +### [Get Relayer Balance](./api/getRelayerBalance) +Retrieves the balance of a specific relayer + +### [RPC](./api/rpc) +Performs a JSON-RPC call using the specified relayer + +### [Sign](./api/sign) +Signs data using the specified relayer + +### [Sign Transaction](./api/signTransaction) +Signs a transaction using the specified relayer (Stellar only) + +### [Sign Typed Data](./api/signTypedData) +Signs typed data using the specified relayer + +### [Get Relayer Status](./api/getRelayerStatus) +Fetches the current status of a specific relayer + +### [Send Transaction](./api/sendTransaction) +Sends a transaction through the specified relayer + +### [List Transactions](./api/listTransactions) +Lists all transactions for a specific relayer with pagination + +### [Get Transaction by Nonce](./api/getTransactionByNonce) +Retrieves a transaction by its nonce value + +### [Delete Pending Transactions](./api/deletePendingTransactions) +Deletes all pending transactions for a specific relayer + +### [Get Transaction by ID](./api/getTransactionById) +Retrieves a specific transaction by its ID + +### [Replace Transaction](./api/replaceTransaction) +Replaces a specific transaction with a new one + +### [Cancel Transaction](./api/cancelTransaction) +Cancels a specific transaction by its ID + +## Plugins + +### [Call Plugin](./api/callPlugin) +Calls a plugin method + +## Notifications + +### [List Notifications](./api/listNotifications) +Lists all notifications with pagination support + +### [Create Notification](./api/createNotification) +Creates a new notification + +### [Get Notification](./api/getNotification) +Retrieves details of a specific notification by ID + +### [Delete Notification](./api/deleteNotification) +Deletes a notification by ID + +### [Update Notification](./api/updateNotification) +Updates an existing notification + +## Signers + +### [List Signers](./api/listSigners) +Lists all signers with pagination support + +### [Create Signer](./api/createSigner) +Creates a new signer + +### [Get Signer](./api/getSigner) +Retrieves details of a specific signer by ID + +### [Delete Signer](./api/deleteSigner) +Deletes a signer by ID + +### [Update Signer](./api/updateSigner) +Updates an existing signer + +## Metrics + +### [Scrape Metrics](./api/scrape_metrics) +Triggers an update of system metrics and returns the result in plain text format + +### [List Metrics](./api/list_metrics) +Returns a list of all available metric names in JSON format + +### [Metric Detail](./api/metric_detail) +Returns the details of a specific metric in plain text format + +## Health + +### [Health](./api/health) +Health routes implementation \ No newline at end of file diff --git a/content/relayer/1.1.x/api/listNotifications.mdx b/content/relayer/1.1.x/api/listNotifications.mdx new file mode 100644 index 00000000..a45ffb04 --- /dev/null +++ b/content/relayer/1.1.x/api/listNotifications.mdx @@ -0,0 +1,25 @@ +--- +title: Notification routes implementation +full: true +_openapi: + method: GET + route: /api/v1/notifications + toc: [] + structuredData: + headings: [] + contents: + - content: >- + Note: OpenAPI documentation for these endpoints can be found in the + `openapi.rs` file + + + Lists all notifications with pagination support. +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + +Note: OpenAPI documentation for these endpoints can be found in the `openapi.rs` file + +Lists all notifications with pagination support. + + \ No newline at end of file diff --git a/content/relayer/1.1.x/api/listRelayers.mdx b/content/relayer/1.1.x/api/listRelayers.mdx new file mode 100644 index 00000000..77db3010 --- /dev/null +++ b/content/relayer/1.1.x/api/listRelayers.mdx @@ -0,0 +1,25 @@ +--- +title: Relayer routes implementation +full: true +_openapi: + method: GET + route: /api/v1/relayers + toc: [] + structuredData: + headings: [] + contents: + - content: >- + Note: OpenAPI documentation for these endpoints can be found in the + `openapi.rs` file + + + Lists all relayers with pagination support. +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + +Note: OpenAPI documentation for these endpoints can be found in the `openapi.rs` file + +Lists all relayers with pagination support. + + \ No newline at end of file diff --git a/content/relayer/1.1.x/api/listSigners.mdx b/content/relayer/1.1.x/api/listSigners.mdx new file mode 100644 index 00000000..1cbd571d --- /dev/null +++ b/content/relayer/1.1.x/api/listSigners.mdx @@ -0,0 +1,25 @@ +--- +title: Signer routes implementation +full: true +_openapi: + method: GET + route: /api/v1/signers + toc: [] + structuredData: + headings: [] + contents: + - content: >- + Note: OpenAPI documentation for these endpoints can be found in the + `openapi.rs` file + + + Lists all signers with pagination support. +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + +Note: OpenAPI documentation for these endpoints can be found in the `openapi.rs` file + +Lists all signers with pagination support. + + \ No newline at end of file diff --git a/content/relayer/1.1.x/api/listTransactions.mdx b/content/relayer/1.1.x/api/listTransactions.mdx new file mode 100644 index 00000000..5235f3aa --- /dev/null +++ b/content/relayer/1.1.x/api/listTransactions.mdx @@ -0,0 +1,15 @@ +--- +title: Lists all transactions for a specific relayer with pagination. +full: true +_openapi: + method: GET + route: /api/v1/relayers/{relayer_id}/transactions/ + toc: [] + structuredData: + headings: [] + contents: [] +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + + \ No newline at end of file diff --git a/content/relayer/1.1.x/api/list_metrics.mdx b/content/relayer/1.1.x/api/list_metrics.mdx new file mode 100644 index 00000000..66a0f51f --- /dev/null +++ b/content/relayer/1.1.x/api/list_metrics.mdx @@ -0,0 +1,33 @@ +--- +title: Metrics routes implementation +full: true +_openapi: + method: GET + route: /metrics + toc: [] + structuredData: + headings: [] + contents: + - content: >- + Note: OpenAPI documentation for these endpoints can be found in the + `openapi.rs` file + + Returns a list of all available metric names in JSON format. + + + # Returns + + + An `HttpResponse` containing a JSON array of metric names. +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + +Note: OpenAPI documentation for these endpoints can be found in the `openapi.rs` file +Returns a list of all available metric names in JSON format. + +# Returns + +An `HttpResponse` containing a JSON array of metric names. + + \ No newline at end of file diff --git a/content/relayer/1.1.x/api/metric_detail.mdx b/content/relayer/1.1.x/api/metric_detail.mdx new file mode 100644 index 00000000..021017d1 --- /dev/null +++ b/content/relayer/1.1.x/api/metric_detail.mdx @@ -0,0 +1,38 @@ +--- +title: Returns the details of a specific metric in plain text format. +full: true +_openapi: + method: GET + route: /metrics/{metric_name} + toc: [] + structuredData: + headings: [] + contents: + - content: >- + # Parameters + + + - `path`: The name of the metric to retrieve details for. + + + # Returns + + + An `HttpResponse` containing the metric details in plain text, or a + 404 error if the metric is + + not found. +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + +# Parameters + +- `path`: The name of the metric to retrieve details for. + +# Returns + +An `HttpResponse` containing the metric details in plain text, or a 404 error if the metric is +not found. + + \ No newline at end of file diff --git a/content/relayer/1.1.x/api/replaceTransaction.mdx b/content/relayer/1.1.x/api/replaceTransaction.mdx new file mode 100644 index 00000000..cc6c5d0e --- /dev/null +++ b/content/relayer/1.1.x/api/replaceTransaction.mdx @@ -0,0 +1,15 @@ +--- +title: Replaces a specific transaction with a new one. +full: true +_openapi: + method: PUT + route: /api/v1/relayers/{relayer_id}/transactions/{transaction_id} + toc: [] + structuredData: + headings: [] + contents: [] +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + + \ No newline at end of file diff --git a/content/relayer/1.1.x/api/rpc.mdx b/content/relayer/1.1.x/api/rpc.mdx new file mode 100644 index 00000000..3dbb0922 --- /dev/null +++ b/content/relayer/1.1.x/api/rpc.mdx @@ -0,0 +1,15 @@ +--- +title: Performs a JSON-RPC call using the specified relayer. +full: true +_openapi: + method: POST + route: /api/v1/relayers/{relayer_id}/rpc + toc: [] + structuredData: + headings: [] + contents: [] +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + + \ No newline at end of file diff --git a/content/relayer/1.1.x/api/scrape_metrics.mdx b/content/relayer/1.1.x/api/scrape_metrics.mdx new file mode 100644 index 00000000..9b43e8c4 --- /dev/null +++ b/content/relayer/1.1.x/api/scrape_metrics.mdx @@ -0,0 +1,30 @@ +--- +title: >- + Triggers an update of system metrics and returns the result in plain text + format. +full: true +_openapi: + method: GET + route: /debug/metrics/scrape + toc: [] + structuredData: + headings: [] + contents: + - content: >- + # Returns + + + An `HttpResponse` containing the updated metrics in plain text, or an + error message if the + + update fails. +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + +# Returns + +An `HttpResponse` containing the updated metrics in plain text, or an error message if the +update fails. + + \ No newline at end of file diff --git a/content/relayer/1.1.x/api/sendTransaction.mdx b/content/relayer/1.1.x/api/sendTransaction.mdx new file mode 100644 index 00000000..086a1322 --- /dev/null +++ b/content/relayer/1.1.x/api/sendTransaction.mdx @@ -0,0 +1,15 @@ +--- +title: Sends a transaction through the specified relayer. +full: true +_openapi: + method: POST + route: /api/v1/relayers/{relayer_id}/transactions + toc: [] + structuredData: + headings: [] + contents: [] +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + + \ No newline at end of file diff --git a/content/relayer/1.1.x/api/sign.mdx b/content/relayer/1.1.x/api/sign.mdx new file mode 100644 index 00000000..73a6e67d --- /dev/null +++ b/content/relayer/1.1.x/api/sign.mdx @@ -0,0 +1,15 @@ +--- +title: Signs data using the specified relayer. +full: true +_openapi: + method: POST + route: /api/v1/relayers/{relayer_id}/sign + toc: [] + structuredData: + headings: [] + contents: [] +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + + \ No newline at end of file diff --git a/content/relayer/1.1.x/api/signTransaction.mdx b/content/relayer/1.1.x/api/signTransaction.mdx new file mode 100644 index 00000000..b95f49c6 --- /dev/null +++ b/content/relayer/1.1.x/api/signTransaction.mdx @@ -0,0 +1,15 @@ +--- +title: Signs a transaction using the specified relayer (Stellar only). +full: true +_openapi: + method: POST + route: /api/v1/relayers/{relayer_id}/sign-transaction + toc: [] + structuredData: + headings: [] + contents: [] +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + + \ No newline at end of file diff --git a/content/relayer/1.1.x/api/signTypedData.mdx b/content/relayer/1.1.x/api/signTypedData.mdx new file mode 100644 index 00000000..edb7b736 --- /dev/null +++ b/content/relayer/1.1.x/api/signTypedData.mdx @@ -0,0 +1,15 @@ +--- +title: Signs typed data using the specified relayer. +full: true +_openapi: + method: POST + route: /api/v1/relayers/{relayer_id}/sign-typed-data + toc: [] + structuredData: + headings: [] + contents: [] +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + + \ No newline at end of file diff --git a/content/relayer/1.1.x/api/updateNotification.mdx b/content/relayer/1.1.x/api/updateNotification.mdx new file mode 100644 index 00000000..b591c02f --- /dev/null +++ b/content/relayer/1.1.x/api/updateNotification.mdx @@ -0,0 +1,15 @@ +--- +title: Updates an existing notification. +full: true +_openapi: + method: PATCH + route: /api/v1/notifications/{notification_id} + toc: [] + structuredData: + headings: [] + contents: [] +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + + \ No newline at end of file diff --git a/content/relayer/1.1.x/api/updateRelayer.mdx b/content/relayer/1.1.x/api/updateRelayer.mdx new file mode 100644 index 00000000..9bd2ea5e --- /dev/null +++ b/content/relayer/1.1.x/api/updateRelayer.mdx @@ -0,0 +1,15 @@ +--- +title: Updates a relayer's information based on the provided update request. +full: true +_openapi: + method: PATCH + route: /api/v1/relayers/{relayer_id} + toc: [] + structuredData: + headings: [] + contents: [] +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + + \ No newline at end of file diff --git a/content/relayer/1.1.x/api/updateSigner.mdx b/content/relayer/1.1.x/api/updateSigner.mdx new file mode 100644 index 00000000..080f7f4c --- /dev/null +++ b/content/relayer/1.1.x/api/updateSigner.mdx @@ -0,0 +1,15 @@ +--- +title: Updates an existing signer. +full: true +_openapi: + method: PATCH + route: /api/v1/signers/{signer_id} + toc: [] + structuredData: + headings: [] + contents: [] +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + + \ No newline at end of file diff --git a/content/relayer/1.1.x/changelog.mdx b/content/relayer/1.1.x/changelog.mdx new file mode 100644 index 00000000..38c7b004 --- /dev/null +++ b/content/relayer/1.1.x/changelog.mdx @@ -0,0 +1,505 @@ +--- +title: Changelog +--- + + +# [v1.1.0](https://github.com/OpenZeppelin/openzeppelin-relayer/releases/tag/v1.1.0) - 2025-08-11 + +## [1.1.0](https://github.com/OpenZeppelin/openzeppelin-relayer/compare/v1.0.0...v1.1.0) (2025-08-11) + + +### πŸš€ Features + +* Add Arbitrum support ([#373](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/373)) ([7b5372b](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/7b5372bf54fe26756ca5db6cb393e0d9d79ae621)) +* add base models ([#5](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/5)) ([55db42b](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/55db42b16d88e95ca8f6927e3b4d07c939e677c8)) +* Add CLA assistant bot ([#130](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/130)) ([4ad5733](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/4ad5733daadefe5e52bd617eaa47039677443745)) +* add directory structure and example ([d946c10](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/d946c10fd96ee2d1ce2e373ba4ccfced31f985f9)) +* add evm intristic gas_limit validation ([dd1b2d6](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/dd1b2d6768d09f051791d0db68c912a38d273715)) +* Add get_status method for EVM and Stellar ([#229](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/229)) ([e84217e](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/e84217e0fa941fcd580ad6b84ab6bfac939dd5f4)) +* Add Launctube plugin example ([#414](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/414)) ([5bda763](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/5bda7635f304923fcd4031f855009228eeefee4b)) +* Add logging improvements ([#28](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/28)) ([bb6751a](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/bb6751a4f868eb82787e7763a7995d3974ecfd49)) +* Add logic to resubmit transaction ([#102](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/102)) ([6c258b6](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/6c258b625dc7edb1d028b771647ff25b12c2b07d)) +* Add node support to environment ([#236](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/236)) ([3ab46f8](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/3ab46f848e7e4c6dee2545d62dc646b33623d63d)) +* Add noop support and refactor status ([#134](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/134)) ([f0e3a17](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/f0e3a177a536c53fe8eff834243d417bb673b744)) +* add optimism extra cost calculation ([#146](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/146)) ([b85e070](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/b85e070074ecc0aa4fbd7d5dc3af6ca0d600220b)) +* Add plugin invoker service ([#290](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/290)) ([489ce02](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/489ce0285cd88a18b1616af94bfc970a4a674228)) +* Add plugins call endpoint ([#279](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/279)) ([c278589](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/c278589f4c6bf88be86788fdd9b68c2f166f5f33)) +* Add queue processing support ([#6](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/6)) ([3ebbac2](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/3ebbac25f1ecb403dec7d090d39882a85227d883)) +* Add release workflow ([#148](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/148)) ([bd9a7e9](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/bd9a7e91a300e6650b08f799aecea4478bb4b974)) +* Add sign tx for evm local signer ([#65](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/65)) ([b17fb36](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/b17fb3625677f1dbcf1ddf3963db13b9b88ca25e)) +* Add status_reason field to transaction responses ([#369](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/369)) ([c489e5d](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/c489e5d39e3cec555caf92ac93266016c547b2bb)) +* Add stellar launchtube plugin ([#401](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/401)) ([801e2f7](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/801e2f7efc8f0cb7eb54f545ce398e6ee24cf6b9)) +* Add support for feebumped tx ([#309](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/309)) ([b4efd2e](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/b4efd2e894fb6534b61a10c5f8872a73d923410c)) +* add support for relayer paused and system disabled state ([#13](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/13)) ([44968a2](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/44968a29ec4f1cf1166c2ad726f2c9a1bac246c3)) +* Add support for stellar InvokeHostFunction transactions ([#284](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/284)) ([32ba63e](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/32ba63e58e3dfc1359b7a5c9f61f9ff2a8b6c317)) +* Add support to plugin list endpoint ([#358](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/358)) ([6517af0](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/6517af0a753db41638b006fa2b896a3ccec0d4ef)) +* add timeout_seconds to EVM relayer configuration ([#169](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/169)) ([6fd59bc](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/6fd59bc0e5993d63608d47e7ba7825a027e26b99)) +* Add transaction status handling for stellar ([#223](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/223)) ([9496eb6](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/9496eb63514afb0bd29c731bebe86ffdcf393362)) +* Add wait API for plugin transactions ([#345](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/345)) ([6069af2](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/6069af256e6cfe8470244731d4bb444b87bd175f)) +* Add worldchain testnet support ([#137](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/137)) ([25751ef](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/25751ef97b7b9fbe0c4b53fab5b762d1696f8c93)) +* Added resolve_plugin_path for script_path ([#340](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/340)) ([0b30739](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/0b30739e51f5ef6c0b97c1da585d403496b2bbac)) +* Adding job tests ([#110](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/110)) ([4d2dd98](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/4d2dd98efedacaded8d4ace118c43dbe25907278)) +* Create initial js plugins library ([#302](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/302)) ([98238e9](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/98238e9a6a30de8dba3bf8d308a82658e29de46f)) +* enabling it to listen on all interfaces - allows for easy docker config ([74a59da](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/74a59da79b314160baf35ec9750e372fbad0f360)) +* enabling it to listen on all interfaces - allows for easy docker config ([23f94c0](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/23f94c07ce46254f7b80df77ce8c4fc59fb4eef6)) +* Enhance Stellar tx handling with fee updates ([#368](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/368)) ([05617d7](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/05617d7cb06ab378c2c2207f9d0a2e11a04cc472)) +* **evm:** Add AWS KMS signer support ([#287](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/287)) ([723a9a8](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/723a9a8d7e625dd3f52b2d678d0e1cd842053e06)) +* **evm:** Implement delete pending txs ([#289](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/289)) ([bc6f829](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/bc6f829e580d42359adebceeddaf38002390e10b)) +* **evm:** Implement json rpc endpoint ([#286](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/286)) ([91528aa](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/91528aab82e3fa3cba08f63feb4ac9879aa8940e)) +* extract networks to json files ([#238](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/238)) ([5ac07b3](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/5ac07b3c570485d7cdbc419a23f373867d7ebe81)) +* handle non-retriable errors and provider health errors ([#233](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/233)) ([7add348](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/7add348da4d06af5ebebcce78d856485e9894ac3)) +* implement balance validation in EVM ([#168](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/168)) ([27fe333](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/27fe333806c28c268af981f5377e188160c845b9)) +* Implement get_balance method for StellarRelayer ([#228](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/228)) ([d92c75f](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/d92c75fe7da1b02ddb7a38df32f98082474e4cd9)) +* implement network config deserializing ([#235](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/235)) ([6d537f9](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/6d537f9298626fefc0d5a45c311a95208e1c8ef5)) +* improve examples ([#119](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/119)) ([7e59aa6](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/7e59aa64f75f3470807396b293e71cd68d3292d1)) +* Improve Redis startup logic ([#120](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/120)) ([8618ecf](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/8618ecf00b4739891fe4ce98caf14f729face896)) +* Improve Redis startup logic ([#120](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/120)) ([8618ecf](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/8618ecf00b4739891fe4ce98caf14f729face896)) +* initial repo setup ([d8815b6](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/d8815b6752931003536aa427370ca8fb1c57231c)) +* Integrate Netlify with antora ([#74](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/74)) ([09e3d48](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/09e3d4894b54c58754b373da239e9d564df69aa9)) +* Local signing for stellar ([#178](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/178)) ([f69270a](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/f69270ade4c9a9239bba874ac74858c8e7375298)) +* Pass arbitrary payloads to script exectution ([#312](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/312)) ([adecaf5](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/adecaf5d73c3df9083c6a3fcf62ed669bc90b25c)) +* Plat 5744 implement an api key authentication mechanism ([#11](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/11)) ([8891887](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/88918872d51ab10632ec6d590689d52e59dfd640)) +* Plat 5768 setup metrics endpoint ([#50](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/50)) ([7c292a5](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/7c292a572a7aef8213969fc72cadca74f9016fe8)) +* Plat 6434 improve authorization header validation ([#122](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/122)) ([eed7c31](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/eed7c31e938c7b6ecaa82774ca5d3a508bb89281)) +* Plat-5749 implement basic webhook notifications service ([#12](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/12)) ([1b47b64](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/1b47b64c318208eb7dc2ec6d62020fab30ccafbb)) +* Plat-5802 openapi sdk client ([#109](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/109)) ([1b4b681](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/1b4b681a3755f60e2934548a9666c60a4465dabb)) +* PLAT-6026 Imp cancel transaction ([#101](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/101)) ([1e5cc47](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/1e5cc47bdc54acafeeefb60489db410b42722b0f)) +* PLAT-6026 Imp cancel transaction ([#101](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/101)) ([1e5cc47](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/1e5cc47bdc54acafeeefb60489db410b42722b0f)) +* Plat-6118 implement logic for syncing relayer state upon service start ([#19](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/19)) ([2ba3629](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/2ba36292a0b8d0d67ddab42d2845a6a0d5f31e3a)) +* Plat-6153 add network definitions for Solana networks ([#26](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/26)) ([ff453d5](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/ff453d59724eeaa194ccf7f83993ce8d649f7432)) +* Plat-6154 add support for solana local signer ([#29](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/29)) ([40caead](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/40caeadde5f08200410912b98943346971084163)) +* plat-6158 implement Solana rpc service ([#36](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/36)) ([8fb50a8](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/8fb50a833e7f9b1773dbe4ca1d77a9609a5d5ec1)) +* Plat-6159 extend relayer config file solana policies ([#38](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/38)) ([4f4602b](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/4f4602b754e71539937447c1743a7f069317598b)) +* Plat-6164 implement feeestimate rpc method ([#61](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/61)) ([43b016c](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/43b016c4e5faa5ee1fedcdadccf3bc768962178e)) +* Plat-6165 implement transfertransaction rpc method ([#63](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/63)) ([c59a3b8](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/c59a3b8894c32470adf10770f4804e272aa829d3)) +* Plat-6167 implement signtransaction rpc method ([#57](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/57)) ([ad7a1ff](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/ad7a1ffe41eb868f54737c1f1b44a52c6d02d172)) +* Plat-6169 implement getsupportedtokens rpc method ([#45](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/45)) ([3f91199](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/3f9119981acd7f92618ba6ec12c3039563368202)) +* Plat-6170 add vault hosted signer support ([#99](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/99)) ([7a9491d](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/7a9491d4094fc21bc87551c68687b4f44f3edd18)) +* Plat-6207 implement trait abstraction relayer ([#43](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/43)) ([abeb7cf](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/abeb7cfccc9e70b26ddd0d41d736352d57d6ade9)) +* plat-6215 add support for rpc failovers and retries ([#231](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/231)) ([ca6d24f](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/ca6d24f1bcdbb912795dcb1496519b49b5e81bf1)) +* Plat-6216 adding network symbol support ([#37](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/37)) ([21f798f](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/21f798fc114de47ae0ed7e127e496bb50ca081a8)) +* Plat-6236 adding validation payload ([#42](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/42)) ([a5ff165](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/a5ff165df14f48d47adee03e8e2c8ef5a899ff57)) +* Plat-6236 adding validation payload ([#42](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/42)) ([a5ff165](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/a5ff165df14f48d47adee03e8e2c8ef5a899ff57)) +* Plat-6239 whitelist policy validation ([#44](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/44)) ([3adb45e](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/3adb45e17b8b23c70e09e422cfca051ebab266f1)) +* Plat-6239 whitelist policy validation ([#44](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/44)) ([3adb45e](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/3adb45e17b8b23c70e09e422cfca051ebab266f1)) +* Plat-6248 implementation dummy of legacy price ([#49](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/49)) ([6319d64](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/6319d64bf27fd75f5192165df885156ca91ea9f0)) +* Plat-6248 implementation dummy of legacy price ([#49](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/49)) ([6319d64](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/6319d64bf27fd75f5192165df885156ca91ea9f0)) +* Plat-6267 add utility script for generating local keystore files ([#69](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/69)) ([b5df7f6](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/b5df7f6b0450118c9123de46689fa115efcdec94)) +* Plat-6291 add webhook notifications for rpc methods ([#72](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/72)) ([2f35d81](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/2f35d81b3711cf2f87dbc6df31b9e0f90432164e)) +* Plat-6299 clean transaction response ([#76](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/76)) ([fc5dd05](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/fc5dd05154bca4a1d740cef058bb797cd3f513a0)) +* Plat-6300 returning the balance of the relayer ([#78](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/78)) ([e0ce8e0](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/e0ce8e04f3950c094c9af3e3413d61cd7162c8e7)) +* Plat-6300 returning the balance of the relayer ([#78](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/78)) ([e0ce8e0](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/e0ce8e04f3950c094c9af3e3413d61cd7162c8e7)) +* Plat-6303 store solana submitted transactions to db and run status check logic ([#398](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/398)) ([e8420bc](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/e8420bca02c20a53b02d9bedc8da1b7a784716dc)) +* Plat-6304 use Authorization header instead of x api key ([#94](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/94)) ([34e8a81](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/34e8a813234ee6aaf2a6956f6dd45f82e47e7861)) +* Plat-6309 Fetching eip1559 prices ([#83](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/83)) ([68d574f](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/68d574fcb159ae3b6502167a9bcf34bb1a56ea7e)) +* Plat-6309 Fetching eip1559 prices ([#83](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/83)) ([68d574f](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/68d574fcb159ae3b6502167a9bcf34bb1a56ea7e)) +* plat-6340 store private keys securely in memory ([#104](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/104)) ([28c2fab](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/28c2fab84f3db6b9d971126cf917263da395c421)) +* PLAT-6350 - Sign EIP-1559 ([#98](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/98)) ([673e420](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/673e4202f9d98bfd02512090fa3daacfa40831fe)) +* PLAT-6350 - Sign EIP-1559 ([#98](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/98)) ([673e420](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/673e4202f9d98bfd02512090fa3daacfa40831fe)) +* PLAT-6374 EIP-1559 default if network support it and not explicit false ([#100](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/100)) ([c982dde](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/c982ddefeba93381ac7d2c5e09f616a60820b8b8)) +* PLAT-6374 EIP-1559 default if network support it and not explicit false ([#100](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/100)) ([c982dde](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/c982ddefeba93381ac7d2c5e09f616a60820b8b8)) +* PLAT-6416 Use generics transaction factory ([#105](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/105)) ([7b94662](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/7b946625af77c6aabd336d34646e9ae62ece3b6a)) +* plat-6433 add minimum length validations for config sensitive values ([#125](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/125)) ([31453c5](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/31453c5586ca4fef70e7ea0e2dcd0260a8a721a6)) +* Plat-6441 document upcoming work ([#131](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/131)) ([377a8bb](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/377a8bb57ff5b3b23abb58d1c3378489c40218cf)) +* PLAT-6442 - Abstraction and unit tests relayer domain ([#117](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/117)) ([643194a](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/643194acd9079ac3ac157e909f0b30199af8b0c9)) +* PLAT-6442 - Abstraction and unit tests relayer domain ([#117](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/117)) ([643194a](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/643194acd9079ac3ac157e909f0b30199af8b0c9)) +* Plat-6457 Ignore utoipa ([#127](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/127)) ([234854a](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/234854afbf30a9a94fa3365f60f035e53e068938)) +* Plat-6457 Ignore utoipa ([#127](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/127)) ([234854a](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/234854afbf30a9a94fa3365f60f035e53e068938)) +* Plat-6459 create mermaid architecture diagram ([#126](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/126)) ([3de147b](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/3de147b907c28d3e9a8a38a2d6b8cd665253c423)) +* plat-6471 add Solana Token 2022 extensions support ([#166](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/166)) ([d35c506](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/d35c506ea298a86897ede5702481403f839f2451)) +* plat-6476 Add support to collect transaction fee ([#135](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/135)) ([4f4a07b](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/4f4a07b2846d2980bbf09734602315702ded9dbe)) +* Plat-6479 added support for rpc custom endpoints ([#138](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/138)) ([3df3d49](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/3df3d49ec6a662698a90630811d717920b7cdf3b)) +* Plat-6521 add turnkey hosted signer support (evm, solana) ([#174](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/174)) ([b24688e](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/b24688ead4fe3015ca3b7c74e56f1906085a5aa3)) +* plat-6522 allow for the use of on chain defi to automatically swap spl ([#198](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/198)) ([dc9e2e2](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/dc9e2e2dd1d46830bc6479c1928a2e7ef7f91fb3)) +* plat-6571 add support for gcp signer ([#221](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/221)) ([0170fa1](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/0170fa12c3ecc64d1c48ed3a726358ed74d4596b)) +* Plat-6677 implement redis repositories for existing collections ([#350](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/350)) ([5fee731](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/5fee731c5f19013f41a12a5b93af79d65bdf777e)) +* Plat-6679 implement startup logic to populate redis from config file ([#359](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/359)) ([5e1c0c8](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/5e1c0c825d3c1185a5c59360a2c857d79b46abba)) +* Plat-6681 expose crud api endpoints ([#365](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/365)) ([f3c3426](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/f3c34266f3f035cd240105833ef4e67711cb0356)) +* Plat-6684 add support for transaction entries expiration ([#394](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/394)) ([6f6f765](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/6f6f765556b2fc16764f8afe02ceedf268c26c13)) +* plat-6817 EVM add support for gas limit calculation ([#355](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/355)) ([dd1b2d6](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/dd1b2d6768d09f051791d0db68c912a38d273715)) +* plat-6873 add storage documentation ([#395](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/395)) ([ffd4ed5](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/ffd4ed58d322bad63be500a084a0b082ac7b59d9)) +* Plugins improvements ([#410](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/410)) ([648a0f1](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/648a0f121a6308e8bde0e09010d2e0c83de5c6ec)) +* Pricing validation on receiving payload EVM ([#59](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/59)) ([1206d42](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/1206d4241dbda84bc861f501d322f6bd33234f0b)) +* Pricing validation on receiving payload EVM ([#59](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/59)) ([1206d42](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/1206d4241dbda84bc861f501d322f6bd33234f0b)) +* Relayer plugins - add support to plugins in configs ([#253](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/253)) ([6a14239](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/6a14239486900b2ef121b5de9e87410c412b65fe)) +* **replace_tx:** Implement replace tx for evm ([#272](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/272)) ([b48e71f](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/b48e71f55fda03bea83e90255b0d180db704cb52)) +* Set default network folder ([#313](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/313)) ([b28c99c](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/b28c99c43bedd921a55660622d845e63890e0d74)) +* Signer service ([#8](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/8)) ([4f85b7b](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/4f85b7bf5b6aa83903ed8febdfe244d54e803642)) +* **signer:** Add GCP Signer to EVM ([#305](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/305)) ([a8817b6](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/a8817b6c87c65731232d0a141338f3996aef2510)) +* Speed support transaction ([#62](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/62)) ([a572af6](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/a572af65ca4f664dce13e705eac37b56dee306fa)) +* Stellar RPC config ([#213](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/213)) ([6fd75ea](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/6fd75ea65bf1a945ba891f99d83b0cdacdf30014)) +* Stellar RPC service ([#183](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/183)) ([9943ffd](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/9943ffd67a709df487264f50eccd03b06cc817d4)) +* Stellar transaction submission ([#199](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/199)) ([c6b72bf](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/c6b72bfba82c7fb9288c07e49bef04cf527d1245)) +* support for multiple custom RPCs with weighted configuration ([#182](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/182)) ([92ea5ad](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/92ea5ad324323b957fcbdce85c37517ec6f963ba)) +* support for retries and failovers in EVM Provider ([#197](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/197)) ([542f21a](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/542f21a9346def9b7fe47e0a29a2bbd5ab2af349)) +* Support plugin timeouts ([#348](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/348)) ([0a1c51e](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/0a1c51e9fe540ba570af25146538992a26b9a8a0)) +* Tx submissions and status mgmt ([#81](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/81)) ([9f829f1](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/9f829f1c59c4221c9cf38c6cb1ff36351a348cd1)) +* Types introduced for plugin params and result ([#351](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/351)) ([dda83a2](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/dda83a296fd5bd5bfca7f7902f4ca035e1bd8796)) +* Update Stellar network config and docs ([#380](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/380)) ([a4e1a0f](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/a4e1a0f38590f21c6d5e917a02fee4f6bef4f075)) +* Update transaction status to mined/expired ([#85](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/85)) ([8f5ee53](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/8f5ee53bbe64d55ccf8015a1c8d203cf5e391f08)) + + +### πŸ› Bug Fixes + +* Add memo validation for InvokeHostFunction ([#294](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/294)) ([6bb4ffa](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/6bb4ffaf9ceb4a8daef29ec5878595cca7041300)) +* change the ampersand to and, as as the shell interpret it ([#206](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/206)) ([d164d6a](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/d164d6a4d63fbf0acdfe1330cf25147e86280af8)) +* Changing base image to wolfi, added node and npm ([#266](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/266)) ([1181996](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/1181996dac6da52f96e164b1c937828a3940d5b8)) +* CLA assistant ([#171](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/171)) ([b326a56](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/b326a5680722e812263aab949003c214795fd2c0)) +* CLA labels ([#173](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/173)) ([e31405b](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/e31405b8cba9ffd2ff991d56444320ff3d069ad0)) +* Codecov changes and adjustments ([#113](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/113)) ([6e62dcf](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/6e62dcf212a917421c7559566136c018e17c38f5)) +* Config example file ([#285](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/285)) ([a020c6f](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/a020c6fcd6f9b638d955d5f2c99aa0e199d8bf6e)) +* Correct env var value in semgrep.yml ([#375](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/375)) ([2e98e21](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/2e98e2149135b97a62b90c302675379642fdf7b3)) +* Docker Compose ([#156](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/156)) ([6ca012f](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/6ca012fb9b50d5c2159c498679673cb27530fc3c)) +* Docker readme file ([#339](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/339)) ([2db9933](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/2db9933def061046cc3585a07249107a236ef98c)) +* docker-scan - chainguard issue ([#255](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/255)) ([c9ab94b](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/c9ab94bcee7b386a33b063504b3e6d2cf188d8b5)) +* Docs link ([#128](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/128)) ([8263828](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/82638284cf13a4da376624362f5353b57365302a)) +* Docs path for crate ([#129](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/129)) ([51cf556](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/51cf556411c9c1f79dbee7f4c3aa25df7fe2af49)) +* **docs:** replaced Monitor for Relayer ([2ff196b](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/2ff196bf772668556210a895d4f83315e579577f)) +* Documentation name for antora ([#121](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/121)) ([63c36f5](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/63c36f5393b1369a169c8617b20952bca30aef0c)) +* Environment variables ([#124](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/124)) ([8d31131](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/8d31131c087a6d0a64ae2dadecb5ae395ad1b575)) +* Fix the codecov yaml syntax ([#108](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/108)) ([ab9ab5b](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/ab9ab5b0c9313d083cd47c71d7faade867c58deb)) +* Flaky logging tests ([#89](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/89)) ([bc909cc](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/bc909cc336613bb5a191c562632278bd3c270b09)) +* Implement stellar sequence sync and tx reset ([#367](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/367)) ([60b5deb](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/60b5deb4915041d60a064cfac1a066406c339517)) +* Inheritance validation ([#374](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/374)) ([f8b921b](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/f8b921b4d6d85b8068428f1e34de121183a02179)) +* Make plugins entry in configs optional ([#300](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/300)) ([f299779](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/f299779318429677fd672d4a2433828971a1b62e)) +* Minor fixes in Plugin docs ([#325](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/325)) ([33bb6a1](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/33bb6a1841f2e84723e49cc81258a930241dc735)) +* Missing libssl and workflow ([#155](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/155)) ([9de7133](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/9de7133c2ba1768f4d989158f19c27444e522f9e)) +* Plat 6286 write tests for metrics and middleware functions ([#70](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/70)) ([18124fb](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/18124fbbfbc26f300648a7a4050ebf9be72465ac)) +* PLAT-6426 Increase test coverage ([#118](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/118)) ([1fa41f0](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/1fa41f0f225c9d515690738e960073396dce66ce)) +* PLAT-6478 create unit test for use of on relayers dotenv ([#139](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/139)) ([509e166](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/509e1664518823ef3844e52e818707f3371ddbff)) +* plat-6480 allow transfering wrapped sol tokens ([#132](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/132)) ([f04e66a](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/f04e66a568c877c2a4c5c5378fb6017c2e41d2c6)) +* Plat-6815 resubmission bug ([#353](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/353)) ([72ac174](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/72ac17471e3a0a6ac35e9a9bb9ff8fe5e8b94bf2)) +* plat-6888 aws kms signer issue ([#411](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/411)) ([3c12c88](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/3c12c88703c92526fe975eabba6ba0ffa9ca9c79)) +* Plugin result + adds tests for plugin ts lib ([#336](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/336)) ([b30246e](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/b30246e8922d3cb5bd3c5b92a7678f7591db5b97)) +* Relayer plugins format output ([#307](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/307)) ([8f25e5f](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/8f25e5f55812e3d346c8bc0ff063cf07e2f0b753)) +* Release merge conflicts ([#163](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/163)) ([4cac422](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/4cac4221817373a1ae7eff92db187dbae2f1665b)) +* remove the ci job dependant from the test job ([#222](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/222)) ([4056610](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/40566108b66c701323145c2889ce0141b84714b8)) +* Replace automatic minor version bumps ([#315](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/315)) ([85784b4](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/85784b486a9508429ae94373a7f3db13d78b39d6)) +* Replace tx request body ([#326](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/326)) ([a20c916](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/a20c916b592891b7a2afafd2e62b32723fc05dc2)) +* SBOM upload error ([#342](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/342)) ([1f9318e](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/1f9318e22cbe59ca03bc617b0986379574e5f770)) +* Semgrep CI integration ([#371](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/371)) ([6b9a6d2](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/6b9a6d24e22b78743f16c566026b34f9912669ad)) +* Semgrep send metrics value ([#381](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/381)) ([315ccbc](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/315ccbca9a48816fc6e0c8133301aa3e3186ff93)) +* Skip releases ([ccafcbe](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/ccafcbe11bc6ea46dacb9c59be578abd45112ad3)) +* Solve issues with new solana_sdk version ([#324](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/324)) ([ab97253](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/ab972533259506bb21e22ec7f899a45d2fc97db5)) +* Switch Redocly build to use standalone html file ([#291](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/291)) ([97a8698](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/97a86980bec6260920a469018fee0d3541d1a063)) +* syntax error in codeql.yml ([#385](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/385)) ([987fd33](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/987fd33566b66b2821490d0769a3c863a778c271)) +* Update configs and dockerfiles in examples ([#298](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/298)) ([2e505ad](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/2e505ad827ab7544f7c6a3fdf4018b1e9428f1d6)) +* Update semgrep.yml ([#347](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/347)) ([5ffb803](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/5ffb8036ca6d3fb5a8cdb34fa5484e7732c842a1)) +* Update Stellar API docs to match implementation ([#292](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/292)) ([96d95e3](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/96d95e35784c25f39afe626b56f11477fd213196)) +* Use unicode character for emoji ([#343](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/343)) ([784e89f](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/784e89fae4ad2ddad037ddbbd0bec6df160e9a6a)) + +[Changes][v1.1.0] + + + +# [v1.0.0](https://github.com/OpenZeppelin/openzeppelin-relayer/releases/tag/v1.0.0) - 2025-06-30 + +## [1.0.0](https://github.com/OpenZeppelin/openzeppelin-relayer/compare/v0.2.0...v1.0.0) (2025-06-30) + + +### πŸš€ Features + +* add base models ([#5](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/5)) ([55db42b](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/55db42b16d88e95ca8f6927e3b4d07c939e677c8)) +* Add CLA assistant bot ([#130](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/130)) ([4ad5733](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/4ad5733daadefe5e52bd617eaa47039677443745)) +* add directory structure and example ([d946c10](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/d946c10fd96ee2d1ce2e373ba4ccfced31f985f9)) +* Add get_status method for EVM and Stellar ([#229](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/229)) ([e84217e](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/e84217e0fa941fcd580ad6b84ab6bfac939dd5f4)) +* Add logging improvements ([#28](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/28)) ([bb6751a](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/bb6751a4f868eb82787e7763a7995d3974ecfd49)) +* Add logic to resubmit transaction ([#102](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/102)) ([6c258b6](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/6c258b625dc7edb1d028b771647ff25b12c2b07d)) +* Add node support to environment ([#236](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/236)) ([3ab46f8](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/3ab46f848e7e4c6dee2545d62dc646b33623d63d)) +* Add noop support and refactor status ([#134](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/134)) ([f0e3a17](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/f0e3a177a536c53fe8eff834243d417bb673b744)) +* add optimism extra cost calculation ([#146](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/146)) ([b85e070](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/b85e070074ecc0aa4fbd7d5dc3af6ca0d600220b)) +* Add plugin invoker service ([#290](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/290)) ([489ce02](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/489ce0285cd88a18b1616af94bfc970a4a674228)) +* Add plugins call endpoint ([#279](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/279)) ([c278589](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/c278589f4c6bf88be86788fdd9b68c2f166f5f33)) +* Add queue processing support ([#6](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/6)) ([3ebbac2](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/3ebbac25f1ecb403dec7d090d39882a85227d883)) +* Add release workflow ([#148](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/148)) ([bd9a7e9](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/bd9a7e91a300e6650b08f799aecea4478bb4b974)) +* Add sign tx for evm local signer ([#65](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/65)) ([b17fb36](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/b17fb3625677f1dbcf1ddf3963db13b9b88ca25e)) +* Add support for feebumped tx ([#309](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/309)) ([b4efd2e](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/b4efd2e894fb6534b61a10c5f8872a73d923410c)) +* add support for relayer paused and system disabled state ([#13](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/13)) ([44968a2](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/44968a29ec4f1cf1166c2ad726f2c9a1bac246c3)) +* Add support for stellar InvokeHostFunction transactions ([#284](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/284)) ([32ba63e](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/32ba63e58e3dfc1359b7a5c9f61f9ff2a8b6c317)) +* add timeout_seconds to EVM relayer configuration ([#169](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/169)) ([6fd59bc](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/6fd59bc0e5993d63608d47e7ba7825a027e26b99)) +* Add transaction status handling for stellar ([#223](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/223)) ([9496eb6](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/9496eb63514afb0bd29c731bebe86ffdcf393362)) +* Add worldchain testnet support ([#137](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/137)) ([25751ef](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/25751ef97b7b9fbe0c4b53fab5b762d1696f8c93)) +* Adding job tests ([#110](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/110)) ([4d2dd98](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/4d2dd98efedacaded8d4ace118c43dbe25907278)) +* Create initial js plugins library ([#302](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/302)) ([98238e9](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/98238e9a6a30de8dba3bf8d308a82658e29de46f)) +* enabling it to listen on all interfaces - allows for easy docker config ([74a59da](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/74a59da79b314160baf35ec9750e372fbad0f360)) +* enabling it to listen on all interfaces - allows for easy docker config ([23f94c0](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/23f94c07ce46254f7b80df77ce8c4fc59fb4eef6)) +* **evm:** Add AWS KMS signer support ([#287](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/287)) ([723a9a8](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/723a9a8d7e625dd3f52b2d678d0e1cd842053e06)) +* **evm:** Implement delete pending txs ([#289](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/289)) ([bc6f829](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/bc6f829e580d42359adebceeddaf38002390e10b)) +* **evm:** Implement json rpc endpoint ([#286](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/286)) ([91528aa](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/91528aab82e3fa3cba08f63feb4ac9879aa8940e)) +* extract networks to json files ([#238](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/238)) ([5ac07b3](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/5ac07b3c570485d7cdbc419a23f373867d7ebe81)) +* handle non-retriable errors and provider health errors ([#233](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/233)) ([7add348](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/7add348da4d06af5ebebcce78d856485e9894ac3)) +* implement balance validation in EVM ([#168](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/168)) ([27fe333](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/27fe333806c28c268af981f5377e188160c845b9)) +* Implement get_balance method for StellarRelayer ([#228](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/228)) ([d92c75f](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/d92c75fe7da1b02ddb7a38df32f98082474e4cd9)) +* implement network config deserializing ([#235](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/235)) ([6d537f9](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/6d537f9298626fefc0d5a45c311a95208e1c8ef5)) +* improve examples ([#119](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/119)) ([7e59aa6](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/7e59aa64f75f3470807396b293e71cd68d3292d1)) +* Improve Redis startup logic ([#120](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/120)) ([8618ecf](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/8618ecf00b4739891fe4ce98caf14f729face896)) +* initial repo setup ([d8815b6](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/d8815b6752931003536aa427370ca8fb1c57231c)) +* Integrate Netlify with antora ([#74](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/74)) ([09e3d48](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/09e3d4894b54c58754b373da239e9d564df69aa9)) +* Local signing for stellar ([#178](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/178)) ([f69270a](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/f69270ade4c9a9239bba874ac74858c8e7375298)) +* Pass arbitrary payloads to script exectution ([#312](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/312)) ([adecaf5](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/adecaf5d73c3df9083c6a3fcf62ed669bc90b25c)) +* Plat 5744 implement an api key authentication mechanism ([#11](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/11)) ([8891887](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/88918872d51ab10632ec6d590689d52e59dfd640)) +* Plat 5768 setup metrics endpoint ([#50](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/50)) ([7c292a5](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/7c292a572a7aef8213969fc72cadca74f9016fe8)) +* Plat 6434 improve authorization header validation ([#122](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/122)) ([eed7c31](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/eed7c31e938c7b6ecaa82774ca5d3a508bb89281)) +* Plat-5749 implement basic webhook notifications service ([#12](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/12)) ([1b47b64](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/1b47b64c318208eb7dc2ec6d62020fab30ccafbb)) +* Plat-5802 openapi sdk client ([#109](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/109)) ([1b4b681](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/1b4b681a3755f60e2934548a9666c60a4465dabb)) +* PLAT-6026 Imp cancel transaction ([#101](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/101)) ([1e5cc47](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/1e5cc47bdc54acafeeefb60489db410b42722b0f)) +* Plat-6118 implement logic for syncing relayer state upon service start ([#19](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/19)) ([2ba3629](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/2ba36292a0b8d0d67ddab42d2845a6a0d5f31e3a)) +* Plat-6153 add network definitions for Solana networks ([#26](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/26)) ([ff453d5](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/ff453d59724eeaa194ccf7f83993ce8d649f7432)) +* Plat-6154 add support for solana local signer ([#29](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/29)) ([40caead](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/40caeadde5f08200410912b98943346971084163)) +* plat-6158 implement Solana rpc service ([#36](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/36)) ([8fb50a8](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/8fb50a833e7f9b1773dbe4ca1d77a9609a5d5ec1)) +* Plat-6159 extend relayer config file solana policies ([#38](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/38)) ([4f4602b](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/4f4602b754e71539937447c1743a7f069317598b)) +* Plat-6164 implement feeestimate rpc method ([#61](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/61)) ([43b016c](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/43b016c4e5faa5ee1fedcdadccf3bc768962178e)) +* Plat-6165 implement transfertransaction rpc method ([#63](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/63)) ([c59a3b8](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/c59a3b8894c32470adf10770f4804e272aa829d3)) +* Plat-6167 implement signtransaction rpc method ([#57](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/57)) ([ad7a1ff](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/ad7a1ffe41eb868f54737c1f1b44a52c6d02d172)) +* Plat-6169 implement getsupportedtokens rpc method ([#45](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/45)) ([3f91199](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/3f9119981acd7f92618ba6ec12c3039563368202)) +* Plat-6170 add vault hosted signer support ([#99](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/99)) ([7a9491d](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/7a9491d4094fc21bc87551c68687b4f44f3edd18)) +* Plat-6207 implement trait abstraction relayer ([#43](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/43)) ([abeb7cf](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/abeb7cfccc9e70b26ddd0d41d736352d57d6ade9)) +* plat-6215 add support for rpc failovers and retries ([#231](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/231)) ([ca6d24f](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/ca6d24f1bcdbb912795dcb1496519b49b5e81bf1)) +* Plat-6216 adding network symbol support ([#37](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/37)) ([21f798f](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/21f798fc114de47ae0ed7e127e496bb50ca081a8)) +* Plat-6236 adding validation payload ([#42](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/42)) ([a5ff165](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/a5ff165df14f48d47adee03e8e2c8ef5a899ff57)) +* Plat-6239 whitelist policy validation ([#44](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/44)) ([3adb45e](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/3adb45e17b8b23c70e09e422cfca051ebab266f1)) +* Plat-6248 implementation dummy of legacy price ([#49](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/49)) ([6319d64](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/6319d64bf27fd75f5192165df885156ca91ea9f0)) +* Plat-6267 add utility script for generating local keystore files ([#69](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/69)) ([b5df7f6](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/b5df7f6b0450118c9123de46689fa115efcdec94)) +* Plat-6291 add webhook notifications for rpc methods ([#72](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/72)) ([2f35d81](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/2f35d81b3711cf2f87dbc6df31b9e0f90432164e)) +* Plat-6299 clean transaction response ([#76](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/76)) ([fc5dd05](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/fc5dd05154bca4a1d740cef058bb797cd3f513a0)) +* Plat-6300 returning the balance of the relayer ([#78](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/78)) ([e0ce8e0](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/e0ce8e04f3950c094c9af3e3413d61cd7162c8e7)) +* Plat-6304 use Authorization header instead of x api key ([#94](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/94)) ([34e8a81](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/34e8a813234ee6aaf2a6956f6dd45f82e47e7861)) +* Plat-6309 Fetching eip1559 prices ([#83](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/83)) ([68d574f](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/68d574fcb159ae3b6502167a9bcf34bb1a56ea7e)) +* plat-6340 store private keys securely in memory ([#104](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/104)) ([28c2fab](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/28c2fab84f3db6b9d971126cf917263da395c421)) +* PLAT-6350 - Sign EIP-1559 ([#98](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/98)) ([673e420](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/673e4202f9d98bfd02512090fa3daacfa40831fe)) +* PLAT-6374 EIP-1559 default if network support it and not explicit false ([#100](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/100)) ([c982dde](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/c982ddefeba93381ac7d2c5e09f616a60820b8b8)) +* PLAT-6416 Use generics transaction factory ([#105](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/105)) ([7b94662](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/7b946625af77c6aabd336d34646e9ae62ece3b6a)) +* plat-6433 add minimum length validations for config sensitive values ([#125](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/125)) ([31453c5](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/31453c5586ca4fef70e7ea0e2dcd0260a8a721a6)) +* Plat-6441 document upcoming work ([#131](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/131)) ([377a8bb](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/377a8bb57ff5b3b23abb58d1c3378489c40218cf)) +* PLAT-6442 - Abstraction and unit tests relayer domain ([#117](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/117)) ([643194a](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/643194acd9079ac3ac157e909f0b30199af8b0c9)) +* Plat-6457 Ignore utoipa ([#127](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/127)) ([234854a](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/234854afbf30a9a94fa3365f60f035e53e068938)) +* Plat-6459 create mermaid architecture diagram ([#126](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/126)) ([3de147b](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/3de147b907c28d3e9a8a38a2d6b8cd665253c423)) +* plat-6471 add Solana Token 2022 extensions support ([#166](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/166)) ([d35c506](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/d35c506ea298a86897ede5702481403f839f2451)) +* plat-6476 Add support to collect transaction fee ([#135](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/135)) ([4f4a07b](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/4f4a07b2846d2980bbf09734602315702ded9dbe)) +* Plat-6479 added support for rpc custom endpoints ([#138](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/138)) ([3df3d49](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/3df3d49ec6a662698a90630811d717920b7cdf3b)) +* Plat-6521 add turnkey hosted signer support (evm, solana) ([#174](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/174)) ([b24688e](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/b24688ead4fe3015ca3b7c74e56f1906085a5aa3)) +* plat-6522 allow for the use of on chain defi to automatically swap spl ([#198](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/198)) ([dc9e2e2](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/dc9e2e2dd1d46830bc6479c1928a2e7ef7f91fb3)) +* plat-6571 add support for gcp signer ([#221](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/221)) ([0170fa1](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/0170fa12c3ecc64d1c48ed3a726358ed74d4596b)) +* Pricing validation on receiving payload EVM ([#59](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/59)) ([1206d42](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/1206d4241dbda84bc861f501d322f6bd33234f0b)) +* Pricing validation on receiving payload EVM ([#59](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/59)) ([1206d42](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/1206d4241dbda84bc861f501d322f6bd33234f0b)) +* Relayer plugins - add support to plugins in configs ([#253](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/253)) ([6a14239](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/6a14239486900b2ef121b5de9e87410c412b65fe)) +* **replace_tx:** Implement replace tx for evm ([#272](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/272)) ([b48e71f](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/b48e71f55fda03bea83e90255b0d180db704cb52)) +* Set default network folder ([#313](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/313)) ([b28c99c](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/b28c99c43bedd921a55660622d845e63890e0d74)) +* Signer service ([#8](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/8)) ([4f85b7b](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/4f85b7bf5b6aa83903ed8febdfe244d54e803642)) +* **signer:** Add GCP Signer to EVM ([#305](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/305)) ([a8817b6](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/a8817b6c87c65731232d0a141338f3996aef2510)) +* Speed support transaction ([#62](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/62)) ([a572af6](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/a572af65ca4f664dce13e705eac37b56dee306fa)) +* Stellar RPC config ([#213](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/213)) ([6fd75ea](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/6fd75ea65bf1a945ba891f99d83b0cdacdf30014)) +* Stellar RPC service ([#183](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/183)) ([9943ffd](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/9943ffd67a709df487264f50eccd03b06cc817d4)) +* Stellar transaction submission ([#199](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/199)) ([c6b72bf](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/c6b72bfba82c7fb9288c07e49bef04cf527d1245)) +* support for multiple custom RPCs with weighted configuration ([#182](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/182)) ([92ea5ad](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/92ea5ad324323b957fcbdce85c37517ec6f963ba)) +* support for retries and failovers in EVM Provider ([#197](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/197)) ([542f21a](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/542f21a9346def9b7fe47e0a29a2bbd5ab2af349)) +* Tx submissions and status mgmt ([#81](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/81)) ([9f829f1](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/9f829f1c59c4221c9cf38c6cb1ff36351a348cd1)) +* Update transaction status to mined/expired ([#85](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/85)) ([8f5ee53](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/8f5ee53bbe64d55ccf8015a1c8d203cf5e391f08)) + + +### πŸ› Bug Fixes + +* Add memo validation for InvokeHostFunction ([#294](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/294)) ([6bb4ffa](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/6bb4ffaf9ceb4a8daef29ec5878595cca7041300)) +* change the ampersand to and, as as the shell interpret it ([#206](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/206)) ([d164d6a](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/d164d6a4d63fbf0acdfe1330cf25147e86280af8)) +* Changing base image to wolfi, added node and npm ([#266](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/266)) ([1181996](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/1181996dac6da52f96e164b1c937828a3940d5b8)) +* CLA assistant ([#171](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/171)) ([b326a56](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/b326a5680722e812263aab949003c214795fd2c0)) +* CLA labels ([#173](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/173)) ([e31405b](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/e31405b8cba9ffd2ff991d56444320ff3d069ad0)) +* Codecov changes and adjustments ([#113](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/113)) ([6e62dcf](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/6e62dcf212a917421c7559566136c018e17c38f5)) +* Config example file ([#285](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/285)) ([a020c6f](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/a020c6fcd6f9b638d955d5f2c99aa0e199d8bf6e)) +* Docker Compose ([#156](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/156)) ([6ca012f](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/6ca012fb9b50d5c2159c498679673cb27530fc3c)) +* docker-scan - chainguard issue ([#255](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/255)) ([c9ab94b](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/c9ab94bcee7b386a33b063504b3e6d2cf188d8b5)) +* Docs link ([#128](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/128)) ([8263828](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/82638284cf13a4da376624362f5353b57365302a)) +* Docs path for crate ([#129](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/129)) ([51cf556](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/51cf556411c9c1f79dbee7f4c3aa25df7fe2af49)) +* **docs:** replaced Monitor for Relayer ([2ff196b](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/2ff196bf772668556210a895d4f83315e579577f)) +* Documentation name for antora ([#121](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/121)) ([63c36f5](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/63c36f5393b1369a169c8617b20952bca30aef0c)) +* Environment variables ([#124](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/124)) ([8d31131](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/8d31131c087a6d0a64ae2dadecb5ae395ad1b575)) +* Fix the codecov yaml syntax ([#108](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/108)) ([ab9ab5b](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/ab9ab5b0c9313d083cd47c71d7faade867c58deb)) +* Flaky logging tests ([#89](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/89)) ([bc909cc](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/bc909cc336613bb5a191c562632278bd3c270b09)) +* Make plugins entry in configs optional ([#300](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/300)) ([f299779](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/f299779318429677fd672d4a2433828971a1b62e)) +* Missing libssl and workflow ([#155](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/155)) ([9de7133](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/9de7133c2ba1768f4d989158f19c27444e522f9e)) +* Plat 6286 write tests for metrics and middleware functions ([#70](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/70)) ([18124fb](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/18124fbbfbc26f300648a7a4050ebf9be72465ac)) +* PLAT-6426 Increase test coverage ([#118](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/118)) ([1fa41f0](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/1fa41f0f225c9d515690738e960073396dce66ce)) +* PLAT-6478 create unit test for use of on relayers dotenv ([#139](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/139)) ([509e166](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/509e1664518823ef3844e52e818707f3371ddbff)) +* plat-6480 allow transfering wrapped sol tokens ([#132](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/132)) ([f04e66a](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/f04e66a568c877c2a4c5c5378fb6017c2e41d2c6)) +* Relayer plugins format output ([#307](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/307)) ([8f25e5f](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/8f25e5f55812e3d346c8bc0ff063cf07e2f0b753)) +* Release merge conflicts ([#163](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/163)) ([4cac422](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/4cac4221817373a1ae7eff92db187dbae2f1665b)) +* remove the ci job dependant from the test job ([#222](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/222)) ([4056610](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/40566108b66c701323145c2889ce0141b84714b8)) +* Replace automatic minor version bumps ([#315](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/315)) ([85784b4](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/85784b486a9508429ae94373a7f3db13d78b39d6)) +* Skip releases ([ccafcbe](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/ccafcbe11bc6ea46dacb9c59be578abd45112ad3)) +* Update configs and dockerfiles in examples ([#298](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/298)) ([2e505ad](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/2e505ad827ab7544f7c6a3fdf4018b1e9428f1d6)) +* Update Stellar API docs to match implementation ([#292](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/292)) ([96d95e3](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/96d95e35784c25f39afe626b56f11477fd213196)) + +[Changes][v1.0.0] + + + +# [v0.2.0](https://github.com/OpenZeppelin/openzeppelin-relayer/releases/tag/v0.2.0) - 2025-05-14 + +## [0.2.0](https://github.com/OpenZeppelin/openzeppelin-relayer/compare/v0.1.1...v0.2.0) (2025-05-14) + + +### πŸš€ Features + +* add optimism extra cost calculation ([#146](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/146)) ([b85e070](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/b85e070074ecc0aa4fbd7d5dc3af6ca0d600220b)) +* add timeout_seconds to EVM relayer configuration ([#169](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/169)) ([6fd59bc](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/6fd59bc0e5993d63608d47e7ba7825a027e26b99)) +* implement balance validation in EVM ([#168](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/168)) ([27fe333](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/27fe333806c28c268af981f5377e188160c845b9)) +* Local signing for stellar ([#178](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/178)) ([f69270a](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/f69270ade4c9a9239bba874ac74858c8e7375298)) +* plat-6471 add Solana Token 2022 extensions support ([#166](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/166)) ([d35c506](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/d35c506ea298a86897ede5702481403f839f2451)) +* Plat-6521 add turnkey hosted signer support (evm, solana) ([#174](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/174)) ([b24688e](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/b24688ead4fe3015ca3b7c74e56f1906085a5aa3)) +* Stellar RPC service ([#183](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/183)) ([9943ffd](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/9943ffd67a709df487264f50eccd03b06cc817d4)) +* Stellar transaction submission ([#199](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/199)) ([c6b72bf](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/c6b72bfba82c7fb9288c07e49bef04cf527d1245)) +* support for multiple custom RPCs with weighted configuration ([#182](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/182)) ([92ea5ad](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/92ea5ad324323b957fcbdce85c37517ec6f963ba)) + + +### πŸ› Bug Fixes + +* CLA assistant ([#171](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/171)) ([b326a56](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/b326a5680722e812263aab949003c214795fd2c0)) +* CLA labels ([#173](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/173)) ([e31405b](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/e31405b8cba9ffd2ff991d56444320ff3d069ad0)) +* Docker Compose ([#156](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/156)) ([6ca012f](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/6ca012fb9b50d5c2159c498679673cb27530fc3c)) +* Missing libssl and workflow ([#155](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/155)) ([9de7133](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/9de7133c2ba1768f4d989158f19c27444e522f9e)) +* Release merge conflicts ([#163](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/163)) ([4cac422](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/4cac4221817373a1ae7eff92db187dbae2f1665b)) +* Skip releases ([ccafcbe](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/ccafcbe11bc6ea46dacb9c59be578abd45112ad3)) + +[Changes][v0.2.0] + + + +# [v0.1.1](https://github.com/OpenZeppelin/openzeppelin-relayer/releases/tag/v0.1.1) - 2025-04-08 + +## [0.1.1](https://github.com/OpenZeppelin/openzeppelin-relayer/compare/v0.1.0...v0.1.1) (2025-04-08) + + +### πŸ› Bug Fixes + +* Skip releases ([e79b2e9](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/e79b2e963439721dd8e151fa0827654e4019df5f)) +* Skip releases with release please ([#158](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/158)) ([e79b2e9](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/e79b2e963439721dd8e151fa0827654e4019df5f)) + + +### βš™οΈ Miscellaneous Chores + +* Fix workflow and missing libs in docker file ([#157](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/157)) ([c7a681d](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/c7a681dea154b06b675a286e936606e2f9ce087b)) +* plat-7575 Docs fixes ([#153](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/153)) ([#154](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/154)) ([44257e8](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/44257e8ea3e658adbf40f69ad809e4e3503e9af4)) + +[Changes][v0.1.1] + + + +# [v0.1.0](https://github.com/OpenZeppelin/openzeppelin-relayer/releases/tag/v0.1.0) - 2025-04-07 + +## 0.1.0 (2025-04-07) + + +### πŸš€ Features + +* add base models ([#5](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/5)) ([55db42b](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/55db42b16d88e95ca8f6927e3b4d07c939e677c8)) +* Add CLA assistant bot ([#130](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/130)) ([4ad5733](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/4ad5733daadefe5e52bd617eaa47039677443745)) +* add directory structure and example ([d946c10](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/d946c10fd96ee2d1ce2e373ba4ccfced31f985f9)) +* Add logging improvements ([#28](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/28)) ([bb6751a](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/bb6751a4f868eb82787e7763a7995d3974ecfd49)) +* Add logic to resubmit transaction ([#102](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/102)) ([6c258b6](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/6c258b625dc7edb1d028b771647ff25b12c2b07d)) +* Add noop support and refactor status ([#134](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/134)) ([f0e3a17](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/f0e3a177a536c53fe8eff834243d417bb673b744)) +* Add queue processing support ([#6](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/6)) ([3ebbac2](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/3ebbac25f1ecb403dec7d090d39882a85227d883)) +* Add release workflow ([#148](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/148)) ([bd9a7e9](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/bd9a7e91a300e6650b08f799aecea4478bb4b974)) +* Add sign tx for evm local signer ([#65](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/65)) ([b17fb36](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/b17fb3625677f1dbcf1ddf3963db13b9b88ca25e)) +* add support for relayer paused and system disabled state ([#13](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/13)) ([44968a2](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/44968a29ec4f1cf1166c2ad726f2c9a1bac246c3)) +* Add worldchain testnet support ([#137](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/137)) ([25751ef](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/25751ef97b7b9fbe0c4b53fab5b762d1696f8c93)) +* Adding job tests ([#110](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/110)) ([4d2dd98](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/4d2dd98efedacaded8d4ace118c43dbe25907278)) +* enabling it to listen on all interfaces - allows for easy docker config ([74a59da](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/74a59da79b314160baf35ec9750e372fbad0f360)) +* enabling it to listen on all interfaces - allows for easy docker config ([23f94c0](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/23f94c07ce46254f7b80df77ce8c4fc59fb4eef6)) +* improve examples ([#119](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/119)) ([7e59aa6](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/7e59aa64f75f3470807396b293e71cd68d3292d1)) +* Improve Redis startup logic ([#120](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/120)) ([8618ecf](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/8618ecf00b4739891fe4ce98caf14f729face896)) +* Improve Redis startup logic ([#120](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/120)) ([8618ecf](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/8618ecf00b4739891fe4ce98caf14f729face896)) +* initial repo setup ([d8815b6](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/d8815b6752931003536aa427370ca8fb1c57231c)) +* Integrate Netlify with antora ([#74](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/74)) ([09e3d48](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/09e3d4894b54c58754b373da239e9d564df69aa9)) +* Plat 5744 implement an api key authentication mechanism ([#11](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/11)) ([8891887](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/88918872d51ab10632ec6d590689d52e59dfd640)) +* Plat 5768 setup metrics endpoint ([#50](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/50)) ([7c292a5](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/7c292a572a7aef8213969fc72cadca74f9016fe8)) +* Plat 6434 improve authorization header validation ([#122](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/122)) ([eed7c31](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/eed7c31e938c7b6ecaa82774ca5d3a508bb89281)) +* Plat-5749 implement basic webhook notifications service ([#12](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/12)) ([1b47b64](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/1b47b64c318208eb7dc2ec6d62020fab30ccafbb)) +* Plat-5802 openapi sdk client ([#109](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/109)) ([1b4b681](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/1b4b681a3755f60e2934548a9666c60a4465dabb)) +* PLAT-6026 Imp cancel transaction ([#101](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/101)) ([1e5cc47](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/1e5cc47bdc54acafeeefb60489db410b42722b0f)) +* PLAT-6026 Imp cancel transaction ([#101](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/101)) ([1e5cc47](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/1e5cc47bdc54acafeeefb60489db410b42722b0f)) +* Plat-6118 implement logic for syncing relayer state upon service start ([#19](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/19)) ([2ba3629](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/2ba36292a0b8d0d67ddab42d2845a6a0d5f31e3a)) +* Plat-6153 add network definitions for Solana networks ([#26](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/26)) ([ff453d5](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/ff453d59724eeaa194ccf7f83993ce8d649f7432)) +* Plat-6154 add support for solana local signer ([#29](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/29)) ([40caead](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/40caeadde5f08200410912b98943346971084163)) +* plat-6158 implement Solana rpc service ([#36](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/36)) ([8fb50a8](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/8fb50a833e7f9b1773dbe4ca1d77a9609a5d5ec1)) +* Plat-6159 extend relayer config file solana policies ([#38](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/38)) ([4f4602b](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/4f4602b754e71539937447c1743a7f069317598b)) +* Plat-6164 implement feeestimate rpc method ([#61](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/61)) ([43b016c](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/43b016c4e5faa5ee1fedcdadccf3bc768962178e)) +* Plat-6165 implement transfertransaction rpc method ([#63](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/63)) ([c59a3b8](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/c59a3b8894c32470adf10770f4804e272aa829d3)) +* Plat-6167 implement signtransaction rpc method ([#57](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/57)) ([ad7a1ff](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/ad7a1ffe41eb868f54737c1f1b44a52c6d02d172)) +* Plat-6169 implement getsupportedtokens rpc method ([#45](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/45)) ([3f91199](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/3f9119981acd7f92618ba6ec12c3039563368202)) +* Plat-6170 add vault hosted signer support ([#99](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/99)) ([7a9491d](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/7a9491d4094fc21bc87551c68687b4f44f3edd18)) +* Plat-6207 implement trait abstraction relayer ([#43](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/43)) ([abeb7cf](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/abeb7cfccc9e70b26ddd0d41d736352d57d6ade9)) +* Plat-6216 adding network symbol support ([#37](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/37)) ([21f798f](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/21f798fc114de47ae0ed7e127e496bb50ca081a8)) +* Plat-6236 adding validation payload ([#42](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/42)) ([a5ff165](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/a5ff165df14f48d47adee03e8e2c8ef5a899ff57)) +* Plat-6236 adding validation payload ([#42](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/42)) ([a5ff165](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/a5ff165df14f48d47adee03e8e2c8ef5a899ff57)) +* Plat-6239 whitelist policy validation ([#44](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/44)) ([3adb45e](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/3adb45e17b8b23c70e09e422cfca051ebab266f1)) +* Plat-6239 whitelist policy validation ([#44](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/44)) ([3adb45e](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/3adb45e17b8b23c70e09e422cfca051ebab266f1)) +* Plat-6248 implementation dummy of legacy price ([#49](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/49)) ([6319d64](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/6319d64bf27fd75f5192165df885156ca91ea9f0)) +* Plat-6248 implementation dummy of legacy price ([#49](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/49)) ([6319d64](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/6319d64bf27fd75f5192165df885156ca91ea9f0)) +* Plat-6267 add utility script for generating local keystore files ([#69](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/69)) ([b5df7f6](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/b5df7f6b0450118c9123de46689fa115efcdec94)) +* Plat-6291 add webhook notifications for rpc methods ([#72](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/72)) ([2f35d81](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/2f35d81b3711cf2f87dbc6df31b9e0f90432164e)) +* Plat-6299 clean transaction response ([#76](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/76)) ([fc5dd05](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/fc5dd05154bca4a1d740cef058bb797cd3f513a0)) +* Plat-6300 returning the balance of the relayer ([#78](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/78)) ([e0ce8e0](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/e0ce8e04f3950c094c9af3e3413d61cd7162c8e7)) +* Plat-6300 returning the balance of the relayer ([#78](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/78)) ([e0ce8e0](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/e0ce8e04f3950c094c9af3e3413d61cd7162c8e7)) +* Plat-6304 use Authorization header instead of x api key ([#94](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/94)) ([34e8a81](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/34e8a813234ee6aaf2a6956f6dd45f82e47e7861)) +* Plat-6309 Fetching eip1559 prices ([#83](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/83)) ([68d574f](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/68d574fcb159ae3b6502167a9bcf34bb1a56ea7e)) +* Plat-6309 Fetching eip1559 prices ([#83](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/83)) ([68d574f](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/68d574fcb159ae3b6502167a9bcf34bb1a56ea7e)) +* plat-6340 store private keys securely in memory ([#104](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/104)) ([28c2fab](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/28c2fab84f3db6b9d971126cf917263da395c421)) +* PLAT-6350 - Sign EIP-1559 ([#98](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/98)) ([673e420](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/673e4202f9d98bfd02512090fa3daacfa40831fe)) +* PLAT-6350 - Sign EIP-1559 ([#98](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/98)) ([673e420](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/673e4202f9d98bfd02512090fa3daacfa40831fe)) +* PLAT-6374 EIP-1559 default if network support it and not explicit false ([#100](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/100)) ([c982dde](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/c982ddefeba93381ac7d2c5e09f616a60820b8b8)) +* PLAT-6374 EIP-1559 default if network support it and not explicit false ([#100](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/100)) ([c982dde](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/c982ddefeba93381ac7d2c5e09f616a60820b8b8)) +* PLAT-6416 Use generics transaction factory ([#105](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/105)) ([7b94662](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/7b946625af77c6aabd336d34646e9ae62ece3b6a)) +* plat-6433 add minimum length validations for config sensitive values ([#125](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/125)) ([31453c5](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/31453c5586ca4fef70e7ea0e2dcd0260a8a721a6)) +* Plat-6441 document upcoming work ([#131](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/131)) ([377a8bb](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/377a8bb57ff5b3b23abb58d1c3378489c40218cf)) +* PLAT-6442 - Abstraction and unit tests relayer domain ([#117](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/117)) ([643194a](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/643194acd9079ac3ac157e909f0b30199af8b0c9)) +* PLAT-6442 - Abstraction and unit tests relayer domain ([#117](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/117)) ([643194a](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/643194acd9079ac3ac157e909f0b30199af8b0c9)) +* Plat-6457 Ignore utoipa ([#127](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/127)) ([234854a](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/234854afbf30a9a94fa3365f60f035e53e068938)) +* Plat-6457 Ignore utoipa ([#127](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/127)) ([234854a](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/234854afbf30a9a94fa3365f60f035e53e068938)) +* Plat-6459 create mermaid architecture diagram ([#126](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/126)) ([3de147b](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/3de147b907c28d3e9a8a38a2d6b8cd665253c423)) +* plat-6476 Add support to collect transaction fee ([#135](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/135)) ([4f4a07b](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/4f4a07b2846d2980bbf09734602315702ded9dbe)) +* Plat-6479 added support for rpc custom endpoints ([#138](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/138)) ([3df3d49](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/3df3d49ec6a662698a90630811d717920b7cdf3b)) +* Pricing validation on receiving payload EVM ([#59](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/59)) ([1206d42](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/1206d4241dbda84bc861f501d322f6bd33234f0b)) +* Pricing validation on receiving payload EVM ([#59](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/59)) ([1206d42](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/1206d4241dbda84bc861f501d322f6bd33234f0b)) +* Signer service ([#8](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/8)) ([4f85b7b](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/4f85b7bf5b6aa83903ed8febdfe244d54e803642)) +* Speed support transaction ([#62](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/62)) ([a572af6](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/a572af65ca4f664dce13e705eac37b56dee306fa)) +* Tx submissions and status mgmt ([#81](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/81)) ([9f829f1](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/9f829f1c59c4221c9cf38c6cb1ff36351a348cd1)) +* Update transaction status to mined/expired ([#85](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/85)) ([8f5ee53](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/8f5ee53bbe64d55ccf8015a1c8d203cf5e391f08)) + + +### πŸ› Bug Fixes + +* Codecov changes and adjustments ([#113](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/113)) ([6e62dcf](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/6e62dcf212a917421c7559566136c018e17c38f5)) +* Docs link ([#128](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/128)) ([8263828](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/82638284cf13a4da376624362f5353b57365302a)) +* Docs path for crate ([#129](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/129)) ([51cf556](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/51cf556411c9c1f79dbee7f4c3aa25df7fe2af49)) +* **docs:** replaced Monitor for Relayer ([2ff196b](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/2ff196bf772668556210a895d4f83315e579577f)) +* Documentation name for antora ([#121](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/121)) ([63c36f5](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/63c36f5393b1369a169c8617b20952bca30aef0c)) +* Environment variables ([#124](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/124)) ([8d31131](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/8d31131c087a6d0a64ae2dadecb5ae395ad1b575)) +* Fix the codecov yaml syntax ([#108](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/108)) ([ab9ab5b](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/ab9ab5b0c9313d083cd47c71d7faade867c58deb)) +* Flaky logging tests ([#89](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/89)) ([bc909cc](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/bc909cc336613bb5a191c562632278bd3c270b09)) +* Plat 6286 write tests for metrics and middleware functions ([#70](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/70)) ([18124fb](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/18124fbbfbc26f300648a7a4050ebf9be72465ac)) +* PLAT-6426 Increase test coverage ([#118](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/118)) ([1fa41f0](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/1fa41f0f225c9d515690738e960073396dce66ce)) +* PLAT-6478 create unit test for use of on relayers dotenv ([#139](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/139)) ([509e166](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/509e1664518823ef3844e52e818707f3371ddbff)) +* plat-6480 allow transfering wrapped sol tokens ([#132](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/132)) ([f04e66a](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/f04e66a568c877c2a4c5c5378fb6017c2e41d2c6)) + + +### πŸ“š Documentation + +* add cargo docs ([#75](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/75)) ([c4dd8e3](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/c4dd8e30525ccaeb563560bc2ef87cdcec5b1790)) +* Add testing instructions ([#107](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/107)) ([c7c2ed7](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/c7c2ed7772d99b4b68ced9fbf8835fa9e46da5e1)) +* Adding configuration documentation ([#48](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/48)) ([929cc1b](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/929cc1bf1e0c6b3be872daf6654abe24eb79b907)) +* Fixing formatting and location of files ([#41](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/41)) ([4d4f153](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/4d4f1530f466a5bd597d0338559ccb33815286f0)) +* Move README to a similar format to Monitor ([#39](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/39)) ([5985339](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/59853396b3786a972ce7bbc793d4dbacc62fe6c0)) +* Readability improvements ([#133](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/133)) ([9220727](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/9220727cc2b4349052c2d96a48c5d9c3012b38b9)) +* Small doc updates - policy field descriptions ([#51](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/51)) ([cc83c49](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/cc83c496bbe2593018b03c414a864691c967ff41)) +* Small fixes and Antora docs improvements ([#40](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/40)) ([655d16d](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/655d16dc658a74b7413ce785dee5b8e33cfb40f7)) +* TG link and other minor doc updates ([#116](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/116)) ([fc68b6a](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/fc68b6afa844d2c2638d031fce44fcc514d59a7d)) +* Update API docs. Fix Dockerfiles ([#77](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/77)) ([0bd6bfe](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/0bd6bfea69d60c1a7e9d6b8a690ba1a2d0e44b74)) + +[Changes][v0.1.0] + + +[v1.1.0]: https://github.com/OpenZeppelin/openzeppelin-relayer/compare/v1.0.0...v1.1.0 +[v1.0.0]: https://github.com/OpenZeppelin/openzeppelin-relayer/compare/v0.2.0...v1.0.0 +[v0.2.0]: https://github.com/OpenZeppelin/openzeppelin-relayer/compare/v0.1.1...v0.2.0 +[v0.1.1]: https://github.com/OpenZeppelin/openzeppelin-relayer/compare/v0.1.0...v0.1.1 +[v0.1.0]: https://github.com/OpenZeppelin/openzeppelin-relayer/tree/v0.1.0 diff --git a/content/relayer/1.1.x/configuration/index.mdx b/content/relayer/1.1.x/configuration/index.mdx new file mode 100644 index 00000000..081bc613 --- /dev/null +++ b/content/relayer/1.1.x/configuration/index.mdx @@ -0,0 +1,527 @@ +--- +title: Configuration +--- + +## Overview + +Most configuration files should live under `./config`, including the signer configurations, under `./config/keys`. +Please ensure appropriate access permissions on all configuration files (for `./config/keys/*`, we recommend `0500`. + + + + +The OpenZeppelin Relayer supports two configuration approaches: + +***File-based Configuration:*** +1. ***`config.json`***: Contains relayer definitions, signer configurations, and network policies +2. ***`.env`*** file: Contains environment variables like API keys and connection strings + +***API-based Configuration:*** +- Full CRUD operations for relayers, signers, and notifications via REST API +- Changes take effect immediately (no container restart required) +- See the ***API Reference*** page for detailed endpoints documentation + +See [Storage Configuration](/relayer/1.1.x/configuration/storage) for detailed information about how file-based and API-based configurations work together, storage behavior, and best practices. + + +For quick setup examples with pre-configured files, see the [examples directory](https://github.com/OpenZeppelin/openzeppelin-relayer/tree/main/examples) in our GitHub repository. + + + +## Environment configuration (.env) + +This defines some base configurations for the Relayer application: + +Copy the example environment file and update values according to your needs + +```bash +cp .env.example .env +``` + +This table lists the environment variables and their default values. + +| Environment Variable | Default Value | Accepted Values | Description | +| --- | --- | --- | --- | +| `RUST_LOG` | `info` | `info, debug, warn, error, trace` | Log level. | +| `REPOSITORY_STORAGE_TYPE` | `in-memory` | `in-memory, redis` | Type of storage used for storing repository config and resources. See [Storage Configuration](/relayer/1.1.x/configuration/storage) for detailed information. | +| `RESET_STORAGE_ON_START` | `false` | `bool` | Clears all resources from storage on startup and reloads entries from the config file. See [Storage Configuration](/relayer/1.1.x/configuration/storage) for usage details. | +| `TRANSACTION_EXPIRATION_HOURS` | `4` | `number` | Number of hours after which transactions in a final state are removed from storage. See [Storage Configuration](/relayer/1.1.x/configuration/storage) for more information. | +| `CONFIG_DIR` | `./config` | `` | Relative path of directory where config files reside | +| `CONFIG_FILE_NAME` | `config.json` | `` | File Name of the configuration file. | +| `RATE_LIMIT_RPS` | `100` | `` | Rate limit for the API in requests per second. | +| `RATE_LIMIT_BURST_SIZE` | `300` | `` | Rate limit burst size. | +| `API_KEY` | `` | `string`, | API key to use for authentication to the relayer server. Minimum length 32 characters. | +| `WEBHOOK_SIGNING_KEY` | `` | `string` | Signing key to use for webhook notifications. Minimum length 32 characters. | +| `LOG_MODE` | `stdout` | `stdout, file` | Write logs either to console or to file. | +| `LOG_DATA_DIR` | `./logs` | `` | Directory to persist log files on host. | +| `LOG_MAX_SIZE (in bytes)` | `1073741824` | `` | Size after which logs needs to be rolled. | +| `METRICS_ENABLED` | `false` | `bool` | Enable metrics server for external tools to scrape metrics. | +| `METRICS_PORT` | `8081` | `` | Port to use for metrics server. | +| `REDIS_URL` | `redis://localhost:6379` | `` | Redis connection URL for the relayer. See [Storage Configuration](/relayer/1.1.x/configuration/storage) for Redis setup details. | +| `REDIS_CONNECTION_TIMEOUT_MS` | `10000` | `` | Connection timeout for Redis in milliseconds. See [Storage Configuration](/relayer/1.1.x/configuration/storage) for Redis configuration. | +| `REDIS_KEY_PREFIX` | `oz-relayer` | `string` | Redis key prefix for namespacing. See [Storage Configuration](/relayer/1.1.x/configuration/storage) for more information. | +| `STORAGE_ENCRYPTION_KEY` | `` | `string` | Encryption key used to encrypt data at rest in Redis storage. See [Storage Configuration](/relayer/1.1.x/configuration/storage) for security details. | +| `RPC_TIMEOUT_MS` | `10000` | `` | Sets the maximum time to wait for RPC connections before timing out. | +| `PROVIDER_MAX_RETRIES` | `3` | `` | Maximum number of retry attempts for provider operations. | +| `PROVIDER_RETRY_BASE_DELAY_MS` | `100` | `` | Base delay between retry attempts in milliseconds. | +| `PROVIDER_RETRY_MAX_DELAY_MS` | `2000` | `` | Maximum delay between retry attempts in milliseconds. | +| `PROVIDER_MAX_FAILOVERS` | `3` | `` | Maximum number of failovers (switching to different providers). | +| `ENABLE_SWAGGER` | `false` | `true, false` | Enable or disable Swagger UI for API documentation. | +| `KEYSTORE_PASSPHRASE` | `` | `` | Passphrase for the keystore file used for signing transactions. | + +### Environment configuration example + +`.env` file config example: + +``` +RUST_LOG=DEBUG +CONFIG_DIR=./config +CONFIG_FILE_NAME=config.json +WEBHOOK_SIGNING_KEY=e1d42480-6f74-4d0b-85f4-b7f0bb690fae +API_KEY=5eefd216-0e44-4ca7-b421-2925f90d30d5 +RATE_LIMIT_RPS=100 +RATE_LIMIT_BURST_SIZE=300 +METRICS_ENABLED=true +METRICS_PORT=8081 +REDIS_URL=redis://localhost:6379 +REDIS_CONNECTION_TIMEOUT_MS=10000 +REDIS_KEY_PREFIX=oz-relayer +RPC_TIMEOUT_MS=10000 +PROVIDER_MAX_RETRIES=3 +PROVIDER_RETRY_BASE_DELAY_MS=100 +PROVIDER_RETRY_MAX_DELAY_MS=2000 +PROVIDER_MAX_FAILOVERS=3 +ENABLE_SWAGGER=false +KEYSTORE_PASSPHRASE=your_keystore_passphrase +STORAGE_ENCRYPTION_KEY=X67aXacJB+krEldv9i2w7NCSFwwOzVV/1ELM2KJJjQw= +REPOSITORY_STORAGE_TYPE=redis +RESET_STORAGE_ON_START=false +TRANSACTION_EXPIRATION_HOURS=8 +``` + +## Main configuration file (config.json) + +This file can exist in any directory, but the default location is `./config/config.json`. + + + +All components defined in `config.json` can also be managed via REST API endpoints. This provides runtime flexibility for adding, updating, or removing relayers, signers, and notifications without restarting the service. See the ***API Reference*** page for detailed endpoints documentation. + + +Key sections in this file include: + +* Signers: Defines transaction signing methods. +* Notifications: Sets up status alerts +* Relayers: Configures networks, notifications channels, policies & singers. +* Networks: Defines blockchain network configurations. +* Plugins: Configures plugins. + +### 1. Signers + +Transaction signers are responsible for cryptographically signing transactions before they are submitted to blockchain networks. + +For comprehensive details on configuring all supported signer types including: + +* Local keystore file signers +* HashiCorp Vault (secret and transit) +* Cloud KMS providers (Google Cloud, AWS) +* Turnkey signers +* Security best practices and troubleshooting + +See the dedicated [Signers Configuration](/relayer/1.1.x/configuration/signers) guide. + + + +Signers can also be managed via API endpoints. + +See the ***API Reference*** page for detailed endpoints documentation. + + +### 2. Notifications + +* `notifications` array containing notification entries: + +```json +"notifications": [ + { + "id": "notification-test", + "type": "webhook", + "url": "https://webhook.site/f95cf78d-742d-4b21-88b7-d683e6fd147b", + "signing_key": { + "type": "env", + "value": "WEBHOOK_SIGNING_KEY" + } + } +] +``` +Available configuration fields +| Field | Type | Description | +| --- | --- | --- | +| id | String | Unique id for the notification | +| type | String | Type of notification (only `webhook` available, for now) | +| url | String | Notification URL | +| signing_key.type | String | Type of key used in signing the notification (`env` or `plain`) | +| signing_key.value | String | Signing key value, env variable name, ... | + + + +Notifications can also be managed via API endpoints. + +See the ***API Reference*** page for detailed endpoints documentation. + + +### 3. Relayers + +* `relayers` array, containing relayer entries: + +```json +"relayers": [ + + "id": "solana-testnet", + "name": "Solana Testnet", + "paused": false, + "notification_id": "notification-test", + "signer_id": "local-signer", + "network_type": "solana", + "network": "testnet", + "custom_rpc_urls": [ + { + "url": "https://primary-rpc.example.com", + "weight": 2 // Higher weight routes more requests to this endpoint. The value must be an integer between 0 and 100 (inclusive). + , + + "url": "https://backup-rpc.example.com", + "weight": 1 + + ], + "policies": + "allowed_programs": [ + "11111111111111111111111111111111", + "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", + "BPFLoaderUpgradeab1e11111111111111111111111" + ] + + } +] +``` + +Available configuration fields +| Field | Type | Description | +| --- | --- | --- | +| id | String | Unique id for the relayer | +| name | String | Human readable name for the relayer | +| paused | Boolean | Whether or not the relayer is paused (`true`, `false`) | +| notification_id | String | ID of a configured notification object | +| signer_id | String | ID of a configured signer | +| network_type | String | Type of network the relayer will connect to (`evm`, `solana`) | +| network | String | Network the relayer will connect to. Must match a network identifier defined in your network configuration files. See [Network Configuration](/relayer/1.1.x/network_configuration) for details on defining networks. | +| custom_rpc_urls | list | Optional custom RPC URLs for the network. If provided, this will be used instead of the public RPC URLs. This is useful for using your own RPC node or a paid service provider. The first url of the list is going to be used as the default | +| policies | list | Overrides default policies. Please refer to the [`Policies`](/relayer/1.1.x/configuration#network-policies) table | + +Policies +| Network type | Policy | Type | Description | +| --- | --- | --- | --- | +| solana, evm | min_balance | unsigned 128 | Minimum balance (in lamports or wei) required for the relayer to operate. Optional. | +| solana | fee_payment_strategy | enum(user,relayer) | Specifies who pays the fee. "user" (default) means the sender pays; "relayer" means the relayer pays. For "user", RPC methods add an instruction to transfer SPL tokens (calculated from the current SOL price plus a configurable margin) from the user to the relayer, ensuring fees are sustainably covered in tokens rather than SOL. | +| solana | swap_config | SwapConfig | Optional object configuring automated token‐swaps on Solana. | +| solana | fee_margin_percentage | f32 | Additional margin percentage added to estimated transaction fees to account for price fluctuations. For example, a value of 10 will add 10% to estimated fees. Optional. | +| solana | max_allowed_fee_lamports | unsigned 64 | Maximum allowed fee (in lamports) for a transaction. Optional. | +| solana | allowed_tokens | `Vector` | List of allowed tokens. Only these tokens are supported if provided. Optional. | +| solana | allowed_programs | `Vector` | List of allowed programs by their identifiers. Only these programs are supported if provided. Optional. | +| solana | allowed_accounts | `Vector` | List of allowed accounts by their public keys. The relayer will only operate with these accounts if provided. | +| solana | disallowed_accounts | `Vector` | List of disallowed accounts by their public keys. These accounts will be explicitly blocked. | +| solana | max_tx_data_size | unsigned 16 | Maximum transaction size. Optional. | +| solana | max_signatures | unsigned 8 | Maximum supported signatures. Optional. | +| evm | gas_price_cap | unsigned 128 | Specify a maximum gas price for every transaction sent with the Relayer. When enabled, any transaction exceeding the cap will have its gasPrice or maxFeePerGas overwritten. (Optional) | +| evm | gas_limit_estimation | bool | Automatic gas_limit calculation. Enabled by default. (Optional) | +| evm | whitelist_receivers | `Vector` | A list of authorized contracts for each transaction sent using the Relayer. Transactions will be rejected if the destination address is not on the list. (Optional) | + +#### RPC URL Configuration + +The relayer supports two ways to configure RPC URLs: + +1. ***Public RPC URLs***: These are the default RPC endpoints provided by the network. They are automatically selected based on the network configuration. +2. ***Custom RPC URLs***: You can specify custom RPC URLs using the `custom_rpc_urls` field in the relayer configuration. Each URL can be configured with an optional weight for high availability: + +```json +"custom_rpc_urls": [ + + "url": "https://primary-rpc.example.com", + "weight": 2 // Higher weight routes more requests to this endpoint. The value must be an integer between 0 and 100 (inclusive). + , + + "url": "https://secondary-rpc.example.com", + "weight": 100, // Max allowed weight + , + + "url": "https://backup-rpc.example.com" // No weight specified, defaults to 100 + , + + "url": "https://backup2-rpc.example.com", + "weight": 0, // A value of 0 disables the endpoint. + +] +``` + +This is useful when you want to: + * Use your own RPC nodes with load balancing + * Use a paid service provider for better reliability and performance + * Override the default public RPC URLs + * Access custom network endpoints + * Configure primary and backup endpoints with different weights + +When both are available, the relayer will: +1. First attempt to use the `custom_rpc_urls` if configured. +2. Fall back to the public RPC URLs if no custom URL is configured. + +For backward compatibility, string arrays are still supported: + +```json +"custom_rpc_urls": ["https://your-rpc.example.com"] +``` + + + + +When using custom RPC URLs: + +* Ensure the URLs are secure (HTTPS) when accessing over public networks +* Keep your API keys and authentication tokens secure +* Test the RPC endpoints' reliability and performance before using it in production +* Configure weights to prioritize endpoints, assigning higher values to more reliable or performant ones. +* The weight must be an integer between 0 and 100 (inclusive). +* A weight of 0 disables the endpoint. +* If a weight is not specified for an endpoint, it defaults to 100. + + + + + +Relayers could also be managed via API endpoints. + +See the ***API Reference*** page for detailed endpoints documentation. + + +### 4. Plugins + +For more information on how to write a plugin, please refer to the [Plugins](/relayer/1.1.x/plugins) page. + +* `plugins` array, containing plugin configurations: + +```json +"plugins": [ + { + "id": "my-plugin", + "path": "my-plugin.ts" + } +] +``` + +Available configuration fields +| Field | Type | Description | +| --- | --- | --- | +| id | String | Unique id for the plugin | +| path | String | Path to the plugin file | + +### 5. Networks + +You can configure networks either: + +* In separate JSON files (recommended for better organization) +* Directly in your main `config.json` + +For comprehensive network configuration details, including: + +* Network field reference +* Configuration examples for all network types +* Network inheritance +* Special tags and their behavior +* Best practices and troubleshooting + +See the dedicated [Network Configuration](/relayer/1.1.x/network_configuration) guide. + +## Configuration File Example + +Full `config/config.json` example with evm and solana relayers definitions using keystore signer: + +```json +{ + "relayers": [ + { + "id": "sepolia-example", + "name": "Sepolia Example", + "network": "sepolia", + "paused": false, + "notification_id": "notification-example", + "signer_id": "local-signer", + "network_type": "evm", + "custom_rpc_urls": [ + { + "url": "https://primary-rpc.example.com", + "weight": 2 + }, + { + "url": "https://backup-rpc.example.com", + "weight": 1 + } + ], + "policies": { + "gas_price_cap": 30000000000000, + "eip1559_pricing": true + } + }, + { + "id": "solana-example", + "name": "Solana Example", + "network": "devnet", + "paused": false, + "notification_id": "notification-example", + "signer_id": "local-signer", + "network_type": "solana", + "custom_rpc_urls": [ + { + "url": "https://primary-solana-rpc.example.com", + "weight": 2 + }, + { + "url": "https://backup-solana-rpc.example.com", + "weight": 1 + } + ], + "policies": { + "fee_payment_strategy": "user", + "min_balance": 0, + "allowed_tokens": [ + { + "mint": "Gh9ZwEmdLJ8DscKNTkTqPbNwLNNBjuSzaG9Vp2KGtKJr", + "max_allowed_fee": 100000000 + }, + { + "mint": "So11111111111111111111111111111111111111112" + } + ] + } + }, + { + "id": "solana-mainnet-example", + "name": "Solana Mainnet Example", + "network": "mainnet-beta", + "paused": false, + "notification_id": "notification-example", + "signer_id": "local-signer", + "network_type": "solana", + "custom_rpc_urls": ["https://your-private-solana-rpc.example.com"], + "policies": { + "fee_payment_strategy": "user", + "min_balance": 0, + "swap_config": { + "cron_schedule": "0 0 * * * *", + "min_balance_threshold": 0, + "strategy": "jupiter-ultra" + }, + "allowed_tokens": [ + { + "mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", + "max_allowed_fee": 100000000, + "swap_config": { + "min_amount": 0, + "max_amount": 0, + "retain_min_amount": 0 + } + }, + { + "mint": "So11111111111111111111111111111111111111112" + } + ] + } + } + ], + "notifications": [ + { + "id": "notification-example", + "type": "webhook", + "url": "https://webhook.site/1384d4d9-21b1-40a0-bcd1-d3f3b66be955", + "signing_key": { + "type": "env", + "value": "WEBHOOK_SIGNING_KEY" + } + } + ], + "signers": [ + { + "id": "local-signer", + "type": "local", + "config": { + "path": "config/keys/local-signer.json", + "passphrase": { + "type": "env", + "value": "KEYSTORE_PASSPHRASE" + } + } + } + ], + "networks": [ + { + "average_blocktime_ms": 12000, + "chain_id": 11155111, + "explorer_urls": [ + "https://api-sepolia.etherscan.io/api", + "https://sepolia.etherscan.io" + ], + "features": [ + "eip1559" + ], + "is_testnet": true, + "network": "sepolia", + "required_confirmations": 6, + "rpc_urls": [ + "https://sepolia.drpc.org", + "https://1rpc.io/sepolia", + "https://ethereum-sepolia-rpc.publicnode.com", + "https://ethereum-sepolia-public.nodies.app" + ], + "symbol": "ETH", + "tags": [ + "deprecated" + ], + "type": "evm" + }, + { + "type": "solana", + "network": "devnet", + "rpc_urls": ["https://api.devnet.solana.com"], + "explorer_urls": ["https://explorer.solana.com?cluster=devnet"], + "average_blocktime_ms": 400, + "is_testnet": true + }, + { + "type": "solana", + "network": "mainnet-beta", + "rpc_urls": ["https://api.mainnet-beta.solana.com"], + "explorer_urls": ["https://explorer.solana.com"], + "average_blocktime_ms": 400, + "is_testnet": false + } + ] +} +``` + +## Configuration Management Approaches + +The OpenZeppelin Relayer supports two complementary approaches for configuration management: + +### File-based Configuration +* Ideal for initial setup and deployment +* Configuration persists across restarts +* Requires container restart for changes to take effect +* Suitable for infrastructure-as-code workflows + +### API-based Configuration +* Enables runtime configuration changes +* No service restarts required +* Perfect for dynamic environments +* Supports automated configuration management + + + +See [Storage Configuration](/relayer/1.1.x/configuration/storage) for detailed information about how file-based and API-based configurations work together, storage behavior, and best practices. diff --git a/content/relayer/1.1.x/configuration/signers.mdx b/content/relayer/1.1.x/configuration/signers.mdx new file mode 100644 index 00000000..56f118e1 --- /dev/null +++ b/content/relayer/1.1.x/configuration/signers.mdx @@ -0,0 +1,328 @@ +--- +title: Signers Configuration +--- + +## Overview + +Signers are responsible for cryptographically signing transactions before they are submitted to blockchain networks. OpenZeppelin Relayer supports multiple signer types to accommodate different security requirements and infrastructure setups. + +Each signer is referenced by its `id` in relayer configurations. + +## Configuration Structure + +Example signer configuration: +```json +"signers": [ + { + "id": "my_id", + "type": "local", + "config": { + "path": "config/keys/local-signer.json", + "passphrase": { + "type": "env", + "value": "KEYSTORE_PASSPHRASE" + } + } + } +] +``` + +## Supported Signer Types + +OpenZeppelin Relayer supports the following signer types: + +* `local`: Keystore file signer +* `vault`: HashiCorp Vault secret signer +* `vault_transit`: HashiCorp Vault Transit signer +* `turnkey`: Turnkey signer +* `google_cloud_kms`: Google Cloud KMS signer +* `aws_kms`: Amazon AWS KMS signer + +## Network Compatibility Matrix + +The following table shows which signer types are compatible with each network type: + +| Signer Type | EVM Networks | Solana Networks | Stellar Networks | +| --- | --- | --- | --- | +| `local` | βœ… Supported | βœ… Supported | βœ… Supported | +| `vault` | βœ… Supported | βœ… Supported | ❌ Not supported | +| `vault_transit` | ❌ Not supported | βœ… Supported | ❌ Not supported | +| `turnkey` | βœ… Supported | βœ… Supported | ❌ Not supported | +| `google_cloud_kms` | βœ… Supported | βœ… Supported | ❌ Not supported | +| `aws_kms` | βœ… Supported | ❌ Not supported | ❌ Not supported | + + + +***Network-specific considerations:*** + +* ***EVM Networks***: Use secp256k1 cryptography. Most signers support EVM networks with proper key generation. +* ***Solana Networks***: Use ed25519 cryptography. Ensure your signer supports ed25519 key generation and signing. +* ***Stellar Networks***: Use ed25519 cryptography with specific Stellar requirements. Limited signer support due to network-specific implementation requirements. +* ***AWS KMS***: Currently optimized for EVM networks with secp256k1 support. +* ***Google Cloud KMS***: Supports both secp256k1 (EVM) and ed25519 (Solana) key types. +* ***Turnkey***: Supports EVM and Solana networks with appropriate key management. + + +## Common Configuration Fields + +All signer types share these common configuration fields: + +| Field | Type | Description | +| --- | --- | --- | +| `id` | String | Unique identifier for the signer (used to reference this signer in relayer configurations) | +| `type` | String | Type of signer (see supported signer types above) | +| `config` | Map | Signer type-specific configuration object | + +## Local Signer Configuration + +The local signer uses encrypted keystore files stored on the filesystem. + +```json +{ + "id": "local-signer", + "type": "local", + "config": { + "path": "config/keys/local-signer.json", + "passphrase": { + "type": "env", + "value": "KEYSTORE_PASSPHRASE" + } + } +} +``` + +Configuration fields: +| Field | Type | Description | +| --- | --- | --- | +| `path` | String | Path to the signer JSON file. Should be under the `./config` directory | +| `passphrase.type` | String | Type of passphrase source (`env` or `plain`) | +| `passphrase.value` | String | Passphrase value or environment variable name | + +## HashiCorp Vault Signer Configuration + +### Vault Secret Signer + +Uses HashiCorp Vault’s secret engine to store private keys. + +```json +{ + "id": "vault-signer", + "type": "vault", + "config": { + "address": "https://vault.example.com", + "role_id": { + "type": "env", + "value": "VAULT_ROLE_ID" + }, + "secret_id": { + "type": "env", + "value": "VAULT_SECRET_ID" + }, + "key_name": "relayer-key", + "mount_point": "secret" + } +} +``` + +Configuration fields: +| Field | Type | Description | +| --- | --- | --- | +| `address` | String | Specifies the Vault API endpoint | +| `role_id.type` | String | Type of value source (`env` or `plain`) | +| `role_id.value` | String | The Vault AppRole role identifier value, or the environment variable name where the AppRole role identifier is stored | +| `secret_id.type` | String | Type of value source (`env` or `plain`) | +| `secret_id.value` | String | The Vault AppRole role secret value, or the environment variable name where the AppRole secret value is stored | +| `key_name` | String | The name of the cryptographic key within Vault's Secret engine that is used for signing operations | +| `mount_point` | String | The mount point for the Secrets engine in Vault. Defaults to `secret` if not explicitly specified. Optional. | + +### Vault Transit Signer + +Uses HashiCorp Vault’s Transit secrets engine for cryptographic operations. + +```json +{ + "id": "vault-transit-signer", + "type": "vault_transit", + "config": { + "address": "https://vault.example.com", + "role_id": { + "type": "env", + "value": "VAULT_ROLE_ID" + }, + "secret_id": { + "type": "env", + "value": "VAULT_SECRET_ID" + }, + "key_name": "relayer-transit-key", + "mount_point": "transit", + "namespace": "production", + "pubkey": "your-public-key-here" + } +} +``` + +Configuration fields: +| Field | Type | Description | +| --- | --- | --- | +| `address` | String | Specifies the Vault API endpoint | +| `role_id.type` | String | Type of value source (`env` or `plain`) | +| `role_id.value` | String | The Vault AppRole role identifier value, or the environment variable name where the AppRole role identifier is stored | +| `secret_id.type` | String | Type of value source (`env` or `plain`) | +| `secret_id.value` | String | The Vault AppRole role secret value, or the environment variable name where the AppRole secret value is stored | +| `key_name` | String | The name of the cryptographic key within Vault's Transit engine that is used for signing operations | +| `mount_point` | String | The mount point for the Transit secrets engine in Vault. Defaults to `transit` if not explicitly specified. Optional. | +| `namespace` | String | The Vault namespace for API calls. This is used only in Vault Enterprise environments. Optional. | +| `pubkey` | String | Public key of the cryptographic key within Vault's Transit engine that is used for signing operations | + +## Turnkey Signer Configuration + +Uses Turnkey’s secure key management infrastructure. + +```json +{ + "id": "turnkey-signer", + "type": "turnkey", + "config": { + "api_public_key": "your-api-public-key", + "api_private_key": { + "type": "env", + "value": "TURNKEY_API_PRIVATE_KEY" + }, + "organization_id": "your-org-id", + "private_key_id": "your-private-key-id", + "public_key": "your-public-key" + } +} +``` + +Configuration fields: +| Field | Type | Description | +| --- | --- | --- | +| `api_public_key` | String | The public key associated with your Turnkey API access credentials. Used for authentication to the Turnkey signing service | +| `api_private_key.type` | String | Type of value source (`env` or `plain`) | +| `api_private_key.value` | String | The Turnkey API private key or environment variable name containing it. Used with the public key to authenticate API requests | +| `organization_id` | String | Your unique Turnkey organization identifier. Required to access resources within your specific organization | +| `private_key_id` | String | The unique identifier of the private key in your Turnkey account that will be used for signing operations | +| `public_key` | String | The public key corresponding to the private key identified by private_key_id. Used for address derivation and signature verification | + +## Google Cloud KMS Signer Configuration + +Uses Google Cloud Key Management Service for secure key operations. + +For EVM transaction signing, ensure your Google Cloud KMS key is created with: +- Protection level: HSM +- Purpose: Asymmetric sign +- Algorithm: "Elliptic Curve secp256k1 - SHA256 Digest" + +This provides secp256k1 compatibility required for Ethereum transactions. + + +```json +{ + "id": "gcp-kms-signer", + "type": "google_cloud_kms", + "config": { + "service_account": { + "project_id": "your-gcp-project", + "private_key_id": { + "type": "env", + "value": "GCP_PRIVATE_KEY_ID" + }, + "private_key": { + "type": "env", + "value": "GCP_PRIVATE_KEY" + }, + "client_email": { + "type": "env", + "value": "GCP_CLIENT_EMAIL" + }, + "client_id": "your-client-id" + }, + "key": { + "location": "us-west2", + "key_ring_id": "relayer-keyring", + "key_id": "relayer-key", + "key_version": 1 + } + } +} +``` + +Configuration fields: +| Field | Type | Description | +| --- | --- | --- | +| service_account.project_id | String | The Google Cloud project ID where your KMS resources are located | +| service_account.private_key_id.type | String | Type of value source for the private key ID (`env` or `plain`) | +| service_account.private_key_id.value | String | The private key ID value or the environment variable name containing it | +| service_account.private_key.type | String | Type of value source for the private key (`env` or `plain`) | +| service_account.private_key.value | String | The Google Cloud service account private key (PEM format) or the environment variable name containing it | +| service_account.client_email.type | String | Type of value source for the client email (`env` or `plain`) | +| service_account.client_email.value | String | The Google Cloud service account client email or the environment variable name containing it | +| service_account.client_id | String | The Google Cloud service account client ID | +| key.location | String | The Google Cloud location (region) where your KMS key ring is located (e.g., "us-west2", "global") | +| key.key_ring_id | String | The KMS key ring ID containing your cryptographic key | +| key.key_id | String | The KMS key ID used for signing operations | +| key.key_version | Integer | The version of the KMS key to use for signing operations. Defaults to 1 | + +## AWS KMS Signer Configuration + +Uses Amazon Web Services Key Management Service for cryptographic operations. + +```json +{ + "id": "aws-kms-signer", + "type": "aws_kms", + "config": { + "region": "us-west-2", + "key_id": "arn:aws:kms:us-west-2:123456789012:key/12345678-1234-1234-1234-123456789012" + } +} +``` + +Configuration fields: +| Field | Type | Description | +| --- | --- | --- | +| region | String | AWS region. If the key is non-replicated across regions, this must match the key’s original region. Optional. If not specified, the default region from shared credentials is used | +| key_id | String | ID of the key in AWS KMS (can be key ID, key ARN, alias name, or alias ARN) | + +## Security Best Practices + +### File Permissions +* Set restrictive permissions on keystore files: `chmod 0500 config/keys/*` +* Ensure configuration directories are properly secured +* Use environment variables for sensitive data like passphrases and API keys + +### Key Management +* Use HSM-backed keys for production environments when available +* Implement proper key rotation policies +* Never commit private keys or sensitive configuration to version control +* Use dedicated service accounts with minimal required permissions + +### Environment Separation +* Use different signers for different environments (development, staging, production) +* Implement proper secrets management in production deployments +* Consider using cloud-native key management services for enhanced security + +## Troubleshooting + +### Common Issues + +***Invalid keystore passphrase*** + +* Verify the passphrase environment variable is correctly set +* Check that the keystore file is not corrupted +* Ensure the keystore format is compatible + +***Cloud KMS authentication failures*** + +* Verify service account credentials are valid and properly formatted +* Check that the service account has necessary permissions for KMS operations +* Ensure the KMS key exists and is in the correct region/project + +***Vault connection issues*** + +* Verify Vault server address and network connectivity +* Check AppRole credentials and permissions +* Ensure the secret/transit engine is properly mounted and configured + +For additional troubleshooting help, check the application logs and refer to the specific cloud provider or service documentation. diff --git a/content/relayer/1.1.x/configuration/storage.mdx b/content/relayer/1.1.x/configuration/storage.mdx new file mode 100644 index 00000000..6a471e8e --- /dev/null +++ b/content/relayer/1.1.x/configuration/storage.mdx @@ -0,0 +1,150 @@ +--- +title: Storage Configuration +--- + +## Overview + +OpenZeppelin Relayer supports two storage backends for persisting configuration data and transaction state. The choice of storage backend affects how configuration is managed, data persistence, and performance characteristics. + + + + +Storage type determines how your configuration changes persist and how file-based and API-based configuration interact. Choose the right storage type for your deployment needs. + + + + + +***Community Contributions Welcome***: Additional storage backends (such as PostgreSQL, MongoDB, or other databases) are welcomed as contributions from the open source community. The storage system is designed to be extensible, making it straightforward to add new storage implementations. + + +## Storage Types + +### In-Memory Storage + +In-memory storage keeps all configuration and transaction data in the application’s memory. + +#### Use Cases +* ***Development and testing environments*** +* ***Temporary deployments*** +* ***Single-instance deployments*** +* ***When data persistence across restarts is not required*** + +#### Characteristics +* ***Fast Performance***: No network overhead for data access +* ***No External Dependencies***: Does not require Redis or other external services +* ***No Persistence***: All data is lost when the container restarts +* ***Single Instance***: Cannot be shared across multiple relayer instances + +#### Configuration Sync Behavior +* Configuration from `config.json` is loaded on every startup +* API changes are ***not*** synchronized back to `config.json` file +* All API-based configuration changes are lost on restart +* File-based configuration always takes precedence on startup + +```bash +# Enable in-memory storage +REPOSITORY_STORAGE_TYPE=in-memory +``` + +### Redis Storage + +Redis storage persists all configuration and transaction data in a Redis database. + +#### Use Cases +* ***Production deployments*** +* ***Multi-instance deployments*** +* ***When data persistence is required*** +* ***Scalable environments*** +* ***When API-based configuration changes should persist*** + +#### Characteristics +* ***Persistent***: Data survives container restarts +* ***Network Dependency***: Requires Redis connection +* ***Encryption***: Supports encryption at rest for sensitive data + +#### Configuration Sync Behavior +* Configuration from `config.json` is loaded into Redis ***only once*** during the first startup +* Subsequent startups use the configuration stored in Redis +* API changes are persisted and survive restarts +* File-based configuration can override Redis by setting `RESET_STORAGE_ON_START=true` + +```bash +# Enable Redis storage +REPOSITORY_STORAGE_TYPE=redis +REDIS_URL=redis://localhost:6379 +STORAGE_ENCRYPTION_KEY=your-encryption-key-here +``` + +## Configuration Reference + +### Core Storage Settings + +| Environment Variable | Default Value | Accepted Values | Description | +| --- | --- | --- | --- | +| `REPOSITORY_STORAGE_TYPE` | `in-memory` | `in-memory, redis` | Type of storage backend used for storing configuration and transaction data. | +| `RESET_STORAGE_ON_START` | `false` | `true, false` | When `true`, clears all data from storage on startup and reloads from config files. Useful for forcing file-based configuration to override stored data. | +| `TRANSACTION_EXPIRATION_HOURS` | `4` | `number` | Number of hours after which transactions in a final state are automatically removed from storage to prevent storage bloat. | + +### Redis-Specific Settings + +| Environment Variable | Default Value | Accepted Values | Description | +| --- | --- | --- | --- | +| `REDIS_URL` | `redis://localhost:6379` | Redis connection string | Full connection URL for the Redis instance. Supports Redis, Redis Sentinel, and Redis Cluster configurations. | +| `REDIS_CONNECTION_TIMEOUT_MS` | `10000` | `number` (milliseconds) | Maximum time to wait when connecting to Redis before timing out. | +| `REDIS_KEY_PREFIX` | `oz-relayer` | `string` | Prefix added to all Redis keys. Useful for namespacing when sharing Redis with other applications. | +| `STORAGE_ENCRYPTION_KEY` | `` | `string` (base64) | Encryption key used to encrypt sensitive data at rest in Redis. Generate using `cargo run --example generate_encryption_key`. | + +## Security Considerations + +### Redis Security + + + + +When using Redis storage in production: + +* ***Use encryption at rest***: Always set `STORAGE_ENCRYPTION_KEY` +* ***Secure Redis access***: Use Redis AUTH, TLS, and network security +* ***Network isolation***: Deploy Redis in a private network +* ***Regular backups***: Implement Redis backup strategy +* ***Monitor access***: Log and monitor Redis access patterns + + + +### Encryption at Rest + +Sensitive configuration data is encrypted before being stored in Redis when `STORAGE_ENCRYPTION_KEY` is provided. + +***Encrypted Data Includes:*** +- Signer private keys and passphrases +- Webhook signing keys +- API keys (when stored in configuration) +- Other sensitive configuration values + +***Generate Encryption Key:*** +```bash +# Generate a secure encryption key +cargo run --example generate_encryption_key + +# Alternative using OpenSSL +openssl rand -base64 32 +``` + +## Transaction Storage Management + +### Automatic Cleanup + +Transactions are automatically removed from storage after reaching their final state to prevent storage bloat: + +```bash +# Configure transaction retention (default: 4 hours) +TRANSACTION_EXPIRATION_HOURS=8 +``` + +***Final Transaction States:*** + +* `confirmed` - Transaction confirmed on blockchain +* `failed` - Transaction failed and will not be retried +* `cancelled` - Transaction was cancelled by user +* `expired`: - Transaction was expired diff --git a/content/relayer/1.1.x/evm.mdx b/content/relayer/1.1.x/evm.mdx new file mode 100644 index 00000000..36b326a7 --- /dev/null +++ b/content/relayer/1.1.x/evm.mdx @@ -0,0 +1,306 @@ +--- +title: EVM Integration +--- + +## Overview + +OpenZeppelin Relayer provides comprehensive support for EVM (Ethereum Virtual Machine) networks, enabling secure transaction relaying, advanced gas management, EIP-1559 support, and robust fee estimation. This page covers everything you need to get started and make the most of EVM-specific features. + +## Features + +* Advanced gas price management with EIP-1559 support +* Dynamic gas limit estimation with fallback mechanisms +* Transaction replacement and acceleration +* Multi-network support (Ethereum, Arbitrum, Optimism, BSC, Polygon, etc.) +* Custom RPC endpoints with load balancing and failover +* Secure transaction signing with multiple signer backends +* Transaction status monitoring and confirmation tracking +* Whitelist-based security policies +* Metrics and observability + +## Supported Networks + +EVM networks are defined via JSON configuration files, providing flexibility to: + +* Configure any EVM-compatible network (Ethereum, Polygon, BSC, Arbitrum, Optimism, etc.) +* Set up custom EVM-compatible networks with specific RPC endpoints +* Create network variants using inheritance from base configurations +* Support both Layer 1 and Layer 2 networks + +For detailed network configuration options, see the [Network Configuration](/relayer/1.1.x/network_configuration) guide. + +## Supported Signers + +* `local` (local keystore files) +* `vault` (HashiCorp Vault secret storage) +* `vault_cloud` (hosted HashiCorp Vault) +* `turnkey` (hosted Turnkey signer) +* `google_cloud_kms` (Google Cloud KMS) +* `aws_kms` (Amazon AWS KMS) + +For detailed signer configuration options, see the [Signers](/relayer/1.1.x/configuration/signers) guide. + + + +In production systems, hosted signers (AWS KMS, Google Cloud KMS, Turnkey) are recommended for the best security model. + + +## Quickstart + +For a step-by-step setup, see [Quick Start Guide](/relayer/1.1.x/quickstart). +Key prerequisites: + +* Rust 2021, version `1.86` or later +* Redis +* Docker (optional) + +Example configuration for an EVM relayer: +```json +{ + "id": "sepolia-example", + "name": "Sepolia Example", + "network": "sepolia", + "paused": false, + "notification_id": "notification-example", + "signer_id": "local-signer", + "network_type": "evm", + "custom_rpc_urls": [ + { + "url": "https://primary-rpc.example.com", + "weight": 100 + }, + { + "url": "https://backup-rpc.example.com", + "weight": 100 + } + ], + "policies": { + "gas_price_cap": 100000000000, + "eip1559_pricing": true, + "gas_limit_estimation": true, + "whitelist_receivers": [ + "0x1234567890123456789012345678901234567890", + "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd" + ], + "min_balance": 1000000000000000000 + } +} +``` + +For more configuration examples, visit the [OpenZeppelin Relayer examples repository](https://github.com/OpenZeppelin/openzeppelin-relayer/tree/main/examples). + +## Configuration + +### Relayer Policies + +In addition to standard relayer configuration and policies, EVM relayers support additional options: + +* `gas_price_cap`: Maximum gas price limit (in wei) for transactions +* `gas_limit_estimation`: Enable/disable automatic gas limit estimation +* `whitelist_receivers`: List of authorized contract addresses for transactions +* `min_balance`: Minimum balance required for the relayer to operate (in wei) +* `eip1559_pricing`: Enable/disable EIP-1559 pricing methodology for transaction fees + +You can check all options in [User Documentation - Relayers](/relayer/1.1.x#3-relayers). + +### Gas Management Configuration + +#### Gas Price Cap +Set a maximum gas price to protect against extreme network congestion: + +```json +{ + "policies": { + "gas_price_cap": 100000000000 + } +} +``` + +#### Gas Limit Estimation +Enable or disable automatic gas limit estimation: + +```json +{ + "policies": { + "gas_limit_estimation": true + } +} +``` + +When disabled, gas limits must be provided explicitly in transaction requests. + +The relayer uses a two-tier approach for gas limit estimation: + +1. ***Primary Method***: Uses the RPC `estimate_gas` method to calculate gas requirements + * The estimated value is increased by 10% as a safety buffer + * Provides accurate estimates for most transaction types +2. ***Fallback Method***: When RPC estimation fails, default gas limits are applied based on transaction type: + * ***Simple ETH transfer*** (no data): 21,000 gas + * ***ERC20 transfer*** (`0xa9059cbb`): 65,000 gas + * ***ERC721/ERC20 transferFrom*** (`0x23b872dd`): 80,000 gas + * ***Complex contracts*** (all other function calls): 200,000 gas + + + +For advanced users working with complex transactions or custom contracts, it is recommended to include an explicit `gas_limit` parameter in the transaction request to ensure optimal gas usage and avoid estimation errors. + + +#### Whitelist Receivers +Restrict transactions to specific contract addresses: + +```json +{ + "policies": { + "whitelist_receivers": [ + "0x1234567890123456789012345678901234567890", + "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd" + ] + } +} +``` + +## API Reference + +The EVM API provides comprehensive transaction management capabilities. + +Common endpoints: + +* `POST /api/v1/relayers//transactions` send transaction +* `GET /api/v1/relayers//transactions` list transactions +* `GET /api/v1/relayers//transactions/` get transaction by id + +### Send Transaction - Speed params + +```bash +curl --location --request POST 'http://localhost:8080/api/v1/relayers/solana-example/transactions' \ +--header 'Authorization: Bearer ' \ +--header 'Content-Type: application/json' \ +--data-raw '{ + "value": 1, + "data": "0x", + "to": "0xd9b55a2ba539031e3c18c9528b0dc3a7f603a93b", + "speed": "average" +}' +``` + +### Send Transaction - Speed params with gas limit included + +```bash +curl --location --request POST 'http://localhost:8080/api/v1/relayers/solana-example/transactions' \ +--header 'Authorization: Bearer ' \ +--header 'Content-Type: application/json' \ +--data-raw '{ + "value": 1, + "data": "0x", + "to": "0xd9b55a2ba539031e3c18c9528b0dc3a7f603a93b", + "speed": "average", + "gas_limit": 21000 +}' +``` + +### Transaction with EIP-1559 Pricing + +```bash +curl --location --request POST 'http://localhost:8080/api/v1/relayers/solana-example/transactions' \ +--header 'Authorization: Bearer ' \ +--header 'Content-Type: application/json' \ +--data-raw '{ + "value": 1, + "data": "0x", + "to": "0xd9b55a2ba539031e3c18c9528b0dc3a7f603a93b", + "max_fee_per_gas": 30000000000, + "max_priority_fee_per_gas": 20000000000 +}' +``` + +### Transaction with Legacy Pricing - gas estimation included + +```bash +curl --location --request POST 'http://localhost:8080/api/v1/relayers/solana-example/transactions' \ +--header 'Authorization: Bearer ' \ +--header 'Content-Type: application/json' \ +--data-raw '{ + "value": 1, + "data": "0x", + "to": "0xd9b55a2ba539031e3c18c9528b0dc3a7f603a93b", + "gas_price": "12312313123" +}' +``` + +### Get Transaction Status + +```bash +curl --location --request GET 'http://localhost:8080/api/v1/relayers/solana-example/transactions/' \ +--header 'Authorization: Bearer ' +``` + +See [API Reference](https://release-v1-0-0%2D%2Dopenzeppelin-relayer.netlify.app/api_docs.html) for full details and examples. + +## Transaction Lifecycle + +### 1. Transaction Submission +* Validate transaction parameters +* Check whitelist policies (if enabled) +* Estimate gas limit (if not provided) +* Calculate gas price based on network conditions + +### 2. Transaction Signing +* Sign transaction using configured signer +* Generate appropriate signature format + +### 3. Transaction Broadcasting +* Submit to network via RPC endpoints +* Handle RPC failures with automatic retries +* Switch to backup RPC endpoints if needed + +### 4. Transaction Monitoring +* Track transaction status and confirmations +* Handle transaction replacements if needed +* Send notifications on status changes + +### 5. Transaction Confirmation +* Wait for required number of confirmations +* Mark transaction as confirmed or failed +* Clean up resources + +## Security Best Practices + +### Network Security +* Use private RPC endpoints in production +* Configure appropriate `gas_price_cap` to prevent excessive fees +* Enable `whitelist_receivers` for controlled environments +* Monitor relayer balance and set appropriate `min_balance` + +### Signer Security +* Use hosted signers (AWS KMS, Google Cloud KMS, Turnkey) in production +* Rotate signer keys regularly +* Implement proper access controls and audit logging +* Never store private keys in plain text + +### Operational Security +* Deploy behind a secure reverse proxy +* Use HTTPS for all communications +* Implement proper rate limiting +* Monitor for unusual transaction patterns + +### Monitoring and Observability + +Enable metrics and monitor: + +* Transaction success rates +* Gas price trends +* RPC endpoint performance +* Relayer balance levels +* Failed transaction patterns + +## Support + +For help with EVM integration: + +* Join our [Telegram](https://t.me/openzeppelin_tg/2) community +* Open an issue on our [GitHub repository](https://github.com/OpenZeppelin/openzeppelin-relayer) +* Check our [comprehensive documentation](https://docs.openzeppelin.com/relayer) + +## License + +This project is licensed under the GNU Affero General Public License v3.0. diff --git a/content/relayer/1.1.x/index.mdx b/content/relayer/1.1.x/index.mdx new file mode 100644 index 00000000..50ebabe4 --- /dev/null +++ b/content/relayer/1.1.x/index.mdx @@ -0,0 +1,335 @@ +--- +title: OpenZeppelin Relayer +--- + +## Overview + +OpenZeppelin Relayer is a service that provides infrastructure to relay transactions to the EVM & Non-EVM networks. It is designed to be used as a backend for dApps that need to interact with these networks. + +## Features + +* ***Multi-Chain Support***: Interact with multiple blockchain networks, including Solana and EVM-based chains. +* ***Transaction Relaying***: Submit transactions to supported blockchain networks efficiently. +* ***Transaction Signing***: Securely sign transactions using configurable key management. +* ***Transaction Fee Estimation***: Estimate transaction fees for better cost management. +* ***Solana Gasless Transactions***: Support for gasless transactions on Solana, enabling users to interact without transaction fees. +* ***Transaction Nonce Management***: Handle nonce management to ensure transaction order. +* ***Transaction Status Monitoring***: Track the status of submitted transactions. +* ***SDK Integration***: Easily interact with the relayer through our companion JavaScript/TypeScript SDK. +* ***Extensible Architecture***: Easily add support for new blockchain networks. +* ***Configurable Network Policies***: Define and enforce network-specific policies for transaction processing. +* ***Metrics and Observability***: Monitor application performance using Prometheus and Grafana. +* ***Docker Support***: Deploy the relayer using Docker for both development and production environments. +* ***Plugins***: Extend the functionality of the relayer with custom logic using TypeScript functions. + +## Supported Networks + +OpenZeppelin Relayer supports multiple blockchain networks through a flexible JSON-based configuration system. Networks are defined in configuration files, allowing you to configure: + +* ***Any EVM-compatible network*** (Ethereum, Polygon, BSC, Arbitrum, Optimism, etc.) +* ***Solana networks*** (mainnet-beta, devnet, testnet, custom RPC endpoints) +* ***Stellar networks*** (Pubnet, Testnet, custom networks) +* ***Create custom network configurations*** with specific RPC endpoints, chain IDs, and network parameters +* ***Use inheritance*** to create network variants that inherit from base configurations + +### Network Types + +| Network Type | Description | +| --- | --- | +| `evm` | Ethereum Virtual Machine compatible networks. Supports any EVM chain by configuring chain ID, RPC URLs, and network-specific parameters. | +| `solana` | Solana blockchain networks. Supports all Solana clusters and custom RPC endpoints. | +| `stellar` | Stellar blockchain networks (Partial support). Supports Stellar Public Network and Testnet. | + +Networks can be loaded from: + +* ***JSON arrays***: Direct network definitions in configuration files +* ***Directory of files***: Multiple JSON files each containing network definitions + +For detailed network configuration options and examples, see the [Network Configuration](/relayer/1.1.x/network_configuration) page. + + + +For information about our development plans and upcoming features, see [Project Roadmap](/relayer/1.1.x/roadmap). + + + + +To get started immediately, see [Quickstart](/relayer/1.1.x/quickstart). + + +## Technical Overview + +```mermaid +flowchart TB + subgraph "Clients" + client[API/SDK] + end + + subgraph "OpenZeppelin Relayer" + subgraph "API Layer" + api[API Routes & Controllers] + middleware[Middleware] + plugins[Plugins] + end + + subgraph "Domain Layer" + domain[Domain Logic] + relayer[Relayer Services] + policies[Policy Enforcement] + end + + subgraph "Infrastructure" + repositories[Repositories] + jobs[Job Queue System] + signer[Signer Services] + provider[Network Providers] + end + + subgraph "Services Layer" + transaction[Transaction Services] + vault[Vault Services] + webhook[Webhook Notifications] + monitoring[Monitoring & Metrics] + end + + subgraph "Configuration" + config_files[Config Files] + env_vars[Environment Variables] + end + end + + subgraph "External Systems" + blockchain[Blockchain Networks] + redis[Redis] + vault_ext[HashiCorp Vault] + metrics[Prometheus/Grafana] + notification[Notification Services] + end + + %% Client connections + client -- "HTTP Requests" --> api + + %% API Layer connections + api -- "Processes requests" --> middleware + middleware -- "Validates & routes" --> domain + middleware -- "Invokes" --> plugins + + %% Domain Layer connections + domain -- "Uses" --> relayer + domain -- "Enforces" --> policies + relayer -- "Processes" --> transaction + plugins -- "Interacts with" --> relayer + + %% Services Layer connections + transaction -- "Signs with" --> signer + transaction -- "Connects via" --> provider + transaction -- "Queues jobs" --> jobs + webhook -- "Notifies" --> notification + monitoring -- "Collects" --> metrics + signer -- "May use" --> vault + + %% Infrastructure connections + repositories -- "Stores data" --> redis + jobs -- "Processes async" --> redis + vault -- "Secrets management" --> vault_ext + provider -- "Interacts with" --> blockchain + + %% Configuration connections + config_files -- "Configures" --> domain + env_vars -- "Configures" --> domain + + %% Styling + classDef apiClass fill:#f9f,stroke:#333,stroke-width:2px + classDef domainClass fill:#bbf,stroke:#333,stroke-width:2px + classDef infraClass fill:#bfb,stroke:#333,stroke-width:2px + classDef serviceClass fill:#fbf,stroke:#333,stroke-width:2px + classDef configClass fill:#fbb,stroke:#333,stroke-width:2px + classDef externalClass fill:#ddd,stroke:#333,stroke-width:1px + + class api,middleware,plugins apiClass + class domain,relayer,policies domainClass + class repositories,jobs,signer,provider infraClass + class transaction,vault,webhook,monitoring serviceClass + class config_files,env_vars configClass + class blockchain,redis,vault_ext,metrics,notification externalClass +``` + +## Project Structure + +The project follows a standard Rust project layout: + +``` +openzeppelin-relayer/ +β”œβ”€β”€ src/ +β”‚ β”œβ”€β”€ api/ # Route and controllers logic +β”‚ β”œβ”€β”€ bootstrap/ # Service initialization logic +β”‚ β”œβ”€β”€ config/ # Configuration logic +β”‚ β”œβ”€β”€ constants/ # Constant values used in the system +β”‚ β”œβ”€β”€ domain/ # Domain logic +β”‚ β”œβ”€β”€ jobs/ # Asynchronous processing logic (queueing) +β”‚ β”œβ”€β”€ logging/ # Logs File rotation logic +β”‚ β”œβ”€β”€ metrics/ # Metrics logic +β”‚ β”œβ”€β”€ models/ # Data structures and types +β”‚ β”œβ”€β”€ repositories/ # Configuration storage +β”‚ β”œβ”€β”€ services/ # Services logic +β”‚ └── utils/ # Helper functions +β”‚ +β”œβ”€β”€ config/ # Configuration files +β”œβ”€β”€ tests/ # Integration tests +β”œβ”€β”€ docs/ # Documentation +β”œβ”€β”€ scripts/ # Utility scripts +β”œβ”€β”€ examples/ # Configuration examples +β”œβ”€β”€ helpers/ # Rust helper scripts +β”œβ”€β”€ plugins/ # Plugins directory +└── ... other root files (Cargo.toml, README.md, etc.) +``` + +For detailed information about each directory and its contents, see [Project Structure Details](/relayer/1.1.x/structure). + +## Getting Started + +### Prerequisites + +* Rust 2021 edition, version `1.86` or later +* Docker (optional, for containerized deployment) +* Node.js, typescript and ts-node (optional, for plugins) + + + +**Ready-to-Use Example Configurations** + +For quick setup with various configurations, check the [examples directory](https://github.com/OpenZeppelin/openzeppelin-relayer/tree/main/examples) in our GitHub repository: + +* `basic-example`: Simple setup with Redis +* `basic-example-logging`: Configuration with file-based logging +* `basic-example-metrics`: Setup with Prometheus and Grafana metrics +* `vault-secret-signer`: Using HashiCorp Vault for key management +* `vault-transit-signer`: Using Vault Transit for secure signing +* `evm-gcp-kms-signer`: Using Google Cloud KMS for EVM secure signing +* `evm-turnkey-signer`: Using Turnkey for EVM secure signing +* `solana-turnkey-signer`: Using Turnkey for Solana secure signing +* `redis-storage`: Using Redis for Storage +* `network-configuration-config-file`: Using Custom network configuration via config file +* `network-configuration-json-file`: Using Custom network configuration via JSON file + +Each example includes a README with step-by-step instructions and Docker Compose configuration. + + +### Install Locally + +1. Clone the repository: + + ```bash + git clone https://github.com/openzeppelin/openzeppelin-relayer + cd openzeppelin-relayer + ``` +2. Verify you have sodium libs installed. If not, follow these instructions: + + * Install a stable libsodium version from [here](https://download.libsodium.org/libsodium/releases/). + * Follow the steps in the [libsodium installation guide](https://doc.libsodium.org/installation). +3. Install dependencies: + + ```bash + cargo build + ``` + +## Running the Relayer + +### Option 1: Run Locally + +```bash +cargo run +``` + + +Before executing the command, ensure that the `.env` and `config.json` files are configured as detailed in the [Configuration References](/relayer/1.1.x/configuration) section. + + +### Option 2: Run with Docker + +The Relayer can be run as either a development or production container using the corresponding Dockerfile (`Dockerfile.development` or `Dockerfile.production`). + +#### Step 1: Configure Environment + +* Edit `.env` at the root of the repository to adjust environment variables +* The appropriate .env file will be included during image build + +#### Step 2: Build the Image + +You can build using Docker Compose (v2). + +```bash +# Default build +docker compose build + +# Or, for a leaner image (and using Dockerfile.production) +DOCKERFILE=Dockerfile.production docker compose build +``` + +#### Step 3: Run the Container + +Use Docker Compose to run the container: + +```bash +docker compose up -d +``` + +For production runs, you can use: + +```bash +DOCKERFILE=Dockerfile.production docker compose up -d +``` + +## Configuration + +OpenZeppelin Relayer supports two configuration approaches: + +***File-based Configuration:*** +- ***`config.json`***: Contains relayer definitions, signer configurations, and network policies +- ***`.env`***: Contains environment variables like API keys and connection strings + +***API-based Configuration:*** +- Runtime configuration management via REST API +- No service restarts required for configuration changes +- Full CRUD operations for relayers, signers, and notifications + + + + +Both approaches can be used together. File-based configuration is loaded on startup, while API changes provide runtime flexibility. Changes to environment variables (`.env`) always require restarting the container. + +When used together, API changes are not synced to file-based configuration. File-based configuration is loaded only once when using persistent storage mode. + +For quick setup examples with pre-configured files, see the [examples directory](https://github.com/OpenZeppelin/openzeppelin-relayer/tree/main/examples) in our GitHub repository. + + + +For comprehensive configuration details, including: + +* Environment variables and their settings +* Main configuration file structure +* Signer configurations (local, vault, cloud KMS, etc.) +* Notification setup +* Relayer policies and network settings +* Plugin configuration +* Complete configuration examples + +See the dedicated [Configuration Guide](/relayer/1.1.x/configuration). + +## Important Considerations + +## Deployment Considerations + + +The OpenZeppelin Relayer is designed to function as a backend service and is not meant to be directly exposed to the public internet. To protect the service from unauthorized access, deploy it behind your own secure backend infrastructureβ€”such as a reverse proxy or firewallβ€”and restrict access to trusted internal components only. Direct exposure can increase the risk of exploitation and security breaches. + + +## Support + +For support or inquiries, contact us on [Telegram](https://t.me/openzeppelin_tg/2). + +## License +This project is licensed under the GNU Affero General Public License v3.0 - see the LICENSE file for details. + +## Security +For security concerns, please refer to our [Security Policy](https://github.com/OpenZeppelin/openzeppelin-relayer/blob/main/SECURITY.md). diff --git a/content/relayer/1.1.x/network_configuration.mdx b/content/relayer/1.1.x/network_configuration.mdx new file mode 100644 index 00000000..725f5e99 --- /dev/null +++ b/content/relayer/1.1.x/network_configuration.mdx @@ -0,0 +1,387 @@ +--- +title: Network Configuration +--- + +The OpenZeppelin Relayer supports multiple blockchain networks through a flexible JSON-based configuration system. This guide covers everything you need to know about configuring networks for your relayer instances. + +## Overview + +Networks are defined in JSON configuration files, allowing you to: + +* Configure ***any EVM-compatible network*** (Ethereum, Polygon, BSC, Arbitrum, Optimism, etc.) +* Set up ***Solana networks*** (mainnet-beta, devnet, testnet, custom RPC endpoints) +* Configure ***Stellar networks*** (Pubnet, Testnet, custom networks) +* Create ***custom network configurations*** with specific RPC endpoints, chain IDs, and network parameters +* Use ***inheritance*** to create network variants without duplicating configuration + +## Network Types + +| Network Type | Description | +| --- | --- | +| `evm` | Ethereum Virtual Machine compatible networks. Supports any EVM chain by configuring chain ID, RPC URLs, and network-specific parameters. | +| `solana` | Solana blockchain networks. Supports all Solana clusters and custom RPC endpoints. | +| `stellar` | Stellar blockchain networks. Supports Stellar Public Network and Testnet. | + +## Configuration Methods + +### Default Network Configuration + +If no `networks` field is specified in your `config.json`, the relayer will automatically load network configurations from the `./config/networks` directory. This is the default behavior. + +```json + + "relayers": [...], + "notifications": [...], + "signers": [...] + // No "networks" field - defaults to "./config/networks" + +``` + + +Once you specify a `networks` field in your configuration, the default `./config/networks` directory will ***not*** be loaded automatically. If you want to use files from that directory, you must explicitly specify the path `"./config/networks"`. + + +You can configure networks in two ways: + +### Method 1: Separate JSON Files + +Specify the path to network configuration files in your main `config.json`: + +```json + + "relayers": [...], + "notifications": [...], + "signers": [...], + "networks": "./config/networks" // Path to directory or file + +``` + + +This is the same as the default behavior, but explicitly specified. You can also point to a different directory or file path. + + +Each JSON file ***must*** contain a top-level `networks` array: + +```json + + "networks": [ + // ... network definitions ... + ] + +``` + +When using a directory structure: +``` +networks/ +β”œβ”€β”€ evm.json # "networks": [...] +β”œβ”€β”€ solana.json # "networks": [...] +└── stellar.json # "networks": [...] +``` + +### Method 2: Direct Configuration + +Define networks directly in your main `config.json` instead of using separate files: + +```json + + "relayers": [...], + "notifications": [...], + "signers": [...], + "networks": [ + { + "type": "evm", + "network": "ethereum-mainnet", + "chain_id": 1, + // ... other fields + + ] +} +``` + +When using this method, the default `./config/networks` directory is ignored, and only the networks defined in this array will be available. + +## Network Field Reference + +### Common Fields + +All network types support these configuration fields: + +| Field | Type | Required | Description | +| --- | --- | --- | --- | +| `type` | string | Yes | Network type: `"evm"`, `"solana"`, or `"stellar"` | +| `network` | string | Yes | Unique network identifier (e.g., "ethereum-mainnet", "polygon-mumbai") | +| `from` | string | No | Name of parent network to inherit from (same type only) | +| `rpc_urls` | array[string] | Yes* | List of RPC endpoint URLs (*Required for base networks, optional for inherited) | +| `explorer_urls` | array[string] | No | List of blockchain explorer URLs | +| `average_blocktime_ms` | number | No | Estimated average time between blocks in milliseconds | +| `is_testnet` | boolean | No | Whether this is a testnet (affects behavior and validation) | +| `tags` | array[string] | No | Arbitrary tags for categorization and filtering | + +### Special Network Tags + +Some tags have special meaning and affect relayer behavior: + +| Tag | Description and Behavior | +| --- | --- | +| `rollup` | Identifies Layer 2 rollup networks (e.g., Arbitrum, Optimism, Base) | +| `optimism` | Identifies Optimism-based networks using the OP Stack (e.g., Optimism, Base, World Chain) | +| `arbitrum-based` | Identifies Arbitrum-based networks using the Arbitrum Stack | +| `no-mempool` | Indicates networks that lack a traditional mempool (e.g., Arbitrum) | +| `deprecated` | Marks networks that are deprecated and may be removed in future versions | + +#### Example: Using Special Tags + +Here’s an example showing how special tags are used in practice: + +```json + + "type": "evm", + "network": "arbitrum-one", + "chain_id": 42161, + "required_confirmations": 1, + "symbol": "ETH", + "rpc_urls": ["https://arb1.arbitrum.io/rpc"], + "tags": ["rollup", "no-mempool"], // Arbitrum is a rollup without mempool + "is_testnet": false + +``` + +These tags help the relayer: + +* Apply specific transaction handling for rollups +* Use optimized fee calculation for OP Stack chains +* Skip mempool-related operations for networks without mempools +* Warn users about deprecated networks + +### EVM-Specific Fields + + +The OpenZeppelin Relayer supports any EVM-based L1 blockchain, as long as it doesn’t deviate significantly from standard EVM behavior. Some L2 networks may also work, depending on how closely they follow EVM conventions. Users are encouraged to add the networks they need via the JSON configuration and test them thoroughly on testnets before deploying to production. + + +| Field | Type | Required | Description | +| --- | --- | --- | --- | +| `chain_id` | number | Yes* | Unique chain identifier (e.g., 1 for Ethereum mainnet, 137 for Polygon) (*Required for base networks, optional for inherited) | +| `required_confirmations` | number | Yes* | Number of block confirmations before considering a transaction final (*Required for base networks, optional for inherited) | +| `symbol` | string | Yes* | Native currency symbol (e.g., "ETH", "MATIC", "BNB") (*Required for base networks, optional for inherited) | +| `features` | array[string] | No | Supported features (e.g., ["eip1559", "london"]) | + +#### Example: EVM Network Configuration + +Here’s an example showing an EVM network configuration: + +```json + + "type": "evm", + "network": "ethereum-mainnet", + "chain_id": 1, // Ethereum mainnet chain ID + "required_confirmations": 12, // High security: 12 confirmations + "symbol": "ETH", // Native currency symbol + "features": ["eip1559"], // Supports EIP-1559 fee market + "rpc_urls": ["https://mainnet.infura.io/v3/YOUR_KEY"], + "is_testnet": false + +``` + +### Solana-Specific Fields + +Currently, Solana networks use only the common fields. Additional Solana-specific configuration options may be added in future versions. + +### Stellar-Specific Fields + +| Field | Type | Required | Description | +| --- | --- | --- | --- | +| `passphrase` | string | No | Network passphrase for transaction signing and network identification (optional for all networks, including base networks) | + +#### Example: Stellar Network Configuration + +Here’s an example showing a Stellar network configuration with passphrase: + +```json + + "type": "stellar", + "network": "pubnet", + "rpc_urls": ["https://mainnet.sorobanrpc.com"], + "explorer_urls": ["https://stellar.expert/explorer/public"], + "passphrase": "Public Global Stellar Network ; September 2015", // Official mainnet passphrase + "average_blocktime_ms": 5000, + "is_testnet": false + +``` + +## Configuration Examples + +### Basic EVM Network + +```json + + "type": "evm", + "network": "ethereum-mainnet", + "chain_id": 1, + "required_confirmations": 12, + "symbol": "ETH", + "rpc_urls": ["https://mainnet.infura.io/v3/YOUR_KEY"], + "explorer_urls": ["https://etherscan.io"], + "average_blocktime_ms": 12000, + "is_testnet": false, + "tags": ["mainnet", "ethereum"] + +``` + +### Layer 2 EVM Network with Tags + +```json + + "type": "evm", + "network": "optimism", + "chain_id": 10, + "required_confirmations": 1, + "symbol": "ETH", + "rpc_urls": [ + "https://mainnet.optimism.io", + "https://optimism.drpc.org" + ], + "features": ["eip1559"], + "tags": ["rollup", "optimism"], + "average_blocktime_ms": 2000, + "is_testnet": false + +``` + +### Solana Network + +```json + + "type": "solana", + "network": "mainnet-beta", + "rpc_urls": ["https://api.mainnet-beta.solana.com"], + "explorer_urls": ["https://explorer.solana.com"], + "average_blocktime_ms": 400, + "is_testnet": false, + "tags": ["mainnet", "solana"] + +``` + +### Stellar Network + +```json + + "type": "stellar", + "network": "pubnet", + "rpc_urls": ["https://mainnet.sorobanrpc.com"], + "passphrase": "Public Global Stellar Network ; September 2015", + "explorer_urls": ["https://stellar.expert/explorer/public"], + "average_blocktime_ms": 5000, + "is_testnet": false, + "tags": ["mainnet", "stellar"] + +``` + +## Network Inheritance + +Networks can inherit from other networks of the same type, allowing you to create variants without duplicating configuration: + +```json + + "networks": [ + { + "type": "evm", + "network": "ethereum-base", + "chain_id": 1, + "required_confirmations": 12, + "symbol": "ETH", + "rpc_urls": ["https://mainnet.infura.io/v3/YOUR_KEY"] + , + + "from": "ethereum-base", + "type": "evm", + "network": "ethereum-sepolia", + "chain_id": 11155111, + "required_confirmations": 3, + "rpc_urls": ["https://sepolia.infura.io/v3/YOUR_KEY"], + "is_testnet": true + + ] +} +``` + +When using inheritance: + +* The child network inherits all fields from the parent +* Fields specified in the child override parent values +* The `from` field must reference a network of the same type + +## Using Networks in Relayer Configuration + +Once networks are defined, reference them in your relayer configurations: + +```json + + "relayers": [ + { + "id": "my-evm-relayer", + "name": "My EVM Relayer", + "network": "ethereum-mainnet", // References network ID + "network_type": "evm", + "signer_id": "my-signer" + + ] + } +} +``` + +## Best Practices + +### 1. Network Organization +* Group related networks in separate files (e.g., `ethereum.json`, `polygon.json`) +* Use consistent naming conventions for network identifiers +* Include both mainnet and testnet configurations + +### 2. RPC URLs +* Always configure multiple RPC URLs for redundancy +* Use private/dedicated RPC endpoints for production +* Ensure URLs are secure (HTTPS) when accessing over public networks + +### 3. Confirmation Requirements +* Set appropriate `required_confirmations` based on network security +* Higher values for mainnet, lower for testnets +* Consider network-specific finality characteristics + +### 4. Tags and Features +* Use tags to categorize networks (e.g., "mainnet", "testnet", "rollup") +* Enable appropriate features (e.g., "eip1559" for supported networks) +* Document custom tags used in your organization + +### 5. Inheritance +* Create base configurations for common settings +* Use inheritance to reduce duplication +* Override only necessary fields in child networks + +## Troubleshooting + +### Common Issues + +***Network not found:*** + +* Ensure the network identifier in relayer config matches exactly +* Check that network configuration files are in the correct location +* Verify JSON syntax is valid + +***RPC connection failures:*** + +* Test RPC URLs independently before configuring +* Ensure firewall/network allows outbound HTTPS connections +* Check API keys are included in RPC URLs where required + +***Invalid configuration:*** + +* Validate required fields are present for network type +* Ensure numeric fields (chain_id, confirmations) are numbers, not strings +* Check that inherited networks reference existing parent networks + +## See Also + +* [Relayer Configuration](/relayer/1.1.x/configuration) +* [Quickstart Guide](/relayer/1.1.x/quickstart) +* [Solana Integration](/relayer/1.1.x/solana) +* [API Reference](/relayer/1.1.x/api) diff --git a/content/relayer/1.1.x/plugins.mdx b/content/relayer/1.1.x/plugins.mdx new file mode 100644 index 00000000..d9f55322 --- /dev/null +++ b/content/relayer/1.1.x/plugins.mdx @@ -0,0 +1,433 @@ +--- +title: Plugins +--- + +## Overview + +OpenZeppelin Relayer supports plugins to extend the functionality of the relayer. + +Plugins are `TypeScript` functions running in the Relayer server that can include any arbitrary logic defined by the Relayer operator. + +The plugin system features: +- ***Handler Pattern***: Simple export-based plugin development +- ***TypeScript Support***: Full type safety and IntelliSense +- ***Plugin API***: Clean interface for interacting with relayers +- ***Docker Integration***: Seamless development and deployment +- ***Comprehensive Error Handling***: Detailed logging and debugging capabilities + +## Configuration + +### Writing a Plugin + +Plugins are declared under `plugins` directory, and are expected to be TypeScript files (`.ts` extension). + +```bash +openzeppelin-relayer/ +β”œβ”€β”€ plugins/ +β”‚ └── my-plugin.ts # Plugin code +└── config/ + └── config.json # Plugins in configuration file +``` + +#### Handler Pattern (Recommended) + +This approach uses a simple `handler` export pattern: + +```typescript +/// Required imports. +import { Speed, PluginAPI } from "@openzeppelin/relayer-sdk"; + +/// Define your plugin parameters interface +type MyPluginParams = { + destinationAddress: string; + amount?: number; + message?: string; + relayerId?: string; +}; + +/// Define your plugin return type +type MyPluginResult = { + success: boolean; + transactionId: string; + message: string; +}; + +/// Export a handler function - that's it! +export async function handler(api: PluginAPI, params: MyPluginParams): Promise { + console.info("πŸš€ Plugin started..."); + + // Validate parameters + if (!params.destinationAddress) { + throw new Error("destinationAddress is required"); + } + + // Use the relayer API + const relayer = api.useRelayer(params.relayerId || "my-relayer"); + + const result = await relayer.sendTransaction({ + to: params.destinationAddress, + value: params.amount || 1, + data: "0x", + gas_limit: 21000, + speed: Speed.FAST, + }); + + console.info(`Transaction submitted: ${result.id}`); + + // Wait for confirmation + await result.wait({ + interval: 5000, // Check every 5 seconds + timeout: 120000 // Timeout after 2 minutes + }); + + return { + success: true, + transactionId: result.id, + message: `Successfully sent ${params.amount || 1} wei to ${params.destinationAddress}` + }; +} +``` + +#### Legacy Pattern (Deprecated, but supported) + + +The `runPlugin()` pattern is deprecated and will be removed in a future version. Please migrate to the handler export pattern above. Legacy plugins will continue to work but will show deprecation warnings. + + +```typescript +import { runPlugin, PluginAPI } from "./lib/plugin"; + +async function myPlugin(api: PluginAPI, params: any) { + // Plugin logic here + return "result"; +} + +runPlugin(myPlugin); // ⚠️ Deprecated - shows warning but still works +``` + +***Example legacy plugin*** (`plugins/examples/example-deprecated.ts`): +```typescript +import { PluginAPI, runPlugin } from "../lib/plugin"; +import { Speed } from "@openzeppelin/relayer-sdk"; + +type Params = { + destinationAddress: string; +}; + +async function example(api: PluginAPI, params: Params): Promise { + console.info("Plugin started..."); + + const relayer = api.useRelayer("sepolia-example"); + const result = await relayer.sendTransaction({ + to: params.destinationAddress, + value: 1, + data: "0x", + gas_limit: 21000, + speed: Speed.FAST, + }); + + await result.wait(); + return "done!"; +} + +runPlugin(example); +``` + +### Declaring in config file + +Plugins are configured in the `./config/config.json` file, under the `plugins` key. + +The file contains a list of plugins, each with an id, path and timeout in seconds (optional). + + +The plugin path is relative to the `/plugins` directory + + +Example: + +```json +{ +"plugins": [ + { + "id": "my-plugin", + "path": "my-plugin.ts", + "timeout": 30 + } +] +} +``` + +### Timeout + +The timeout is the maximum time **in seconds** that the plugin can run. If the plugin exceeds the timeout, it will be terminated with an error. + +The timeout is optional, and if not provided, the default is 300 seconds (5 minutes). + +## Plugin Development Guidelines + +### TypeScript Best Practices + +* ***Define Parameter Types***: Always create interfaces or types for your plugin parameters +* ***Define Return Types***: Specify what your plugin returns for better developer experience +* ***Handle Errors Gracefully***: Use try-catch blocks and return structured error responses +* ***Validate Input***: Check required parameters and provide meaningful error messages +* ***Use Async/Await***: Modern async patterns for better readability + +### Testing Your Plugin + +You can test your handler function directly: + +```typescript +import { handler } from './my-plugin'; + +// Mock API for testing (in real scenarios, use proper mocking) +const mockApi = { + useRelayer: (id: string) => ({ + sendTransaction: async (tx: any) => ({ id: "test-tx-123", wait: async () => {} }) + }) +} as any; + +const result = await handler(mockApi, { + destinationAddress: "0x742d35Cc6640C21a1c7656d2c9C8F6bF5e7c3F8A", + amount: 1000 +}); +console.log(result); +``` + +## Invocation + +Plugins are invoked by hitting the `api/v1/plugins/plugin-id/call` endpoint. + +The endpoint accepts a `POST` request. Example post request body: + +```json +{ + "destinationAddress": "0x742d35Cc6640C21a1c7656d2c9C8F6bF5e7c3F8A", + "amount": 1000000000000000, + "message": "Hello from OpenZeppelin Relayer!" +} +``` + +The parameters are passed directly to your plugin's `handler` function. + +## Debugging + +When invoking a plugin, the response will include: + +* `logs`: The logs from the plugin execution. +* `return_value`: The returned value of the plugin execution. +* `error`: An error message if the plugin execution failed. +* `traces`: A list of messages sent between the plugin and the Relayer instance. This includes all the payloads passed through the `PluginAPI` object. + +### Complete Example + +1. ***Plugin Code*** (`plugins/example.ts`): + +```typescript +import { Speed, PluginAPI } from "@openzeppelin/relayer-sdk"; + +type ExampleParams = { + destinationAddress: string; + amount?: number; + message?: string; +}; + +type ExampleResult = { + success: boolean; + transactionId: string; + transactionHash: string | null; + message: string; + timestamp: string; +}; + +export async function handler(api: PluginAPI, params: ExampleParams): Promise { + console.info("πŸš€ Example plugin started"); + console.info(`πŸ“‹ Parameters:`, JSON.stringify(params, null, 2)); + + try { + // Validate parameters + if (!params.destinationAddress) { + throw new Error("destinationAddress is required"); + } + + const amount = params.amount || 1; + const message = params.message || "Hello from OpenZeppelin Relayer!"; + + console.info(`πŸ’° Sending ${amount} wei to ${params.destinationAddress}`); + + // Get relayer and send transaction + const relayer = api.useRelayer("my-relayer"); + const result = await relayer.sendTransaction({ + to: params.destinationAddress, + value: amount, + data: "0x", + gas_limit: 21000, + speed: Speed.FAST, + }); + + console.info(`βœ… Transaction submitted: ${result.id}`); + + // Wait for confirmation + const confirmation = await result.wait({ + interval: 5000, + timeout: 120000 + }); + + console.info(`πŸŽ‰ Transaction confirmed: ${confirmation.hash}`); + + return { + success: true, + transactionId: result.id, + transactionHash: confirmation.hash || null, + message: `Successfully sent ${amount} wei to ${params.destinationAddress}. ${message}`, + timestamp: new Date().toISOString() + }; + + } catch (error) { + console.error("❌ Plugin execution failed:", error); + return { + success: false, + transactionId: "", + transactionHash: null, + message: `Plugin failed: ${(error as Error).message}`, + timestamp: new Date().toISOString() + }; + } +} +``` + +1. ***Plugin Configuration*** (`config/config.json`): + +```json +{ + "plugins": [ + { + "id": "example-plugin", + "path": "example-plugin.ts", + "timeout": 30 + } + ] +} +``` + +1. ***API Invocation***: + +```bash +curl -X POST http://localhost:8080/api/v1/plugins/example-plugin/call \ +-H "Content-Type: application/json" \ +-H "Authorization: Bearer YOUR_API_KEY" \ +-d '{ + "destinationAddress": "0x742d35Cc6640C21a1c7656d2c9C8F6bF5e7c3F8A", + "amount": 1000000000000000, + "message": "Test transaction from plugin" +}' +``` + +1. ***API Response***: + +```json +{ + "success": true, + "message": "Plugin called successfully", + "logs": [ + { + "level": "info", + "message": "πŸš€ Example plugin started" + }, + { + "level": "info", + "message": "πŸ’° Sending 1000000000000000 wei to 0x742d35Cc6640C21a1c7656d2c9C8F6bF5e7c3F8A" + }, + { + "level": "info", + "message": "βœ… Transaction submitted: tx-123456" + }, + { + "level": "info", + "message": "πŸŽ‰ Transaction confirmed: 0xabc123..." + } + ], + "return_value": { + "success": true, + "transactionId": "tx-123456", + "transactionHash": "0xabc123def456...", + "message": "Successfully sent 1000000000000000 wei to 0x742d35Cc6640C21a1c7656d2c9C8F6bF5e7c3F8A. Test transaction from plugin", + "timestamp": "2024-01-15T10:30:00.000Z" + }, + "error": "", + "traces": [ + { + "relayer_id": "my-relayer", + "method": "sendTransaction", + "payload": { + "to": "0x742d35Cc6640C21a1c7656d2c9C8F6bF5e7c3F8A", + "value": "1000000000000000", + "data": "0x", + "gas_limit": 21000, + "speed": "fast" + } + } + ] +} +``` + +## Response Fields + +* ***`logs`***: Terminal output from the plugin (console.log, console.error, etc.) +* ***`return_value`***: The value returned by your plugin's handler function +* ***`error`***: Error message if the plugin execution failed +* ***`traces`***: Messages exchanged between the plugin and the Relayer instance via PluginAPI + +## Migration from Legacy Pattern + +### Current Status + +* βœ… ***Legacy plugins still work*** - No immediate action required +* ⚠️ ***Deprecation warnings*** - Legacy plugins will show console warnings +* πŸ“… ***Future removal*** - The `runPlugin` pattern will be removed in a future major version +* 🎯 ***Recommended action*** - Migrate to handler pattern for new plugins + +### Migration Steps + +If you have existing plugins using `runPlugin()`, migration is simple: + +***Before (Legacy - still works)***: +```typescript +import { runPlugin, PluginAPI } from "./lib/plugin"; + +async function myPlugin(api: PluginAPI, params: any): Promise { + // Your plugin logic + return result; +} + +runPlugin(myPlugin); // ⚠️ Shows deprecation warning +``` + +***After (Modern - recommended)***: +```typescript +import { PluginAPI } from "@openzeppelin/relayer-sdk"; + +export async function handler(api: PluginAPI, params: any): Promise { + // Same plugin logic - just export as handler! + return result; +} +``` + +### Step-by-Step Migration + +1. ***Remove the `runPlugin()` call*** at the bottom of your file +2. ***Rename your function to `handler`*** (or create a new handler export) +3. ***Export the `handler` function*** using `export async function handler` +4. ***Add proper TypeScript types*** for better development experience +5. ***Test your plugin*** to ensure it works with the new pattern +6. ***Update your documentation*** to reflect the new pattern + +### Backwards Compatibility + +The relayer will automatically detect which pattern your plugin uses: + +* If it finds a `handler` export β†’ uses modern pattern +* If no `handler` but `runPlugin()` was called β†’ uses legacy pattern with warning +* If neither β†’ shows clear error message + +This ensures a smooth transition period where both patterns work simultaneously. diff --git a/content/relayer/1.1.x/quickstart.mdx b/content/relayer/1.1.x/quickstart.mdx new file mode 100644 index 00000000..7870c2bc --- /dev/null +++ b/content/relayer/1.1.x/quickstart.mdx @@ -0,0 +1,163 @@ +--- +title: Quick Start Guide +--- + +This guide provides step-by-step instructions for setting up OpenZeppelin Relayer. It includes prerequisites, installation, and configuration examples. + +## Prerequisites + +* Rust 2021, version `1.86` or later. +* Redis +* Docker (optional, for containerized deployment) +* Node.js, typescript and ts-node (optional, for plugins) + +## Configuration + +### Step 1: Clone the Repository + +Clone the repository and navigate to the project directory: + +```bash +git clone https://github.com/OpenZeppelin/openzeppelin-relayer +cd openzeppelin-relayer +``` + +### Step 2: Create Configuration Files + +Create environment configuration: + +```bash +cp .env.example .env +``` + +These files are already partially configured. We will add missing data in next steps. + +Ready-to-Use Example Configurations + +For quick setup with various configurations, check the [examples directory](https://github.com/OpenZeppelin/openzeppelin-relayer/tree/main/examples) in our GitHub repository: + +### Step 3: Create a Signer + +Generate a new signer keystore for the basic example: + +```bash +cargo run --example create_key -- \ + --password \ + --output-dir examples/basic-example/config/keys \ + --filename local-signer.json +``` +Replace `` with a strong password. + + + + +Your password must contain at least: + +* 12 characters +* One uppercase letter +* One lowercase letter +* One number +* One special character + + + +Next, update the `KEYSTORE_PASSPHRASE` in `.env` with the password you used above. + +### Step 4: Configure Notifications + +#### Configure Webhook URL + +Edit the file `config/config.json` and update the `notifications[0].url` field with your webhook URL. For a quick test, you can use a temporary URL from [Webhook.site](https://webhook.site). + +#### Configure Webhook Signing Key + +Generate a webhook signing key: + +```bash +cargo run --example generate_uuid +``` + + + +Alternatively, you can use any online UUID generator tool if you don’t want to run the included command. + + +Copy the generated UUID and update the `WEBHOOK_SIGNING_KEY` entry in `.env`. + +### Step 5: Configure API Key + +Generate an API key signing key for development: + +```bash +cargo run --example generate_uuid +``` + + + +You can also use UUID generator with a simple command on your terminal. + +```bash +uuidgen +``` + +Alternatively, you can use any online UUID generator tool. + + +Copy the generated UUID and update the `API_KEY` entry in `.env`. + +### Step 6: Run the Service + +#### Local + +Run Redis container: + +```sh +docker run --name openzeppelin-redis \ + -p 6379:6379 \ + -d redis:latest +``` + +Run Relayer service: + +```bash +cargo run +``` + +#### Docker + +Building and Running the docker image: + +```bash +docker compose up -d +``` + +By default docker compose command uses `Dockerfile.development` to build the image. If you want to use `Dockerfile.production`, you can use the following command: + +```bash +DOCKERFILE=Dockerfile.production docker compose up -d +``` + +### Step 7: Test the Relayer + +Verify the service by sending a GET request: + +```bash +curl -X GET http://localhost:8080/api/v1/relayers \ + -H "Content-Type: application/json" \ + -H "AUTHORIZATION: Bearer YOUR_API_KEY" +``` +Replace `YOUR_API_KEY` with the API key you configured in your `.env` file. + +Expected Result: A successful request should return an HTTP 200 status code along with the list of relayers. + +## Using the relayer through the API + +For detailed API usage, refer to the [API Reference](./api) page. + +## Using the relayer through the SDK + +For documentation and examples on how to consume Relayer service via SDK check [SDK documentation](https://github.com/OpenZeppelin/openzeppelin-relayer-sdk). + +## Additional Resources and Troubleshooting + +Troubleshooting: If you encounter issues during setup or deployment, verify your environment variables, check container logs, and review your configuration files for syntax errors. diff --git a/content/relayer/1.1.x/roadmap.mdx b/content/relayer/1.1.x/roadmap.mdx new file mode 100644 index 00000000..80dc0279 --- /dev/null +++ b/content/relayer/1.1.x/roadmap.mdx @@ -0,0 +1,111 @@ +--- +title: OpenZeppelin Relayer Roadmap +--- + +This document outlines the planned development roadmap for the OpenZeppelin Relayer project. Please note that priorities and timelines may shift based on community feedback, security considerations, and emerging blockchain ecosystem needs. + + + +This roadmap represents our current plans and is subject to change. We will update this document regularly to reflect our progress and any changes in direction. + + +## General Roadmap + +* **Stability Improvements** + * Enhanced error handling and recovery mechanisms: Implement robust exception management and failover processes to minimize downtime. + * Improved background job processing: Optimize task scheduling and queuing systems to ensure smooth and reliable asynchronous operations. + * Comprehensive test coverage: Extend unit, integration, and regression tests across all components. + * End-to-End (E2E) testing: Simulate real-world scenarios to verify complete system functionality. + * Performance optimizations: Enhance throughput and reduce latency for high-demand scenarios. + * Stress and load testing: Identify and address performance bottlenecks under extreme conditions. +* **Security Enhancements** + * External security audit: Engage third-party experts to identify and remediate vulnerabilities. + * Continuous security monitoring: Implement ongoing surveillance and incident response protocols to swiftly address threats. +* **Developer Experience** + * SDK improvements: Expand SDK capabilities, add multi-language support, and simplify integration processes. + * Enhanced documentation: Develop interactive guides, detailed API references, and comprehensive troubleshooting tips. + * Additional examples and best practices: Provide real-world usage scenarios and community-contributed tutorials to ease onboarding. +* **Features** + * Redis storage integration: Leverage Redis for fast, scalable data storage across all system components. + * Enhanced relayer balance management: Implement real-time monitoring and alerts to maintain optimal balance status. + * Dynamic gas price updates: Regularly fetch and update gas prices from multiple reliable sources to ensure accurate fee estimations. +* **Scaling Improvements** + * Horizontal scaling capabilities: Design the system architecture to seamlessly distribute workloads across multiple instances. + +## Network-Specific Roadmap + +### EVM Networks (πŸ—οΈ In Progress) + +#### Current Status +* Basic Transaction Submission +* Fee Estimation +* Transaction Status Tracking +* Flexible Network Configuration System (any EVM-compatible network via JSON configuration) +* Hosted signers support (AWS KMS, GCP, Turnkey) +* Custom RPC Endpoints +* RPC Retries and Failover Mechanisms + +#### Upcoming Features +* L2 improvements +* SDK client improvements +* Full CRUD API support + +### Solana (πŸ—οΈ In Progress) + +#### Current Status +* Solana Paymaster Specification Support +* Fee estimation +* Gasless transactions +* Hosted Signer Integrations (Vault, GCP, Turnkey) +* Custom RPC Endpoints +* RPC Retries and Failover Mechanisms + +#### Upcoming Features +* Extended RPC Methods +* Improved Transaction Status Checks +* Full CRUD API support + +### Stellar (πŸ—οΈ In Progress) + +#### Current Status +* Supports payment and InvokeHostFunction operations, pre-built XDR transactions, and fee bump transactions, +* Advanced transaction status logic +* Stellar-specific endpoints +* Expanded signer support +* Transaction lifecycle management logic +* Custom RPC Endpoints +* RPC Retries and Failover Mechanisms + +#### Upcoming Features +* Relayer security policies: Transaction amount limits, destination whitelisting, time bound and limit operations +* Hosted signers +* Full CRUD API support + +## Community and Documentation + +### Continuous +* **Documentation** + * Comprehensive API reference + * Tutorials and guides + * Integration examples +* **Community Engagement** + * Contributing guidelines + * Support for community-driven improvements + +## Notes on Prioritization + + + + +Our development priorities are influenced by several factors: + +1. **Security**: Security enhancements always take precedence +2. **Stability**: Ensuring reliable operation across all supported networks +3. **Community Feedback**: Features requested by the community +4. **Ecosystem Developments**: Adapting to changes in blockchain protocols + + + +This roadmap is a living document and will be updated regularly to reflect changing priorities and completed milestones. We welcome community input on our direction and priorities. + +To contribute to discussions about the roadmap, please join our community channels or open an issue on our GitHub repository with your suggestions. diff --git a/content/relayer/1.1.x/solana.mdx b/content/relayer/1.1.x/solana.mdx new file mode 100644 index 00000000..649eea8f --- /dev/null +++ b/content/relayer/1.1.x/solana.mdx @@ -0,0 +1,220 @@ +--- +title: Solana Integration +--- + +## Overview + +OpenZeppelin Relayer provides robust support for Solana networks, enabling secure transaction relaying, automated token swaps, gasless transactions, and advanced fee management. This page covers everything you need to get started and make the most of Solana-specific features. + +## Features + +* Automated token swaps via Jupiter DEX (mainnet-beta only) +* Gasless transactions (user or relayer pays fees) +* Secure transaction signing with multiple signer backends +* Transaction status monitoring and nonce management +* Custom RPC endpoints and network policies +* Metrics and observability + +## Supported Networks + +Solana networks are defined via JSON configuration files, providing flexibility to: + +* Configure standard Solana clusters: `mainnet-beta`, `devnet`, `testnet` +* Set up custom Solana-compatible networks with specific RPC endpoints +* Create network variants using inheritance from base configurations + +Example Solana network configurations: + +```json +{ + "networks": [ + { + "type": "solana", + "network": "solana-mainnet", + "rpc_urls": ["https://api.mainnet-beta.solana.com"], + "explorer_urls": ["https://explorer.solana.com"], + "is_testnet": false, + "tags": ["mainnet", "solana"] + }, + { + "type": "solana", + "network": "solana-devnet", + "rpc_urls": ["https://api.devnet.solana.com"], + "explorer_urls": ["https://explorer.solana.com?cluster=devnet"], + "is_testnet": true, + "tags": ["devnet", "solana"] + }, + { + "type": "solana", + "network": "solana-custom", + "rpc_urls": ["https://your-custom-solana-rpc.example.com"], + "tags": ["custom", "solana"] + } + ] +} +``` + +For detailed network configuration options, see the [Network Configuration](/relayer/1.1.x/network_configuration) guide. + +## Supported Signers + +* `vault_transit` (hosted) +* `turnkey` (hosted) +* `google_cloud_kms` (hosted) +* `local` (local) +* `vault` (local) + + + +In production systems, hosted signers are recommended for the best security model. + + +## Quickstart + +For a step-by-step setup, see [Quick Start Guide](/relayer/1.1.x/quickstart). +Key prerequisites: + +* Rust 2021, version `1.86` or later +* Redis +* Docker (optional) + +Example configuration for a Solana relayer: +```json +{ + "id": "solana-example", + "name": "Solana Example", + "network": "devnet", + "paused": false, + "notification_id": "notification-example", + "signer_id": "local-signer", + "network_type": "solana", + "custom_rpc_urls": [ + { + "url": "https://primary-solana-rpc.example.com", + "weight": 100 + }, + { + "url": "https://backup-solana-rpc.example.com", + "weight": 100 + } + ], + "policies": { + "fee_payment_strategy": "user", + "min_balance": 0, + "allowed_tokens": [ + { + "mint": "So111...", + "max_allowed_fee": 100000000 + } + ], + "swap_config": { + "strategy": "jupiter-swap", + "cron_schedule": "0 0 * * * *", + "min_balance_threshold": 1000000, + "jupiter_swap_options": { + "dynamic_compute_unit_limit": true, + "priority_level": "high", + "priority_fee_max_lamports": 1000000000 + } + } + } +} +``` + +For more configuration examples, visit the [OpenZeppelin Relayer examples repository](https://github.com/OpenZeppelin/openzeppelin-relayer/tree/main/examples). + +## Configuration + +### Relayer Policies + +In addition to standard relayer configuration and policies, Solana relayers support additional options: + +* `fee_payment_strategy`: `"user"` or `"relayer"` (who pays transaction fees) +* `allowed_tokens`: List of SPL tokens supported for swaps and fee payments +* `allowed_programs`, `allowed_accounts`, `disallowed_accounts`: Restrict relayer operations to specific programs/accounts +* `swap_config`: Automated token swap settings (see below) + +You can check all options in [User Documentation - Relayers](/relayer/1.1.x#3-relayers). + +### Automated token swap configuration options: + +* `strategy`: The swap engine to use. Supported values: `"jupiter-swap"` (Jupiter Swap API), `"jupiter-ultra"` (Jupiter Ultra API). +* `cron_schedule`: Cron expression defining how often scheduled swaps should run (e.g., `"0 0 * * * *"` for every hour). +* `min_balance_threshold`: Minimum token balance (in lamports) that triggers a swap. If the relayer’s balance drops below this, a swap is attempted. +* `jupiter_swap_options`: Advanced options for Jupiter swaps, such as: + * `dynamic_compute_unit_limit`: If `true`, dynamically adjusts compute units for swap transactions. + * `priority_level`: Priority for the swap transaction. Supported values: `"medium"`, `"high"`, `"veryHigh"`. + * `priority_fee_max_lamports`: Maximum priority fee (in lamports) to pay for a swap transaction. +* Per-token swap limits: + * `min_amount`: Minimum amount of a token to swap in a single operation. + * `max_amount`: Maximum amount of a token to swap in a single operation. + * `retain_min_amount`: Minimum amount of a token to retain in the relayer account after a swap (prevents swapping the entire balance). + +## Automated Token Swaps + +The relayer can perform automated token swaps on Solana when user fee_payment_strategy is used for relayer using: + +* ***jupiter-swap*** – via the Jupiter Swap API +* ***jupiter-ultra*** – via the Jupiter Ultra API + +Swaps can be set to work as: + +* ***Scheduled Swaps***: Background jobs run swaps based on your cron schedule. +* ***On-Demand Swaps***: If a transaction fails due to insufficient funds, the relayer attempts a swap before returning an error. + +## API Reference + +The Solana API conforms to the [Paymaster spec](https://docs.google.com/document/d/1lweO5WH12QJaSAu5RG_wUistyk_nFeT6gy1CdvyCEHg/edit?tab=t.0#heading=h.4yldgprkuvav). + +Common endpoints: +- `POST /api/v1/relayers//rpc` + Methods: + +* `feeEstimate`, +* `prepareTransaction`, +* `transferTransaction`, +* `signTransaction`, +* `signAndSendTransaction`, +* `getSupportedTokens` +* `getSupportedFeatures` + +Example: Estimate fee for a transaction +```bash +curl --location --request POST 'http://localhost:8080/api/v1/relayers/solana-example/rpc' \ +--header 'Authorization: Bearer ' \ +--header 'Content-Type: application/json' \ +--data-raw '{ + "jsonrpc": "2.0", + "method": "feeEstimate", + "params": { + "transaction": "", + "fee_token": "" + }, + "id": 1 +}' +``` + +See [API Reference](https://release-v1-0-0%2D%2Dopenzeppelin-relayer.netlify.app/api_docs.html) and [SDK examples](https://github.com/OpenZeppelin/openzeppelin-relayer-sdk/tree/main/examples/solana) for full details and examples. + +## Security + +* Do not expose the relayer directly to the public internet. +* Deploy behind a secure backend (reverse proxy, firewall). +* Use hosted signers in production systems. + +## Troubleshooting + +* Check environment variables and configuration files for errors +* Review container logs for issues + +## Roadmap + +* See [Project Roadmap](/relayer/1.1.x/roadmap) for upcoming features + +## Support + +For help, join our [Telegram](https://t.me/openzeppelin_tg/2) or open an issue on GitHub. + +## License + +This project is licensed under the GNU Affero General Public License v3.0. diff --git a/content/relayer/1.1.x/stellar.mdx b/content/relayer/1.1.x/stellar.mdx new file mode 100644 index 00000000..11981988 --- /dev/null +++ b/content/relayer/1.1.x/stellar.mdx @@ -0,0 +1,331 @@ +--- +title: Stellar Integration +--- + +## Overview + +OpenZeppelin Relayer provides comprehensive support for Stellar networks, enabling secure transaction relaying, Soroban smart contract operations, and advanced transaction management. This integration supports both standard Stellar operations and the latest Soroban smart contract functionality. + + +Stellar support is currently under active development. The API interactions and specifics described below may evolve. + + +## Features + +* Full Soroban smart contract support (invocation, deployment, WASM uploads) +* Standard Stellar payment operations +* Support for all Stellar operations via XDR transaction submission +* Fee bump transaction support +* Secure transaction signing with multiple signer backends +* Transaction status monitoring and sequence number management +* Custom RPC endpoints and network policies +* Metrics and observability + +## Supported Networks + +Stellar networks are defined via JSON configuration files, providing flexibility to: + +* Configure standard Stellar clusters: `mainnet`, `testnet` +* Set up custom Stellar-compatible networks with specific RPC endpoints +* Define network passphrases for proper transaction signing + +Example Stellar network configurations: + +```json +{ + "networks": [ + { + "type": "stellar", + "network": "mainnet", + "rpc_urls": ["https://mainnet.sorobanrpc.com"], + "explorer_urls": ["https://stellar.expert/explorer/public"], + "average_blocktime_ms": 5000, + "is_testnet": false, + "passphrase": "Public Global Stellar Network ; September 2015" + }, + { + "type": "stellar", + "network": "testnet", + "rpc_urls": ["https://soroban-testnet.stellar.org"], + "explorer_urls": ["https://stellar.expert/explorer/testnet"], + "average_blocktime_ms": 5000, + "is_testnet": true, + "passphrase": "Test SDF Network ; September 2015" + } + ] +} +``` + +For detailed network configuration options, see the [Network Configuration](/relayer/1.1.x/network_configuration) guide. + +## Quickstart + +For a step-by-step setup, see [Quick Start Guide](/relayer/1.1.x/quickstart). +Key prerequisites: + +* Rust 2021, version `1.86` or later +* Redis +* Docker (optional) + +Example configuration for a Stellar relayer: +```json +{ + "id": "stellar-example", + "name": "Stellar Example", + "network": "testnet", + "paused": false, + "notification_id": "notification-example", + "signer_id": "local-signer", + "network_type": "stellar" +} +``` + +For more configuration examples, visit the [OpenZeppelin Relayer examples repository](https://github.com/OpenZeppelin/openzeppelin-relayer/tree/main/examples). + +## Configuration + +### Relayer Policies + +Stellar relayers support standard relayer configuration options. Check all options in [User Documentation - Relayers](/relayer/1.1.x#3-relayers). + +## API Reference + +### Transaction Operations + +The Stellar API supports a variety of transaction operations: + +| Method Name | Required Parameters | Description | +| --- | --- | --- | +| Send Transaction | `network`, `operations` (or `transaction_xdr`) | Submit a transaction to the Stellar network. Supports payment and Soroban operations directly, or any Stellar operation via pre-built XDR transactions. Also supports fee bump transactions for managing transaction fees. | +| Get Transaction Details | `transaction_id` | Retrieve a specific transaction by its ID. | +| List Transactions | (none) | List transactions for the relayer with pagination support. | + +### Supported Operation Types + +| Operation Type | Description | +| --- | --- | +| `payment` | Transfer native XLM or other assets between accounts | +| `invoke_contract` | Call a deployed Soroban smart contract function | +| `create_contract` | Deploy a new Soroban smart contract from WASM hash | +| `upload_wasm` | Upload WASM contract code to the Stellar ledger | + +### Transaction Structure + +***Required fields:*** +- `network`: The Stellar network ("testnet", "mainnet", etc.) +- Either `operations` (array of operations) OR `transaction_xdr` (base64-encoded XDR) - but not both + +***Optional fields:*** +- `source_account`: The Stellar account that will be the source of the transaction (defaults to relayer’s address) +- `memo`: Transaction memo (see Memo Types below) +- `valid_until`: Transaction expiration time (ISO 8601 format) +- `transaction_xdr`: Pre-built transaction XDR (base64 encoded, signed or unsigned) - mutually exclusive with `operations` +- `fee_bump`: Boolean flag to request fee-bump wrapper (only valid with signed `transaction_xdr`) +- `max_fee`: Maximum fee for fee bump transactions in stroops (defaults to 1,000,000 = 0.1 XLM) + +### Transaction Input Methods + +The relayer supports three ways to submit transactions: + +1. ***Operations-based***: Build a transaction by specifying the `operations` array (recommended for most use cases) +2. ***Transaction XDR (unsigned)***: Submit a pre-built unsigned transaction using `transaction_xdr` field (advanced use case) +3. ***Transaction XDR (signed) with fee bump***: Submit a signed transaction using `transaction_xdr` with `fee_bump: true` to wrap it in a fee bump transaction + +Example: Send Transaction +```bash +curl --location --request POST 'http://localhost:8080/api/v1/relayers//transactions' \ +--header 'Authorization: Bearer ' \ +--header 'Content-Type: application/json' \ +--data-raw '{ + "network": "testnet", + "operations": [ + { + "type": "payment", + "destination": "GD77B6LYQ5XDCW6CND7CQMA23FSV7MZQGLBAU5OMEOXQM6XFTCMWQQCJ", + "asset": { + "type": "native" + }, + "amount": 1000000 + } + ], + "memo": { + "type": "text", + "value": "Payment for services" + } +}' +``` + +See [API Reference](https://release-v1-0-0%2D%2Dopenzeppelin-relayer.netlify.app/api_docs.html) for full details and examples. + +### Asset Types + +Assets in Stellar operations must be specified with a type field: + +***Native XLM:*** +```json +"type": "native" +``` + +***Credit Asset (4 characters or less):*** +```json +{ + "type": "credit_alphanum4", + "code": "USDC", + "issuer": "GA5ZSEJYB37JRC5AVCIA5MOP4RHTM335X2KGX3IHOJAPP5RE34K4KZVN" +} +``` + +***Credit Asset (5-12 characters):*** +```json +{ + "type": "credit_alphanum12", + "code": "LONGASSET", + "issuer": "GA5ZSEJYB37JRC5AVCIA5MOP4RHTM335X2KGX3IHOJAPP5RE34K4KZVN" +} +``` + +### Memo Types + +Transactions can include optional memos: + +* ***No Memo***: `"type": "none"` +* ***Text Memo***: `"type": "text", "value": "Payment for services"` (max 28 UTF-8 bytes) +* ***ID Memo***: `"type": "id", "value": "12345"` +* ***Hash Memo***: `"type": "hash", "value": "deadbeef..."` (32 bytes hex) +* ***Return Memo***: `"type": "return", "value": "deadbeef..."` (32 bytes hex) + + + +Memos are not supported for Soroban contract operations (invoke_contract, create_contract, upload_wasm). Attempting to include a memo with these operations will result in an error. + + +### Soroban Contract Operations + +#### Invoke Contract + +Call a deployed Soroban smart contract: + +```bash +curl --location --request POST 'http://localhost:8080/api/v1/relayers//transactions' \ +--header 'Authorization: Bearer ' \ +--header 'Content-Type: application/json' \ +--data-raw ' + "network": "testnet", + "operations": [ + { + "type": "invoke_contract", + "contract_address": "CA7QYNF7SOWQ3GLR2BGMZEHXAVIRZA4KVWLTJJFC7MGXUA74P7UJUWDA", + "function_name": "transfer", + "args": [ + {"address": "GCRID3RFJXOBEB73FWRYJJ4II5E5UQ413F7LTM4W5KI54NBHQDRUXVLY", + "address": "GD77B6LYQ5XDCW6CND7CQMA23FSV7MZQGLBAU5OMEOXQM6XFTCMWQQCJ", + "i128": {"hi": "0", "lo": "1000000"} + ], + "auth": "type": "source_account" + } + ] +}' +``` + +#### Create Contract + +Deploy a new Soroban smart contract: + +```bash +curl --location --request POST 'http://localhost:8080/api/v1/relayers//transactions' \ +--header 'Authorization: Bearer ' \ +--header 'Content-Type: application/json' \ +--data-raw '{ + "network": "testnet", + "operations": [ + { + "type": "create_contract", + "source": { + "from": "address", + "address": "GCRID3RFJXOBEB73FWRYJJ4II5E5UQ413F7LTM4W5KI54NBHQDRUXVLY" + }, + "wasm_hash": "d3b2f6f8a1c5e9b4a7d8c2e1f5a9b3c6e8d4f7a2b5c8e1d4f7a0b3c6e9d2f5a8", + "salt": "0000000000000000000000000000000000000000000000000000000000000001" + } + ] +}' +``` + +#### Upload WASM + +Upload contract code to the Stellar ledger: + +```bash +curl --location --request POST 'http://localhost:8080/api/v1/relayers//transactions' \ +--header 'Authorization: Bearer ' \ +--header 'Content-Type: application/json' \ +--data-raw '{ + "network": "testnet", + "operations": [ + { + "type": "upload_wasm", + "wasm": { + "type": "base64", + "base64": "AGFzbQEAAAABBgFgAX8BfwMCAQAFAwEAAQcPAgVoZWxsbwAACG1lbW9yeTIDCgQAAAAL" + } + } + ] +}' +``` + +### ScVal Argument Format + +When invoking contract functions, arguments must be provided as ScVal values in JSON format: + +| Type | Format | Description | +| --- | --- | --- | +| U64 | `"u64": "1000000"` | Unsigned 64-bit integer | +| I64 | `"i64": "-500"` | Signed 64-bit integer | +| U32 | `"u32": 42` | Unsigned 32-bit integer | +| I32 | `"i32": -42` | Signed 32-bit integer | +| Boolean | `"bool": true` | Boolean value | +| String | `"string": "hello world"` | UTF-8 string | +| Symbol | `"symbol": "transfer"` | Symbol (used for function names) | +| Address | `"address": "GCRID3RFJXOBEB73FWRYJJ4II5E5UQ413F7LTM4W5KI54NBHQDRUXVLY"` | Stellar account or contract address | +| Bytes | `"bytes": "deadbeef"` | Hex-encoded byte array | +| Vector | `"vec": [{"u32": 1, "u32": 2, "u32": 3]}` | Array of ScVal values | +| Map | `"map": [{"key": {"symbol": "name", "val": "string": "MyToken"}]}` | Key-value pairs | + +Additional types like U128, I128, U256, and I256 are also supported using multi-part representations. + +### Authorization Modes + +Soroban operations support different authorization modes: + +| Type | Description | +| --- | --- | +| `none` | No authorization required | +| `source_account` | Use the transaction source account (default) | +| `addresses` | Use specific addresses (future feature) | +| `xdr` | Advanced: provide base64-encoded XDR entries. This allows you to provide pre-signed SorobanAuthorizationEntry objects for complex authorization scenarios. See the [official Stellar documentation on authorization](https://developers.stellar.org/docs/learn/smart-contract-internals/authorization) for detailed information about SorobanAuthorizationEntries. | + +## Security + +* Do not expose the relayer directly to the public internet +* Deploy behind a secure backend (reverse proxy, firewall) +* Use hosted signers in production systems +* Ensure proper network passphrases are configured for transaction signing + +## Troubleshooting + +* Check environment variables and configuration files for errors +* Verify network passphrase matches the target network +* Review container logs for Stellar-specific errors +* Ensure Soroban RPC endpoints are properly configured for contract operations + +## Roadmap + +* See [Project Roadmap](/relayer/1.1.x/roadmap) for upcoming features + +## Support + +For help, join our [Telegram](https://t.me/openzeppelin_tg/2) or open an issue on GitHub. + +## License + +This project is licensed under the GNU Affero General Public License v3.0. diff --git a/content/relayer/1.1.x/structure.mdx b/content/relayer/1.1.x/structure.mdx new file mode 100644 index 00000000..0704bb4a --- /dev/null +++ b/content/relayer/1.1.x/structure.mdx @@ -0,0 +1,106 @@ +--- +title: Project Structure +--- + +This document provides detailed information about each directory in the OpenZeppelin Relayer project. + +## Source Code Organization + +### `src/` Directory +The main source code directory contains the core implementation files organized into several modules: + +* `api/`: Route and controllers logic + * Manages HTTP routing and delegates incoming requests to controllers +* `bootstrap/`: Service initialization + * Bootstraps and initializes application services +* `config/`: Configuration management + * Handles system configuration and environment settings +* `constants/`: Global constants + * Provides static values used across the application +* `domain/`: Business domain logic + * Encapsulates core business rules and domain-specific functionality +* `jobs/`: Asynchronous job processing + * Manages background task queueing and execution +* `logging/`: Logging and file rotation + * Implements logging functionalities and log file management +* `metrics/`: Metrics collection + * Collects and reports application performance and usage metrics +* `models/`: Core data models and types + * Defines data structures and type definitions for the system +* `repositories/`: Configuration storage + * Provides interfaces for storing and retrieving configuration data +* `services/`: Business service logic + * Implements core business functionalities and service operations +* `utils/`: Utility functions + * Offers helper functions and common utilities for the application + +## Documentation + +### `docs/` Directory +Project documentation: + +* User guides +* API documentation +* Configuration examples +* Architecture diagrams + +## Configuration + +### `config/` Directory + +Houses system configuration file and keys: + +* `config.json` configuration file +* keystore files referenced from config.json file + +## Tests + +### `test/` Directory + +Includes comprehensive testing suites to ensure system reliability: + +* End-to-end tests that simulate real-world user scenarios + +## Scripts + +### `scripts/` Directory + +Utility scripts. + +## Examples + +### `examples/` Directory + +Provides practical examples and sample configurations to help users get started: + +* Demonstrates typical service configurations for various environments +* Acts as a quick-start guide for customizing and deploying the relayer +* Serves as a reference for best practices in configuration and deployment + +## Development Tools + +### Pre-commit Hooks +Located in the project root: + +* Code formatting checks +* Linting rules +* Commit message validation + +### Build Configuration +Core build files: + +* `Cargo.toml`: Project dependencies and metadata +* `rustfmt.toml`: Code formatting rules +* `rust-toolchain.toml`: Rust version and components + +## Docker Support + +The project includes Docker configurations for different environments: + +* `Dockerfile.development`: Development container setup +* `Dockerfile.production`: Production-ready container + + + +For detailed information about running the relayers in containers, see the Docker deployment section in the main documentation. + diff --git a/content/relayer/api/callPlugin.mdx b/content/relayer/api/callPlugin.mdx index fe557873..e55f43e0 100644 --- a/content/relayer/api/callPlugin.mdx +++ b/content/relayer/api/callPlugin.mdx @@ -1,5 +1,5 @@ --- -title: Calls a plugin method. +title: Execute a plugin and receive the sanitized result full: true _openapi: method: POST @@ -7,9 +7,22 @@ _openapi: toc: [] structuredData: headings: [] - contents: [] + contents: + - content: >- + Logs and traces are only returned when the plugin is configured with + `emit_logs` / `emit_traces`. + + Plugin-provided errors are normalized into a consistent payload + (`code`, `details`) and a derived + + message so downstream clients receive a stable shape regardless of how + the handler threw. --- {/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} +Logs and traces are only returned when the plugin is configured with `emit_logs` / `emit_traces`. +Plugin-provided errors are normalized into a consistent payload (`code`, `details`) and a derived +message so downstream clients receive a stable shape regardless of how the handler threw. + \ No newline at end of file diff --git a/content/relayer/api/index.mdx b/content/relayer/api/index.mdx index 89580fb1..414d82da 100644 --- a/content/relayer/api/index.mdx +++ b/content/relayer/api/index.mdx @@ -4,111 +4,111 @@ title: Relayer API Reference ## Relayers -### [List Relayers](./api/listRelayers) +### [List Relayers](/relayer/api/listRelayers) Lists all relayers with pagination support -### [Create Relayer](./api/createRelayer) +### [Create Relayer](/relayer/api/createRelayer) Creates a new relayer -### [Get Relayer](./api/getRelayer) +### [Get Relayer](/relayer/api/getRelayer) Retrieves details of a specific relayer by ID -### [Delete Relayer](./api/deleteRelayer) +### [Delete Relayer](/relayer/api/deleteRelayer) Deletes a relayer by ID -### [Update Relayer](./api/updateRelayer) +### [Update Relayer](/relayer/api/updateRelayer) Updates a relayer's information -### [Get Relayer Balance](./api/getRelayerBalance) +### [Get Relayer Balance](/relayer/api/getRelayerBalance) Retrieves the balance of a specific relayer -### [RPC](./api/rpc) +### [RPC](/relayer/api/rpc) Performs a JSON-RPC call using the specified relayer -### [Sign](./api/sign) +### [Sign](/relayer/api/sign) Signs data using the specified relayer -### [Sign Transaction](./api/signTransaction) +### [Sign Transaction](/relayer/api/signTransaction) Signs a transaction using the specified relayer (Stellar only) -### [Sign Typed Data](./api/signTypedData) +### [Sign Typed Data](/relayer/api/signTypedData) Signs typed data using the specified relayer -### [Get Relayer Status](./api/getRelayerStatus) +### [Get Relayer Status](/relayer/api/getRelayerStatus) Fetches the current status of a specific relayer -### [Send Transaction](./api/sendTransaction) +### [Send Transaction](/relayer/api/sendTransaction) Sends a transaction through the specified relayer -### [List Transactions](./api/listTransactions) +### [List Transactions](/relayer/api/listTransactions) Lists all transactions for a specific relayer with pagination -### [Get Transaction by Nonce](./api/getTransactionByNonce) +### [Get Transaction by Nonce](/relayer/api/getTransactionByNonce) Retrieves a transaction by its nonce value -### [Delete Pending Transactions](./api/deletePendingTransactions) +### [Delete Pending Transactions](/relayer/api/deletePendingTransactions) Deletes all pending transactions for a specific relayer -### [Get Transaction by ID](./api/getTransactionById) +### [Get Transaction by ID](/relayer/api/getTransactionById) Retrieves a specific transaction by its ID -### [Replace Transaction](./api/replaceTransaction) +### [Replace Transaction](/relayer/api/replaceTransaction) Replaces a specific transaction with a new one -### [Cancel Transaction](./api/cancelTransaction) +### [Cancel Transaction](/relayer/api/cancelTransaction) Cancels a specific transaction by its ID ## Plugins -### [Call Plugin](./api/callPlugin) +### [Call Plugin](/relayer/api/callPlugin) Calls a plugin method ## Notifications -### [List Notifications](./api/listNotifications) +### [List Notifications](/relayer/api/listNotifications) Lists all notifications with pagination support -### [Create Notification](./api/createNotification) +### [Create Notification](/relayer/api/createNotification) Creates a new notification -### [Get Notification](./api/getNotification) +### [Get Notification](/relayer/api/getNotification) Retrieves details of a specific notification by ID -### [Delete Notification](./api/deleteNotification) +### [Delete Notification](/relayer/api/deleteNotification) Deletes a notification by ID -### [Update Notification](./api/updateNotification) +### [Update Notification](/relayer/api/updateNotification) Updates an existing notification ## Signers -### [List Signers](./api/listSigners) +### [List Signers](/relayer/api/listSigners) Lists all signers with pagination support -### [Create Signer](./api/createSigner) +### [Create Signer](/relayer/api/createSigner) Creates a new signer -### [Get Signer](./api/getSigner) +### [Get Signer](/relayer/api/getSigner) Retrieves details of a specific signer by ID -### [Delete Signer](./api/deleteSigner) +### [Delete Signer](/relayer/api/deleteSigner) Deletes a signer by ID -### [Update Signer](./api/updateSigner) +### [Update Signer](/relayer/api/updateSigner) Updates an existing signer ## Metrics -### [Scrape Metrics](./api/scrape_metrics) +### [Scrape Metrics](/relayer/api/scrape_metrics) Triggers an update of system metrics and returns the result in plain text format -### [List Metrics](./api/list_metrics) +### [List Metrics](/relayer/api/list_metrics) Returns a list of all available metric names in JSON format -### [Metric Detail](./api/metric_detail) +### [Metric Detail](/relayer/api/metric_detail) Returns the details of a specific metric in plain text format ## Health -### [Health](./api/health) -Health routes implementation \ No newline at end of file +### [Health](/relayer/api/health) +Health routes implementation diff --git a/content/relayer/configuration/index.mdx b/content/relayer/configuration/index.mdx index 331b61bc..4296c69a 100644 --- a/content/relayer/configuration/index.mdx +++ b/content/relayer/configuration/index.mdx @@ -102,10 +102,12 @@ TRANSACTION_EXPIRATION_HOURS=8 This file can exist in any directory, but the default location is `./config/config.json`. + All components defined in `config.json` can also be managed via REST API endpoints. This provides runtime flexibility for adding, updating, or removing relayers, signers, and notifications without restarting the service. See the ***API Reference*** page for detailed endpoints documentation. + Key sections in this file include: @@ -125,6 +127,7 @@ For comprehensive details on configuring all supported signer types including: * HashiCorp Vault (secret and transit) * Cloud KMS providers (Google Cloud, AWS) * Turnkey signers +* CDP signers * Security best practices and troubleshooting See the dedicated [Signers Configuration](/relayer/configuration/signers) guide. @@ -175,7 +178,7 @@ See the ***API Reference*** page for detailed endpoints documentation. ```json "relayers": [ - + { "id": "solana-testnet", "name": "Solana Testnet", "paused": false, @@ -187,19 +190,19 @@ See the ***API Reference*** page for detailed endpoints documentation. { "url": "https://primary-rpc.example.com", "weight": 2 // Higher weight routes more requests to this endpoint. The value must be an integer between 0 and 100 (inclusive). - , - + }, + { "url": "https://backup-rpc.example.com", "weight": 1 - + } ], - "policies": + "policies": { "allowed_programs": [ "11111111111111111111111111111111", "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", "BPFLoaderUpgradeab1e11111111111111111111111" ] - + } } ] ``` @@ -226,13 +229,13 @@ Available configuration fields | solana | fee_margin_percentage | f32 | Additional margin percentage added to estimated transaction fees to account for price fluctuations. For example, a value of 10 will add 10% to estimated fees. Optional. | | solana | max_allowed_fee_lamports | unsigned 64 | Maximum allowed fee (in lamports) for a transaction. Optional. | | solana | allowed_tokens | `Vector` | List of allowed tokens. Only these tokens are supported if provided. Optional. | -| solana | allowed_programs | `Vector` | List of allowed programs by their identifiers. Only these programs are supported if provided. Optional. | +| solana | allowed_programs | `Vector` | List of allowed programs by their identifiers. Only these programs are supported if provided. | | solana | allowed_accounts | `Vector` | List of allowed accounts by their public keys. The relayer will only operate with these accounts if provided. | | solana | disallowed_accounts | `Vector` | List of disallowed accounts by their public keys. These accounts will be explicitly blocked. | -| solana | max_tx_data_size | unsigned 16 | Maximum transaction size. Optional. | -| solana | max_signatures | unsigned 8 | Maximum supported signatures. Optional. | -| evm | gas_price_cap | unsigned 128 | Specify a maximum gas price for every transaction sent with the Relayer. When enabled, any transaction exceeding the cap will have its gasPrice or maxFeePerGas overwritten. (Optional) | -| evm | gas_limit_estimation | bool | Automatic gas_limit calculation. Enabled by default. (Optional) | +| solana | max_tx_data_size | `unsigned 16` | Maximum transaction size. Optional. | +| solana | max_signatures | `unsigned 8` | Maximum supported signatures. Optional. | +| evm | gas_price_cap | `unsigned 128` | Specify a maximum gas price for every transaction sent with the Relayer. When enabled, any transaction exceeding the cap will have its gasPrice or maxFeePerGas overwritten. (Optional) | +| evm | gas_limit_estimation | `bool` | Automatic gas_limit calculation. Enabled by default. (Optional) | | evm | whitelist_receivers | `Vector` | A list of authorized contracts for each transaction sent using the Relayer. Transactions will be rejected if the destination address is not on the list. (Optional) | #### RPC URL Configuration @@ -244,21 +247,21 @@ The relayer supports two ways to configure RPC URLs: ```json "custom_rpc_urls": [ - + { "url": "https://primary-rpc.example.com", "weight": 2 // Higher weight routes more requests to this endpoint. The value must be an integer between 0 and 100 (inclusive). - , - + }, + { "url": "https://secondary-rpc.example.com", "weight": 100, // Max allowed weight - , - + }, + { "url": "https://backup-rpc.example.com" // No weight specified, defaults to 100 - , - + }, + { "url": "https://backup2-rpc.example.com", "weight": 0, // A value of 0 disables the endpoint. - + } ] ``` @@ -521,6 +524,9 @@ The OpenZeppelin Relayer supports two complementary approaches for configuration * Perfect for dynamic environments * Supports automated configuration management + See [Storage Configuration](/relayer/configuration/storage) for detailed information about how file-based and API-based configurations work together, storage behavior, and best practices. + + diff --git a/content/relayer/configuration/signers.mdx b/content/relayer/configuration/signers.mdx index 56f118e1..6332f3bb 100644 --- a/content/relayer/configuration/signers.mdx +++ b/content/relayer/configuration/signers.mdx @@ -37,6 +37,7 @@ OpenZeppelin Relayer supports the following signer types: * `turnkey`: Turnkey signer * `google_cloud_kms`: Google Cloud KMS signer * `aws_kms`: Amazon AWS KMS signer +* `cdp`: Coinbase Developer Platform signer ## Network Compatibility Matrix @@ -47,21 +48,24 @@ The following table shows which signer types are compatible with each network ty | `local` | βœ… Supported | βœ… Supported | βœ… Supported | | `vault` | βœ… Supported | βœ… Supported | ❌ Not supported | | `vault_transit` | ❌ Not supported | βœ… Supported | ❌ Not supported | -| `turnkey` | βœ… Supported | βœ… Supported | ❌ Not supported | -| `google_cloud_kms` | βœ… Supported | βœ… Supported | ❌ Not supported | +| `turnkey` | βœ… Supported | βœ… Supported | βœ… Supported | +| `google_cloud_kms` | βœ… Supported | βœ… Supported | βœ… Supported | | `aws_kms` | βœ… Supported | ❌ Not supported | ❌ Not supported | +| `cdp` | βœ… Supported | βœ… Supported | ❌ Not supported | + ***Network-specific considerations:*** * ***EVM Networks***: Use secp256k1 cryptography. Most signers support EVM networks with proper key generation. * ***Solana Networks***: Use ed25519 cryptography. Ensure your signer supports ed25519 key generation and signing. -* ***Stellar Networks***: Use ed25519 cryptography with specific Stellar requirements. Limited signer support due to network-specific implementation requirements. +* ***Stellar Networks***: Use ed25519 cryptography with specific Stellar requirements. Supported by local, Google Cloud KMS, and Turnkey signers. * ***AWS KMS***: Currently optimized for EVM networks with secp256k1 support. -* ***Google Cloud KMS***: Supports both secp256k1 (EVM) and ed25519 (Solana) key types. -* ***Turnkey***: Supports EVM and Solana networks with appropriate key management. +* ***Google Cloud KMS***: Supports secp256k1 (EVM) and ed25519 (Solana, Stellar) key types. +* ***Turnkey***: Supports EVM, Solana, and Stellar networks with appropriate key management. + ## Common Configuration Fields @@ -69,9 +73,9 @@ All signer types share these common configuration fields: | Field | Type | Description | | --- | --- | --- | -| `id` | String | Unique identifier for the signer (used to reference this signer in relayer configurations) | -| `type` | String | Type of signer (see supported signer types above) | -| `config` | Map | Signer type-specific configuration object | +| id | String | Unique identifier for the signer (used to reference this signer in relayer configurations) | +| type | String | Type of signer (see supported signer types above) | +| config | Map | Signer type-specific configuration object | ## Local Signer Configuration @@ -94,9 +98,9 @@ The local signer uses encrypted keystore files stored on the filesystem. Configuration fields: | Field | Type | Description | | --- | --- | --- | -| `path` | String | Path to the signer JSON file. Should be under the `./config` directory | -| `passphrase.type` | String | Type of passphrase source (`env` or `plain`) | -| `passphrase.value` | String | Passphrase value or environment variable name | +| path | String | Path to the signer JSON file. Should be under the `./config` directory | +| passphrase.type | String | Type of passphrase source (`env` or `plain`) | +| passphrase.value | String | Passphrase value or environment variable name | ## HashiCorp Vault Signer Configuration @@ -127,13 +131,13 @@ Uses HashiCorp Vault’s secret engine to store private keys. Configuration fields: | Field | Type | Description | | --- | --- | --- | -| `address` | String | Specifies the Vault API endpoint | -| `role_id.type` | String | Type of value source (`env` or `plain`) | -| `role_id.value` | String | The Vault AppRole role identifier value, or the environment variable name where the AppRole role identifier is stored | -| `secret_id.type` | String | Type of value source (`env` or `plain`) | -| `secret_id.value` | String | The Vault AppRole role secret value, or the environment variable name where the AppRole secret value is stored | -| `key_name` | String | The name of the cryptographic key within Vault's Secret engine that is used for signing operations | -| `mount_point` | String | The mount point for the Secrets engine in Vault. Defaults to `secret` if not explicitly specified. Optional. | +| address | String | Specifies the Vault API endpoint | +| role_id.type | String | Type of value source (`env` or `plain`) | +| role_id.value | String | The Vault AppRole role identifier value, or the environment variable name where the AppRole role identifier is stored | +| secret_id.type | String | Type of value source (`env` or `plain`) | +| secret_id.value | String | The Vault AppRole role secret value, or the environment variable name where the AppRole secret value is stored | +| key_name | String | The name of the cryptographic key within Vault’s Secret engine that is used for signing operations | +| mount_point | String | The mount point for the Secrets engine in Vault. Defaults to `secret` if not explicitly specified. Optional. | ### Vault Transit Signer @@ -164,15 +168,15 @@ Uses HashiCorp Vault’s Transit secrets engine for cryptographic operations. Configuration fields: | Field | Type | Description | | --- | --- | --- | -| `address` | String | Specifies the Vault API endpoint | -| `role_id.type` | String | Type of value source (`env` or `plain`) | -| `role_id.value` | String | The Vault AppRole role identifier value, or the environment variable name where the AppRole role identifier is stored | -| `secret_id.type` | String | Type of value source (`env` or `plain`) | -| `secret_id.value` | String | The Vault AppRole role secret value, or the environment variable name where the AppRole secret value is stored | -| `key_name` | String | The name of the cryptographic key within Vault's Transit engine that is used for signing operations | -| `mount_point` | String | The mount point for the Transit secrets engine in Vault. Defaults to `transit` if not explicitly specified. Optional. | -| `namespace` | String | The Vault namespace for API calls. This is used only in Vault Enterprise environments. Optional. | -| `pubkey` | String | Public key of the cryptographic key within Vault's Transit engine that is used for signing operations | +| address | String | Specifies the Vault API endpoint | +| role_id.type | String | Type of value source (`env` or `plain`) | +| role_id.value | String | The Vault AppRole role identifier value, or the environment variable name where the AppRole role identifier is stored | +| secret_id.type | String | Type of value source (`env` or `plain`) | +| secret_id.value | String | The Vault AppRole role secret value, or the environment variable name where the AppRole secret value is stored | +| key_name | String | The name of the cryptographic key within Vault’s Transit engine that is used for signing operations | +| mount_point | String | The mount point for the Transit secrets engine in Vault. Defaults to `transit` if not explicitly specified. Optional. | +| namespace | String | The Vault namespace for API calls. This is used only in Vault Enterprise environments. Optional. | +| pubkey | String | Public key of the cryptographic key within Vault’s Transit engine that is used for signing operations | ## Turnkey Signer Configuration @@ -198,24 +202,33 @@ Uses Turnkey’s secure key management infrastructure. Configuration fields: | Field | Type | Description | | --- | --- | --- | -| `api_public_key` | String | The public key associated with your Turnkey API access credentials. Used for authentication to the Turnkey signing service | -| `api_private_key.type` | String | Type of value source (`env` or `plain`) | -| `api_private_key.value` | String | The Turnkey API private key or environment variable name containing it. Used with the public key to authenticate API requests | -| `organization_id` | String | Your unique Turnkey organization identifier. Required to access resources within your specific organization | -| `private_key_id` | String | The unique identifier of the private key in your Turnkey account that will be used for signing operations | -| `public_key` | String | The public key corresponding to the private key identified by private_key_id. Used for address derivation and signature verification | +| api_public_key | String | The public key associated with your Turnkey API access credentials. Used for authentication to the Turnkey signing service | +| api_private_key.type | String | Type of value source (`env` or `plain`) | +| api_private_key.value | String | The Turnkey API private key or environment variable name containing it. Used with the public key to authenticate API requests | +| organization_id | String | Your unique Turnkey organization identifier. Required to access resources within your specific organization | +| private_key_id | String | The unique identifier of the private key in your Turnkey account that will be used for signing operations | +| public_key | String | The public key corresponding to the private key identified by private_key_id. Used for address derivation and signature verification | ## Google Cloud KMS Signer Configuration Uses Google Cloud Key Management Service for secure key operations. -For EVM transaction signing, ensure your Google Cloud KMS key is created with: + + + +***Network-specific key requirements:*** + +For ***EVM*** transaction signing, ensure your Google Cloud KMS key is created with: - Protection level: HSM - Purpose: Asymmetric sign - Algorithm: "Elliptic Curve secp256k1 - SHA256 Digest" -This provides secp256k1 compatibility required for Ethereum transactions. +For ***Solana*** and ***Stellar*** transaction signing, ensure your Google Cloud KMS key is created with: +- Protection level: Software or HSM +- Purpose: Asymmetric sign +- Algorithm: "Elliptic Curve ED25519 Key" + ```json { @@ -285,6 +298,39 @@ Configuration fields: | region | String | AWS region. If the key is non-replicated across regions, this must match the key’s original region. Optional. If not specified, the default region from shared credentials is used | | key_id | String | ID of the key in AWS KMS (can be key ID, key ARN, alias name, or alias ARN) | +## CDP Signer Configuration + +Uses CDP’s secure key management infrastructure. + +```json +{ + "id": "cdp-signer", + "type": "cdp", + "config": { + "api_key_id": "your-cdp-api-key-id", + "api_key_secret": { + "type": "env", + "value": "CDP_API_KEY_SECRET" + }, + "wallet_secret": { + "type": "env", + "value": "CDP_WALLET_SECRET" + }, + "account_address": "your-cdp-evm-or-solana-account-address" + } +} +``` + +Configuration fields: +| Field | Type | Description | +| --- | --- | --- | +| api_key_id | String | The Key ID of a Secret API Key. Used for authentication to the CDP signing service | +| api_key_secret.type | String | Type of value source (`env` or `plain`) | +| api_key_secret.value | String | The API key secret or environment variable name containing it. Used with the Key ID to authenticate API requests | +| wallet_secret.type | String | Type of value source (`env` or `plain`) | +| wallet_secret.value | String | The Wallet Secret or environment variable name containing it. Used to authorize API requests for signing operations. | +| account_address | String | The address of the CDP EVM EOA or CDP Solana Account used for signing operations. | + ## Security Best Practices ### File Permissions diff --git a/content/relayer/configuration/storage.mdx b/content/relayer/configuration/storage.mdx index 6a471e8e..61133950 100644 --- a/content/relayer/configuration/storage.mdx +++ b/content/relayer/configuration/storage.mdx @@ -13,10 +13,12 @@ Storage type determines how your configuration changes persist and how file-base + ***Community Contributions Welcome***: Additional storage backends (such as PostgreSQL, MongoDB, or other databases) are welcomed as contributions from the open source community. The storage system is designed to be extensible, making it straightforward to add new storage implementations. + ## Storage Types @@ -53,7 +55,7 @@ Redis storage persists all configuration and transaction data in a Redis databas #### Use Cases * ***Production deployments*** -* ***Multi-instance deployments*** +* ***Multi-instance deployments*** * ***When data persistence is required*** * ***Scalable environments*** * ***When API-based configuration changes should persist*** diff --git a/content/relayer/evm.mdx b/content/relayer/evm.mdx index 393bf377..dc50de0a 100644 --- a/content/relayer/evm.mdx +++ b/content/relayer/evm.mdx @@ -37,13 +37,16 @@ For detailed network configuration options, see the [Network Configuration](/rel * `turnkey` (hosted Turnkey signer) * `google_cloud_kms` (Google Cloud KMS) * `aws_kms` (Amazon AWS KMS) +* `cdp` (hosted Coinbase Developer Platform signer) For detailed signer configuration options, see the [Signers](/relayer/configuration/signers) guide. + -In production systems, hosted signers (AWS KMS, Google Cloud KMS, Turnkey) are recommended for the best security model. +In production systems, hosted signers (AWS KMS, Google Cloud KMS, Turnkey, CDP) are recommended for the best security model. + ## Quickstart @@ -75,19 +78,19 @@ Example configuration for an EVM relayer: } ], "policies": { - "gas_price_cap": 100000000000, - "eip1559_pricing": true, - "gas_limit_estimation": true, - "whitelist_receivers": [ - "0x1234567890123456789012345678901234567890", - "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd" - ], - "min_balance": 1000000000000000000 + "gas_price_cap": 100000000000, + "eip1559_pricing": true, + "gas_limit_estimation": true, + "whitelist_receivers": [ + "0x1234567890123456789012345678901234567890", + "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd" + ], + "min_balance": 1000000000000000000 } -} +}, ``` -For more configuration examples, visit the [OpenZeppelin Relayer examples repository](https://github.com/OpenZeppelin/openzeppelin-relayer/tree/main/examples). +For more configuration examples, visit the [OpenZeppelin Relayer examples repository, window=_blank](https://github.com/OpenZeppelin/openzeppelin-relayer/tree/main/examples). ## Configuration @@ -101,7 +104,7 @@ In addition to standard relayer configuration and policies, EVM relayers support * `min_balance`: Minimum balance required for the relayer to operate (in wei) * `eip1559_pricing`: Enable/disable EIP-1559 pricing methodology for transaction fees -You can check all options in [User Documentation - Relayers](/relayer#3-relayers). +You can check all options in [User Documentation - Relayers](/relayer#3_relayers). ### Gas Management Configuration @@ -111,7 +114,7 @@ Set a maximum gas price to protect against extreme network congestion: ```json { "policies": { - "gas_price_cap": 100000000000 + "gas_price_cap": 100000000000 // 100 Gwei maximum } } ``` @@ -122,7 +125,7 @@ Enable or disable automatic gas limit estimation: ```json { "policies": { - "gas_limit_estimation": true + "gas_limit_estimation": true // Enable automatic estimation } } ``` @@ -140,10 +143,12 @@ The relayer uses a two-tier approach for gas limit estimation: * ***ERC721/ERC20 transferFrom*** (`0x23b872dd`): 80,000 gas * ***Complex contracts*** (all other function calls): 200,000 gas + For advanced users working with complex transactions or custom contracts, it is recommended to include an explicit `gas_limit` parameter in the transaction request to ensure optimal gas usage and avoid estimation errors. + #### Whitelist Receivers Restrict transactions to specific contract addresses: @@ -172,65 +177,65 @@ Common endpoints: ### Send Transaction - Speed params ```bash -curl --location --request POST 'http://localhost:8080/api/v1/relayers/solana-example/transactions' \ +curl --location --request POST 'http://localhost:8080/api/v1/relayers/sepolia-example/transactions' \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --data-raw '{ - "value": 1, - "data": "0x", - "to": "0xd9b55a2ba539031e3c18c9528b0dc3a7f603a93b", - "speed": "average" + "value": 1, + "data": "0x", + "to": "0xd9b55a2ba539031e3c18c9528b0dc3a7f603a93b", + "speed": "average" }' ``` ### Send Transaction - Speed params with gas limit included ```bash -curl --location --request POST 'http://localhost:8080/api/v1/relayers/solana-example/transactions' \ +curl --location --request POST 'http://localhost:8080/api/v1/relayers/sepolia-example/transactions' \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --data-raw '{ - "value": 1, - "data": "0x", - "to": "0xd9b55a2ba539031e3c18c9528b0dc3a7f603a93b", - "speed": "average", - "gas_limit": 21000 + "value": 1, + "data": "0x", + "to": "0xd9b55a2ba539031e3c18c9528b0dc3a7f603a93b", + "speed": "average", + "gas_limit": 21000 }' ``` ### Transaction with EIP-1559 Pricing ```bash -curl --location --request POST 'http://localhost:8080/api/v1/relayers/solana-example/transactions' \ +curl --location --request POST 'http://localhost:8080/api/v1/relayers/sepolia-example/transactions' \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --data-raw '{ - "value": 1, - "data": "0x", - "to": "0xd9b55a2ba539031e3c18c9528b0dc3a7f603a93b", - "max_fee_per_gas": 30000000000, - "max_priority_fee_per_gas": 20000000000 + "value": 1, + "data": "0x", + "to": "0xd9b55a2ba539031e3c18c9528b0dc3a7f603a93b", + "max_fee_per_gas": 30000000000, + "max_priority_fee_per_gas": 20000000000, }' ``` ### Transaction with Legacy Pricing - gas estimation included ```bash -curl --location --request POST 'http://localhost:8080/api/v1/relayers/solana-example/transactions' \ +curl --location --request POST 'http://localhost:8080/api/v1/relayers/sepolia-example/transactions' \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --data-raw '{ - "value": 1, - "data": "0x", - "to": "0xd9b55a2ba539031e3c18c9528b0dc3a7f603a93b", - "gas_price": "12312313123" + "value": 1, + "data": "0x", + "to": "0xd9b55a2ba539031e3c18c9528b0dc3a7f603a93b", + "gas_price": "12312313123" }' ``` ### Get Transaction Status ```bash -curl --location --request GET 'http://localhost:8080/api/v1/relayers/solana-example/transactions/' \ +curl --location --request GET 'http://localhost:8080/api/v1/relayers/sepolia-example/transactions/' \ --header 'Authorization: Bearer ' ``` diff --git a/content/relayer/index.mdx b/content/relayer/index.mdx index 1f4f6674..8478169c 100644 --- a/content/relayer/index.mdx +++ b/content/relayer/index.mdx @@ -47,19 +47,31 @@ Networks can be loaded from: For detailed network configuration options and examples, see the [Network Configuration](/relayer/network_configuration) page. + For information about our development plans and upcoming features, see [Project Roadmap](/relayer/roadmap). + + To get started immediately, see [Quickstart](/relayer/quickstart). + ## Technical Overview ```mermaid +%%{init: { + 'theme': 'base', + 'themeVariables': { + 'background': '#ffffff', + 'mainBkg': '#ffffff', + 'primaryBorderColor': '#cccccc' + } +}}%% flowchart TB subgraph "Clients" client[API/SDK] @@ -208,6 +220,8 @@ For quick setup with various configurations, check the [examples directory](http * `evm-gcp-kms-signer`: Using Google Cloud KMS for EVM secure signing * `evm-turnkey-signer`: Using Turnkey for EVM secure signing * `solana-turnkey-signer`: Using Turnkey for Solana secure signing +* `evm-cdp-signer`: Using CDP for EVM secure signing +* `solana-cdp-signer`: Using CDP for Solana secure signing * `redis-storage`: Using Redis for Storage * `network-configuration-config-file`: Using Custom network configuration via config file * `network-configuration-json-file`: Using Custom network configuration via JSON file @@ -242,7 +256,7 @@ cargo run ``` -Before executing the command, ensure that the `.env` and `config.json` files are configured as detailed in the [Configuration References](/relayer/configuration) section. +Before executing the command, ensure that the `.env` and `config.json` files are configured as detailed in the [Configuration References](/relayer#configuration_references) section. ### Option 2: Run with Docker diff --git a/content/relayer/latest-versions.js b/content/relayer/latest-versions.js new file mode 100644 index 00000000..0f69c24b --- /dev/null +++ b/content/relayer/latest-versions.js @@ -0,0 +1,17 @@ +/** + * @typedef {Object} VersionConfig + * @property {string} label - Display label for the version + * @property {string} value - Internal value identifier + * @property {string} path - URL path for the version + * @property {boolean} isStable - Whether this is a stable release + */ + +export const latestStable = "1.1.x"; + +/** @type {VersionConfig[]} */ + +export const allVersions = [ + { label: "v1.1.x (latest stable)", value: "1.1.x", path: "/relayer/1.1.x", isStable: true }, + { label: "v1.0.x", value: "1.0.x", path: "/relayer/1.0.x", isStable: true }, + { label: "Development", value: "development", path: "/relayer", isStable: false } +]; diff --git a/content/relayer/network_configuration.mdx b/content/relayer/network_configuration.mdx index a81bb4ca..4e4ac53f 100644 --- a/content/relayer/network_configuration.mdx +++ b/content/relayer/network_configuration.mdx @@ -29,12 +29,12 @@ Networks are defined in JSON configuration files, allowing you to: If no `networks` field is specified in your `config.json`, the relayer will automatically load network configurations from the `./config/networks` directory. This is the default behavior. ```json - +{ "relayers": [...], "notifications": [...], "signers": [...] // No "networks" field - defaults to "./config/networks" - +} ``` @@ -48,12 +48,12 @@ You can configure networks in two ways: Specify the path to network configuration files in your main `config.json`: ```json - +{ "relayers": [...], "notifications": [...], "signers": [...], "networks": "./config/networks" // Path to directory or file - +} ``` @@ -63,19 +63,19 @@ This is the same as the default behavior, but explicitly specified. You can also Each JSON file ***must*** contain a top-level `networks` array: ```json - +{ "networks": [ // ... network definitions ... ] - +} ``` When using a directory structure: ``` networks/ -β”œβ”€β”€ evm.json # "networks": [...] -β”œβ”€β”€ solana.json # "networks": [...] -└── stellar.json # "networks": [...] +β”œβ”€β”€ evm.json # {"networks": [...]} +β”œβ”€β”€ solana.json # {"networks": [...]} +└── stellar.json # {"networks": [...]} ``` ### Method 2: Direct Configuration @@ -83,7 +83,7 @@ networks/ Define networks directly in your main `config.json` instead of using separate files: ```json - +{ "relayers": [...], "notifications": [...], "signers": [...], @@ -93,7 +93,7 @@ Define networks directly in your main `config.json` instead of using separate fi "network": "ethereum-mainnet", "chain_id": 1, // ... other fields - + } ] } ``` @@ -124,9 +124,10 @@ Some tags have special meaning and affect relayer behavior: | Tag | Description and Behavior | | --- | --- | | `rollup` | Identifies Layer 2 rollup networks (e.g., Arbitrum, Optimism, Base) | -| `optimism` | Identifies Optimism-based networks using the OP Stack (e.g., Optimism, Base, World Chain) | +| `optimism-based` | Identifies Optimism-based networks using the OP Stack (e.g., Optimism, Base, World Chain) | +| `optimism` _(deprecated)_ | ***DEPRECATED***: Use `optimism-based` instead. This tag will be removed in a future version. | | `arbitrum-based` | Identifies Arbitrum-based networks using the Arbitrum Stack | -| `no-mempool` | Indicates networks that lack a traditional mempool (e.g., Arbitrum) | +| `no-mempool` | Indicates networks that lack a traditional mempool (e.g., Arbitrum). Note: The relayer also treats networks tagged as `arbitrum-based` or `optimism-based` as lacking a mempool, even if `no-mempool` is not present. | | `deprecated` | Marks networks that are deprecated and may be removed in future versions | #### Example: Using Special Tags @@ -134,7 +135,7 @@ Some tags have special meaning and affect relayer behavior: Here’s an example showing how special tags are used in practice: ```json - +{ "type": "evm", "network": "arbitrum-one", "chain_id": 42161, @@ -143,7 +144,7 @@ Here’s an example showing how special tags are used in practice: "rpc_urls": ["https://arb1.arbitrum.io/rpc"], "tags": ["rollup", "no-mempool"], // Arbitrum is a rollup without mempool "is_testnet": false - +} ``` These tags help the relayer: @@ -171,7 +172,7 @@ The OpenZeppelin Relayer supports any EVM-based L1 blockchain, as long as it doe Here’s an example showing an EVM network configuration: ```json - +{ "type": "evm", "network": "ethereum-mainnet", "chain_id": 1, // Ethereum mainnet chain ID @@ -180,7 +181,7 @@ Here’s an example showing an EVM network configuration: "features": ["eip1559"], // Supports EIP-1559 fee market "rpc_urls": ["https://mainnet.infura.io/v3/YOUR_KEY"], "is_testnet": false - +} ``` ### Solana-Specific Fields @@ -198,7 +199,7 @@ Currently, Solana networks use only the common fields. Additional Solana-specifi Here’s an example showing a Stellar network configuration with passphrase: ```json - +{ "type": "stellar", "network": "pubnet", "rpc_urls": ["https://mainnet.sorobanrpc.com"], @@ -206,7 +207,7 @@ Here’s an example showing a Stellar network configuration with passphrase: "passphrase": "Public Global Stellar Network ; September 2015", // Official mainnet passphrase "average_blocktime_ms": 5000, "is_testnet": false - +} ``` ## Configuration Examples @@ -214,7 +215,7 @@ Here’s an example showing a Stellar network configuration with passphrase: ### Basic EVM Network ```json - +{ "type": "evm", "network": "ethereum-mainnet", "chain_id": 1, @@ -225,13 +226,13 @@ Here’s an example showing a Stellar network configuration with passphrase: "average_blocktime_ms": 12000, "is_testnet": false, "tags": ["mainnet", "ethereum"] - +} ``` ### Layer 2 EVM Network with Tags ```json - +{ "type": "evm", "network": "optimism", "chain_id": 10, @@ -242,16 +243,16 @@ Here’s an example showing a Stellar network configuration with passphrase: "https://optimism.drpc.org" ], "features": ["eip1559"], - "tags": ["rollup", "optimism"], + "tags": ["rollup", "optimism-based"], "average_blocktime_ms": 2000, "is_testnet": false - +} ``` ### Solana Network ```json - +{ "type": "solana", "network": "mainnet-beta", "rpc_urls": ["https://api.mainnet-beta.solana.com"], @@ -259,13 +260,13 @@ Here’s an example showing a Stellar network configuration with passphrase: "average_blocktime_ms": 400, "is_testnet": false, "tags": ["mainnet", "solana"] - +} ``` ### Stellar Network ```json - +{ "type": "stellar", "network": "pubnet", "rpc_urls": ["https://mainnet.sorobanrpc.com"], @@ -274,7 +275,7 @@ Here’s an example showing a Stellar network configuration with passphrase: "average_blocktime_ms": 5000, "is_testnet": false, "tags": ["mainnet", "stellar"] - +} ``` ## Network Inheritance @@ -282,7 +283,7 @@ Here’s an example showing a Stellar network configuration with passphrase: Networks can inherit from other networks of the same type, allowing you to create variants without duplicating configuration: ```json - +{ "networks": [ { "type": "evm", @@ -291,8 +292,8 @@ Networks can inherit from other networks of the same type, allowing you to creat "required_confirmations": 12, "symbol": "ETH", "rpc_urls": ["https://mainnet.infura.io/v3/YOUR_KEY"] - , - + }, + { "from": "ethereum-base", "type": "evm", "network": "ethereum-sepolia", @@ -300,7 +301,7 @@ Networks can inherit from other networks of the same type, allowing you to creat "required_confirmations": 3, "rpc_urls": ["https://sepolia.infura.io/v3/YOUR_KEY"], "is_testnet": true - + } ] } ``` @@ -316,17 +317,16 @@ When using inheritance: Once networks are defined, reference them in your relayer configurations: ```json - - "relayers": [ - { - "id": "my-evm-relayer", - "name": "My EVM Relayer", - "network": "ethereum-mainnet", // References network ID - "network_type": "evm", - "signer_id": "my-signer" - - ] - } +{ + "relayers": [ + { + "id": "my-evm-relayer", + "name": "My EVM Relayer", + "network": "ethereum-mainnet", // References network ID + "network_type": "evm", + "signer_id": "my-signer" + } + ] } ``` @@ -381,7 +381,7 @@ Once networks are defined, reference them in your relayer configurations: ## See Also -* [Relayer Configuration](/relayer/configuration) +* [Relayer Configuration](/relayer#relayer_configuration) * [Quickstart Guide](/relayer/quickstart) * [Solana Integration](/relayer/solana) * [API Reference](/relayer/api) diff --git a/content/relayer/plugins.mdx b/content/relayer/plugins.mdx index d9f55322..c529dc6f 100644 --- a/content/relayer/plugins.mdx +++ b/content/relayer/plugins.mdx @@ -12,6 +12,7 @@ The plugin system features: - ***Handler Pattern***: Simple export-based plugin development - ***TypeScript Support***: Full type safety and IntelliSense - ***Plugin API***: Clean interface for interacting with relayers +- ***Key-Value Storage***: Persistent state and locking for plugins - ***Docker Integration***: Seamless development and deployment - ***Comprehensive Error Handling***: Detailed logging and debugging capabilities @@ -31,11 +32,11 @@ openzeppelin-relayer/ #### Handler Pattern (Recommended) -This approach uses a simple `handler` export pattern: +This approach uses a simple `handler` export pattern with a single context parameter: ```typescript /// Required imports. -import { Speed, PluginAPI } from "@openzeppelin/relayer-sdk"; +import { Speed, PluginContext, pluginError } from "@openzeppelin/relayer-sdk"; /// Define your plugin parameters interface type MyPluginParams = { @@ -43,22 +44,23 @@ type MyPluginParams = { amount?: number; message?: string; relayerId?: string; -}; +} /// Define your plugin return type type MyPluginResult = { - success: boolean; transactionId: string; - message: string; -}; + confirmed: boolean; + note?: string; +} /// Export a handler function - that's it! -export async function handler(api: PluginAPI, params: MyPluginParams): Promise { +export async function handler(context: PluginContext): Promise { + const { api, params, kv } = context; console.info("πŸš€ Plugin started..."); // Validate parameters if (!params.destinationAddress) { - throw new Error("destinationAddress is required"); + throw pluginError("destinationAddress is required", { code: 'MISSING_PARAM', status: 400, details: { field: 'destinationAddress' } }); } // Use the relayer API @@ -74,6 +76,9 @@ export async function handler(api: PluginAPI, params: MyPluginParams): Promise -The `runPlugin()` pattern is deprecated and will be removed in a future version. Please migrate to the handler export pattern above. Legacy plugins will continue to work but will show deprecation warnings. +The legacy patterns below are deprecated and will be removed in a future version. Please migrate to the single-context handler pattern. Legacy plugins continue to work but will show deprecation warnings. The two-parameter handler does not have access to the KV store. ```typescript -import { runPlugin, PluginAPI } from "./lib/plugin"; +// Legacy: runPlugin pattern (deprecated) +import { runPlugin, PluginAPI } from "../lib/plugin"; async function myPlugin(api: PluginAPI, params: any) { - // Plugin logic here - return "result"; + // Plugin logic here (no KV access) + return "result"; } -runPlugin(myPlugin); // ⚠️ Deprecated - shows warning but still works +runPlugin(myPlugin); ``` -***Example legacy plugin*** (`plugins/examples/example-deprecated.ts`): +***Legacy handler (two-parameter, deprecated, no KV)***: ```typescript -import { PluginAPI, runPlugin } from "../lib/plugin"; -import { Speed } from "@openzeppelin/relayer-sdk"; - -type Params = { - destinationAddress: string; -}; - -async function example(api: PluginAPI, params: Params): Promise { - console.info("Plugin started..."); - - const relayer = api.useRelayer("sepolia-example"); - const result = await relayer.sendTransaction({ - to: params.destinationAddress, - value: 1, - data: "0x", - gas_limit: 21000, - speed: Speed.FAST, - }); +import { PluginAPI } from "@openzeppelin/relayer-sdk"; - await result.wait(); - return "done!"; +export async function handler(api: PluginAPI, params: any): Promise { + // Same logic as before, but no KV access in this form + return "done!"; } - -runPlugin(example); ``` ### Declaring in config file @@ -146,7 +133,7 @@ The plugin path is relative to the `/plugins` directory Example: ```json -{ + "plugins": [ { "id": "my-plugin", @@ -154,7 +141,6 @@ Example: "timeout": 30 } ] -} ``` ### Timeout @@ -175,22 +161,36 @@ The timeout is optional, and if not provided, the default is 300 seconds (5 minu ### Testing Your Plugin -You can test your handler function directly: +You can test your handler function directly with a mocked context: ```typescript import { handler } from './my-plugin'; +import type { PluginContext } from '@openzeppelin/relayer-sdk'; + +const mockContext = { + api: { + useRelayer: (_id: string) => ({ + sendTransaction: async () => ({ id: 'test-tx-123', wait: async () => ({ hash: '0xhash' }) }) + }) + }, + params: { + destinationAddress: '0x742d35Cc6640C21a1c7656d2c9C8F6bF5e7c3F8A', + amount: 1000 + }, + kv: { + set: async () => true, + get: async () => null, + del: async () => true, + exists: async () => false, + scan: async () => [], + clear: async () => 0, + withLock: async (_k: string, fn: () => Promise) => fn(), + connect: async () => {}, + disconnect: async () => {} + } +} as unknown as PluginContext; -// Mock API for testing (in real scenarios, use proper mocking) -const mockApi = { - useRelayer: (id: string) => ({ - sendTransaction: async (tx: any) => ({ id: "test-tx-123", wait: async () => {} }) - }) -} as any; - -const result = await handler(mockApi, { - destinationAddress: "0x742d35Cc6640C21a1c7656d2c9C8F6bF5e7c3F8A", - amount: 1000 -}); +const result = await handler(mockContext); console.log(result); ``` @@ -202,97 +202,81 @@ The endpoint accepts a `POST` request. Example post request body: ```json { - "destinationAddress": "0x742d35Cc6640C21a1c7656d2c9C8F6bF5e7c3F8A", - "amount": 1000000000000000, - "message": "Hello from OpenZeppelin Relayer!" + "params": { + "destinationAddress": "0x742d35Cc6640C21a1c7656d2c9C8F6bF5e7c3F8A", + "amount": 1000000000000000, + "message": "Hello from OpenZeppelin Relayer!" + } } ``` -The parameters are passed directly to your plugin's `handler` function. +The parameters are passed directly to your plugin’s `handler` function. -## Debugging +## Responses -When invoking a plugin, the response will include: +API responses use the `ApiResponse` envelope: ` success, data, error, metadata `. -* `logs`: The logs from the plugin execution. -* `return_value`: The returned value of the plugin execution. -* `error`: An error message if the plugin execution failed. -* `traces`: A list of messages sent between the plugin and the Relayer instance. This includes all the payloads passed through the `PluginAPI` object. +### Success responses (HTTP 200) + +* `data` contains your handler return value (decoded from JSON when possible). +* `metadata.logs?` and `metadata.traces?` are only populated if the plugin configuration enables `emit_logs` / `emit_traces`. +* `error` is `null`. + +### Plugin errors (HTTP 4xx) + +* Throwing `pluginError(...)` (or any `Error`) is normalized into a consistent HTTP payload. +* `error` provides the client-facing message, derived from the thrown error or from log output when the message is empty. +* `data` carries ` code?: string, details?: any ` reported by the plugin. +* `metadata` follows the same visibility rules (`emit_logs` / `emit_traces`). ### Complete Example 1. ***Plugin Code*** (`plugins/example.ts`): ```typescript -import { Speed, PluginAPI } from "@openzeppelin/relayer-sdk"; - -type ExampleParams = { - destinationAddress: string; - amount?: number; - message?: string; -}; +import { Speed, PluginContext, pluginError } from "@openzeppelin/relayer-sdk"; type ExampleResult = { - success: boolean; transactionId: string; transactionHash: string | null; message: string; timestamp: string; -}; - -export async function handler(api: PluginAPI, params: ExampleParams): Promise { - console.info("πŸš€ Example plugin started"); - console.info(`πŸ“‹ Parameters:`, JSON.stringify(params, null, 2)); - - try { - // Validate parameters - if (!params.destinationAddress) { - throw new Error("destinationAddress is required"); - } - - const amount = params.amount || 1; - const message = params.message || "Hello from OpenZeppelin Relayer!"; - - console.info(`πŸ’° Sending ${amount} wei to ${params.destinationAddress}`); - - // Get relayer and send transaction - const relayer = api.useRelayer("my-relayer"); - const result = await relayer.sendTransaction({ - to: params.destinationAddress, - value: amount, - data: "0x", - gas_limit: 21000, - speed: Speed.FAST, - }); - - console.info(`βœ… Transaction submitted: ${result.id}`); - - // Wait for confirmation - const confirmation = await result.wait({ - interval: 5000, - timeout: 120000 - }); - - console.info(`πŸŽ‰ Transaction confirmed: ${confirmation.hash}`); - - return { - success: true, - transactionId: result.id, - transactionHash: confirmation.hash || null, - message: `Successfully sent ${amount} wei to ${params.destinationAddress}. ${message}`, - timestamp: new Date().toISOString() - }; - - } catch (error) { - console.error("❌ Plugin execution failed:", error); - return { - success: false, - transactionId: "", - transactionHash: null, - message: `Plugin failed: ${(error as Error).message}`, - timestamp: new Date().toISOString() - }; - } +} + +export async function handler(context: PluginContext): Promise { + const { api, params, kv } = context; + console.info("πŸš€ Example plugin started"); + console.info(`πŸ“‹ Parameters:`, JSON.stringify(params, null, 2)); + + if (!params.destinationAddress) { + throw pluginError("destinationAddress is required", { code: 'MISSING_PARAM', status: 400, details: { field: 'destinationAddress' } }); + } + + const amount = params.amount || 1; + const message = params.message || "Hello from OpenZeppelin Relayer!"; + + console.info(`πŸ’° Sending ${amount} wei to ${params.destinationAddress}`); + + const relayer = api.useRelayer("my-relayer"); + const result = await relayer.sendTransaction({ + to: params.destinationAddress, + value: amount, + data: "0x", + gas_limit: 21000, + speed: Speed.FAST, + }); + + // Example persistence + await kv.set('last_transaction', result.id); + + const confirmation = await result.wait({ interval: 5000, timeout: 120000 }); + + return { + transactionId: result.id, + transactionHash: confirmation.hash || null, + message: `Successfully sent ${amount} wei to ${params.destinationAddress}. ${message}`, + timestamp: new Date().toISOString(), + }; } ``` @@ -317,117 +301,176 @@ curl -X POST http://localhost:8080/api/v1/plugins/example-plugin/call \ -H "Content-Type: application/json" \ -H "Authorization: Bearer YOUR_API_KEY" \ -d '{ - "destinationAddress": "0x742d35Cc6640C21a1c7656d2c9C8F6bF5e7c3F8A", - "amount": 1000000000000000, - "message": "Test transaction from plugin" + "params": { + "destinationAddress": "0x742d35Cc6640C21a1c7656d2c9C8F6bF5e7c3F8A", + "amount": 1000000000000000, + "message": "Test transaction from plugin" + } }' ``` -1. ***API Response***: +1. ***API Response (Success)***: ```json { "success": true, - "message": "Plugin called successfully", - "logs": [ - { - "level": "info", - "message": "πŸš€ Example plugin started" - }, - { - "level": "info", - "message": "πŸ’° Sending 1000000000000000 wei to 0x742d35Cc6640C21a1c7656d2c9C8F6bF5e7c3F8A" - }, - { - "level": "info", - "message": "βœ… Transaction submitted: tx-123456" - }, - { - "level": "info", - "message": "πŸŽ‰ Transaction confirmed: 0xabc123..." - } - ], - "return_value": { - "success": true, + "data": { "transactionId": "tx-123456", - "transactionHash": "0xabc123def456...", - "message": "Successfully sent 1000000000000000 wei to 0x742d35Cc6640C21a1c7656d2c9C8F6bF5e7c3F8A. Test transaction from plugin", - "timestamp": "2024-01-15T10:30:00.000Z" + "confirmed": true, + "note": "Sent 1000000000000000 wei to 0x742d35Cc..." }, - "error": "", - "traces": [ - { - "relayer_id": "my-relayer", - "method": "sendTransaction", - "payload": { - "to": "0x742d35Cc6640C21a1c7656d2c9C8F6bF5e7c3F8A", - "value": "1000000000000000", - "data": "0x", - "gas_limit": 21000, - "speed": "fast" - } - } - ] + "metadata": { + "logs": [ { "level": "info", "message": "πŸš€ Example plugin started" } ], + "traces": [ { "relayerId": "my-relayer", "method": "sendTransaction", "payload": { /* ... */ } } ] + }, + "error": null } + ``` -## Response Fields +2. **API Response (Error)**: -* ***`logs`***: Terminal output from the plugin (console.log, console.error, etc.) -* ***`return_value`***: The value returned by your plugin's handler function -* ***`error`***: Error message if the plugin execution failed -* ***`traces`***: Messages exchanged between the plugin and the Relayer instance via PluginAPI +```json +{ + "success": false, + "data": + { + "code": "MISSING_PARAM", + "details": { "field": "destinationAddress" } + }, + "metadata": { + "logs": [ { "level": "error", "message": "destinationAddress is required" } ] + }, + "error": "destinationAddress is required" +} -## Migration from Legacy Pattern +``` -### Current Status +== Response Fields -* βœ… ***Legacy plugins still work*** - No immediate action required -* ⚠️ ***Deprecation warnings*** - Legacy plugins will show console warnings -* πŸ“… ***Future removal*** - The `runPlugin` pattern will be removed in a future major version -* 🎯 ***Recommended action*** - Migrate to handler pattern for new plugins +- **`data`**: The value returned by your plugin's handler function (decoded from JSON when possible) +- **`metadata.logs`**: Terminal output from the plugin (console.log, console.error, etc.) when `emit_logs` is true +- **`metadata.traces`**: Messages exchanged between the plugin and the Relayer via PluginAPI when `emit_traces` is true +- **`error`**: Error message if the plugin execution failed (business errors) -### Migration Steps +== Key-Value Storage -If you have existing plugins using `runPlugin()`, migration is simple: +The Relayer provides a built-in key-value store for plugins to maintain persistent state across invocations. This addresses the core problem of enabling persistent state management and programmatic configuration updates for plugins. -***Before (Legacy - still works)***: -```typescript -import { runPlugin, PluginAPI } from "./lib/plugin"; +=== Why a KV store? + +- Plugins execute as isolated processes with no persistent memory +- No mechanism exists to maintain state between invocations +- Plugins requiring shared state or coordination need safe concurrency primitives + +=== Configuration + +- Reuses the same Redis URL as the Relayer via the `REDIS_URL` environment variable +- No extra configuration is required +- Keys are namespaced per plugin ID to prevent collisions + +=== Usage + +Access the KV store through the `kv` property in the `PluginContext`: + +[source,typescript] +``` +export async function handler(context: PluginContext) { + const { kv } = context; + // Set a value (with optional TTL in seconds) + await kv.set('my-key', { data: 'value' }, { ttlSec: 3600 }); + // Get a value + const value = await kv.get<{ data: string }>('my-key'); + // Atomic update with lock + const updated = await kv.withLock('counter-lock', async () => { + const count = (await kv.get('counter')) ?? 0; + const next = count + 1; + await kv.set('counter', next); + return next; + }, { ttlSec: 10 }); + + return { value, updated }; +} + +``` + +=== Available Methods -async function myPlugin(api: PluginAPI, params: any): Promise { +- `get(key: string): Promise` +- `set(key: string, value: unknown, opts?: { ttlSec?: number }): Promise` +- `del(key: string): Promise` +- `exists(key: string): Promise` +- `listKeys(pattern?: string, batch?: number): Promise` +- `clear(): Promise` +- `withLock(key: string, fn: () => Promise, opts?: { ttlSec?: number; onBusy?: 'throw' | 'skip' }): Promise` + +Keys must match `[A-Za-z0-9:_-]{1,512}` and are automatically namespaced per plugin. + +== Migration from Legacy Patterns + +=== Current Status + +- βœ… **Legacy plugins still work** - No immediate action required +- ⚠️ **Deprecation warnings** - Legacy plugins will show console warnings +- πŸ“… **Future removal** - The legacy `runPlugin` and two-parameter `handler(api, params)` will be removed in a future major version +- 🎯 **Recommended action** - Migrate to single-parameter `PluginContext` handler for new plugins and KV access + +=== Migration Steps + +If you have existing plugins using `runPlugin()` or the two-parameter handler, migration is simple: + +**Before (Legacy runPlugin - still works)**: +[source,typescript] +``` +import runPlugin, PluginAPI from "./lib/plugin"; + +async function myPlugin(api: PluginAPI, params: any): Promise // Your plugin logic return result; -} + runPlugin(myPlugin); // ⚠️ Shows deprecation warning ``` -***After (Modern - recommended)***: -```typescript -import { PluginAPI } from "@openzeppelin/relayer-sdk"; +**Intermediate (Legacy two-parameter - still works, no KV)**: +[source,typescript] +``` +import PluginAPI from "@openzeppelin/relayer-sdk"; + +export async function handler(api: PluginAPI, params: any): Promise + // Same plugin logic - ⚠️ Deprecated, no KV access + return result; + +``` + +**After (Modern context - recommended, with KV)**: +[source,typescript] +``` +import PluginContext from "@openzeppelin/relayer-sdk"; + +export async function handler(context: PluginContext): Promise + const api, params, kv = context; + // Same plugin logic plus KV access! + return result; -export async function handler(api: PluginAPI, params: any): Promise { - // Same plugin logic - just export as handler! - return result; -} ``` -### Step-by-Step Migration +=== Step-by-Step Migration -1. ***Remove the `runPlugin()` call*** at the bottom of your file -2. ***Rename your function to `handler`*** (or create a new handler export) -3. ***Export the `handler` function*** using `export async function handler` -4. ***Add proper TypeScript types*** for better development experience -5. ***Test your plugin*** to ensure it works with the new pattern -6. ***Update your documentation*** to reflect the new pattern +1. **Remove the `runPlugin()` call** at the bottom of your file +2. **Rename your function to `handler`** (or create a new handler export) +3. **Export the `handler` function** using `export async function handler` +4. **Add proper TypeScript types** for better development experience +5. **Test your plugin** to ensure it works with the new pattern +6. **Update your documentation** to reflect the new pattern -### Backwards Compatibility +=== Backwards Compatibility The relayer will automatically detect which pattern your plugin uses: -* If it finds a `handler` export β†’ uses modern pattern -* If no `handler` but `runPlugin()` was called β†’ uses legacy pattern with warning -* If neither β†’ shows clear error message +- If handler accepts one parameter β†’ modern context pattern (with KV) +- If handler accepts two parameters β†’ legacy pattern (no KV, with warning) +- If `runPlugin()` was called β†’ legacy pattern (no KV, with warning) +- If neither β†’ shows clear error message This ensures a smooth transition period where both patterns work simultaneously. diff --git a/content/relayer/quickstart.mdx b/content/relayer/quickstart.mdx index 7870c2bc..d74ef682 100644 --- a/content/relayer/quickstart.mdx +++ b/content/relayer/quickstart.mdx @@ -77,10 +77,12 @@ Generate a webhook signing key: cargo run --example generate_uuid ``` + Alternatively, you can use any online UUID generator tool if you don’t want to run the included command. + Copy the generated UUID and update the `WEBHOOK_SIGNING_KEY` entry in `.env`. @@ -92,6 +94,7 @@ Generate an API key signing key for development: cargo run --example generate_uuid ``` + You can also use UUID generator with a simple command on your terminal. @@ -102,6 +105,7 @@ uuidgen Alternatively, you can use any online UUID generator tool. + Copy the generated UUID and update the `API_KEY` entry in `.env`. @@ -152,7 +156,7 @@ Expected Result: A successful request should return an HTTP 200 status code alon ## Using the relayer through the API -For detailed API usage, refer to the [API Reference](./api) page. +For detailed API usage, refer to the [API Reference](https://release-v1-0-0%2D%2Dopenzeppelin-relayer.netlify.app/api_docs.html) page. ## Using the relayer through the SDK diff --git a/content/relayer/roadmap.mdx b/content/relayer/roadmap.mdx index 80dc0279..0fbfbfbf 100644 --- a/content/relayer/roadmap.mdx +++ b/content/relayer/roadmap.mdx @@ -4,10 +4,12 @@ title: OpenZeppelin Relayer Roadmap This document outlines the planned development roadmap for the OpenZeppelin Relayer project. Please note that priorities and timelines may shift based on community feedback, security considerations, and emerging blockchain ecosystem needs. + This roadmap represents our current plans and is subject to change. We will update this document regularly to reflect our progress and any changes in direction. + ## General Roadmap diff --git a/content/relayer/solana.mdx b/content/relayer/solana.mdx index 3f311923..0ca27f94 100644 --- a/content/relayer/solana.mdx +++ b/content/relayer/solana.mdx @@ -63,11 +63,14 @@ For detailed network configuration options, see the [Network Configuration](/rel * `google_cloud_kms` (hosted) * `local` (local) * `vault` (local) +* `cdp` (hosted) + In production systems, hosted signers are recommended for the best security model. + ## Quickstart @@ -89,23 +92,14 @@ Example configuration for a Solana relayer: "signer_id": "local-signer", "network_type": "solana", "custom_rpc_urls": [ - { - "url": "https://primary-solana-rpc.example.com", - "weight": 100 - }, - { - "url": "https://backup-solana-rpc.example.com", - "weight": 100 - } + { "url": "https://primary-solana-rpc.example.com", "weight": 100 }, + { "url": "https://backup-solana-rpc.example.com", "weight": 100 } ], "policies": { "fee_payment_strategy": "user", "min_balance": 0, "allowed_tokens": [ - { - "mint": "So111...", - "max_allowed_fee": 100000000 - } + { "mint": "So111...", "max_allowed_fee": 100000000 } ], "swap_config": { "strategy": "jupiter-swap", @@ -121,7 +115,7 @@ Example configuration for a Solana relayer: } ``` -For more configuration examples, visit the [OpenZeppelin Relayer examples repository](https://github.com/OpenZeppelin/openzeppelin-relayer/tree/main/examples). +For more configuration examples, visit the [OpenZeppelin Relayer examples repository, window=_blank](https://github.com/OpenZeppelin/openzeppelin-relayer/tree/main/examples). ## Configuration @@ -129,12 +123,16 @@ For more configuration examples, visit the [OpenZeppelin Relayer examples reposi In addition to standard relayer configuration and policies, Solana relayers support additional options: -* `fee_payment_strategy`: `"user"` or `"relayer"` (who pays transaction fees) -* `allowed_tokens`: List of SPL tokens supported for swaps and fee payments +* `fee_payment_strategy`: `"user"` or `"relayer"` (who pays transaction fees). "user" is default value. + * `"user"`: Users pay transaction fees in tokens (relayer receives fee payment from user) + * `"relayer"`: ***Relayer pays for all transaction fees*** using SOL from the relayer’s account +* `allowed_tokens`: List of SPL tokens supported for swaps and fee payments. Restrict relayer operations to specific tokens. Optional. + * ***When not set or empty, all tokens are allowed*** for transactions and fee payments + * When configured, only tokens in this list can be used for transfers and fee payments * `allowed_programs`, `allowed_accounts`, `disallowed_accounts`: Restrict relayer operations to specific programs/accounts * `swap_config`: Automated token swap settings (see below) -You can check all options in [User Documentation - Relayers](/relayer#3-relayers). +You can check all options in [User Documentation - Relayers](/relayer#3_relayers). ### Automated token swap configuration options: @@ -164,7 +162,7 @@ Swaps can be set to work as: ## API Reference -The Solana API conforms to the [Paymaster spec](https://docs.google.com/document/d/1lweO5WH12QJaSAu5RG_wUistyk_nFeT6gy1CdvyCEHg/edit?tab=t.0#heading=h.4yldgprkuvav). +The Solana API conforms to the [Paymaster spec, window=_blank](https://docs.google.com/document/d/1lweO5WH12QJaSAu5RG_wUistyk_nFeT6gy1CdvyCEHg/edit?tab=t.0#heading=h.4yldgprkuvav). Common endpoints: - `POST /api/v1/relayers//rpc` @@ -178,6 +176,17 @@ Common endpoints: * `getSupportedTokens` * `getSupportedFeatures` + + + +***Fee Token Parameter Behavior:*** + +When using `fee_payment_strategy: "relayer"`, the `fee_token` parameter in RPC methods becomes ***informational only***. The relayer pays all transaction fees in SOL regardless of the specified fee token. In this mode, you can use either `"So11111111111111111111111111111112"` (WSOL) or `"11111111111111111111111111111111"` (native SOL) as the fee_token value. + +When using `fee_payment_strategy: "user"`, the `fee_token` parameter determines which token the user will pay fees in, and must be a supported token from the `allowed_tokens` list (if configured). + + + Example: Estimate fee for a transaction ```bash curl --location --request POST 'http://localhost:8080/api/v1/relayers/solana-example/rpc' \ @@ -194,7 +203,7 @@ curl --location --request POST 'http://localhost:8080/api/v1/relayers/solana-exa }' ``` -See [API Reference](https://release-v1-0-0%2D%2Dopenzeppelin-relayer.netlify.app/api_docs.html) and [SDK examples](https://github.com/OpenZeppelin/openzeppelin-relayer-sdk/tree/main/examples/solana) for full details and examples. +See [API Reference](https://release-v1-0-0%2D%2Dopenzeppelin-relayer.netlify.app/api_docs.html) and [SDK examples, window=_blank](https://github.com/OpenZeppelin/openzeppelin-relayer-sdk/tree/main/examples/solana) for full details and examples. ## Security diff --git a/content/relayer/stellar.mdx b/content/relayer/stellar.mdx index 68f1e962..e9f01bf8 100644 --- a/content/relayer/stellar.mdx +++ b/content/relayer/stellar.mdx @@ -80,13 +80,40 @@ Example configuration for a Stellar relayer: } ``` -For more configuration examples, visit the [OpenZeppelin Relayer examples repository](https://github.com/OpenZeppelin/openzeppelin-relayer/tree/main/examples). +For more configuration examples, visit the [OpenZeppelin Relayer examples repository, window=_blank](https://github.com/OpenZeppelin/openzeppelin-relayer/tree/main/examples). ## Configuration ### Relayer Policies -Stellar relayers support standard relayer configuration options. Check all options in [User Documentation - Relayers](/relayer#3-relayers). +Stellar relayers support standard relayer configuration options along with Stellar-specific policies: + +| Policy | Type | Default | Description | +| --- | --- | --- | --- | +| `min_balance` | integer | None | Minimum balance in stroops (1 XLM = 10,000,000 stroops) required for the relayer account | +| `max_fee` | integer | None | Maximum transaction fee in stroops the relayer is willing to pay | +| `timeout_seconds` | integer | None | Transaction timeout in seconds | +| `concurrent_transactions` | boolean | false | Enable concurrent transaction processing. When enabled, bypasses the lane gating mechanism that normally ensures sequential processing for each relayer. Only enable this when your relayer manages transactions from multiple accounts with independent sequence number pools. | + +Example configuration with policies: +```json +{ + "id": "stellar-example", + "name": "Stellar Example", + "network": "testnet", + "paused": false, + "network_type": "stellar", + "signer_id": "local-signer", + "policies": { + "min_balance": 10000000, + "max_fee": 1000000, + "timeout_seconds": 30, + "concurrent_transactions": false + } +} +``` + +For general relayer configuration options, check [User Documentation - Relayers](/relayer#3_relayers). ## API Reference @@ -129,9 +156,10 @@ The relayer supports three ways to submit transactions: 1. ***Operations-based***: Build a transaction by specifying the `operations` array (recommended for most use cases) 2. ***Transaction XDR (unsigned)***: Submit a pre-built unsigned transaction using `transaction_xdr` field (advanced use case) -3. ***Transaction XDR (signed) with fee bump***: Submit a signed transaction using `transaction_xdr` with `fee_bump: true` to wrap it in a fee bump transaction +3. ***Transaction XDR (signed)***: Submit a signed transaction using `transaction_xdr` with `fee_bump: true` (required for signed XDR) to wrap it in a fee bump transaction + +#### Example 1: Operations-based Transaction -Example: Send Transaction ```bash curl --location --request POST 'http://localhost:8080/api/v1/relayers//transactions' \ --header 'Authorization: Bearer ' \ @@ -142,19 +170,64 @@ curl --location --request POST 'http://localhost:8080/api/v1/relayers//transactions' \ +--header 'Authorization: Bearer ' \ +--header 'Content-Type: application/json' \ +--data-raw '{ + "network": "testnet", + "transaction_xdr": "AAAAAgAAAACige4lTdwSB/sto4SniEdJ2kOa2X65s5bqkd40J4DjSwAAAGQAAHAkAAAADgAAAAAAAAAAAAAAAQAAAAAAAAABAAAAAKKB7iVN3BIH+y2jhKeIR0naQ5rZfrmzluqR3jQngONLAAAAAAAAAAAAD0JAAAAAAAAAAAA=" }' ``` +The `transaction_xdr` field should contain a base64-encoded unsigned transaction envelope. This is useful when: +- You need precise control over transaction structure +- You want to use advanced Stellar features not exposed via the operations API + +#### Example 3: Signed Transaction XDR + +Submit a pre-signed transaction with fee bump wrapper. ***Note: `fee_bump: true` is required when submitting signed XDR***: + +```bash +curl --location --request POST 'http://localhost:8080/api/v1/relayers//transactions' \ +--header 'Authorization: Bearer ' \ +--header 'Content-Type: application/json' \ +--data-raw '{ + "network": "testnet", + "transaction_xdr": "AAAAAgAAAABjc+mbXCnvmVk4lxqVl7s0LAz5slXqmkHBg8PpH7p3DgAAAGQABpK0AAAACQAAAAAAAAAAAAAAAQAAAAAAAAABAAAAAGN0qQBW8x3mfbwGGYndt2uq4O4sZPUrDx5HlwuQke9zAAAAAAAAAAAAAA9CAAAAAQAAAAA=", + "fee_bump": true, + "max_fee": 10000000 +}' +``` + +The fee bump feature is useful when: +- You have a pre-signed transaction from another system or wallet +- You want the relayer to pay transaction fees on behalf of the original signer +- You need to increase the fee for a transaction to ensure timely execution + + + + +When using `transaction_xdr`: +- The XDR must be properly formatted and valid for the target network +- For unsigned XDR, the relayer will add its signature before submission +- ***For signed XDR, `fee_bump: true` is mandatory*** - the relayer requires this to wrap the signed transaction in a fee bump envelope +- The `max_fee` parameter (in stroops) controls the maximum fee for fee bump transactions (defaults to 1,000,000 = 0.1 XLM) + + + See [API Reference](https://release-v1-0-0%2D%2Dopenzeppelin-relayer.netlify.app/api_docs.html) for full details and examples. ### Asset Types @@ -163,7 +236,7 @@ Assets in Stellar operations must be specified with a type field: ***Native XLM:*** ```json -"type": "native" +{"type": "native"} ``` ***Credit Asset (4 characters or less):*** @@ -194,10 +267,12 @@ Transactions can include optional memos: * ***Hash Memo***: `"type": "hash", "value": "deadbeef..."` (32 bytes hex) * ***Return Memo***: `"type": "return", "value": "deadbeef..."` (32 bytes hex) + Memos are not supported for Soroban contract operations (invoke_contract, create_contract, upload_wasm). Attempting to include a memo with these operations will result in an error. + ### Soroban Contract Operations @@ -209,7 +284,7 @@ Call a deployed Soroban smart contract: curl --location --request POST 'http://localhost:8080/api/v1/relayers//transactions' \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ ---data-raw ' +--data-raw '{ "network": "testnet", "operations": [ { @@ -217,11 +292,11 @@ curl --location --request POST 'http://localhost:8080/api/v1/relayers/ } title="Monitor" description="Monitor onchain activity in real time to watch critical events, detect anomalies, trigger alerts on your preferred channels, and set automated responses with Relayer." diff --git a/src/components/banners/index.tsx b/src/components/banners/index.tsx index 06392a0c..d5cb0e1d 100644 --- a/src/components/banners/index.tsx +++ b/src/components/banners/index.tsx @@ -1,6 +1,12 @@ "use client"; +import { MonitorVersionSelector } from "../selectors/monitor-version-selector"; +import { RelayerVersionSelector } from "../selectors/relayer-version-selector"; import { AlphaBanner } from "./alpha-banner"; +import { MonitorDevelopmentBanner } from "./monitor-development-banner"; +import { MonitorOldVersionBanner } from "./monitor-old-version-banner"; +import { RelayerDevelopmentBanner } from "./relayer-development-banner"; +import { RelayerOldVersionBanner } from "./relayer-old-version-banner"; import { VersionBanner } from "./version-banner"; export function Banners() { @@ -8,6 +14,12 @@ export function Banners() { <> + + + + + + ); } diff --git a/src/components/banners/monitor-development-banner.tsx b/src/components/banners/monitor-development-banner.tsx new file mode 100644 index 00000000..bb8f9dd4 --- /dev/null +++ b/src/components/banners/monitor-development-banner.tsx @@ -0,0 +1,41 @@ +"use client"; + +import { latestStable } from "content/monitor/latest-versions"; +import { Callout } from "fumadocs-ui/components/callout"; +import Link from "next/link"; +import { usePathname } from "next/navigation"; + +export function MonitorDevelopmentBanner() { + const pathname = usePathname(); + + // Only show on monitor pages at root (development version) + if (!pathname.startsWith("/monitor")) return null; + + // Check if this is the development version (no version in path) + // Only match actual version patterns + const versionMatch = pathname.match(/^\/monitor\/([\d.]+x)/); + // If there's a version segment , don't show banner + if (versionMatch) { + return null; + } + + // Generate the stable version URL by replacing the path + const stableVersionUrl = pathname.replace( + /^\/monitor/, + `/monitor/${latestStable}`, + ); + + return ( + + You're viewing documentation for unreleased features from the main branch. + For production use, see the{" "} + + latest stable version (v{latestStable}) + + . + + ); +} diff --git a/src/components/banners/monitor-old-version-banner.tsx b/src/components/banners/monitor-old-version-banner.tsx new file mode 100644 index 00000000..8b49a7b1 --- /dev/null +++ b/src/components/banners/monitor-old-version-banner.tsx @@ -0,0 +1,48 @@ +"use client"; + +import { latestStable } from "content/monitor/latest-versions"; +import { Callout } from "fumadocs-ui/components/callout"; +import Link from "next/link"; +import { usePathname } from "next/navigation"; + +export function MonitorOldVersionBanner() { + const pathname = usePathname(); + + // Only show on monitor pages + if (!pathname.startsWith("/monitor")) return null; + + // Check if this is an old version (not latest stable) + // Only match actual version patterns (e.g., 1.0.x, 2.1.x, etc.) + const versionMatch = pathname.match(/^\/monitor\/([\d.]+x)/); + + if (!versionMatch) { + // This is development version (no version in path), not old version + return null; + } + + const currentVersion = versionMatch[1]; + + // Only show if this is NOT the latest stable version + if (currentVersion === latestStable) { + return null; + } + + // Generate the latest version URL + const latestVersionUrl = pathname.replace( + `/monitor/${currentVersion}`, + `/monitor/${latestStable}`, + ); + + return ( + + + You're viewing an older version (v{currentVersion}). The latest + documentation is available for the current version. Click here to visit + latest version. + + + ); +} diff --git a/src/components/banners/relayer-development-banner.tsx b/src/components/banners/relayer-development-banner.tsx new file mode 100644 index 00000000..af14fd8b --- /dev/null +++ b/src/components/banners/relayer-development-banner.tsx @@ -0,0 +1,42 @@ +"use client"; + +import { latestStable } from "content/relayer/latest-versions"; +import { Callout } from "fumadocs-ui/components/callout"; +import Link from "next/link"; +import { usePathname } from "next/navigation"; + +export function RelayerDevelopmentBanner() { + const pathname = usePathname(); + + // Only show on relayer pages at root (development version) + if (!pathname.startsWith("/relayer")) return null; + + // Check if this is the development version (no version in path) + // Only match actual version patterns (e.g., 1.0.x, 1.1.x, etc.) + const versionMatch = pathname.match(/^\/relayer\/([\d.]+x)/); + + // If there's a version segment, don't show banner + if (versionMatch) { + return null; + } + + // Generate the stable version URL by replacing the path + const stableVersionUrl = pathname.replace( + /^\/relayer/, + `/relayer/${latestStable}`, + ); + + return ( + + You're viewing documentation for unreleased features from the main branch. + For production use, see the{" "} + + latest stable version (v{latestStable}) + + . + + ); +} diff --git a/src/components/banners/relayer-old-version-banner.tsx b/src/components/banners/relayer-old-version-banner.tsx new file mode 100644 index 00000000..072ebede --- /dev/null +++ b/src/components/banners/relayer-old-version-banner.tsx @@ -0,0 +1,47 @@ +"use client"; + +import { latestStable } from "content/relayer/latest-versions"; +import { Callout } from "fumadocs-ui/components/callout"; +import Link from "next/link"; +import { usePathname } from "next/navigation"; + +export function RelayerOldVersionBanner() { + const pathname = usePathname(); + + // Only show on relayer pages + if (!pathname.startsWith("/relayer")) return null; + + // Check if this is an old version (not latest stable) + // Only match actual version patterns (e.g., 1.0.x, 1.1.x, etc.) + const versionMatch = pathname.match(/^\/relayer\/([\d.]+x)/); + + if (!versionMatch) { + // This is development version (no version in path), not old version + return null; + } + const currentVersion = versionMatch[1]; + + // Only show if this is NOT the latest stable version + if (currentVersion === latestStable) { + return null; + } + + // Generate the latest version URL + const latestVersionUrl = pathname.replace( + `/relayer/${currentVersion}`, + `/relayer/${latestStable}`, + ); + + return ( + + + You're viewing an older version (v{currentVersion}). The latest + documentation is available for the current version. Click here to visit + latest version. + + + ); +} diff --git a/src/components/banners/version-banner.tsx b/src/components/banners/version-banner.tsx index d9d19cb6..c2231076 100644 --- a/src/components/banners/version-banner.tsx +++ b/src/components/banners/version-banner.tsx @@ -8,6 +8,8 @@ import { usePathname } from "next/navigation"; export function VersionBanner() { const pathname = usePathname(); + if (pathname.startsWith("/monitor") || pathname.startsWith("/relayer")) + return null; // Check if this is a versioned page (contains version patterns) const versionMatch = pathname.match(/\/([\d.]+x?)(?:\/|$)/); diff --git a/src/components/selectors/monitor-version-selector.tsx b/src/components/selectors/monitor-version-selector.tsx new file mode 100644 index 00000000..18d574d2 --- /dev/null +++ b/src/components/selectors/monitor-version-selector.tsx @@ -0,0 +1,8 @@ +"use client"; + +import { allVersions } from "content/monitor/latest-versions"; +import { VersionSelector } from "./version-selector"; + +export function MonitorVersionSelector() { + return ; +} diff --git a/src/components/selectors/relayer-version-selector.tsx b/src/components/selectors/relayer-version-selector.tsx new file mode 100644 index 00000000..61bd2e92 --- /dev/null +++ b/src/components/selectors/relayer-version-selector.tsx @@ -0,0 +1,8 @@ +"use client"; + +import { allVersions } from "content/relayer/latest-versions"; +import { VersionSelector } from "./version-selector"; + +export function RelayerVersionSelector() { + return ; +} diff --git a/src/components/selectors/version-selector.tsx b/src/components/selectors/version-selector.tsx new file mode 100644 index 00000000..168fc1eb --- /dev/null +++ b/src/components/selectors/version-selector.tsx @@ -0,0 +1,144 @@ +"use client"; + +import { ChevronDown } from "lucide-react"; +import { usePathname, useRouter } from "next/navigation"; +import { + Popover, + PopoverContent, + PopoverTrigger, +} from "@/components/ui/popover"; + +export interface VersionConfig { + label: string; + value: string; + path: string; + isStable: boolean; +} + +export interface VersionSelectorProps { + /** + * The path prefix to check (e.g., "/monitor", "/relayer") + */ + pathPrefix: string; + + /** + * Array of available versions + */ + versions: VersionConfig[]; + + /** + * Optional: Custom fallback version index when no version is detected + * Defaults to finding the "development" version or the last item + */ + fallbackVersionIndex?: number; +} + +export function VersionSelector({ + pathPrefix, + versions, + fallbackVersionIndex, +}: VersionSelectorProps) { + const pathname = usePathname(); + const router = useRouter(); + + // Only show on pages matching the path prefix + if (!pathname.startsWith(pathPrefix)) return null; + + // Detect current version from pathname + const getCurrentVersion = () => { + // Check if pathname includes a version slug + const escapedPrefix = pathPrefix.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); + const versionMatch = pathname.match( + new RegExp(`^${escapedPrefix}/([^/]+)`), + ); + + if (versionMatch && versionMatch[1] !== "") { + const versionSlug = versionMatch[1]; + // Try to find matching version + const version = versions.find((v) => v.value === versionSlug); + if (version) return version; + } + + // If no version in path, return development version or fallback + const developmentVersion = versions.find((v) => v.value === "development"); + if (developmentVersion) return developmentVersion; + + // Use custom fallback index or last item + const fallbackIndex = + fallbackVersionIndex !== undefined + ? fallbackVersionIndex + : versions.length - 1; + + return versions[fallbackIndex]; + }; + + const currentVersion = getCurrentVersion(); + + const handleVersionChange = (version: VersionConfig) => { + let newPath: string; + + if (pathname === pathPrefix || pathname === `${pathPrefix}/`) { + // On index page + newPath = version.path; + } else { + // On subpage - preserve the subpage path + const escapedPrefix = pathPrefix.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); + // Match and remove only version patterns (e.g., /1.0.x/, /1.1.x/) + // This regex removes prefix and optional version segment, keeping page paths + const subPath = pathname.replace( + new RegExp(`^${escapedPrefix}(?:/[\\d.]+x)?`), + "", + ); + newPath = version.path + (subPath || ""); + } + + router.push(newPath); + }; + + return ( + + + {currentVersion.label} + + + +
+ {versions.map((version) => ( + + ))} +
+
+
+ ); +} diff --git a/src/navigation/ethereum-evm.json b/src/navigation/ethereum-evm.json index 03c13812..0846c78a 100644 --- a/src/navigation/ethereum-evm.json +++ b/src/navigation/ethereum-evm.json @@ -795,16 +795,16 @@ { "type": "folder", "name": "Relayer", + "index": { + "type": "page", + "name": "Overview", + "url": "/relayer/1.1.x" + }, "children": [ - { - "type": "page", - "name": "Overview", - "url": "/relayer" - }, { "type": "page", "name": "Quickstart", - "url": "/relayer/quickstart" + "url": "/relayer/1.1.x/quickstart" }, { "type": "folder", @@ -812,35 +812,35 @@ "index": { "type": "page", "name": "Overview", - "url": "/relayer/configuration" + "url": "/relayer/1.1.x/configuration" }, "children": [ { "type": "page", "name": "Signers", - "url": "/relayer/configuration/signers" + "url": "/relayer/1.1.x/configuration/signers" }, { "type": "page", "name": "Network Configuration", - "url": "/relayer/network_configuration" + "url": "/relayer/1.1.x/network_configuration" }, { "type": "page", "name": "Storage Configuration", - "url": "/relayer/configuration/storage" + "url": "/relayer/1.1.x/configuration/storage" } ] }, { "type": "page", "name": "EVM Integration", - "url": "/relayer/evm" + "url": "/relayer/1.1.x/evm" }, { "type": "page", "name": "Solana Integration", - "url": "/relayer/solana" + "url": "/relayer/1.1.x/solana" }, { "type": "folder", @@ -848,7 +848,7 @@ "index": { "type": "page", "name": "Overview", - "url": "/relayer/api" + "url": "/relayer/1.1.x/api" }, "children": [ { @@ -858,92 +858,92 @@ { "type": "page", "name": "List Relayers", - "url": "/relayer/api/listRelayers" + "url": "/relayer/1.1.x/api/listRelayers" }, { "type": "page", "name": "Create Relayer", - "url": "/relayer/api/createRelayer" + "url": "/relayer/1.1.x/api/createRelayer" }, { "type": "page", "name": "Get Relayer", - "url": "/relayer/api/getRelayer" + "url": "/relayer/1.1.x/api/getRelayer" }, { "type": "page", "name": "Delete Relayer", - "url": "/relayer/api/deleteRelayer" + "url": "/relayer/1.1.x/api/deleteRelayer" }, { "type": "page", "name": "Update Relayer", - "url": "/relayer/api/updateRelayer" + "url": "/relayer/1.1.x/api/updateRelayer" }, { "type": "page", "name": "Get Relayer Balance", - "url": "/relayer/api/getRelayerBalance" + "url": "/relayer/1.1.x/api/getRelayerBalance" }, { "type": "page", "name": "RPC", - "url": "/relayer/api/rpc" + "url": "/relayer/1.1.x/api/rpc" }, { "type": "page", "name": "Sign", - "url": "/relayer/api/sign" + "url": "/relayer/1.1.x/api/sign" }, { "type": "page", "name": "Sign Transaction", - "url": "/relayer/api/signTransaction" + "url": "/relayer/1.1.x/api/signTransaction" }, { "type": "page", "name": "Sign Typed Data", - "url": "/relayer/api/signTypedData" + "url": "/relayer/1.1.x/api/signTypedData" }, { "type": "page", "name": "Get Relayer Status", - "url": "/relayer/api/getRelayerStatus" + "url": "/relayer/1.1.x/api/getRelayerStatus" }, { "type": "page", "name": "Send Transaction", - "url": "/relayer/api/sendTransaction" + "url": "/relayer/1.1.x/api/sendTransaction" }, { "type": "page", "name": "List Transactions", - "url": "/relayer/api/listTransactions" + "url": "/relayer/1.1.x/api/listTransactions" }, { "type": "page", "name": "Get Transaction by Nonce", - "url": "/relayer/api/getTransactionByNonce" + "url": "/relayer/1.1.x/api/getTransactionByNonce" }, { "type": "page", "name": "Delete Pending Transactions", - "url": "/relayer/api/deletePendingTransactions" + "url": "/relayer/1.1.x/api/deletePendingTransactions" }, { "type": "page", "name": "Get Transaction by ID", - "url": "/relayer/api/getTransactionById" + "url": "/relayer/1.1.x/api/getTransactionById" }, { "type": "page", "name": "Replace Transaction", - "url": "/relayer/api/replaceTransaction" + "url": "/relayer/1.1.x/api/replaceTransaction" }, { "type": "page", "name": "Cancel Transaction", - "url": "/relayer/api/cancelTransaction" + "url": "/relayer/1.1.x/api/cancelTransaction" } ] }, @@ -954,7 +954,7 @@ { "type": "page", "name": "Call Plugin", - "url": "/relayer/api/callPlugin" + "url": "/relayer/1.1.x/api/callPlugin" } ] }, @@ -965,27 +965,27 @@ { "type": "page", "name": "List Notifications", - "url": "/relayer/api/listNotifications" + "url": "/relayer/1.1.x/api/listNotifications" }, { "type": "page", "name": "Create Notification", - "url": "/relayer/api/createNotification" + "url": "/relayer/1.1.x/api/createNotification" }, { "type": "page", "name": "Get Notification", - "url": "/relayer/api/getNotification" + "url": "/relayer/1.1.x/api/getNotification" }, { "type": "page", "name": "Delete Notification", - "url": "/relayer/api/deleteNotification" + "url": "/relayer/1.1.x/api/deleteNotification" }, { "type": "page", "name": "Update Notification", - "url": "/relayer/api/updateNotification" + "url": "/relayer/1.1.x/api/updateNotification" } ] }, @@ -996,27 +996,27 @@ { "type": "page", "name": "List Signers", - "url": "/relayer/api/listSigners" + "url": "/relayer/1.1.x/api/listSigners" }, { "type": "page", "name": "Create Signer", - "url": "/relayer/api/createSigner" + "url": "/relayer/1.1.x/api/createSigner" }, { "type": "page", "name": "Get Signer", - "url": "/relayer/api/getSigner" + "url": "/relayer/1.1.x/api/getSigner" }, { "type": "page", "name": "Delete Signer", - "url": "/relayer/api/deleteSigner" + "url": "/relayer/1.1.x/api/deleteSigner" }, { "type": "page", "name": "Update Signer", - "url": "/relayer/api/updateSigner" + "url": "/relayer/1.1.x/api/updateSigner" } ] }, @@ -1027,17 +1027,17 @@ { "type": "page", "name": "Scrape Metrics", - "url": "/relayer/api/scrape_metrics" + "url": "/relayer/1.1.x/api/scrape_metrics" }, { "type": "page", "name": "List Metrics", - "url": "/relayer/api/list_metrics" + "url": "/relayer/1.1.x/api/list_metrics" }, { "type": "page", "name": "Metric Detail", - "url": "/relayer/api/metric_detail" + "url": "/relayer/1.1.x/api/metric_detail" } ] }, @@ -1048,7 +1048,7 @@ { "type": "page", "name": "Health", - "url": "/relayer/api/health" + "url": "/relayer/1.1.x/api/health" } ] } @@ -1057,22 +1057,22 @@ { "type": "page", "name": "Project Structure", - "url": "/relayer/structure" + "url": "/relayer/1.1.x/structure" }, { "type": "page", "name": "Project Roadmap", - "url": "/relayer/roadmap" + "url": "/relayer/1.1.x/roadmap" }, { "type": "page", "name": "Plugins", - "url": "/relayer/plugins" + "url": "/relayer/1.1.x/plugins" }, { "type": "page", "name": "Changelog", - "url": "/relayer/changelog" + "url": "/relayer/1.1.x/changelog" }, { "type": "page", @@ -1088,58 +1088,58 @@ "index": { "type": "page", "name": "Overview", - "url": "/monitor" + "url": "/monitor/1.1.x" }, "children": [ { "type": "page", "name": "Quickstart", - "url": "/monitor/quickstart" + "url": "/monitor/1.1.x/quickstart" }, { "type": "page", "name": "Architecture Guide", - "url": "/monitor/architecture" + "url": "/monitor/1.1.x/architecture" }, { "type": "page", "name": "Project Structure", - "url": "/monitor/project-structure" + "url": "/monitor/1.1.x/project-structure" }, { "type": "page", "name": "RPC Client", - "url": "/monitor/rpc" + "url": "/monitor/1.1.x/rpc" }, { "type": "page", "name": "Custom scripts", - "url": "/monitor/scripts" + "url": "/monitor/1.1.x/scripts" }, { "type": "page", "name": "Error Handling", - "url": "/monitor/error" + "url": "/monitor/1.1.x/error" }, { "type": "page", "name": "Testing", - "url": "/monitor/testing" + "url": "/monitor/1.1.x/testing" }, { "type": "page", "name": "Contribution guidelines", - "url": "/monitor/contribution" + "url": "/monitor/1.1.x/contribution" }, { "type": "page", "name": "Changelog", - "url": "/monitor/changelog" + "url": "/monitor/1.1.x/changelog" }, { "type": "page", - "name": "Technical Rust Documentation", - "url": "https://docs-v1-0--openzeppelin-monitor.netlify.app/openzeppelin_monitor/", + "name": "Rust Book", + "url": "https://docs-v1-1--openzeppelin-monitor.netlify.app/openzeppelin_monitor/", "external": true } ] diff --git a/src/navigation/stellar.json b/src/navigation/stellar.json index 9b3bea6d..a9af8521 100644 --- a/src/navigation/stellar.json +++ b/src/navigation/stellar.json @@ -265,16 +265,16 @@ { "type": "folder", "name": "Relayer", + "index": { + "type": "page", + "name": "Overview", + "url": "/relayer/1.1.x" + }, "children": [ - { - "type": "page", - "name": "Overview", - "url": "/relayer" - }, { "type": "page", "name": "Quickstart", - "url": "/relayer/quickstart" + "url": "/relayer/1.1.x/quickstart" }, { "type": "folder", @@ -282,30 +282,30 @@ "index": { "type": "page", "name": "Overview", - "url": "/relayer/configuration" + "url": "/relayer/1.1.x/configuration" }, "children": [ { "type": "page", "name": "Signers", - "url": "/relayer/configuration/signers" + "url": "/relayer/1.1.x/configuration/signers" }, { "type": "page", "name": "Network Configuration", - "url": "/relayer/network_configuration" + "url": "/relayer/1.1.x/network_configuration" }, { "type": "page", "name": "Storage Configuration", - "url": "/relayer/configuration/storage" + "url": "/relayer/1.1.x/configuration/storage" } ] }, { "type": "page", "name": "Stellar Integration", - "url": "/relayer/stellar" + "url": "/relayer/1.1.x/stellar" }, { "type": "folder", @@ -313,7 +313,7 @@ "index": { "type": "page", "name": "Overview", - "url": "/relayer/api" + "url": "/relayer/1.1.x/api" }, "children": [ { @@ -323,92 +323,92 @@ { "type": "page", "name": "List Relayers", - "url": "/relayer/api/listRelayers" + "url": "/relayer/1.1.x/api/listRelayers" }, { "type": "page", "name": "Create Relayer", - "url": "/relayer/api/createRelayer" + "url": "/relayer/1.1.x/api/createRelayer" }, { "type": "page", "name": "Get Relayer", - "url": "/relayer/api/getRelayer" + "url": "/relayer/1.1.x/api/getRelayer" }, { "type": "page", "name": "Delete Relayer", - "url": "/relayer/api/deleteRelayer" + "url": "/relayer/1.1.x/api/deleteRelayer" }, { "type": "page", "name": "Update Relayer", - "url": "/relayer/api/updateRelayer" + "url": "/relayer/1.1.x/api/updateRelayer" }, { "type": "page", "name": "Get Relayer Balance", - "url": "/relayer/api/getRelayerBalance" + "url": "/relayer/1.1.x/api/getRelayerBalance" }, { "type": "page", "name": "RPC", - "url": "/relayer/api/rpc" + "url": "/relayer/1.1.x/api/rpc" }, { "type": "page", "name": "Sign", - "url": "/relayer/api/sign" + "url": "/relayer/1.1.x/api/sign" }, { "type": "page", "name": "Sign Transaction", - "url": "/relayer/api/signTransaction" + "url": "/relayer/1.1.x/api/signTransaction" }, { "type": "page", "name": "Sign Typed Data", - "url": "/relayer/api/signTypedData" + "url": "/relayer/1.1.x/api/signTypedData" }, { "type": "page", "name": "Get Relayer Status", - "url": "/relayer/api/getRelayerStatus" + "url": "/relayer/1.1.x/api/getRelayerStatus" }, { "type": "page", "name": "Send Transaction", - "url": "/relayer/api/sendTransaction" + "url": "/relayer/1.1.x/api/sendTransaction" }, { "type": "page", "name": "List Transactions", - "url": "/relayer/api/listTransactions" + "url": "/relayer/1.1.x/api/listTransactions" }, { "type": "page", "name": "Get Transaction by Nonce", - "url": "/relayer/api/getTransactionByNonce" + "url": "/relayer/1.1.x/api/getTransactionByNonce" }, { "type": "page", "name": "Delete Pending Transactions", - "url": "/relayer/api/deletePendingTransactions" + "url": "/relayer/1.1.x/api/deletePendingTransactions" }, { "type": "page", "name": "Get Transaction by ID", - "url": "/relayer/api/getTransactionById" + "url": "/relayer/1.1.x/api/getTransactionById" }, { "type": "page", "name": "Replace Transaction", - "url": "/relayer/api/replaceTransaction" + "url": "/relayer/1.1.x/api/replaceTransaction" }, { "type": "page", "name": "Cancel Transaction", - "url": "/relayer/api/cancelTransaction" + "url": "/relayer/1.1.x/api/cancelTransaction" } ] }, @@ -419,7 +419,7 @@ { "type": "page", "name": "Call Plugin", - "url": "/relayer/api/callPlugin" + "url": "/relayer/1.1.x/api/callPlugin" } ] }, @@ -430,27 +430,27 @@ { "type": "page", "name": "List Notifications", - "url": "/relayer/api/listNotifications" + "url": "/relayer/1.1.x/api/listNotifications" }, { "type": "page", "name": "Create Notification", - "url": "/relayer/api/createNotification" + "url": "/relayer/1.1.x/api/createNotification" }, { "type": "page", "name": "Get Notification", - "url": "/relayer/api/getNotification" + "url": "/relayer/1.1.x/api/getNotification" }, { "type": "page", "name": "Delete Notification", - "url": "/relayer/api/deleteNotification" + "url": "/relayer/1.1.x/api/deleteNotification" }, { "type": "page", "name": "Update Notification", - "url": "/relayer/api/updateNotification" + "url": "/relayer/1.1.x/api/updateNotification" } ] }, @@ -461,27 +461,27 @@ { "type": "page", "name": "List Signers", - "url": "/relayer/api/listSigners" + "url": "/relayer/1.1.x/api/listSigners" }, { "type": "page", "name": "Create Signer", - "url": "/relayer/api/createSigner" + "url": "/relayer/1.1.x/api/createSigner" }, { "type": "page", "name": "Get Signer", - "url": "/relayer/api/getSigner" + "url": "/relayer/1.1.x/api/getSigner" }, { "type": "page", "name": "Delete Signer", - "url": "/relayer/api/deleteSigner" + "url": "/relayer/1.1.x/api/deleteSigner" }, { "type": "page", "name": "Update Signer", - "url": "/relayer/api/updateSigner" + "url": "/relayer/1.1.x/api/updateSigner" } ] }, @@ -492,17 +492,17 @@ { "type": "page", "name": "Scrape Metrics", - "url": "/relayer/api/scrape_metrics" + "url": "/relayer/1.1.x/api/scrape_metrics" }, { "type": "page", "name": "List Metrics", - "url": "/relayer/api/list_metrics" + "url": "/relayer/1.1.x/api/list_metrics" }, { "type": "page", "name": "Metric Detail", - "url": "/relayer/api/metric_detail" + "url": "/relayer/1.1.x/api/metric_detail" } ] }, @@ -513,7 +513,7 @@ { "type": "page", "name": "Health", - "url": "/relayer/api/health" + "url": "/relayer/1.1.x/api/health" } ] } @@ -522,22 +522,22 @@ { "type": "page", "name": "Project Structure", - "url": "/relayer/structure" + "url": "/relayer/1.1.x/structure" }, { "type": "page", "name": "Project Roadmap", - "url": "/relayer/roadmap" + "url": "/relayer/1.1.x/roadmap" }, { "type": "page", "name": "Plugins", - "url": "/relayer/plugins" + "url": "/relayer/1.1.x/plugins" }, { "type": "page", "name": "Changelog", - "url": "/relayer/changelog" + "url": "/relayer/1.1.x/changelog" }, { "type": "page", @@ -550,56 +550,61 @@ { "type": "folder", "name": "Monitor", + "index": { + "type": "page", + "name": "Overview", + "url": "/monitor/1.1.x" + }, "children": [ { "type": "page", "name": "Quickstart", - "url": "/monitor/quickstart" + "url": "/monitor/1.1.x/quickstart" }, { "type": "page", "name": "Architecture Guide", - "url": "/monitor/architecture" + "url": "/monitor/1.1.x/architecture" }, { "type": "page", "name": "Project Structure", - "url": "/monitor/project-structure" + "url": "/monitor/1.1.x/project-structure" }, { "type": "page", "name": "RPC Client", - "url": "/monitor/rpc" + "url": "/monitor/1.1.x/rpc" }, { "type": "page", "name": "Custom scripts", - "url": "/monitor/scripts" + "url": "/monitor/1.1.x/scripts" }, { "type": "page", "name": "Error Handling", - "url": "/monitor/error" + "url": "/monitor/1.1.x/error" }, { "type": "page", "name": "Testing", - "url": "/monitor/testing" + "url": "/monitor/1.1.x/testing" }, { "type": "page", "name": "Contribution guidelines", - "url": "/monitor/contribution" + "url": "/monitor/1.1.x/contribution" }, { "type": "page", "name": "Changelog", - "url": "/monitor/changelog" + "url": "/monitor/1.1.x/changelog" }, { "type": "page", - "name": "Technical Rust Documentation", - "url": "https://docs-v1-0--openzeppelin-monitor.netlify.app/openzeppelin_monitor/", + "name": "Rust Book", + "url": "https://docs-v1-1--openzeppelin-monitor.netlify.app/openzeppelin_monitor/", "external": true } ]