diff --git a/README.md b/README.md index fd189ed4..4703fc7f 100644 --- a/README.md +++ b/README.md @@ -10,23 +10,23 @@ > **โš ๏ธ EXPERIMENTAL SOFTWARE WARNING** > This repository contains experimental smart contract code. While the framework is feature-complete and tested, it is not yet audited for production use. Use at your own risk and do not deploy with real assets without proper security review. -## ๐Ÿš€ What is Bloxchain Protocol? +## โšก Get started: create a wallet -Bloxchain Protocol is a **revolutionary blockchain security architecture** that eliminates single-point failures through **mandatory multi-signature workflows** and **atomic transaction breakdown**. Unlike traditional smart contracts that execute immediately, Bloxchain implements **time-locked operations** and **meta-transactions** with **role separation** to provide enterprise-grade security. +After [foundation and CopyBlox are deployed](#deployment) on a network (e.g. Sepolia), you can create your own secure wallet (AccountBlox clone) in a few steps: -### ๐ŸŽฏ Core Innovation: EngineBlox Multi-Phase Workflows +```bash +npm run create-wallet +``` -**EngineBlox** is the core library that powers Bloxchain Protocol's enterprise-grade security architecture. It breaks traditional atomic blockchain transactions into **multi-phase workflows** where: +The script is interactive: choose the network, **basic wallet (AccountBlox)** or a custom blox, then set owner / broadcaster / recovery and time-lock. It uses your `.env.deployment` deployer key and writes the new clone address (and Sepolia explorer link) when done. +Non-interactive (all defaults): `CREATE_WALLET_USE_DEFAULTS=1 node scripts/deployment/create-wallet-copyblox.js` + +## ๐Ÿš€ What is Bloxchain Protocol? -- **Smart contracts control storage access** (not individual wallets) -- **Every transaction requires minimum 2 signatures** (optional: multi-role setup) -- **Time-locked operations** provide intervention windows -- **Meta-transactions** enable gasless, delegated execution -- **Dynamic role-based access control** adapts without code changes -- **Modular composition** enables building enterprise applications through component assembly +Enterprise-grade security through **multi-phase workflows**: time-locked operations and meta-transactions with **role separation**, so contracts control storage and operations require at least two signatures. **EngineBlox** powers time-locks, gasless execution, and dynamic RBAC via modular composition. ![Bloxchain Protocol Actions](./images/sandblox-screenshot.png) -*[SandBlox](https://sandblox.app/) Transactions - Main interface showing contract operations* +*[SandBlox](https://sandblox.app/) โ€“ contract operations* ## ๐Ÿ—๏ธ Architecture Overview @@ -39,10 +39,6 @@ graph TB B --> D[RuntimeRBAC] B --> E[GuardController] - B --> K[BareBlox] - C --> G[SecureBlox] - C --> H[RoleBlox] - D --> H C --> I[AccountBlox] D --> I E --> I @@ -72,819 +68,148 @@ graph TB style P6 fill:#c8e6c9 ``` -### ๐Ÿ—๏ธ Modular Composition Architecture - -Bloxchain Protocol uses a **modular composition pattern** where components can be combined to build enterprise-grade applications: - -- **BaseStateMachine**: Foundation for all blox contracts -- **SecureOwnable**: Multi-role security (Owner, Broadcaster, Recovery) -- **RuntimeRBAC**: Dynamic role-based access control -- **GuardController**: Controlled endpoint for external contract interactions with dynamic access and workflow definition -- **HookManager**: External hook contract attachment (experimental) - -**Template Contracts** (in `contracts/examples/templates/`): -- **BareBlox**: Minimal BaseStateMachine only -- **SecureBlox**: Basic SecureOwnable functionality -- **RoleBlox**: SecureOwnable + RuntimeRBAC -- **AccountBlox**: GuardController + RuntimeRBAC + SecureOwnable -- **MachineBlox**: GuardController + RuntimeRBAC + SecureOwnable + HookManager (experimental) - -### ๐Ÿ“ฆ Example Applications +### Modular composition -The `contracts/examples/` directory contains real-world applications demonstrating Bloxchain Protocol capabilities: +- **BaseStateMachine** โ†’ **SecureOwnable**, **RuntimeRBAC**, **GuardController** (and optional **HookManager**) +- **Template:** **AccountBlox** (see `contracts/examples/templates/`) +- **Examples:** SimpleVault, SimpleRWA20, PayBlox, **CopyBlox** (clone factory), GuardianSafe, BasicERC20 -| Application | Use Case | Key Features | -|-------------|----------|-------------| -| **SimpleVault** | Secure asset management | Time-locked ETH/ERC20 withdrawals with multi-signature approval | -| **SimpleRWA20** | Tokenized real-world assets | Secure token minting/burning with meta-transaction support | -| **PayBlox** | Payment management system | Payment tracking, accounting, and execution with time-delay workflows | -| **CopyBlox** | Blox cloning factory | EIP-1167 minimal proxy pattern for deploying multiple blox instances | -| **GuardianSafe** | Safe wallet integration | Safe wallet wrapper with Bloxchain security workflows | -| **BasicERC20** | Basic token example | Standard ERC20 token implementation using Bloxchain security | +### Security model -### ๐Ÿ›ก๏ธ Security Model - -**Mandatory Multi-Signature Architecture:** -- **Time-Delay Workflow**: Request โ†’ Wait โ†’ Approve (2 signatures) -- **Meta-Transaction Workflow**: Sign โ†’ Execute (2 signatures, role separation) -- **No Single-Point Failures**: Contract controls storage, not wallets -- **Temporal Security**: Time-locks provide intervention windows - -**Core System Roles**: -- **Owner Role**: Administrative control, can approve operations after timelock, or by signing a Meta-transaction (single wallet) -- **Broadcaster Role**: Meta-transaction execution, gas sponsorship (up to 3 wallets) -- **Recovery Role**: Emergency operations, limited scope (single wallet) +- **Time-delay:** Request โ†’ wait โ†’ Approve (2 signatures). **Meta-tx:** Sign โ†’ Execute (role separation). +- **Roles:** Owner (admin, approve), Broadcaster (execute meta-tx, gas), Recovery (emergency). ## ๐Ÿš€ Quick Start -### Prerequisites +**Prerequisites:** Node.js v18+ ```bash -# Install Node.js (v18 or higher) -node --version -``` - -### Installation - -```bash -# Clone the repository git clone https://github.com/PracticalParticle/Bloxchain-Protocol.git cd Bloxchain-Protocol - -# Install dependencies npm install - -# Compile contracts npm run compile:foundry - -# Run tests npm run test:foundry ``` -### ๐Ÿ“ฆ Install Packages - -**Install the SDK and Contracts packages**: [@bloxchain/sdk](https://www.npmjs.com/package/@bloxchain/sdk) ยท [@bloxchain/contracts](https://www.npmjs.com/package/@bloxchain/contracts) - -```bash -# Install TypeScript SDK -npm install @bloxchain/sdk - -# Install Contracts package -npm install @bloxchain/contracts -``` - -### TypeScript SDK Usage - -```typescript -// Import from @bloxchain/sdk package -import { - SecureOwnable, - RuntimeRBAC, - Definitions, - type Address, - type PublicClient, - type WalletClient -} from '@bloxchain/sdk'; - -// Import contracts from @bloxchain/contracts package -import '@bloxchain/contracts/core/security/SecureOwnable.sol'; -``` - -### ๐ŸŒ Testnet Deployment - -**Sepolia Testnet Support**: -```bash -# Deploy to Sepolia testnet (configure hardhat.config.ts / .env.deployment first) -npm run deploy:hardhat -- --network sepolia - -# Or use SandBlox for interactive testing -# Visit: https://sandblox.app/ -``` - -**Supported Networks**: -- **Local Development**: Hardhat Network (built-in, no setup required) -- **Ethereum Sepolia**: Testnet deployment and testing -- **SandBlox Platform**: Interactive testing environment +**SDK / contracts:** `npm install @bloxchain/sdk @bloxchain/contracts` +**Networks:** Local (Hardhat), [Sepolia](https://sepolia.etherscan.io/), [SandBlox](https://sandblox.app/) ## Deployment -### Deploying foundation libraries (public networks) - -Foundation libraries (EngineBlox, SecureOwnableDefinitions, RuntimeRBACDefinitions, GuardControllerDefinitions) can be deployed to public networks using Hardhat: - -1. **Configure deployment env** - Copy `env.deployment.example` to `.env.deployment` and set: - - `DEPLOY_RPC_URL` โ€“ RPC URL (e.g. [Infura](https://infura.io/) or [Alchemy](https://alchemy.com/) for Sepolia) - - `DEPLOY_PRIVATE_KEY` โ€“ Deployer wallet private key (no leading `0x` or with `0x`) - - Optionally `DEPLOY_CHAIN_ID` (Sepolia: `11155111`) and `DEPLOY_NETWORK_NAME` +1. Copy `env.deployment.example` to `.env.deployment` and set `DEPLOY_RPC_URL`, `DEPLOY_PRIVATE_KEY`; optionally `DEPLOY_CHAIN_ID` (Sepolia: `11155111`) and `DEPLOY_NETWORK_NAME`. +2. **Foundation (libraries + AccountBlox):** `npm run deploy:hardhat:foundation` + Or: `npx hardhat run scripts/deployment/deploy-foundation-libraries.js --network sepolia` +3. **Example (CopyBlox):** `npx hardhat run scripts/deployment/deploy-example-copyblox.js --network sepolia` -2. **Deploy to Sepolia** - ```bash - npm run deploy:hardhat:foundation - ``` - Or with an explicit network: - ```bash - npx hardhat run scripts/deploy-foundation-libraries.js --network sepolia - ``` - -Deployed addresses are written to **`deployed-addresses.json`** under the network key (e.g. `sepolia`, `development`). +Addresses are written to **`deployed-addresses.json`**. ### Deployed addresses **Ethereum Sepolia (testnet)** +#### Foundation (libraries) + | Contract | Address | |----------|---------| -| EngineBlox | [`0x524632c2a77b27a11f536f4e568570dc2aaafe99`](https://sepolia.etherscan.io/address/0x524632c2a77b27a11f536f4e568570dc2aaafe99) | -| SecureOwnableDefinitions | [`0x0b722d1bad16e449482d69a13c42373a9d8ce2cf`](https://sepolia.etherscan.io/address/0x0b722d1bad16e449482d69a13c42373a9d8ce2cf) | -| RuntimeRBACDefinitions | [`0x5c64e07d6193475b7869b33cef00fbae1ec27938`](https://sepolia.etherscan.io/address/0x5c64e07d6193475b7869b33cef00fbae1ec27938) | -| GuardControllerDefinitions | [`0xcd56a07a1285c5a6cc070d17a63b5a31e151de0e`](https://sepolia.etherscan.io/address/0xcd56a07a1285c5a6cc070d17a63b5a31e151de0e) | +| EngineBlox | [`0xd0db4bcfac215e86371c55ba9d91030082fe7adb`](https://sepolia.etherscan.io/address/0xd0db4bcfac215e86371c55ba9d91030082fe7adb) | +| SecureOwnableDefinitions | [`0xd21e88564377cbbed7885416cf0462b1a7e424aa`](https://sepolia.etherscan.io/address/0xd21e88564377cbbed7885416cf0462b1a7e424aa) | +| RuntimeRBACDefinitions | [`0x03156b0dcbd104c397aa3463705964b933ed4d3f`](https://sepolia.etherscan.io/address/0x03156b0dcbd104c397aa3463705964b933ed4d3f) | +| GuardControllerDefinitions | [`0x4b828c8575fcb375158d0926fd2ca01e5f41ca1f`](https://sepolia.etherscan.io/address/0x4b828c8575fcb375158d0926fd2ca01e5f41ca1f) | +#### Account -## ๐Ÿ“– Usage Examples +| Contract | Address | +|----------|---------| +| AccountBlox | [`0x5886d5760551fae5f826ebb71d5b8a125da57a15`](https://sepolia.etherscan.io/address/0x5886d5760551fae5f826ebb71d5b8a125da57a15) | -### Basic Ownership Management +#### Examples -```typescript -// Import from @bloxchain/sdk package -import { SecureOwnable, type Address, type PublicClient, type WalletClient } from '@bloxchain/sdk'; -import { createPublicClient, createWalletClient, http } from 'viem'; -import { sepolia } from 'viem/chains'; - -// Initialize clients -const publicClient = createPublicClient({ chain: sepolia, transport: http() }); -const walletClient = createWalletClient({ chain: sepolia, transport: http() }); - -// Initialize SecureOwnable client -const secureOwnable = new SecureOwnable( - publicClient, - walletClient, - contractAddress, - chain -); - -// Request ownership transfer (time-locked) -const txResult = await secureOwnable.transferOwnershipRequest({ - from: ownerAddress -}); - -// Approve after time-lock period -const approvalResult = await secureOwnable.transferOwnershipDelayedApproval( - txId, - { from: ownerAddress } -); -``` +| Contract | Address | +|----------|---------| +| CopyBlox | [`0xc380cb5a483f32614365619ef9bbcf360f62836e`](https://sepolia.etherscan.io/address/0xc380cb5a483f32614365619ef9bbcf360f62836e) | -### Meta-Transactions (Gasless) +## ๐Ÿ“– Usage Examples ```typescript -// Create meta-transaction parameters -const metaTxParams = await secureOwnable.createMetaTxParams( - contractAddress, - '0x12345678', // function selector - BigInt(24), // deadline in hours - BigInt('50000000000'), // max gas price - signer -); - -// Generate unsigned meta-transaction -const metaTx = await secureOwnable.generateUnsignedMetaTransactionForExisting( - txId, - metaTxParams -); - -// Sign the meta-transaction (client-side) -const signature = await walletClient.signMessage({ - message: { raw: metaTx.message as Uint8Array }, - account: signer -}); - -// Execute with meta-transaction -await secureOwnable.transferOwnershipApprovalWithMetaTx( - { ...metaTx, signature }, - { from: broadcasterAddress } -); -``` +import { SecureOwnable } from '@bloxchain/sdk'; -### Dynamic Role-Based Access Control +const secureOwnable = new SecureOwnable(publicClient, walletClient, contractAddress, chain); -```typescript -// Import from @bloxchain/sdk package -import { RuntimeRBAC } from '@bloxchain/sdk'; -import { encodeAbiParameters } from 'viem'; - -// Initialize RuntimeRBAC client -const runtimeRBAC = new RuntimeRBAC( - publicClient, - walletClient, - contractAddress, - chain -); - -// Create custom role via batch configuration -const actions = [{ - actionType: 'CREATE_ROLE', - data: abi.encode( - ['string', 'uint256', 'tuple[]'], - ['TreasuryManager', 5, functionPermissions] - ) -}]; - -await runtimeRBAC.roleConfigBatchRequestAndApprove( - metaTx, - { from: broadcasterAddress } -); - -// Query role information -const role = await runtimeRBAC.getRole(roleHash); -const wallets = await runtimeRBAC.getWalletsInRole(roleHash); +// Time-locked ownership transfer +await secureOwnable.transferOwnershipRequest({ from: ownerAddress }); +await secureOwnable.transferOwnershipDelayedApproval(txId, { from: ownerAddress }); ``` -## ๐Ÿ” Runtime RBAC: Dynamic Role-Based Access Control - -Bloxchain Protocol implements **Runtime RBAC** (Role-Based Access Control) that enables dynamic role configuration without contract upgrades. This system provides enterprise-grade access control through: +Meta-transactions (gasless) and Runtime RBAC examples: see [@bloxchain/sdk](https://www.npmjs.com/package/@bloxchain/sdk) and the repo `sdk/` and `test/` directories. -### Key Features - -- **Batch Configuration**: Atomic role management operations via `roleConfigBatch` -- **Function-Level Permissions**: Granular permissions using action bitmaps -- **Dynamic Role Creation**: Create, update, and remove roles at runtime -- **Handler Selectors**: Support for handler functions with execution selector permissions -- **Protected Roles**: System roles (Owner, Broadcaster, Recovery) cannot be modified - -### Runtime RBAC Workflow - -```typescript -// Create a custom role with specific permissions -const actions = [{ - actionType: 'CREATE_ROLE', - data: abi.encode( - ['string', 'uint256', 'tuple[]'], - ['TreasuryManager', 5, functionPermissions] - ) -}]; - -// Execute via meta-transaction for gasless operation -await runtimeRBAC.roleConfigBatchRequestAndApprove(metaTx, { - from: broadcasterAddress -}); -``` +## ๐Ÿ” Runtime RBAC & GuardController -### Permission Model - -- **Action Bitmaps**: Compact representation of allowed actions (Request, Approve, Cancel, Sign, Execute) -- **Function Selectors**: Per-function permission granularity -- **Role Separation**: Mandatory separation between signing and execution roles -- **Wallet Limits**: Configurable maximum wallets per role - -## ๐Ÿ›ก๏ธ GuardController: Controlled Endpoint for External Interactions - -**GuardController** provides a **controlled endpoint** for external contract interactions, enabling dynamic definition of access and workflows for external contracts. It serves as a secure gateway that delegates control to external addresses while maintaining strict security boundaries. - -### Key Features - -- **Dynamic Access Definition**: Configure access and workflows for external contracts at runtime -- **Target Whitelisting**: Per-function selector whitelist restricts which contract addresses can be called -- **Defense-in-Depth Security**: Multiple layers of validation (whitelist + permissions + time-locks) -- **Workflow Support**: Time-locked and meta-transaction workflows for all external interactions -- **Function Schema Registration**: Runtime function registration with action-level permissions - -### Security Model - -**Target Whitelist Enforcement**: -- Each function selector has its own target address whitelist -- Target MUST be explicitly whitelisted for the function selector -- Empty whitelist = explicit deny (no targets allowed) -- Prevents exploitation of global function selector permissions - -**Workflow Execution**: -1. Register function schemas with supported actions -2. Configure target whitelists per function selector (REQUIRED) -3. Create roles and assign function permissions (via RuntimeRBAC) -4. Execute operations via time-lock or meta-transaction workflows -5. Target whitelist is ALWAYS validated before execution - -### Use Cases - -- **Multi-Signature Wallet Integration**: Secure delegation to external wallet contracts -- **DAO Governance**: Controlled execution of governance proposals -- **DeFi Protocol Integration**: Secure interaction with external DeFi protocols -- **Cross-Contract Operations**: Orchestrate complex multi-contract workflows - -### Example Usage - -```solidity -// GuardController enables secure external contract calls -contract MyController is GuardController, RuntimeRBAC, SecureOwnable { - // Configure target whitelist for a function selector - function setupExternalCall() external { - GuardConfigAction[] memory actions = new GuardConfigAction[](1); - actions[0] = GuardConfigAction({ - actionType: GuardConfigActionType.ADD_TARGET_TO_WHITELIST, - data: abi.encode(functionSelector, targetAddress) - }); - executeGuardConfigBatch(actions); - } - - // Execute external call with time-lock workflow - function callExternalContract() external { - executeWithTimeLock( - targetAddress, - 0, // value - functionSelector, - params, - gasLimit, - operationType - ); - } -} -``` +- **Runtime RBAC:** Dynamic roles via `roleConfigBatch`; function-level permissions (action bitmaps), protected system roles. Use `RuntimeRBAC` from `@bloxchain/sdk` for role creation and queries. +- **GuardController:** Controlled external calls: per-function target whitelist, time-lock/meta-tx workflows. Register schemas, whitelist targets, then execute via EngineBlox workflows. See `AccountBlox` and example contracts. ## ๐Ÿ“‹ Definition Data Layer -The **Definition Data Layer** enables modular contract initialization through the `IDefinition` interface. Definition contracts provide: - -### Core Components - -- **Function Schemas**: Define supported functions, operation types, and action permissions -- **Role Permissions**: Map roles to function permissions with action bitmaps -- **Pure Functions**: All definition functions are `pure` for immutability -- **Modular Initialization**: Load definitions during contract initialization without increasing contract size - -### Definition Contract Structure - -```solidity -interface IDefinition { - function getFunctionSchemas() external pure returns (EngineBlox.FunctionSchema[] memory); - function getRolePermissions() external pure returns (RolePermission memory); -} -``` +`IDefinition` supplies **function schemas** and **role permissions** as `pure` functions; definitions live in separate libraries to keep contract size down. See `contracts/.../lib/definitions/` and SDK for discovery. -### Benefits +## ๐Ÿงช Fuzz Testing -- **Contract Size Optimization**: Definitions stored in separate libraries -- **Modular Design**: Easy to extend and customize -- **Type Safety**: Compile-time validation of function schemas -- **Runtime Discovery**: Dynamic querying of contract capabilities via SDK - -### Example Definition Contract - -```solidity -library SimpleVaultDefinitions { - function getFunctionSchemas() public pure returns (EngineBlox.FunctionSchema[] memory) { - // Define function schemas with operation types and action permissions - } - - function getRolePermissions() public pure returns (IDefinition.RolePermission memory) { - // Define role-to-permission mappings - } -} -``` - -## ๐Ÿงช Comprehensive Fuzz Testing - -Bloxchain Protocol includes **comprehensive fuzz testing** with **37 test suites** and **309 tests** (all passing) covering all security-critical components and edge cases. See [test/foundry/docs](test/foundry/docs/) for the Attack Vectors Codex and coverage report. - -### Test Coverage - -| Test Suite | Coverage Area | Test Count | -|------------|---------------|------------| -| **ComprehensiveStateMachineFuzz** | State machine security, reentrancy protection, EIP-150 OOG, no delegatecall | 23 tests | -| **ComprehensiveSecurityEdgeCasesFuzz** | Bitmap attacks, hook vulnerabilities, payment race conditions | 10 tests | -| **ComprehensiveMetaTransactionFuzz** | Meta-transaction security, signature validation, nonce, chainId | 14 tests | -| **ComprehensiveInputValidationFuzz** | Input validation, array manipulation, edge cases | 13 tests | -| **ComprehensivePaymentSecurityFuzz** | Payment management, race conditions, fee-on-transfer tokens | 7 tests | -| **ComprehensiveHookSystemFuzz** | Hook execution, interface compliance | 2 tests | -| **ComprehensiveAccessControlFuzz** | Access control, permission validation, state after removal | 14 tests | -| **ComprehensiveDefinitionSecurityFuzz** | Definition loading, schema validation | 20 tests | -| **ComprehensiveGasExhaustionFuzz** | Gas limits, batch operations | 17 tests | -| **ComprehensiveWhitelistSchemaFuzz** | Target whitelisting, function schemas | 8 tests | -| **ComprehensiveEIP712AndViewFuzz** | EIP-712 domain determinism, view consistency, signer recovery, excess msg.value | 4 tests | -| **ComprehensiveCompositeFuzz** | Composite attack vectors | 5 tests | -| **ComprehensiveInitializationFuzz** | Initialization security, reentrancy | 9 tests | -| **ComprehensiveEventForwardingFuzz** | Event forwarding, external integrations | 2 tests | -| **GuardControllerFuzz** | Guard controller workflows | 4 tests | -| **SecureOwnableFuzz** | Ownership management security | 5 tests | -| **RuntimeRBACFuzz** | Runtime RBAC operations | 3 tests | -| **StateMachineWorkflowFuzz** | Workflow state transitions | 5 tests | -| **MetaTransactionSecurityFuzz** | Meta-transaction security | 6 tests | -| **ProtectedResourceFuzz** | Protected resource access | 4 tests | -| **EdgeCasesFuzz** | General edge cases | 4 tests | -| **RBACPermissionFuzz** | RBAC permission validation | 3 tests | -| **SystemMacroSelectorSecurityFuzz** | System selector security | 6 tests | - -### Security Focus Areas - -- **Reentrancy Protection**: All state-changing functions protected -- **Bitmap Security**: Overflow/underflow prevention, invalid enum handling -- **Hook Security**: Execution order, interface compliance, gas exhaustion -- **Payment Security**: Race conditions, front-running prevention -- **Access Control**: Permission escalation, role manipulation -- **Meta-Transaction Security**: Signature validation, replay protection -- **Gas Exhaustion**: Batch size limits, operation limits -- **Composite Attacks**: Multi-vector attack scenarios - -### Running Fuzz Tests +**37 suites, 309 tests** (state machine, meta-tx, RBAC, GuardController, payments, hooks, definitions, gas limits, composite attacks). See [test/foundry/docs](test/foundry/docs/) for the Attack Vectors Codex. ```bash -# Run all Foundry fuzz tests npm run test:foundry:fuzz - -# Run Foundry tests with verbose output -npm run test:foundry:verbose - -# Run specific fuzz test suite (using forge directly) -forge test --match-path "test/foundry/fuzz/ComprehensiveStateMachineFuzz.t.sol" --fuzz-runs 10000 +# Or: forge test --match-path "test/foundry/fuzz/ComprehensiveStateMachineFuzz.t.sol" --fuzz-runs 10000 ``` ## ๐Ÿ”ง Development Tools -### Interactive Testing Platform - -**[SandBlox](https://sandblox.app/)** - Comprehensive testing platform for Bloxchain Protocol: -- **Live Contract Interaction** with real-time state monitoring -- **Multi-signature workflow testing** with visual role management -- **Meta-transaction workflow testing** for gasless operation development -- **Time-lock operation management** with automated workflow tracking -- **Sepolia Testnet Support** - Deploy and test on Ethereum Sepolia testnet - -### Contract Compilation & Size Monitoring +**[SandBlox](https://sandblox.app/)** โ€“ Live contract interaction, multi-sig and meta-tx workflows, Sepolia support. ```bash -# Compile contracts with Foundry -npm run compile:foundry - -# Compile with size checking -npm run compile:foundry:size - -# Verify contracts are under 24KB limit -# Output shows contract sizes and optimization status -``` - -### Testing Infrastructure - -```bash -# Run Foundry tests -npm run test:foundry - -# Run Foundry fuzz tests (comprehensive security testing) -npm run test:foundry:fuzz - -# Run Foundry tests with verbose output -npm run test:foundry:verbose - -# Run Foundry coverage -npm run test:foundry:coverage - -# Run sanity checks -npm run test:sanity:secure-ownable -npm run test:sanity:simple-vault -npm run test:sanity:simple-rwa20 - -# End-to-end testing -npm run test:e2e +npm run compile:foundry # compile; add :size for 24KB check +npm run test:foundry # tests +npm run test:foundry:fuzz # fuzz +npm run test:sanity:secure-ownable # sanity (optional) +npm run docgen && npm run format # docs & format ``` -### Documentation Generation - -```bash -# Generate contract documentation -npm run docgen +## ๐Ÿ“š Documentation -# Format Solidity code -npm run format -``` - -## ๐Ÿ“š Comprehensive Documentation - -### ๐Ÿ—๏ธ Architecture & Design -- **[Protocol Architecture](./sdk/typescript/docs/bloxchain-architecture.md)** - Core design principles -- **[State Machine Engine](./sdk/typescript/docs/state-machine-engine.md)** - SecureOperationState engine -- **[Architecture Patterns](./sdk/typescript/docs/architecture-patterns.md)** - Design patterns - -### ๐Ÿš€ Developer Guides -- **[Getting Started](./sdk/typescript/docs/getting-started.md)** - Quick setup guide -- **[API Reference](./sdk/typescript/docs/api-reference.md)** - Complete API docs -- **[SecureOwnable Guide](./sdk/typescript/docs/secure-ownable.md)** - Ownership management -- **[RuntimeRBAC Guide](./sdk/typescript/docs/dynamic-rbac.md)** - Role-based access control - -### ๐Ÿ” Advanced Topics -- **[Best Practices](./sdk/typescript/docs/best-practices.md)** - Development guidelines -- **[Examples](./sdk/typescript/docs/examples-basic.md)** - Code samples -- **[Types & Interfaces](./sdk/typescript/docs/types-interfaces.md)** - Type definitions +- [Protocol Architecture](./sdk/typescript/docs/bloxchain-architecture.md) ยท [State Machine](./sdk/typescript/docs/state-machine-engine.md) ยท [Getting Started](./sdk/typescript/docs/getting-started.md) ยท [API Reference](./sdk/typescript/docs/api-reference.md) ยท [SecureOwnable](./sdk/typescript/docs/secure-ownable.md) ยท [RuntimeRBAC](./sdk/typescript/docs/dynamic-rbac.md) ยท [Best Practices](./sdk/typescript/docs/best-practices.md) ยท [Examples](./sdk/typescript/docs/examples-basic.md) ## ๐Ÿ›ก๏ธ Security Features -### Multi-Phase Security Model - -**Time-Delay Workflow:** -``` -Request Phase: Role A โ†’ Creates time-locked transaction -โ†“ (Mandatory time delay) -Approval Phase: Role A or B โ†’ Reviews and approves -โ†“ -Execution Phase: Contract โ†’ Validates and executes -``` - -**Meta-Transaction Workflow:** -``` -Signing Phase: Signer Role โ†’ Creates cryptographic approval -โ†“ -Execution Phase: Executor Role โ†’ Submits signed transaction -โ†“ -Validation Phase: Contract โ†’ Verifies signatures and executes -``` - -**Function-Level Permissions**: -- **Time-Delay Operations**: Request, approve, and cancel permissions -- **Meta-Transaction Operations**: Sign and execute permissions with role separation -- **Dynamic Role Management**: Create, update, and delete custom roles -- **System Administration**: Owner, broadcaster, and recovery role management - -### Cryptographic Security - -- **EIP-712 Compliant**: Structured data signing for meta-transactions -- **Per-Signer Nonces**: Replay attack prevention -- **Role Separation**: Mandatory separation between signing and execution -- **Time-Lock Enforcement**: Mathematical guarantees for temporal security +- **Time-delay:** Request โ†’ (wait) โ†’ Approve โ†’ Execute. **Meta-tx:** Sign โ†’ Execute (signer โ‰  executor). +- **EIP-712** structured data, per-signer nonces, time-lock enforcement. Function-level permissions: Request/Approve/Cancel, Sign/Execute, plus dynamic RBAC. ## ๐ŸŒŸ Key Benefits -### For Developers -- **Eliminates Single-Point Failures**: Mandatory multi-signature architecture -- **Gasless Transactions**: Meta-transaction support with role separation -- **Dynamic Security**: Runtime role configuration without upgrades -- **Type Safety**: Comprehensive TypeScript SDK with full type definitions - -### For Enterprises -- **Enterprise-Grade Security**: Time-locked operations with intervention windows -- **Regulatory Compliance**: Built-in audit trails and role management -- **Operational Flexibility**: Dynamic role configuration and workflow adaptation -- **Cost Efficiency**: Gasless transactions and optimized contract size - -### For Users -- **Enhanced Security**: Multi-layer validation with temporal separation -- **Better UX**: Gasless transactions and delegated execution -- **Recovery Options**: Built-in recovery mechanisms with time-locked access -- **Transparency**: Complete audit trails and event monitoring +**Developers:** No single-point failure; gasless meta-tx; runtime RBAC; type-safe SDK. **Enterprises:** Time-locks, audit trails, under-24KB contracts. **Users:** Recovery options, transparency. ## ๐Ÿ”ฌ Technical Specifications -### Smart Contract Architecture - -**Core Library Implementation**: -- **EngineBlox Library v1.0.0**: Core state machine with mandatory multi-signature workflows -- **BaseStateMachine**: Foundation for all security contracts with meta-transaction support -- **SecureOwnable**: Multi-role security with Owner, Broadcaster, and Recovery roles -- **RuntimeRBAC**: Runtime role configuration with function-level permissions -- **GuardController**: Controlled endpoint for external contract interactions with dynamic access and workflow definition -- **HookManager**: External hook contract attachment for state machine actions - -**Contract Hierarchy**: -```solidity -// Core Library -library EngineBlox { - struct SecureOperationState { - bool initialized; - uint256 txCounter; - uint256 timeLockPeriodSec; - mapping(uint256 => TxRecord) txRecords; - mapping(bytes32 => Role) roles; - // ... additional state management - } -} - -// Base State Machine -abstract contract BaseStateMachine is Initializable, ERC165Upgradeable { - EngineBlox.SecureOperationState internal _secureState; - // Meta-transaction utilities and state queries -} - -// Security Extensions -abstract contract SecureOwnable is BaseStateMachine, ISecureOwnable { - // Multi-role security with time-locked operations -} - -abstract contract RuntimeRBAC is BaseStateMachine { - // Runtime role-based access control with batch configuration -} - -abstract contract GuardController is BaseStateMachine { - // Controlled endpoint for external contract interactions - // Dynamically defines access and workflows for external contracts - // Target whitelisting per function selector (defense-in-depth security) -} - -abstract contract HookManager is BaseStateMachine { - // External hook contract attachment for state machine actions -} -``` - -**Technical Features**: -- **Solidity Version**: 0.8.34 (fixed version for reproducible builds) -- **OpenZeppelin**: ^5.4.0 (with upgradeable contracts) -- **Contract Size**: < 24KB (optimized for mainnet deployment) -- **Gas Optimization**: Library-based architecture with modular definitions -- **EIP-712 Compliance**: Structured data signing for meta-transactions -- **Role Separation**: Mandatory separation between signing and execution roles - -### TypeScript SDK -- **Viem Integration**: Modern Ethereum development with type safety -- **Comprehensive Interfaces**: Full contract interaction capabilities -- **Meta-Transaction Utilities**: Complete meta-transaction generation and signing -- **Event Monitoring**: Real-time event parsing and monitoring - -### Testing & Quality -- **Comprehensive Fuzz Testing**: 36 test suites, 290 tests covering all security-critical components -- **Foundry Testing**: Primary testing framework with fuzz testing and invariant checking -- **Hardhat Support**: Alternative testing framework for compatibility -- **Sanity Checks**: Production-ready validation scripts -- **Contract Size Monitoring**: Automated size optimization verification -- **Security Edge Cases**: Extensive coverage of attack vectors and vulnerabilities - -## ๐Ÿšง Implementation Status - -### โœ… Available Features -**Core Components**: -- โœ… **EngineBlox Library v1.0.0**: Centralized state management with multi-phase workflows -- โœ… **BaseStateMachine**: Foundation contract with core state machine functionality -- โœ… **SecureOwnable**: Multi-role security with Owner, Broadcaster, and Recovery roles -- โœ… **RuntimeRBAC**: Dynamic role-based access control with runtime configuration -- โœ… **GuardController**: Controlled endpoint for external contract interactions with dynamic access and workflow definition -- โœ… **HookManager**: External hook contract attachment for state machine actions (experimental) -- โœ… **Template Contracts**: BareBlox, SecureBlox, RoleBlox, AccountBlox, MachineBlox -- โœ… **Example Applications**: SimpleVault, SimpleRWA20, PayBlox, CopyBlox, GuardianSafe, BasicERC20 -- โœ… **TypeScript SDK**: Full client library with comprehensive documentation -- โœ… **Comprehensive Fuzz Testing**: 36 test suites, 290 tests covering security edge cases -- โœ… **Runtime RBAC**: Dynamic role configuration without contract upgrades -- โœ… **Definition Data Layer**: Modular initialization via IDefinition interface -- โœ… **Sepolia Testnet Support**: Live deployment and testing on Ethereum Sepolia testnet - -**Security Features**: -- โœ… **Mandatory Multi-Signature**: Every transaction requires minimum 2 signatures -- โœ… **Role Separation**: Meta-transactions enforce signer โ‰  executor separation -- โœ… **Time-Lock Operations**: Configurable delays with intervention windows -- โœ… **Dynamic RBAC**: Runtime role configuration without contract upgrades -- โœ… **Function Target Whitelisting**: Per-function selector target address restrictions -- โœ… **Function Schemas**: Runtime function registration with action-level permissions -- โœ… **Handler Selectors**: Support for handler functions with execution selector permissions -- โœ… **Audit Trails**: Complete transaction history with cryptographic proofs +**Stack:** Solidity 0.8.34, OpenZeppelin ^5.4.0 (upgradeable). **Libraries:** EngineBlox โ†’ BaseStateMachine โ†’ SecureOwnable, RuntimeRBAC, GuardController, HookManager. Contract size under 24KB; EIP-712; Viem-based TypeScript SDK. **Testing:** Foundry (fuzz + invariant), Hardhat, sanity scripts. All core components, template (AccountBlox), example apps, and Sepolia deployment are implemented and covered by tests. ## ๐Ÿ”ฎ Roadmap -### Planned - -- **Formal Verification** โ€“ Automated verification of security and correctness properties -- **Security Audit** โ€“ Third-party security audit by leading blockchain security firms - +Planned: **Formal verification**; **third-party security audit**. ## ๐Ÿค Contributing -We welcome contributions to the Bloxchain Protocol! Please see our comprehensive [Contributing Guidelines](CONTRIBUTING.md) for detailed information on: - -- **Development Setup** - Complete environment configuration -- **Code Standards** - Solidity and TypeScript guidelines -- **Testing Requirements** - 100% coverage and comprehensive test suites -- **Security Considerations** - Security review process and best practices -- **Pull Request Process** - Detailed submission and review workflow -- **Applications Development** - Fork-first approach for community applications - -**Key Requirements:** -- Follow our [Code of Conduct](CODE_OF_CONDUCT.md) -- Maintain 100% test coverage -- Keep contracts under 24KB size limit -- Use `npm run format` for Solidity formatting -- Include comprehensive documentation updates - -### Development Workflow - -**Setup & Testing**: -```bash -# Install dependencies -npm install - -# Compile contracts with Foundry -npm run compile:foundry - -# Run comprehensive test suite -npm run test:foundry - -# Run fuzz tests for security validation -npm run test:foundry:fuzz - -# Run invariant tests -npm run test:foundry:invariant - -# Run sanity checks -npm run test:sanity:secure-ownable -npm run test:sanity:simple-vault -npm run test:sanity:simple-rwa20 -``` - -**Documentation & Deployment**: -```bash -# Generate documentation and format code -npm run docgen -npm run format - -# Deploy to local Hardhat network -npm run deploy:hardhat - -# Deploy to Sepolia testnet (configure network in hardhat.config.ts or .env.deployment) -npm run deploy:hardhat -- --network sepolia -``` +See [Contributing Guidelines](CONTRIBUTING.md) (setup, code standards, testing, security, PR process). Key requirements: [Code of Conduct](CODE_OF_CONDUCT.md), 100% test coverage, contracts under 24KB, `npm run format`. Deploy: `npm run deploy:hardhat` (local) or `npm run deploy:hardhat -- --network sepolia`. ## ๐Ÿ“„ License -This project is licensed under the **Mozilla Public License 2.0 (MPL-2.0)** - see the [LICENSE](LICENSE) file for details. - -### Core Framework License - -**Key Benefits of MPL-2.0:** -- **Open Source**: Free to use, modify, and distribute -- **Commercial Use**: Clear commercial use permissions -- **Patent Protection**: Protects contributors from patent litigation -- **Weak Copyleft**: Allows proprietary integration while keeping core open -- **No Vendor Lock-in**: Freedom to modify without proprietary restrictions - -### Applications Directory License Structure -**Covered Software:** -- Core framework contracts (`contracts/core/`) -- TypeScript SDK (`sdk/typescript/`) -- Documentation and guides -- Testing infrastructure -- Build scripts and tooling - -### Examples Directory Exclusion - -**Important**: The `contracts/examples/` directory and its subdirectories are **EXCLUDED** from MPL-2.0 licensing: - -- **Examples are NOT covered by MPL-2.0** -- **Examples are NOT part of the "Covered Software"** -- **Examples are NOT subject to MPL-2.0 terms** -- **Each example maintains its own licensing terms** -- **Examples are NOT officially supported** by Bloxchain Protocol - -**Important**: The `applications/` directory is **EXCLUDED** from MPL-2.0 licensing: - -- **Core Framework**: Licensed under MPL-2.0 (contracts, SDK, documentation) -- **Applications**: Each application has its own separate license -- **Community Applications** (`applications/community/`): Various open-source licenses (MIT, Apache 2.0, GPL v3, etc.) -- **Proprietary Applications** (`applications/proprietary/`): Commercial/proprietary licenses -See individual LICENSE files in each example subdirectory for specific terms. - -**Applications are:** -- โŒ **NOT covered by MPL-2.0** -- โŒ **NOT officially supported** by Bloxchain Protocol -- โŒ **NOT part of the core framework** -- โœ… **Licensed separately** with their own terms -- โœ… **Used at your own risk** - -### Contributing License Agreement - -See individual LICENSE files in each application directory for specific terms. - -By contributing to Bloxchain Protocol, you agree that your contributions will be licensed under the Mozilla Public License 2.0 (MPL-2.0). See [CONTRIBUTING.md](CONTRIBUTING.md) for more details. +**MPL-2.0** โ€“ see [LICENSE](LICENSE). Covers core contracts (`contracts/core/`), SDK (`sdk/typescript/`), docs, tests, tooling. **Excluded:** `contracts/examples/` and `applications/` have their own licenses (see per-directory LICENSE files). Contributions under MPL-2.0; see [CONTRIBUTING.md](CONTRIBUTING.md). ## ๐Ÿ™ Acknowledgments -- **[Particle Crypto Security](https://particlecs.com/)** for the innovative Bloxchain Protocol implementation -- **OpenZeppelin** for secure smart contract components and upgradeable patterns -- **Viem** for modern TypeScript blockchain interactions -- **Hardhat** for comprehensive development and testing framework -- **Foundry** for advanced fuzz testing and security validation +[Particle CS](https://particlecs.com/), OpenZeppelin, Viem, Hardhat, Foundry. ## ๐Ÿ“ž Support & Community -- **Documentation**: Comprehensive guides in [`sdk/typescript/docs/`](./sdk/typescript/docs/) -- **Examples**: Real-world implementations in [`contracts/examples/`](./contracts/examples/) -- **Testing Platform**: Interactive development with [SandBlox](https://sandblox.app/) -- **Company Website**: Learn more at [Particle CS](https://particlecs.com/) -- **Issues**: Report bugs and request features via GitHub Issues -- **Discussions**: Join community discussions for questions and collaboration +Docs: [`sdk/typescript/docs/`](./sdk/typescript/docs/). Examples: [`contracts/examples/`](./contracts/examples/). Testing: [SandBlox](https://sandblox.app/). [Issues](https://github.com/PracticalParticle/Bloxchain-Protocol/issues) ยท [Discussions](https://github.com/PracticalParticle/Bloxchain-Protocol/discussions). --- -Created by [Particle Crypto Security](https://particlecs.com/) -Copyright ยฉ 2025 Particle Crypto Security. All rights reserved. \ No newline at end of file +Created by [Particle Crypto Security](https://particlecs.com/) ยท Copyright ยฉ 2025 Particle Crypto Security. \ No newline at end of file diff --git a/abi/BareBlox.abi.json b/abi/CopyBlox.abi.json similarity index 86% rename from abi/BareBlox.abi.json rename to abi/CopyBlox.abi.json index e64e82e9..2fe439e5 100644 --- a/abi/BareBlox.abi.json +++ b/abi/CopyBlox.abi.json @@ -1,9 +1,52 @@ [ + { + "inputs": [], + "name": "FailedDeployment", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "balance", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "needed", + "type": "uint256" + } + ], + "name": "InsufficientBalance", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "provided", + "type": "address" + } + ], + "name": "InvalidAddress", + "type": "error" + }, { "inputs": [], "name": "InvalidInitialization", "type": "error" }, + { + "inputs": [ + { + "internalType": "address", + "name": "item", + "type": "address" + } + ], + "name": "InvalidOperation", + "type": "error" + }, { "inputs": [ { @@ -36,6 +79,16 @@ "name": "NotInitializing", "type": "error" }, + { + "inputs": [], + "name": "NotSupported", + "type": "error" + }, + { + "inputs": [], + "name": "OperationFailed", + "type": "error" + }, { "inputs": [ { @@ -68,6 +121,86 @@ "name": "ResourceNotFound", "type": "error" }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "original", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "clone", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "initialOwner", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "cloneNumber", + "type": "uint256" + } + ], + "name": "BloxCloned", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "cloneAddress", + "type": "address" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "txId", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "bytes4", + "name": "functionSelector", + "type": "bytes4" + }, + { + "indexed": false, + "internalType": "enum EngineBlox.TxStatus", + "name": "status", + "type": "uint8" + }, + { + "indexed": false, + "internalType": "address", + "name": "requester", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "target", + "type": "address" + }, + { + "indexed": false, + "internalType": "bytes32", + "name": "operationType", + "type": "bytes32" + } + ], + "name": "CloneEventForwarded", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -100,6 +233,10 @@ "name": "Initialized", "type": "event" }, + { + "stateMutability": "payable", + "type": "fallback" + }, { "inputs": [ { @@ -1342,6 +1479,10 @@ "stateMutability": "view", "type": "function" }, + { + "stateMutability": "payable", + "type": "receive" + }, { "inputs": [ { @@ -1374,5 +1515,133 @@ "outputs": [], "stateMutability": "nonpayable", "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "bloxAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "initialOwner", + "type": "address" + }, + { + "internalType": "address", + "name": "broadcaster", + "type": "address" + }, + { + "internalType": "address", + "name": "recovery", + "type": "address" + }, + { + "internalType": "uint256", + "name": "timeLockPeriodSec", + "type": "uint256" + } + ], + "name": "cloneBlox", + "outputs": [ + { + "internalType": "address", + "name": "cloneAddress", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "getCloneCount", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "index", + "type": "uint256" + } + ], + "name": "getCloneAtIndex", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "cloneAddress", + "type": "address" + } + ], + "name": "isClone", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "txId", + "type": "uint256" + }, + { + "internalType": "bytes4", + "name": "functionSelector", + "type": "bytes4" + }, + { + "internalType": "enum EngineBlox.TxStatus", + "name": "status", + "type": "uint8" + }, + { + "internalType": "address", + "name": "requester", + "type": "address" + }, + { + "internalType": "address", + "name": "target", + "type": "address" + }, + { + "internalType": "bytes32", + "name": "operationType", + "type": "bytes32" + } + ], + "name": "forwardTxEvent", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" } ] \ No newline at end of file diff --git a/abi/RoleBlox.abi.json b/abi/RoleBlox.abi.json deleted file mode 100644 index ffe699b2..00000000 --- a/abi/RoleBlox.abi.json +++ /dev/null @@ -1,2994 +0,0 @@ -[ - { - "inputs": [ - { - "internalType": "uint256", - "name": "array1Length", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "array2Length", - "type": "uint256" - } - ], - "name": "ArrayLengthMismatch", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "currentSize", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "maxSize", - "type": "uint256" - } - ], - "name": "BatchSizeExceeded", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "resourceId", - "type": "bytes32" - } - ], - "name": "CannotModifyProtected", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "bytes4", - "name": "functionSelector", - "type": "bytes4" - } - ], - "name": "ContractFunctionMustBeProtected", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidInitialization", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "from", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "to", - "type": "uint256" - } - ], - "name": "InvalidRange", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "caller", - "type": "address" - } - ], - "name": "NoPermission", - "type": "error" - }, - { - "inputs": [], - "name": "NotInitializing", - "type": "error" - }, - { - "inputs": [], - "name": "NotSupported", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "internalType": "address", - "name": "contractAddress", - "type": "address" - } - ], - "name": "OnlyCallableByContract", - "type": "error" - }, - { - "inputs": [], - "name": "PendingSecureRequest", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "rangeSize", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "maxRangeSize", - "type": "uint256" - } - ], - "name": "RangeSizeExceeded", - "type": "error" - }, - { - "inputs": [], - "name": "ReentrancyGuardReentrantCall", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "resourceId", - "type": "bytes32" - } - ], - "name": "ResourceNotFound", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "internalType": "address", - "name": "owner", - "type": "address" - } - ], - "name": "RestrictedOwner", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "internalType": "address", - "name": "recovery", - "type": "address" - } - ], - "name": "RestrictedOwnerRecovery", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "internalType": "address", - "name": "recovery", - "type": "address" - } - ], - "name": "RestrictedRecovery", - "type": "error" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "bytes4", - "name": "functionSelector", - "type": "bytes4" - }, - { - "indexed": false, - "internalType": "bytes", - "name": "data", - "type": "bytes" - } - ], - "name": "ComponentEvent", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint64", - "name": "version", - "type": "uint64" - } - ], - "name": "Initialized", - "type": "event" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "handlerContract", - "type": "address" - }, - { - "internalType": "bytes4", - "name": "handlerSelector", - "type": "bytes4" - }, - { - "internalType": "enum EngineBlox.TxAction", - "name": "action", - "type": "uint8" - }, - { - "internalType": "uint256", - "name": "deadline", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "maxGasPrice", - "type": "uint256" - }, - { - "internalType": "address", - "name": "signer", - "type": "address" - } - ], - "name": "createMetaTxParams", - "outputs": [ - { - "components": [ - { - "internalType": "uint256", - "name": "chainId", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "nonce", - "type": "uint256" - }, - { - "internalType": "address", - "name": "handlerContract", - "type": "address" - }, - { - "internalType": "bytes4", - "name": "handlerSelector", - "type": "bytes4" - }, - { - "internalType": "enum EngineBlox.TxAction", - "name": "action", - "type": "uint8" - }, - { - "internalType": "uint256", - "name": "deadline", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "maxGasPrice", - "type": "uint256" - }, - { - "internalType": "address", - "name": "signer", - "type": "address" - } - ], - "internalType": "struct EngineBlox.MetaTxParams", - "name": "", - "type": "tuple" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "newBroadcaster", - "type": "address" - }, - { - "internalType": "uint256", - "name": "location", - "type": "uint256" - } - ], - "name": "executeBroadcasterUpdate", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "newRecoveryAddress", - "type": "address" - } - ], - "name": "executeRecoveryUpdate", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "enum IRuntimeRBAC.RoleConfigActionType", - "name": "actionType", - "type": "uint8" - }, - { - "internalType": "bytes", - "name": "data", - "type": "bytes" - } - ], - "internalType": "struct IRuntimeRBAC.RoleConfigAction[]", - "name": "actions", - "type": "tuple[]" - } - ], - "name": "executeRoleConfigBatch", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "newTimeLockPeriodSec", - "type": "uint256" - } - ], - "name": "executeTimeLockUpdate", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "newOwner", - "type": "address" - } - ], - "name": "executeTransferOwnership", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes4", - "name": "functionSelector", - "type": "bytes4" - } - ], - "name": "functionSchemaExists", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "txId", - "type": "uint256" - }, - { - "components": [ - { - "internalType": "uint256", - "name": "chainId", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "nonce", - "type": "uint256" - }, - { - "internalType": "address", - "name": "handlerContract", - "type": "address" - }, - { - "internalType": "bytes4", - "name": "handlerSelector", - "type": "bytes4" - }, - { - "internalType": "enum EngineBlox.TxAction", - "name": "action", - "type": "uint8" - }, - { - "internalType": "uint256", - "name": "deadline", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "maxGasPrice", - "type": "uint256" - }, - { - "internalType": "address", - "name": "signer", - "type": "address" - } - ], - "internalType": "struct EngineBlox.MetaTxParams", - "name": "metaTxParams", - "type": "tuple" - } - ], - "name": "generateUnsignedMetaTransactionForExisting", - "outputs": [ - { - "components": [ - { - "components": [ - { - "internalType": "uint256", - "name": "txId", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "releaseTime", - "type": "uint256" - }, - { - "internalType": "enum EngineBlox.TxStatus", - "name": "status", - "type": "uint8" - }, - { - "components": [ - { - "internalType": "address", - "name": "requester", - "type": "address" - }, - { - "internalType": "address", - "name": "target", - "type": "address" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "gasLimit", - "type": "uint256" - }, - { - "internalType": "bytes32", - "name": "operationType", - "type": "bytes32" - }, - { - "internalType": "bytes4", - "name": "executionSelector", - "type": "bytes4" - }, - { - "internalType": "bytes", - "name": "executionParams", - "type": "bytes" - } - ], - "internalType": "struct EngineBlox.TxParams", - "name": "params", - "type": "tuple" - }, - { - "internalType": "bytes32", - "name": "message", - "type": "bytes32" - }, - { - "internalType": "bytes", - "name": "result", - "type": "bytes" - }, - { - "components": [ - { - "internalType": "address", - "name": "recipient", - "type": "address" - }, - { - "internalType": "uint256", - "name": "nativeTokenAmount", - "type": "uint256" - }, - { - "internalType": "address", - "name": "erc20TokenAddress", - "type": "address" - }, - { - "internalType": "uint256", - "name": "erc20TokenAmount", - "type": "uint256" - } - ], - "internalType": "struct EngineBlox.PaymentDetails", - "name": "payment", - "type": "tuple" - } - ], - "internalType": "struct EngineBlox.TxRecord", - "name": "txRecord", - "type": "tuple" - }, - { - "components": [ - { - "internalType": "uint256", - "name": "chainId", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "nonce", - "type": "uint256" - }, - { - "internalType": "address", - "name": "handlerContract", - "type": "address" - }, - { - "internalType": "bytes4", - "name": "handlerSelector", - "type": "bytes4" - }, - { - "internalType": "enum EngineBlox.TxAction", - "name": "action", - "type": "uint8" - }, - { - "internalType": "uint256", - "name": "deadline", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "maxGasPrice", - "type": "uint256" - }, - { - "internalType": "address", - "name": "signer", - "type": "address" - } - ], - "internalType": "struct EngineBlox.MetaTxParams", - "name": "params", - "type": "tuple" - }, - { - "internalType": "bytes32", - "name": "message", - "type": "bytes32" - }, - { - "internalType": "bytes", - "name": "signature", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "data", - "type": "bytes" - } - ], - "internalType": "struct EngineBlox.MetaTransaction", - "name": "", - "type": "tuple" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "requester", - "type": "address" - }, - { - "internalType": "address", - "name": "target", - "type": "address" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "gasLimit", - "type": "uint256" - }, - { - "internalType": "bytes32", - "name": "operationType", - "type": "bytes32" - }, - { - "internalType": "bytes4", - "name": "executionSelector", - "type": "bytes4" - }, - { - "internalType": "bytes", - "name": "executionParams", - "type": "bytes" - }, - { - "components": [ - { - "internalType": "uint256", - "name": "chainId", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "nonce", - "type": "uint256" - }, - { - "internalType": "address", - "name": "handlerContract", - "type": "address" - }, - { - "internalType": "bytes4", - "name": "handlerSelector", - "type": "bytes4" - }, - { - "internalType": "enum EngineBlox.TxAction", - "name": "action", - "type": "uint8" - }, - { - "internalType": "uint256", - "name": "deadline", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "maxGasPrice", - "type": "uint256" - }, - { - "internalType": "address", - "name": "signer", - "type": "address" - } - ], - "internalType": "struct EngineBlox.MetaTxParams", - "name": "metaTxParams", - "type": "tuple" - } - ], - "name": "generateUnsignedMetaTransactionForNew", - "outputs": [ - { - "components": [ - { - "components": [ - { - "internalType": "uint256", - "name": "txId", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "releaseTime", - "type": "uint256" - }, - { - "internalType": "enum EngineBlox.TxStatus", - "name": "status", - "type": "uint8" - }, - { - "components": [ - { - "internalType": "address", - "name": "requester", - "type": "address" - }, - { - "internalType": "address", - "name": "target", - "type": "address" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "gasLimit", - "type": "uint256" - }, - { - "internalType": "bytes32", - "name": "operationType", - "type": "bytes32" - }, - { - "internalType": "bytes4", - "name": "executionSelector", - "type": "bytes4" - }, - { - "internalType": "bytes", - "name": "executionParams", - "type": "bytes" - } - ], - "internalType": "struct EngineBlox.TxParams", - "name": "params", - "type": "tuple" - }, - { - "internalType": "bytes32", - "name": "message", - "type": "bytes32" - }, - { - "internalType": "bytes", - "name": "result", - "type": "bytes" - }, - { - "components": [ - { - "internalType": "address", - "name": "recipient", - "type": "address" - }, - { - "internalType": "uint256", - "name": "nativeTokenAmount", - "type": "uint256" - }, - { - "internalType": "address", - "name": "erc20TokenAddress", - "type": "address" - }, - { - "internalType": "uint256", - "name": "erc20TokenAmount", - "type": "uint256" - } - ], - "internalType": "struct EngineBlox.PaymentDetails", - "name": "payment", - "type": "tuple" - } - ], - "internalType": "struct EngineBlox.TxRecord", - "name": "txRecord", - "type": "tuple" - }, - { - "components": [ - { - "internalType": "uint256", - "name": "chainId", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "nonce", - "type": "uint256" - }, - { - "internalType": "address", - "name": "handlerContract", - "type": "address" - }, - { - "internalType": "bytes4", - "name": "handlerSelector", - "type": "bytes4" - }, - { - "internalType": "enum EngineBlox.TxAction", - "name": "action", - "type": "uint8" - }, - { - "internalType": "uint256", - "name": "deadline", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "maxGasPrice", - "type": "uint256" - }, - { - "internalType": "address", - "name": "signer", - "type": "address" - } - ], - "internalType": "struct EngineBlox.MetaTxParams", - "name": "params", - "type": "tuple" - }, - { - "internalType": "bytes32", - "name": "message", - "type": "bytes32" - }, - { - "internalType": "bytes", - "name": "signature", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "data", - "type": "bytes" - } - ], - "internalType": "struct EngineBlox.MetaTransaction", - "name": "", - "type": "tuple" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "roleHash", - "type": "bytes32" - } - ], - "name": "getActiveRolePermissions", - "outputs": [ - { - "components": [ - { - "internalType": "bytes4", - "name": "functionSelector", - "type": "bytes4" - }, - { - "internalType": "uint16", - "name": "grantedActionsBitmap", - "type": "uint16" - }, - { - "internalType": "bytes4[]", - "name": "handlerForSelectors", - "type": "bytes4[]" - } - ], - "internalType": "struct EngineBlox.FunctionPermission[]", - "name": "", - "type": "tuple[]" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "getBroadcasters", - "outputs": [ - { - "internalType": "address[]", - "name": "", - "type": "address[]" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes4", - "name": "functionSelector", - "type": "bytes4" - } - ], - "name": "getFunctionSchema", - "outputs": [ - { - "components": [ - { - "internalType": "string", - "name": "functionSignature", - "type": "string" - }, - { - "internalType": "bytes4", - "name": "functionSelector", - "type": "bytes4" - }, - { - "internalType": "bytes32", - "name": "operationType", - "type": "bytes32" - }, - { - "internalType": "string", - "name": "operationName", - "type": "string" - }, - { - "internalType": "uint16", - "name": "supportedActionsBitmap", - "type": "uint16" - }, - { - "internalType": "bool", - "name": "isProtected", - "type": "bool" - }, - { - "internalType": "bytes4[]", - "name": "handlerForSelectors", - "type": "bytes4[]" - } - ], - "internalType": "struct EngineBlox.FunctionSchema", - "name": "", - "type": "tuple" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes4", - "name": "functionSelector", - "type": "bytes4" - } - ], - "name": "getFunctionWhitelistTargets", - "outputs": [ - { - "internalType": "address[]", - "name": "", - "type": "address[]" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes4", - "name": "functionSelector", - "type": "bytes4" - } - ], - "name": "getHooks", - "outputs": [ - { - "internalType": "address[]", - "name": "hooks", - "type": "address[]" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "getPendingTransactions", - "outputs": [ - { - "internalType": "uint256[]", - "name": "", - "type": "uint256[]" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "getRecovery", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "roleHash", - "type": "bytes32" - } - ], - "name": "getRole", - "outputs": [ - { - "internalType": "string", - "name": "roleName", - "type": "string" - }, - { - "internalType": "bytes32", - "name": "roleHashReturn", - "type": "bytes32" - }, - { - "internalType": "uint256", - "name": "maxWallets", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "walletCount", - "type": "uint256" - }, - { - "internalType": "bool", - "name": "isProtected", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "signer", - "type": "address" - } - ], - "name": "getSignerNonce", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "getSupportedFunctions", - "outputs": [ - { - "internalType": "bytes4[]", - "name": "", - "type": "bytes4[]" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "getSupportedOperationTypes", - "outputs": [ - { - "internalType": "bytes32[]", - "name": "", - "type": "bytes32[]" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "getSupportedRoles", - "outputs": [ - { - "internalType": "bytes32[]", - "name": "", - "type": "bytes32[]" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "getTimeLockPeriodSec", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "txId", - "type": "uint256" - } - ], - "name": "getTransaction", - "outputs": [ - { - "components": [ - { - "internalType": "uint256", - "name": "txId", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "releaseTime", - "type": "uint256" - }, - { - "internalType": "enum EngineBlox.TxStatus", - "name": "status", - "type": "uint8" - }, - { - "components": [ - { - "internalType": "address", - "name": "requester", - "type": "address" - }, - { - "internalType": "address", - "name": "target", - "type": "address" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "gasLimit", - "type": "uint256" - }, - { - "internalType": "bytes32", - "name": "operationType", - "type": "bytes32" - }, - { - "internalType": "bytes4", - "name": "executionSelector", - "type": "bytes4" - }, - { - "internalType": "bytes", - "name": "executionParams", - "type": "bytes" - } - ], - "internalType": "struct EngineBlox.TxParams", - "name": "params", - "type": "tuple" - }, - { - "internalType": "bytes32", - "name": "message", - "type": "bytes32" - }, - { - "internalType": "bytes", - "name": "result", - "type": "bytes" - }, - { - "components": [ - { - "internalType": "address", - "name": "recipient", - "type": "address" - }, - { - "internalType": "uint256", - "name": "nativeTokenAmount", - "type": "uint256" - }, - { - "internalType": "address", - "name": "erc20TokenAddress", - "type": "address" - }, - { - "internalType": "uint256", - "name": "erc20TokenAmount", - "type": "uint256" - } - ], - "internalType": "struct EngineBlox.PaymentDetails", - "name": "payment", - "type": "tuple" - } - ], - "internalType": "struct EngineBlox.TxRecord", - "name": "", - "type": "tuple" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "fromTxId", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "toTxId", - "type": "uint256" - } - ], - "name": "getTransactionHistory", - "outputs": [ - { - "components": [ - { - "internalType": "uint256", - "name": "txId", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "releaseTime", - "type": "uint256" - }, - { - "internalType": "enum EngineBlox.TxStatus", - "name": "status", - "type": "uint8" - }, - { - "components": [ - { - "internalType": "address", - "name": "requester", - "type": "address" - }, - { - "internalType": "address", - "name": "target", - "type": "address" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "gasLimit", - "type": "uint256" - }, - { - "internalType": "bytes32", - "name": "operationType", - "type": "bytes32" - }, - { - "internalType": "bytes4", - "name": "executionSelector", - "type": "bytes4" - }, - { - "internalType": "bytes", - "name": "executionParams", - "type": "bytes" - } - ], - "internalType": "struct EngineBlox.TxParams", - "name": "params", - "type": "tuple" - }, - { - "internalType": "bytes32", - "name": "message", - "type": "bytes32" - }, - { - "internalType": "bytes", - "name": "result", - "type": "bytes" - }, - { - "components": [ - { - "internalType": "address", - "name": "recipient", - "type": "address" - }, - { - "internalType": "uint256", - "name": "nativeTokenAmount", - "type": "uint256" - }, - { - "internalType": "address", - "name": "erc20TokenAddress", - "type": "address" - }, - { - "internalType": "uint256", - "name": "erc20TokenAmount", - "type": "uint256" - } - ], - "internalType": "struct EngineBlox.PaymentDetails", - "name": "payment", - "type": "tuple" - } - ], - "internalType": "struct EngineBlox.TxRecord[]", - "name": "", - "type": "tuple[]" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "wallet", - "type": "address" - } - ], - "name": "getWalletRoles", - "outputs": [ - { - "internalType": "bytes32[]", - "name": "", - "type": "bytes32[]" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "roleHash", - "type": "bytes32" - } - ], - "name": "getWalletsInRole", - "outputs": [ - { - "internalType": "address[]", - "name": "", - "type": "address[]" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "roleHash", - "type": "bytes32" - }, - { - "internalType": "address", - "name": "wallet", - "type": "address" - } - ], - "name": "hasRole", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "initialized", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes4", - "name": "functionSelector", - "type": "bytes4" - }, - { - "internalType": "enum EngineBlox.TxAction", - "name": "action", - "type": "uint8" - } - ], - "name": "isActionSupportedByFunction", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "owner", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "components": [ - { - "internalType": "uint256", - "name": "txId", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "releaseTime", - "type": "uint256" - }, - { - "internalType": "enum EngineBlox.TxStatus", - "name": "status", - "type": "uint8" - }, - { - "components": [ - { - "internalType": "address", - "name": "requester", - "type": "address" - }, - { - "internalType": "address", - "name": "target", - "type": "address" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "gasLimit", - "type": "uint256" - }, - { - "internalType": "bytes32", - "name": "operationType", - "type": "bytes32" - }, - { - "internalType": "bytes4", - "name": "executionSelector", - "type": "bytes4" - }, - { - "internalType": "bytes", - "name": "executionParams", - "type": "bytes" - } - ], - "internalType": "struct EngineBlox.TxParams", - "name": "params", - "type": "tuple" - }, - { - "internalType": "bytes32", - "name": "message", - "type": "bytes32" - }, - { - "internalType": "bytes", - "name": "result", - "type": "bytes" - }, - { - "components": [ - { - "internalType": "address", - "name": "recipient", - "type": "address" - }, - { - "internalType": "uint256", - "name": "nativeTokenAmount", - "type": "uint256" - }, - { - "internalType": "address", - "name": "erc20TokenAddress", - "type": "address" - }, - { - "internalType": "uint256", - "name": "erc20TokenAmount", - "type": "uint256" - } - ], - "internalType": "struct EngineBlox.PaymentDetails", - "name": "payment", - "type": "tuple" - } - ], - "internalType": "struct EngineBlox.TxRecord", - "name": "txRecord", - "type": "tuple" - }, - { - "components": [ - { - "internalType": "uint256", - "name": "chainId", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "nonce", - "type": "uint256" - }, - { - "internalType": "address", - "name": "handlerContract", - "type": "address" - }, - { - "internalType": "bytes4", - "name": "handlerSelector", - "type": "bytes4" - }, - { - "internalType": "enum EngineBlox.TxAction", - "name": "action", - "type": "uint8" - }, - { - "internalType": "uint256", - "name": "deadline", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "maxGasPrice", - "type": "uint256" - }, - { - "internalType": "address", - "name": "signer", - "type": "address" - } - ], - "internalType": "struct EngineBlox.MetaTxParams", - "name": "params", - "type": "tuple" - }, - { - "internalType": "bytes32", - "name": "message", - "type": "bytes32" - }, - { - "internalType": "bytes", - "name": "signature", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "data", - "type": "bytes" - } - ], - "internalType": "struct EngineBlox.MetaTransaction", - "name": "metaTx", - "type": "tuple" - } - ], - "name": "roleConfigBatchRequestAndApprove", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "components": [ - { - "internalType": "uint256", - "name": "txId", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "releaseTime", - "type": "uint256" - }, - { - "internalType": "enum EngineBlox.TxStatus", - "name": "status", - "type": "uint8" - }, - { - "components": [ - { - "internalType": "address", - "name": "requester", - "type": "address" - }, - { - "internalType": "address", - "name": "target", - "type": "address" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "gasLimit", - "type": "uint256" - }, - { - "internalType": "bytes32", - "name": "operationType", - "type": "bytes32" - }, - { - "internalType": "bytes4", - "name": "executionSelector", - "type": "bytes4" - }, - { - "internalType": "bytes", - "name": "executionParams", - "type": "bytes" - } - ], - "internalType": "struct EngineBlox.TxParams", - "name": "params", - "type": "tuple" - }, - { - "internalType": "bytes32", - "name": "message", - "type": "bytes32" - }, - { - "internalType": "bytes", - "name": "result", - "type": "bytes" - }, - { - "components": [ - { - "internalType": "address", - "name": "recipient", - "type": "address" - }, - { - "internalType": "uint256", - "name": "nativeTokenAmount", - "type": "uint256" - }, - { - "internalType": "address", - "name": "erc20TokenAddress", - "type": "address" - }, - { - "internalType": "uint256", - "name": "erc20TokenAmount", - "type": "uint256" - } - ], - "internalType": "struct EngineBlox.PaymentDetails", - "name": "payment", - "type": "tuple" - } - ], - "internalType": "struct EngineBlox.TxRecord", - "name": "txRecord", - "type": "tuple" - }, - { - "components": [ - { - "internalType": "uint256", - "name": "chainId", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "nonce", - "type": "uint256" - }, - { - "internalType": "address", - "name": "handlerContract", - "type": "address" - }, - { - "internalType": "bytes4", - "name": "handlerSelector", - "type": "bytes4" - }, - { - "internalType": "enum EngineBlox.TxAction", - "name": "action", - "type": "uint8" - }, - { - "internalType": "uint256", - "name": "deadline", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "maxGasPrice", - "type": "uint256" - }, - { - "internalType": "address", - "name": "signer", - "type": "address" - } - ], - "internalType": "struct EngineBlox.MetaTxParams", - "name": "params", - "type": "tuple" - }, - { - "internalType": "bytes32", - "name": "message", - "type": "bytes32" - }, - { - "internalType": "bytes", - "name": "signature", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "data", - "type": "bytes" - } - ], - "internalType": "struct EngineBlox.MetaTransaction", - "name": "metaTx", - "type": "tuple" - } - ], - "name": "transferOwnershipApprovalWithMetaTx", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "txId", - "type": "uint256" - } - ], - "name": "transferOwnershipCancellation", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "components": [ - { - "internalType": "uint256", - "name": "txId", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "releaseTime", - "type": "uint256" - }, - { - "internalType": "enum EngineBlox.TxStatus", - "name": "status", - "type": "uint8" - }, - { - "components": [ - { - "internalType": "address", - "name": "requester", - "type": "address" - }, - { - "internalType": "address", - "name": "target", - "type": "address" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "gasLimit", - "type": "uint256" - }, - { - "internalType": "bytes32", - "name": "operationType", - "type": "bytes32" - }, - { - "internalType": "bytes4", - "name": "executionSelector", - "type": "bytes4" - }, - { - "internalType": "bytes", - "name": "executionParams", - "type": "bytes" - } - ], - "internalType": "struct EngineBlox.TxParams", - "name": "params", - "type": "tuple" - }, - { - "internalType": "bytes32", - "name": "message", - "type": "bytes32" - }, - { - "internalType": "bytes", - "name": "result", - "type": "bytes" - }, - { - "components": [ - { - "internalType": "address", - "name": "recipient", - "type": "address" - }, - { - "internalType": "uint256", - "name": "nativeTokenAmount", - "type": "uint256" - }, - { - "internalType": "address", - "name": "erc20TokenAddress", - "type": "address" - }, - { - "internalType": "uint256", - "name": "erc20TokenAmount", - "type": "uint256" - } - ], - "internalType": "struct EngineBlox.PaymentDetails", - "name": "payment", - "type": "tuple" - } - ], - "internalType": "struct EngineBlox.TxRecord", - "name": "txRecord", - "type": "tuple" - }, - { - "components": [ - { - "internalType": "uint256", - "name": "chainId", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "nonce", - "type": "uint256" - }, - { - "internalType": "address", - "name": "handlerContract", - "type": "address" - }, - { - "internalType": "bytes4", - "name": "handlerSelector", - "type": "bytes4" - }, - { - "internalType": "enum EngineBlox.TxAction", - "name": "action", - "type": "uint8" - }, - { - "internalType": "uint256", - "name": "deadline", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "maxGasPrice", - "type": "uint256" - }, - { - "internalType": "address", - "name": "signer", - "type": "address" - } - ], - "internalType": "struct EngineBlox.MetaTxParams", - "name": "params", - "type": "tuple" - }, - { - "internalType": "bytes32", - "name": "message", - "type": "bytes32" - }, - { - "internalType": "bytes", - "name": "signature", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "data", - "type": "bytes" - } - ], - "internalType": "struct EngineBlox.MetaTransaction", - "name": "metaTx", - "type": "tuple" - } - ], - "name": "transferOwnershipCancellationWithMetaTx", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "txId", - "type": "uint256" - } - ], - "name": "transferOwnershipDelayedApproval", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "transferOwnershipRequest", - "outputs": [ - { - "internalType": "uint256", - "name": "txId", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "components": [ - { - "internalType": "uint256", - "name": "txId", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "releaseTime", - "type": "uint256" - }, - { - "internalType": "enum EngineBlox.TxStatus", - "name": "status", - "type": "uint8" - }, - { - "components": [ - { - "internalType": "address", - "name": "requester", - "type": "address" - }, - { - "internalType": "address", - "name": "target", - "type": "address" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "gasLimit", - "type": "uint256" - }, - { - "internalType": "bytes32", - "name": "operationType", - "type": "bytes32" - }, - { - "internalType": "bytes4", - "name": "executionSelector", - "type": "bytes4" - }, - { - "internalType": "bytes", - "name": "executionParams", - "type": "bytes" - } - ], - "internalType": "struct EngineBlox.TxParams", - "name": "params", - "type": "tuple" - }, - { - "internalType": "bytes32", - "name": "message", - "type": "bytes32" - }, - { - "internalType": "bytes", - "name": "result", - "type": "bytes" - }, - { - "components": [ - { - "internalType": "address", - "name": "recipient", - "type": "address" - }, - { - "internalType": "uint256", - "name": "nativeTokenAmount", - "type": "uint256" - }, - { - "internalType": "address", - "name": "erc20TokenAddress", - "type": "address" - }, - { - "internalType": "uint256", - "name": "erc20TokenAmount", - "type": "uint256" - } - ], - "internalType": "struct EngineBlox.PaymentDetails", - "name": "payment", - "type": "tuple" - } - ], - "internalType": "struct EngineBlox.TxRecord", - "name": "txRecord", - "type": "tuple" - }, - { - "components": [ - { - "internalType": "uint256", - "name": "chainId", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "nonce", - "type": "uint256" - }, - { - "internalType": "address", - "name": "handlerContract", - "type": "address" - }, - { - "internalType": "bytes4", - "name": "handlerSelector", - "type": "bytes4" - }, - { - "internalType": "enum EngineBlox.TxAction", - "name": "action", - "type": "uint8" - }, - { - "internalType": "uint256", - "name": "deadline", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "maxGasPrice", - "type": "uint256" - }, - { - "internalType": "address", - "name": "signer", - "type": "address" - } - ], - "internalType": "struct EngineBlox.MetaTxParams", - "name": "params", - "type": "tuple" - }, - { - "internalType": "bytes32", - "name": "message", - "type": "bytes32" - }, - { - "internalType": "bytes", - "name": "signature", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "data", - "type": "bytes" - } - ], - "internalType": "struct EngineBlox.MetaTransaction", - "name": "metaTx", - "type": "tuple" - } - ], - "name": "updateBroadcasterApprovalWithMetaTx", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "txId", - "type": "uint256" - } - ], - "name": "updateBroadcasterCancellation", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "components": [ - { - "internalType": "uint256", - "name": "txId", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "releaseTime", - "type": "uint256" - }, - { - "internalType": "enum EngineBlox.TxStatus", - "name": "status", - "type": "uint8" - }, - { - "components": [ - { - "internalType": "address", - "name": "requester", - "type": "address" - }, - { - "internalType": "address", - "name": "target", - "type": "address" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "gasLimit", - "type": "uint256" - }, - { - "internalType": "bytes32", - "name": "operationType", - "type": "bytes32" - }, - { - "internalType": "bytes4", - "name": "executionSelector", - "type": "bytes4" - }, - { - "internalType": "bytes", - "name": "executionParams", - "type": "bytes" - } - ], - "internalType": "struct EngineBlox.TxParams", - "name": "params", - "type": "tuple" - }, - { - "internalType": "bytes32", - "name": "message", - "type": "bytes32" - }, - { - "internalType": "bytes", - "name": "result", - "type": "bytes" - }, - { - "components": [ - { - "internalType": "address", - "name": "recipient", - "type": "address" - }, - { - "internalType": "uint256", - "name": "nativeTokenAmount", - "type": "uint256" - }, - { - "internalType": "address", - "name": "erc20TokenAddress", - "type": "address" - }, - { - "internalType": "uint256", - "name": "erc20TokenAmount", - "type": "uint256" - } - ], - "internalType": "struct EngineBlox.PaymentDetails", - "name": "payment", - "type": "tuple" - } - ], - "internalType": "struct EngineBlox.TxRecord", - "name": "txRecord", - "type": "tuple" - }, - { - "components": [ - { - "internalType": "uint256", - "name": "chainId", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "nonce", - "type": "uint256" - }, - { - "internalType": "address", - "name": "handlerContract", - "type": "address" - }, - { - "internalType": "bytes4", - "name": "handlerSelector", - "type": "bytes4" - }, - { - "internalType": "enum EngineBlox.TxAction", - "name": "action", - "type": "uint8" - }, - { - "internalType": "uint256", - "name": "deadline", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "maxGasPrice", - "type": "uint256" - }, - { - "internalType": "address", - "name": "signer", - "type": "address" - } - ], - "internalType": "struct EngineBlox.MetaTxParams", - "name": "params", - "type": "tuple" - }, - { - "internalType": "bytes32", - "name": "message", - "type": "bytes32" - }, - { - "internalType": "bytes", - "name": "signature", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "data", - "type": "bytes" - } - ], - "internalType": "struct EngineBlox.MetaTransaction", - "name": "metaTx", - "type": "tuple" - } - ], - "name": "updateBroadcasterCancellationWithMetaTx", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "txId", - "type": "uint256" - } - ], - "name": "updateBroadcasterDelayedApproval", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "newBroadcaster", - "type": "address" - }, - { - "internalType": "uint256", - "name": "location", - "type": "uint256" - } - ], - "name": "updateBroadcasterRequest", - "outputs": [ - { - "internalType": "uint256", - "name": "txId", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "components": [ - { - "internalType": "uint256", - "name": "txId", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "releaseTime", - "type": "uint256" - }, - { - "internalType": "enum EngineBlox.TxStatus", - "name": "status", - "type": "uint8" - }, - { - "components": [ - { - "internalType": "address", - "name": "requester", - "type": "address" - }, - { - "internalType": "address", - "name": "target", - "type": "address" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "gasLimit", - "type": "uint256" - }, - { - "internalType": "bytes32", - "name": "operationType", - "type": "bytes32" - }, - { - "internalType": "bytes4", - "name": "executionSelector", - "type": "bytes4" - }, - { - "internalType": "bytes", - "name": "executionParams", - "type": "bytes" - } - ], - "internalType": "struct EngineBlox.TxParams", - "name": "params", - "type": "tuple" - }, - { - "internalType": "bytes32", - "name": "message", - "type": "bytes32" - }, - { - "internalType": "bytes", - "name": "result", - "type": "bytes" - }, - { - "components": [ - { - "internalType": "address", - "name": "recipient", - "type": "address" - }, - { - "internalType": "uint256", - "name": "nativeTokenAmount", - "type": "uint256" - }, - { - "internalType": "address", - "name": "erc20TokenAddress", - "type": "address" - }, - { - "internalType": "uint256", - "name": "erc20TokenAmount", - "type": "uint256" - } - ], - "internalType": "struct EngineBlox.PaymentDetails", - "name": "payment", - "type": "tuple" - } - ], - "internalType": "struct EngineBlox.TxRecord", - "name": "txRecord", - "type": "tuple" - }, - { - "components": [ - { - "internalType": "uint256", - "name": "chainId", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "nonce", - "type": "uint256" - }, - { - "internalType": "address", - "name": "handlerContract", - "type": "address" - }, - { - "internalType": "bytes4", - "name": "handlerSelector", - "type": "bytes4" - }, - { - "internalType": "enum EngineBlox.TxAction", - "name": "action", - "type": "uint8" - }, - { - "internalType": "uint256", - "name": "deadline", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "maxGasPrice", - "type": "uint256" - }, - { - "internalType": "address", - "name": "signer", - "type": "address" - } - ], - "internalType": "struct EngineBlox.MetaTxParams", - "name": "params", - "type": "tuple" - }, - { - "internalType": "bytes32", - "name": "message", - "type": "bytes32" - }, - { - "internalType": "bytes", - "name": "signature", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "data", - "type": "bytes" - } - ], - "internalType": "struct EngineBlox.MetaTransaction", - "name": "metaTx", - "type": "tuple" - } - ], - "name": "updateRecoveryRequestAndApprove", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "components": [ - { - "internalType": "uint256", - "name": "txId", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "releaseTime", - "type": "uint256" - }, - { - "internalType": "enum EngineBlox.TxStatus", - "name": "status", - "type": "uint8" - }, - { - "components": [ - { - "internalType": "address", - "name": "requester", - "type": "address" - }, - { - "internalType": "address", - "name": "target", - "type": "address" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "gasLimit", - "type": "uint256" - }, - { - "internalType": "bytes32", - "name": "operationType", - "type": "bytes32" - }, - { - "internalType": "bytes4", - "name": "executionSelector", - "type": "bytes4" - }, - { - "internalType": "bytes", - "name": "executionParams", - "type": "bytes" - } - ], - "internalType": "struct EngineBlox.TxParams", - "name": "params", - "type": "tuple" - }, - { - "internalType": "bytes32", - "name": "message", - "type": "bytes32" - }, - { - "internalType": "bytes", - "name": "result", - "type": "bytes" - }, - { - "components": [ - { - "internalType": "address", - "name": "recipient", - "type": "address" - }, - { - "internalType": "uint256", - "name": "nativeTokenAmount", - "type": "uint256" - }, - { - "internalType": "address", - "name": "erc20TokenAddress", - "type": "address" - }, - { - "internalType": "uint256", - "name": "erc20TokenAmount", - "type": "uint256" - } - ], - "internalType": "struct EngineBlox.PaymentDetails", - "name": "payment", - "type": "tuple" - } - ], - "internalType": "struct EngineBlox.TxRecord", - "name": "txRecord", - "type": "tuple" - }, - { - "components": [ - { - "internalType": "uint256", - "name": "chainId", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "nonce", - "type": "uint256" - }, - { - "internalType": "address", - "name": "handlerContract", - "type": "address" - }, - { - "internalType": "bytes4", - "name": "handlerSelector", - "type": "bytes4" - }, - { - "internalType": "enum EngineBlox.TxAction", - "name": "action", - "type": "uint8" - }, - { - "internalType": "uint256", - "name": "deadline", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "maxGasPrice", - "type": "uint256" - }, - { - "internalType": "address", - "name": "signer", - "type": "address" - } - ], - "internalType": "struct EngineBlox.MetaTxParams", - "name": "params", - "type": "tuple" - }, - { - "internalType": "bytes32", - "name": "message", - "type": "bytes32" - }, - { - "internalType": "bytes", - "name": "signature", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "data", - "type": "bytes" - } - ], - "internalType": "struct EngineBlox.MetaTransaction", - "name": "metaTx", - "type": "tuple" - } - ], - "name": "updateTimeLockRequestAndApprove", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "initialOwner", - "type": "address" - }, - { - "internalType": "address", - "name": "broadcaster", - "type": "address" - }, - { - "internalType": "address", - "name": "recovery", - "type": "address" - }, - { - "internalType": "uint256", - "name": "timeLockPeriodSec", - "type": "uint256" - }, - { - "internalType": "address", - "name": "eventForwarder", - "type": "address" - } - ], - "name": "initialize", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes4", - "name": "interfaceId", - "type": "bytes4" - } - ], - "name": "supportsInterface", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - } -] \ No newline at end of file diff --git a/contracts/examples/applications/CopyBlox/CopyBlox.sol b/contracts/examples/applications/CopyBlox/CopyBlox.sol index 3527068b..4ca8c77e 100644 --- a/contracts/examples/applications/CopyBlox/CopyBlox.sol +++ b/contracts/examples/applications/CopyBlox/CopyBlox.sol @@ -27,12 +27,7 @@ contract CopyBlox is BaseStateMachine, IEventForwarder { using EnumerableSet for EnumerableSet.AddressSet; /** - * @dev Counter to track the total number of clones created - */ - uint256 private _cloneCount; - - /** - * @dev Set to store all created clone addresses + * @dev Set to store all created clone addresses (length used as clone count) */ EnumerableSet.AddressSet private _clones; @@ -91,50 +86,16 @@ contract CopyBlox is BaseStateMachine, IEventForwarder { address recovery, uint256 timeLockPeriodSec ) external nonReentrant returns (address cloneAddress) { - // Validate addresses - SharedValidation.validateNotZeroAddress(bloxAddress); SharedValidation.validateNotZeroAddress(initialOwner); SharedValidation.validateNotZeroAddress(broadcaster); SharedValidation.validateNotZeroAddress(recovery); - - // Prevent cloning self - if (bloxAddress == address(this)) { - revert SharedValidation.InvalidAddress(bloxAddress); - } - - // Validate that bloxAddress is a contract - if (bloxAddress.code.length == 0) { - revert SharedValidation.InvalidAddress(bloxAddress); - } - - // Verify that the blox contract implements IBaseStateMachine interface - if (!bloxAddress.supportsInterface(type(IBaseStateMachine).interfaceId)) { - revert SharedValidation.InvalidOperation(bloxAddress); - } - - // Check for overflow on clone count - if (_cloneCount == type(uint256).max) { - revert SharedValidation.OperationFailed(); - } - - // CHECKS: All validations complete - - // EFFECTS: Update state before external calls (CEI pattern) - uint256 newCloneCount = _cloneCount + 1; - _cloneCount = newCloneCount; - - // Clone the blox contract using EIP-1167 minimal proxy pattern + + _validateBloxImplementation(bloxAddress); // rejects zero (code.length==0), self, non-contract, non-IBaseStateMachine + + // Clone first (no state change yet) cloneAddress = Clones.clone(bloxAddress); - - // Add clone to the set (before initialization call) - _clones.add(cloneAddress); - - // INTERACTIONS: External calls after state updates - // Set eventForwarder to CopyBlox address to centralize events from clones address eventForwarder = address(this); - - // Initialize the cloned contract - // We use a low-level call to handle any initialize function signature + (bool success, ) = cloneAddress.call( abi.encodeWithSignature( "initialize(address,address,address,uint256,address)", @@ -145,33 +106,30 @@ contract CopyBlox is BaseStateMachine, IEventForwarder { eventForwarder ) ); - - if (!success) { - // Revert state changes on failure - _clones.remove(cloneAddress); - _cloneCount = newCloneCount - 1; - revert SharedValidation.OperationFailed(); - } - - emit BloxCloned(bloxAddress, cloneAddress, initialOwner, newCloneCount); - + if (!success) revert SharedValidation.OperationFailed(); + + _clones.add(cloneAddress); + emit BloxCloned(bloxAddress, cloneAddress, initialOwner, _clones.length()); return cloneAddress; } /** - * @notice Get the total number of clones created - * @return The total number of clones created by this CopyBlox instance + * @dev Validates that an address is not zero, not this contract, has code, and implements IBaseStateMachine. */ - function getCloneCount() external view returns (uint256) { - return _cloneCount; + function _validateBloxImplementation(address bloxAddress) internal view { + if (bloxAddress == address(this)) revert SharedValidation.InvalidAddress(bloxAddress); + if (bloxAddress.code.length == 0) revert SharedValidation.InvalidAddress(bloxAddress); + if (!bloxAddress.supportsInterface(type(IBaseStateMachine).interfaceId)) { + revert SharedValidation.InvalidOperation(bloxAddress); + } } /** - * @notice Get all clone addresses - * @return An array of all clone addresses created by this CopyBlox instance + * @notice Get the total number of clones created + * @return The total number of clones created by this CopyBlox instance */ - function getAllClones() external view returns (address[] memory) { - return _clones.values(); + function getCloneCount() external view returns (uint256) { + return _clones.length(); } /** @@ -192,15 +150,6 @@ contract CopyBlox is BaseStateMachine, IEventForwarder { return _clones.contains(cloneAddress); } - /** - * @notice Get the total number of clones in the set - * @return The number of clones in the enumerable set - * @dev This should match getCloneCount() but uses the set length - */ - function getClonesLength() external view returns (uint256) { - return _clones.length(); - } - // ============ IEventForwarder IMPLEMENTATION ============ /** @@ -242,8 +191,7 @@ contract CopyBlox is BaseStateMachine, IEventForwarder { address target, bytes32 operationType ) external override { - // Verify that the caller is a clone created by this CopyBlox - require(_clones.contains(msg.sender), "CopyBlox: Only clones can forward events"); + if (!_clones.contains(msg.sender)) revert SharedValidation.NoPermission(msg.sender); // Emit event with clone address for tracking emit CloneEventForwarded( diff --git a/contracts/examples/BasicERC20.sol b/contracts/examples/extra/BasicERC20.sol similarity index 100% rename from contracts/examples/BasicERC20.sol rename to contracts/examples/extra/BasicERC20.sol diff --git a/contracts/examples/templates/AccountBlox.sol b/contracts/examples/templates/AccountBlox.sol index 0f0eabe5..1e0803a6 100644 --- a/contracts/examples/templates/AccountBlox.sol +++ b/contracts/examples/templates/AccountBlox.sol @@ -12,7 +12,7 @@ import "../../core/pattern/Account.sol"; * - RuntimeRBAC: Runtime role creation and management * - SecureOwnable: Secure ownership transfer and management * - * Top-level initializer: only concrete contracts (AccountBlox, MachineBlox) use the initializer modifier; + * Top-level initializer: only concrete contracts (AccountBlox) use the initializer modifier; * Account.initialize uses onlyInitializing and is invoked from here. */ contract AccountBlox is Account { diff --git a/contracts/examples/templates/BareBlox.sol b/contracts/examples/templates/BareBlox.sol deleted file mode 100644 index 312e50be..00000000 --- a/contracts/examples/templates/BareBlox.sol +++ /dev/null @@ -1,54 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.8.34; - -import "../../core/base/BaseStateMachine.sol"; - -/** - * @title BareBlox - * @dev A minimal implementation using only BaseStateMachine for core state machine functionality - * - * This contract provides the most basic state abstraction implementation using only - * the core state machine capabilities from BaseStateMachine. It includes: - * - Basic initialization with core roles (owner, broadcaster, recovery) - * - Time-lock period configuration - * - Event forwarding support - * - All core state machine functionality (meta-transactions, state queries, etc.) - * - * This is the minimal viable implementation for applications that only need - * the core state machine functionality without additional security features. - */ -contract BareBlox is BaseStateMachine { - /** - * @notice Initializer to initialize BareBlox - * @param initialOwner The initial owner address - * @param broadcaster The broadcaster address - * @param recovery The recovery address - * @param timeLockPeriodSec The timelock period in seconds - * @param eventForwarder The event forwarder address (optional) - */ - function initialize( - address initialOwner, - address broadcaster, - address recovery, - uint256 timeLockPeriodSec, - address eventForwarder - ) public virtual initializer { - _initializeBaseStateMachine( - initialOwner, - broadcaster, - recovery, - timeLockPeriodSec, - eventForwarder - ); - // Add any additional initialization logic here - } - - // Add your custom implementation here - // All BaseStateMachine functionality is available: - // - Meta-transaction utilities - // - State queries (getTransactionHistory, getTransaction, etc.) - // - Role and permission queries - // - System state queries - // - Centralized transaction management functions -} - diff --git a/contracts/examples/templates/MachineBlox.sol b/contracts/examples/templates/MachineBlox.sol deleted file mode 100644 index a4dfe4db..00000000 --- a/contracts/examples/templates/MachineBlox.sol +++ /dev/null @@ -1,78 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.8.34; - -import "../../core/pattern/Account.sol"; -import "../../core/base/BaseStateMachine.sol"; -import "../../experimental/hook/HookManager.sol"; -import "../../core/lib/utils/SharedValidation.sol"; - -/** - * @title MachineBlox - * @dev Complete controller implementation with hook management capabilities. - * - * Extends the Account pattern with: - * - HookManager: External hook contract attachment for state machine actions - * - * ETH handling: direct receive is disabled; use deposit() to credit ETH. - */ -contract MachineBlox is Account, HookManager { - /** - * @notice Initializer to initialize MachineBlox (Account + HookManager). - * @param initialOwner The initial owner address - * @param broadcaster The broadcaster address - * @param recovery The recovery address - * @param timeLockPeriodSec The timelock period in seconds - * @param eventForwarder The event forwarder address (optional) - */ - function initialize( - address initialOwner, - address broadcaster, - address recovery, - uint256 timeLockPeriodSec, - address eventForwarder - ) public virtual override(Account) initializer { - Account.initialize(initialOwner, broadcaster, recovery, timeLockPeriodSec, eventForwarder); - } - - /** - * @dev See {IERC165-supportsInterface}. - */ - function supportsInterface(bytes4 interfaceId) public view virtual override(Account, BaseStateMachine) returns (bool) { - return Account.supportsInterface(interfaceId) || BaseStateMachine.supportsInterface(interfaceId); - } - - /** - * @dev Resolve ambiguity between BaseStateMachine and HookManager for post-action hook. - * Ensures HookManager's external hook execution is wired into the unified - * BaseStateMachine post-transaction entry point. - */ - function _postActionHook( - EngineBlox.TxRecord memory txRecord - ) internal virtual override(BaseStateMachine, HookManager) { - HookManager._postActionHook(txRecord); - } - - /** - * @dev Explicit deposit function for ETH deposits. - * @notice Users must call this function to deposit ETH to the contract. - * @notice Direct ETH transfers to the contract will revert (receive/fallback revert). - * @notice Uses inherited EthReceived(address indexed sender, uint256 value) from Account. - */ - function deposit() external payable { - emit EthReceived(msg.sender, msg.value); - } - - /** - * @dev Override Account's receive to reject direct ETH; use deposit() instead. - */ - receive() external payable override { - revert SharedValidation.NotSupported(); - } - - /** - * @dev Override Account's fallback (same behavior: reject). - */ - fallback() external payable override { - revert SharedValidation.NotSupported(); - } -} diff --git a/contracts/examples/templates/RoleBlox.sol b/contracts/examples/templates/RoleBlox.sol deleted file mode 100644 index f6898b4b..00000000 --- a/contracts/examples/templates/RoleBlox.sol +++ /dev/null @@ -1,49 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.8.34; - -import "../../core/access/RuntimeRBAC.sol"; -import "../../core/security/SecureOwnable.sol"; -import "../../core/base/BaseStateMachine.sol"; - -/** - * @title RoleBlox - * @dev A basic implementation of state abstraction with runtime role-based access control using RuntimeRBAC and SecureOwnable - * - * This contract combines both RuntimeRBAC and SecureOwnable functionality: - * - RuntimeRBAC provides runtime role creation and management - * - SecureOwnable provides secure ownership transfer and management - * - Both inherit from BaseStateMachine, ensuring proper initialization order - */ -contract RoleBlox is RuntimeRBAC, SecureOwnable { - /** - * @notice Initializer to initialize RoleBlox - * @param initialOwner The initial owner address - * @param broadcaster The broadcaster address - * @param recovery The recovery address - * @param timeLockPeriodSec The timelock period in seconds - * @param eventForwarder The event forwarder address (optional) - */ - function initialize( - address initialOwner, - address broadcaster, - address recovery, - uint256 timeLockPeriodSec, - address eventForwarder - ) public virtual override(RuntimeRBAC, SecureOwnable) initializer { - // Initialize both parent contracts - // The guarded initialization ensures BaseStateMachine is only initialized once - RuntimeRBAC.initialize(initialOwner, broadcaster, recovery, timeLockPeriodSec, eventForwarder); - SecureOwnable.initialize(initialOwner, broadcaster, recovery, timeLockPeriodSec, eventForwarder); - - // Add any RoleBlox-specific initialization logic here - } - - /** - * @dev See {IERC165-supportsInterface}. - */ - function supportsInterface(bytes4 interfaceId) public view virtual override(RuntimeRBAC, SecureOwnable) returns (bool) { - return RuntimeRBAC.supportsInterface(interfaceId) || SecureOwnable.supportsInterface(interfaceId); - } - -} - diff --git a/contracts/examples/templates/SecureBlox.sol b/contracts/examples/templates/SecureBlox.sol deleted file mode 100644 index 4ec43505..00000000 --- a/contracts/examples/templates/SecureBlox.sol +++ /dev/null @@ -1,38 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.8.34; - -import "../../core/security/SecureOwnable.sol"; - -/** - * @title SecureBlox - * @dev A basic implementation of state abstraction using SecureOwnable for secure ownership management - */ -contract SecureBlox is SecureOwnable { - /** - * @notice Initializer to initialize SecureBlox - * @param initialOwner The initial owner address - * @param broadcaster The broadcaster address - * @param recovery The recovery address - * @param timeLockPeriodSec The timelock period in seconds - * @param eventForwarder The event forwarder address (optional) - */ - function initialize( - address initialOwner, - address broadcaster, - address recovery, - uint256 timeLockPeriodSec, - address eventForwarder - ) public virtual override initializer { - super.initialize( - initialOwner, - broadcaster, - recovery, - timeLockPeriodSec, - eventForwarder - ); - // add your initialization logic here - } - - // add your implementation here -} - diff --git a/docs/BareBlox.md b/docs/BareBlox.md deleted file mode 100644 index c1251227..00000000 --- a/docs/BareBlox.md +++ /dev/null @@ -1,50 +0,0 @@ -# Solidity API - -# BareBlox - -A minimal implementation using only BaseStateMachine for core state machine functionality - -This contract provides the most basic state abstraction implementation using only -the core state machine capabilities from BaseStateMachine. It includes: -- Basic initialization with core roles (owner, broadcaster, recovery) -- Time-lock period configuration -- Event forwarding support -- All core state machine functionality (meta-transactions, state queries, etc.) - -This is the minimal viable implementation for applications that only need -the core state machine functionality without additional security features. - - - - -## Functions - -### initialize - -```solidity -function initialize(address initialOwner, address broadcaster, address recovery, uint256 timeLockPeriodSec, address eventForwarder) public nonpayable -``` - - - -**Parameters:** -- `` (): The initial owner address -- `` (): The broadcaster address -- `` (): The recovery address -- `` (): The timelock period in seconds -- `` (): The event forwarder address (optional) - - - ---- - - -## Events - - -## Structs - - -## Enums - - diff --git a/docs/MachineBlox.md b/docs/MachineBlox.md deleted file mode 100644 index 724c2935..00000000 --- a/docs/MachineBlox.md +++ /dev/null @@ -1,187 +0,0 @@ -# Solidity API - -# MachineBlox - -Complete controller implementation with hook management capabilities - -This contract combines: -- GuardController: Execution workflows and time-locked transactions -- RuntimeRBAC: Runtime role creation and management -- SecureOwnable: Secure ownership transfer and management -- HookManager: External hook contract attachment for state machine actions - - - - -## Functions - -### initialize - -```solidity -function initialize(address initialOwner, address broadcaster, address recovery, uint256 timeLockPeriodSec, address eventForwarder) public nonpayable -``` - - - -**Parameters:** -- `` (): The initial owner address -- `` (): The broadcaster address -- `` (): The recovery address -- `` (): The timelock period in seconds -- `` (): The event forwarder address (optional) - - - ---- - -### supportsInterface - -```solidity -function supportsInterface(bytes4 interfaceId) public view returns (bool) -``` - -See {IERC165-supportsInterface}. - - - - ---- - -### _requestTransaction - -```solidity -function _requestTransaction(address requester, address target, uint256 value, uint256 gasLimit, bytes32 operationType, bytes4 functionSelector, bytes params) internal nonpayable returns (struct EngineBlox.TxRecord) -``` - - - - - - ---- - -### _approveTransaction - -```solidity -function _approveTransaction(uint256 txId) internal nonpayable returns (struct EngineBlox.TxRecord) -``` - - - - - - ---- - -### _approveTransactionWithMetaTx - -```solidity -function _approveTransactionWithMetaTx(struct EngineBlox.MetaTransaction metaTx) internal nonpayable returns (struct EngineBlox.TxRecord) -``` - - - - - - ---- - -### _cancelTransaction - -```solidity -function _cancelTransaction(uint256 txId) internal nonpayable returns (struct EngineBlox.TxRecord) -``` - - - - - - ---- - -### _cancelTransactionWithMetaTx - -```solidity -function _cancelTransactionWithMetaTx(struct EngineBlox.MetaTransaction metaTx) internal nonpayable returns (struct EngineBlox.TxRecord) -``` - - - - - - ---- - -### _requestAndApproveTransaction - -```solidity -function _requestAndApproveTransaction(struct EngineBlox.MetaTransaction metaTx) internal nonpayable returns (struct EngineBlox.TxRecord) -``` - - - - - - ---- - -### deposit - -```solidity -function deposit() external payable -``` - - - - - - ---- - -### fallback - -```solidity -function fallback() external payable -``` - -Fallback function to reject accidental calls - - - - ---- - -### receive - -```solidity -function receive() external payable -``` - - - - - - ---- - - -## Events - -### EthReceived - -```solidity -event EthReceived(address from, uint256 amount) -``` - -Explicit deposit function for ETH deposits - - ---- - - -## Structs - - -## Enums - - diff --git a/docs/RoleBlox.md b/docs/RoleBlox.md deleted file mode 100644 index 1925e30d..00000000 --- a/docs/RoleBlox.md +++ /dev/null @@ -1,58 +0,0 @@ -# Solidity API - -# RoleBlox - -A basic implementation of state abstraction with runtime role-based access control using RuntimeRBAC and SecureOwnable - -This contract combines both RuntimeRBAC and SecureOwnable functionality: -- RuntimeRBAC provides runtime role creation and management -- SecureOwnable provides secure ownership transfer and management -- Both inherit from BaseStateMachine, ensuring proper initialization order - - - - -## Functions - -### initialize - -```solidity -function initialize(address initialOwner, address broadcaster, address recovery, uint256 timeLockPeriodSec, address eventForwarder) public nonpayable -``` - - - -**Parameters:** -- `` (): The initial owner address -- `` (): The broadcaster address -- `` (): The recovery address -- `` (): The timelock period in seconds -- `` (): The event forwarder address (optional) - - - ---- - -### supportsInterface - -```solidity -function supportsInterface(bytes4 interfaceId) public view returns (bool) -``` - -See {IERC165-supportsInterface}. - - - - ---- - - -## Events - - -## Structs - - -## Enums - - diff --git a/docs/SecureBlox.md b/docs/SecureBlox.md deleted file mode 100644 index 844592f7..00000000 --- a/docs/SecureBlox.md +++ /dev/null @@ -1,40 +0,0 @@ -# Solidity API - -# SecureBlox - -A basic implementation of state abstraction using SecureOwnable for secure ownership management - - - - -## Functions - -### initialize - -```solidity -function initialize(address initialOwner, address broadcaster, address recovery, uint256 timeLockPeriodSec, address eventForwarder) public nonpayable -``` - - - -**Parameters:** -- `` (): The initial owner address -- `` (): The broadcaster address -- `` (): The recovery address -- `` (): The timelock period in seconds -- `` (): The event forwarder address (optional) - - - ---- - - -## Events - - -## Structs - - -## Enums - - diff --git a/env.example b/env.example index c67351ee..24cebbb5 100644 --- a/env.example +++ b/env.example @@ -28,14 +28,11 @@ REMOTE_FROM= # Contract Addresses (optional - can be provided at runtime) -# Sanity tests (scripts/sanity and scripts/sanity-sdk) use only ACCOUNTBLOX_ADDRESS. +# Sanity tests (scripts/sanity and scripts/sanity-sdk) use ACCOUNTBLOX_ADDRESS. ACCOUNTBLOX_ADDRESS= -SECUREBLOX_ADDRESS= -ROLEBLOX_ADDRESS= -BAREBLOX_ADDRESS= SIMPLE_VAULT_ADDRESS= SIMPLE_RWA20_ADDRESS= -ERC20_BLOX_ADDRESS= +COPYBLOX_ADDRESS= # Alternative RPC Configuration (if using custom network) # CUSTOM_RPC_URL=https://your-custom-rpc-url:8545 @@ -55,21 +52,14 @@ TEST_WALLET_4_PRIVATE_KEY= TEST_WALLET_5_PRIVATE_KEY= # Deployment Configuration Flags -# Set to 'true' or 'false' to control which Bloxchain contracts to deploy (names kept for backward compatibility). -# Default: SecureBlox=false, RoleBlox=false, BareBlox=false -DEPLOY_SECUREBLOX=false -DEPLOY_ROLEBLOX=false -DEPLOY_BAREBLOX=false -DEPLOY_ACCOUNTBLOX=false +# Guardian contract: AccountBlox only. Set DEPLOY_ACCOUNTBLOX=false to skip. +DEPLOY_ACCOUNTBLOX=true # Example Contract Deployment Flags -# Set to 'true' or 'false' to control which example contracts to deploy -# Default: Both example contracts=false +# Set to 'true' to deploy; default: false DEPLOY_SIMPLE_VAULT=false DEPLOY_SIMPLE_RWA20=false -DEPLOY_ERC20_BLOX=false -DEPLOY_FACTORY_BLOX=false -DEPLOY_WALLET_BLOX=false +DEPLOY_COPYBLOX=false # Definition Library Addresses (per network) # These are the addresses of the deployed definition libraries @@ -81,29 +71,22 @@ RUNTIME_RBAC_DEFINITIONS_ADDRESS= # DEPLOYMENT CONFIGURATION GUIDE # ============================================================================= # -# DEPLOYMENT FLAGS: -# DEPLOY_SECUREBLOX=true/false - Deploy standard SecureBlox contract -# DEPLOY_ROLEBLOX=true/false - Deploy RoleBlox contract -# DEPLOY_BAREBLOX=true/false - Deploy minimal BareBlox contract -# DEPLOY_SIMPLE_VAULT=true/false - Deploy SimpleVault example contract -# DEPLOY_SIMPLE_RWA20=true/false - Deploy SimpleRWA20 example contract -# DEPLOY_ERC20_BLOX=true/false - Deploy ERC20Blox example contract -# DEPLOY_FACTORY_BLOX=true/false - Deploy FactoryBlox (clone factory) example contract -# DEPLOY_WALLET_BLOX=true/false - Deploy BloxchainWallet (Account + ICopyable) example contract +# GUARDIAN CONTRACT: +# DEPLOY_ACCOUNTBLOX=true/false - Deploy AccountBlox (default: true). Set false to skip. +# +# EXAMPLE CONTRACT FLAGS: +# DEPLOY_SIMPLE_VAULT=true/false - Deploy SimpleVault example contract +# DEPLOY_SIMPLE_RWA20=true/false - Deploy SimpleRWA20 example contract +# DEPLOY_COPYBLOX=true/false - Deploy CopyBlox (clone blox via EIP-1167, event forwarding) # # DEPLOYMENT SCENARIOS: -# ๐Ÿ—๏ธ Full Development: All core flags=true, Example flags=false -# ๐ŸŽฏ Minimal Testing: Only DEPLOY_BAREBLOX=true -# ๐Ÿ”ง Standard Testing: Only DEPLOY_SECUREBLOX=true -# ๐Ÿš€ Production Ready: Only DEPLOY_ROLEBLOX=true -# ๐Ÿฆ Examples Only: Only example flags=true (for example contract testing) +# ๐Ÿ—๏ธ Guardian only: DEPLOY_ACCOUNTBLOX=true, example flags=false (default) +# ๐Ÿฆ Examples: Set example flags=true (for example contract testing) # # EXAMPLE CONTRACTS: # ๐Ÿฆ SimpleVault: Example vault contract with Bloxchain integration # ๐Ÿฆ SimpleRWA20: Example RWA token contract with Bloxchain integration -# ๐Ÿฆ ERC20Blox: Example ERC20 token with SecureOwnable, RuntimeRBAC, GuardController -# ๐Ÿญ FactoryBlox: Clone factory with RBAC and GuardController (cloneBlox, whitelist) -# ๐Ÿ‘› BloxchainWallet: Official wallet controller (Account, ICopyable, 1โ€“90 day timelock) +# ๐Ÿ“‹ CopyBlox: Clone any IBaseStateMachine blox, centralize events from clones # # ============================================================================= # TEST MODE USAGE GUIDE @@ -130,10 +113,10 @@ RUNTIME_RBAC_DEFINITIONS_ADDRESS= # 3. Run tests: node scripts/sanity/secure-ownable/run-tests.js # # DEPLOYMENT EXAMPLES: -# Deploy only examples: -# DEPLOY_SIMPLE_VAULT=true DEPLOY_SIMPLE_RWA20=true DEPLOY_ERC20_BLOX=true DEPLOY_FACTORY_BLOX=true DEPLOY_WALLET_BLOX=true truffle migrate +# Deploy guardian only (default): +# truffle migrate # -# Deploy everything (full development): -# All flags=true truffle migrate +# Deploy with examples: +# DEPLOY_SIMPLE_VAULT=true DEPLOY_SIMPLE_RWA20=true DEPLOY_COPYBLOX=true truffle migrate # # ============================================================================= diff --git a/migrations/2_deploy_guardian_contracts.cjs b/migrations/2_deploy_guardian_contracts.cjs index 73dc25a9..425ea311 100644 --- a/migrations/2_deploy_guardian_contracts.cjs +++ b/migrations/2_deploy_guardian_contracts.cjs @@ -1,8 +1,5 @@ -// Migration 2: Deploy Guardian Contracts (built on foundation libraries) -require('dotenv').config(); -const SecureBlox = artifacts.require("SecureBlox"); -const RoleBlox = artifacts.require("RoleBlox"); -const BareBlox = artifacts.require("BareBlox"); +// Migration 2: Deploy Guardian Contracts (AccountBlox only) +require('dotenv').config({ quiet: true }); const AccountBlox = artifacts.require("AccountBlox"); const { saveArtifactNetwork } = require('./helpers/save-artifact-network.cjs'); @@ -22,16 +19,9 @@ module.exports = async function(deployer, network, accounts) { console.log(`๐Ÿš€ Migration 2: Deploying Guardian Contracts on ${network}`); console.log(`๐Ÿ“‹ Using account: ${accounts[0]}`); - // Configuration flags - set to true/false to control which contracts to deploy - const deploySecureBlox = process.env.DEPLOY_SECUREBLOX === 'true'; // Default: false - const deployRoleBlox = process.env.DEPLOY_ROLEBLOX === 'true'; // Default: false - const deployBareBlox = process.env.DEPLOY_BAREBLOX === 'true'; // Default: false - const deployAccountBlox = process.env.DEPLOY_ACCOUNTBLOX === 'true'; // Default: false + const deployAccountBlox = process.env.DEPLOY_ACCOUNTBLOX !== 'false'; // Default: true console.log("\n๐ŸŽฏ Deployment Configuration:"); - console.log(` SecureBlox: ${deploySecureBlox ? 'โœ… YES' : 'โŒ NO'}`); - console.log(` RoleBlox: ${deployRoleBlox ? 'โœ… YES' : 'โŒ NO'}`); - console.log(` BareBlox: ${deployBareBlox ? 'โœ… YES' : 'โŒ NO'}`); console.log(` AccountBlox: ${deployAccountBlox ? 'โœ… YES' : 'โŒ NO'}`); // Get deployed foundation libraries from Migration 1 @@ -80,228 +70,10 @@ module.exports = async function(deployer, network, accounts) { console.log("โœ… Using RuntimeRBACDefinitions at:", drd.address); console.log("โœ… Using GuardControllerDefinitions at:", gcd.address); - // Step 2: Deploy SecureBlox (if enabled) - let secureBlox = null; - if (deploySecureBlox) { - console.log("\n๐Ÿ“ฆ Step 2: Deploying SecureBlox..."); - - // Link all required libraries to SecureBlox - await deployer.link(EngineBlox, SecureBlox); - await deployer.link(SecureOwnableDefinitions, SecureBlox); - - // Deploy SecureBlox - await deployer.deploy(SecureBlox); - secureBlox = await SecureBlox.deployed(); - console.log("โœ… SecureBlox deployed at:", secureBlox.address); - - // Get web3 instance for nonce checking - const web3 = secureBlox.constructor.web3 || global.web3; - - // Wait for nonce to sync after deployment - const currentNonce = await web3.eth.getTransactionCount(accounts[0], 'pending'); - console.log(` Current account nonce: ${currentNonce}`); - const synced = await waitForNonceSync(web3, accounts[0], currentNonce); - if (!synced) { - console.log(` โš ๏ธ Warning: Nonce sync failed after max retries, proceeding anyway`); - } - - // Initialize SecureBlox - console.log("๐Ÿ”ง Initializing SecureBlox..."); - try { - // Use estimateGas to get more detailed error information - try { - const gasEstimate = await secureBlox.initialize.estimateGas( - accounts[0], // initialOwner - accounts[1], // broadcaster - accounts[2], // recovery - 1, // timeLockPeriodSec - "0x0000000000000000000000000000000000000000" // eventForwarder (none) - ); - console.log(" Gas estimate:", gasEstimate.toString()); - } catch (gasError) { - console.log(" โš ๏ธ Gas estimation failed - this indicates the transaction will revert"); - console.log(" Gas error:", gasError.message); - if (gasError.data) { - console.log(" Gas error data:", gasError.data); - // Try to decode error selector - if (gasError.data.result) { - const errorSelector = gasError.data.result.slice(0, 10); - console.log(" Error selector:", errorSelector); - } - } - } - - const tx = await secureBlox.initialize( - accounts[0], // initialOwner - accounts[1], // broadcaster - accounts[2], // recovery - 1, // timeLockPeriodSec - "0x0000000000000000000000000000000000000000" // eventForwarder (none) - ); - console.log("โœ… SecureBlox initialized successfully"); - console.log(" Transaction hash:", tx.tx); - - // Save network info to artifact (fixes issue when network_id is "*") - await saveArtifactNetwork(SecureBlox, secureBlox.address, web3, network); - } catch (error) { - console.log("โŒ SecureBlox initialization failed:"); - console.log(" Error message:", error.message); - console.log(" Error reason:", error.reason); - console.log(" Error data:", JSON.stringify(error.data, null, 2)); - - // Extract error selector if available - if (error.data && error.data.result) { - const errorSelector = error.data.result.slice(0, 10); - console.log(" Error selector:", errorSelector); - console.log(" Full error result:", error.data.result); - } - - // Try to get more details from the transaction - if (error.receipt) { - console.log(" Transaction receipt:", JSON.stringify(error.receipt, null, 2)); - } - - console.log("โš ๏ธ Contract deployed but not initialized. This may be expected for upgradeable contracts."); - throw error; // Re-throw to stop migration - } - } else { - console.log("\n๐Ÿ“ฆ Step 2: Skipping SecureBlox deployment (disabled)"); - } - - // Step 3: Deploy RoleBlox (if enabled) - let roleBlox = null; - if (deployRoleBlox) { - console.log("\n๐Ÿ“ฆ Step 3: Deploying RoleBlox..."); - - // Link all required libraries to RoleBlox - await deployer.link(EngineBlox, RoleBlox); - await deployer.link(SecureOwnableDefinitions, RoleBlox); - await deployer.link(RuntimeRBACDefinitions, RoleBlox); - - // Deploy RoleBlox - await deployer.deploy(RoleBlox); - roleBlox = await RoleBlox.deployed(); - console.log("โœ… RoleBlox deployed at:", roleBlox.address); - // Get web3 from deployed contract instance (available for error handling) - const web3 = roleBlox.constructor.web3 || global.web3; - - // Wait for nonce to sync after deployment - const currentNonce = await web3.eth.getTransactionCount(accounts[0], 'pending'); - console.log(` Current account nonce: ${currentNonce}`); - const synced = await waitForNonceSync(web3, accounts[0], currentNonce); - if (!synced) { - console.log(` โš ๏ธ Warning: Nonce sync failed after max retries, proceeding anyway`); - } - - // Save network info to artifact (fixes issue when network_id is "*") - await saveArtifactNetwork(RoleBlox, roleBlox.address, web3, network); - - // Initialize RoleBlox - console.log("๐Ÿ”ง Initializing RoleBlox..."); - try { - const tx = await roleBlox.initialize( - accounts[0], // initialOwner - accounts[1], // broadcaster - accounts[2], // recovery - 1, // timeLockPeriodSec - "0x0000000000000000000000000000000000000000" // eventForwarder (none) - ); - console.log("โœ… RoleBlox initialized successfully"); - console.log(" Transaction hash:", tx.tx); - } catch (error) { - console.log("โŒ RoleBlox initialization failed:"); - console.log(" Error message:", error.message); - console.log(" Error reason:", error.reason); - console.log(" Error data:", error.data); - console.log(" Full error:", JSON.stringify(error, null, 2)); - - // Try to decode the error if it's a revert - if (error.data) { - try { - const decodedError = await web3.eth.call({ - to: roleBlox.address, - data: error.data - }); - console.log(" Decoded error data:", decodedError); - } catch (decodeError) { - console.log(" Could not decode error data:", decodeError.message); - } - } - - console.log("โš ๏ธ Contract deployed but not initialized. This may be expected for upgradeable contracts."); - } - } else { - console.log("\n๐Ÿ“ฆ Step 3: Skipping RoleBlox deployment (disabled)"); - } - - // Step 4: Deploy BareBlox (if enabled) - let bareBlox = null; - if (deployBareBlox) { - console.log("\n๐Ÿ“ฆ Step 4: Deploying BareBlox..."); - - // Link required libraries - await deployer.link(EngineBlox, BareBlox); - - // Deploy BareBlox - await deployer.deploy(BareBlox); - bareBlox = await BareBlox.deployed(); - console.log("โœ… BareBlox deployed at:", bareBlox.address); - // Get web3 from deployed contract instance - const web3 = bareBlox.constructor.web3 || global.web3; - - // Wait for nonce to sync after deployment - const currentNonce = await web3.eth.getTransactionCount(accounts[0], 'pending'); - console.log(` Current account nonce: ${currentNonce}`); - const synced = await waitForNonceSync(web3, accounts[0], currentNonce); - if (!synced) { - console.log(` โš ๏ธ Warning: Nonce sync failed after max retries, proceeding anyway`); - } - - // Save network info to artifact (fixes issue when network_id is "*") - await saveArtifactNetwork(BareBlox, bareBlox.address, web3, network); - - // Initialize BareBlox - console.log("๐Ÿ”ง Initializing BareBlox..."); - const initialOwner = accounts[0]; - const broadcaster = accounts[1]; - const recovery = accounts[2]; - const timeLockPeriodSec = 3600; // 1 hour - const eventForwarder = "0x0000000000000000000000000000000000000000"; - - console.log("Initial Owner:", initialOwner); - console.log("Broadcaster:", broadcaster); - console.log("Recovery:", recovery); - console.log("Time Lock Period:", timeLockPeriodSec, "seconds"); - - try { - await bareBlox.initialize( - initialOwner, - broadcaster, - recovery, - timeLockPeriodSec, - eventForwarder - ); - console.log("โœ… BareBlox initialized successfully!"); - - // Verify deployment - const isInitialized = await bareBlox.initialized(); - - console.log("- Initialized:", isInitialized); - } catch (error) { - console.log("โŒ BareBlox initialization failed:"); - console.log(" Error message:", error.message); - console.log(" Error reason:", error.reason); - console.log(" Error data:", error.data); - console.log(" Full error:", JSON.stringify(error, null, 2)); - } - } else { - console.log("\n๐Ÿ“ฆ Step 4: Skipping BareBlox deployment (disabled)"); - } - - // Step 5: Deploy AccountBlox (if enabled) + // Step 2: Deploy AccountBlox (if enabled) let accountBlox = null; if (deployAccountBlox) { - console.log("\n๐Ÿ“ฆ Step 5: Deploying AccountBlox..."); + console.log("\n๐Ÿ“ฆ Step 2: Deploying AccountBlox..."); // Link all required libraries to AccountBlox (includes GuardControllerDefinitions) await deployer.link(EngineBlox, AccountBlox); @@ -362,14 +134,11 @@ module.exports = async function(deployer, network, accounts) { console.log("โš ๏ธ Contract deployed but not initialized. This may be expected for upgradeable contracts."); } } else { - console.log("\n๐Ÿ“ฆ Step 5: Skipping AccountBlox deployment (disabled)"); + console.log("\n๐Ÿ“ฆ Step 2: Skipping AccountBlox deployment (disabled)"); } console.log("\n๐ŸŽ‰ Migration 2 completed successfully!"); console.log("๐Ÿ“‹ Guardian Contracts Deployed & Initialized:"); - if (secureBlox) console.log(` SecureBlox: ${secureBlox.address}`); - if (roleBlox) console.log(` RoleBlox: ${roleBlox.address}`); - if (bareBlox) console.log(` BareBlox: ${bareBlox.address}`); if (accountBlox) console.log(` AccountBlox: ${accountBlox.address}`); // Save deployed addresses to file for auto mode fallback @@ -386,24 +155,6 @@ module.exports = async function(deployer, network, accounts) { addresses[network] = {}; } - if (secureBlox) { - addresses[network].SecureBlox = { - address: secureBlox.address, - deployedAt: new Date().toISOString() - }; - } - if (roleBlox) { - addresses[network].RoleBlox = { - address: roleBlox.address, - deployedAt: new Date().toISOString() - }; - } - if (bareBlox) { - addresses[network].BareBlox = { - address: bareBlox.address, - deployedAt: new Date().toISOString() - }; - } if (accountBlox) { addresses[network].AccountBlox = { address: accountBlox.address, @@ -420,23 +171,17 @@ module.exports = async function(deployer, network, accounts) { console.log(` SecureOwnableDefinitions: ${sod.address}`); console.log(` RuntimeRBACDefinitions: ${drd.address}`); console.log("๐Ÿ›ก๏ธ Guardian Contracts (Deployed & Initialized):"); - if (secureBlox) console.log(` SecureBlox: ${secureBlox.address}`); - if (roleBlox) console.log(` RoleBlox: ${roleBlox.address}`); - if (bareBlox) console.log(` BareBlox: ${bareBlox.address}`); if (accountBlox) console.log(` AccountBlox: ${accountBlox.address}`); console.log("\nโœ… All contracts deployed and initialized successfully!"); - console.log("๐ŸŽฏ Ready for analyzer testing with fully functional contracts!"); console.log("๐Ÿ”ง Initialization Parameters:"); console.log(` Owner: ${accounts[0]}`); console.log(` Broadcaster: ${accounts[1] || accounts[0]}`); console.log(` Recovery: ${accounts[2] || accounts[0]}`); - console.log(` Time Lock Period: 60 seconds (1 minute) for SecureBlox/RoleBlox, 3600 seconds (1 hour) for BareBlox`); + console.log(` Time Lock Period: 1 second`); console.log(` Event Forwarder: None`); - console.log("\n๐Ÿ’ก Usage Examples:"); - console.log(" Deploy only SecureBlox: DEPLOY_SECUREBLOX=true DEPLOY_ROLEBLOX=false DEPLOY_BAREBLOX=false DEPLOY_ACCOUNTBLOX=false truffle migrate"); - console.log(" Deploy only BareBlox: DEPLOY_SECUREBLOX=false DEPLOY_ROLEBLOX=false DEPLOY_BAREBLOX=true DEPLOY_ACCOUNTBLOX=false truffle migrate"); - console.log(" Deploy only AccountBlox: DEPLOY_SECUREBLOX=false DEPLOY_ROLEBLOX=false DEPLOY_BAREBLOX=false DEPLOY_ACCOUNTBLOX=true truffle migrate"); - console.log(" Deploy all (default): truffle migrate"); + console.log("\n๐Ÿ’ก Usage:"); + console.log(" Deploy AccountBlox (default): truffle migrate"); + console.log(" Skip AccountBlox: DEPLOY_ACCOUNTBLOX=false truffle migrate"); }; diff --git a/migrations/3_deploy_example_contracts.cjs b/migrations/3_deploy_example_contracts.cjs index fd2ab3af..c4e6093a 100644 --- a/migrations/3_deploy_example_contracts.cjs +++ b/migrations/3_deploy_example_contracts.cjs @@ -1,11 +1,9 @@ // SPDX-License-Identifier: MPL-2.0 -// Migration 3: Deploy Example Contracts (SimpleVault, SimpleRWA20, ERC20Blox, FactoryBlox, BloxchainWallet) +// Migration 3: Deploy Example Contracts (SimpleVault, SimpleRWA20, CopyBlox) const SimpleVault = artifacts.require("SimpleVault"); const SimpleRWA20 = artifacts.require("SimpleRWA20"); -const ERC20Blox = artifacts.require("ERC20Blox"); -const FactoryBlox = artifacts.require("FactoryBlox"); -const BloxchainWallet = artifacts.require("BloxchainWallet"); +const CopyBlox = artifacts.require("CopyBlox"); // Import the deployed library artifacts to get their addresses const EngineBlox = artifacts.require("EngineBlox"); @@ -16,8 +14,6 @@ const GuardControllerDefinitions = artifacts.require("GuardControllerDefinitions // Import the example-specific definitions const SimpleVaultDefinitions = artifacts.require("SimpleVaultDefinitions"); const SimpleRWA20Definitions = artifacts.require("SimpleRWA20Definitions"); -const ERC20BloxDefinitions = artifacts.require("ERC20BloxDefinitions"); -const FactoryBloxDefinitions = artifacts.require("FactoryBloxDefinitions"); const { saveArtifactNetwork } = require('./helpers/save-artifact-network.cjs'); module.exports = async function(deployer, network, accounts) { @@ -30,25 +26,19 @@ module.exports = async function(deployer, network, accounts) { // Configuration flags - set to true/false to control which contracts to deploy const deploySimpleVault = process.env.DEPLOY_SIMPLE_VAULT === 'true'; // Default: false const deploySimpleRWA20 = process.env.DEPLOY_SIMPLE_RWA20 === 'true'; // Default: false - const deployERC20Blox = process.env.DEPLOY_ERC20_BLOX === 'true'; // Default: false - const deployFactoryBlox = process.env.DEPLOY_FACTORY_BLOX === 'true'; // Default: false - const deployWalletBlox = process.env.DEPLOY_WALLET_BLOX === 'true'; // Default: false + const deployCopyBlox = process.env.DEPLOY_COPYBLOX === 'true'; // Default: false console.log("\n๐ŸŽฏ Deployment Configuration:"); console.log(` SimpleVault: ${deploySimpleVault ? 'โœ… YES' : 'โŒ NO'}`); console.log(` SimpleRWA20: ${deploySimpleRWA20 ? 'โœ… YES' : 'โŒ NO'}`); - console.log(` ERC20Blox: ${deployERC20Blox ? 'โœ… YES' : 'โŒ NO'}`); - console.log(` FactoryBlox: ${deployFactoryBlox ? 'โœ… YES' : 'โŒ NO'}`); - console.log(` BloxchainWallet: ${deployWalletBlox ? 'โœ… YES' : 'โŒ NO'}`); + console.log(` CopyBlox: ${deployCopyBlox ? 'โœ… YES' : 'โŒ NO'}`); try { // Step 1: Deploy Example-Specific Definitions Libraries (only if needed) let simpleVaultDefinitions = null; let simpleRWA20Definitions = null; - let erc20BloxDefinitions = null; - let factoryBloxDefinitions = null; - if (deploySimpleVault || deploySimpleRWA20 || deployERC20Blox || deployFactoryBlox || deployWalletBlox) { + if (deploySimpleVault || deploySimpleRWA20) { console.log("\n๐Ÿ“ฆ Step 1: Deploying Example-Specific Definitions Libraries..."); if (deploySimpleVault) { @@ -64,20 +54,6 @@ module.exports = async function(deployer, network, accounts) { simpleRWA20Definitions = await SimpleRWA20Definitions.deployed(); console.log(`โœ… SimpleRWA20Definitions deployed at: ${simpleRWA20Definitions.address}`); } - - if (deployERC20Blox) { - // Deploy ERC20BloxDefinitions - await deployer.deploy(ERC20BloxDefinitions); - erc20BloxDefinitions = await ERC20BloxDefinitions.deployed(); - console.log(`โœ… ERC20BloxDefinitions deployed at: ${erc20BloxDefinitions.address}`); - } - - if (deployFactoryBlox) { - // Deploy FactoryBloxDefinitions - await deployer.deploy(FactoryBloxDefinitions); - factoryBloxDefinitions = await FactoryBloxDefinitions.deployed(); - console.log(`โœ… FactoryBloxDefinitions deployed at: ${factoryBloxDefinitions.address}`); - } } else { console.log("\n๐Ÿ“ฆ Step 1: Skipping Example-Specific Definitions Libraries (no contracts enabled)"); } @@ -227,124 +203,41 @@ module.exports = async function(deployer, network, accounts) { console.log("\n๐Ÿ“ฆ Step 4: Skipping SimpleRWA20 deployment (disabled)"); } - // Step 5: Deploy ERC20Blox (if enabled) - let erc20Blox = null; - if (deployERC20Blox) { - console.log("\n๐Ÿ“ฆ Step 5: Deploying ERC20Blox..."); - await deployer.link(sa, ERC20Blox); - await deployer.link(sod, ERC20Blox); - await deployer.link(drbd, ERC20Blox); - await deployer.link(gcd, ERC20Blox); - await deployer.link(erc20BloxDefinitions, ERC20Blox); - await deployer.deploy(ERC20Blox); - erc20Blox = await ERC20Blox.deployed(); - console.log(`โœ… ERC20Blox deployed at: ${erc20Blox.address}`); - const web3Erc20 = erc20Blox.constructor.web3 || global.web3; - await saveArtifactNetwork(ERC20Blox, erc20Blox.address, web3Erc20, network); - - // Initialize ERC20Blox (5 params) - console.log("๐Ÿ”ง Initializing ERC20Blox..."); - try { - await erc20Blox.initialize( - accounts[0], // initialOwner - accounts[1], // broadcaster - accounts[2], // recovery - 1, // timeLockPeriodInSeconds (1 second for fast testing) - "0x0000000000000000000000000000000000000000" // eventForwarder (none) - ); - console.log("โœ… ERC20Blox initialize(5 params) succeeded"); - } catch (error) { - console.log("โŒ ERC20Blox initialize failed:", error.message); - console.log("โš ๏ธ Contract deployed but not initialized."); - } - - // Initialize ERC20 token name/symbol (reinitializer(2)) - try { - const tx = await erc20Blox.initializeToken("ERC20Blox", "BLOX20"); - console.log("โœ… ERC20Blox initializeToken succeeded"); - console.log(" Transaction hash:", tx.tx); - } catch (error) { - console.log("โŒ ERC20Blox initializeToken failed:", error.message); - } - } else { - console.log("\n๐Ÿ“ฆ Step 5: Skipping ERC20Blox deployment (disabled)"); - } - - // Step 6: Deploy FactoryBlox (if enabled) - let factoryBlox = null; - if (deployFactoryBlox) { - console.log("\n๐Ÿ“ฆ Step 6: Deploying FactoryBlox..."); - await deployer.link(sa, FactoryBlox); - await deployer.link(sod, FactoryBlox); - await deployer.link(drbd, FactoryBlox); - await deployer.link(gcd, FactoryBlox); - await deployer.link(factoryBloxDefinitions, FactoryBlox); - await deployer.deploy(FactoryBlox); - factoryBlox = await FactoryBlox.deployed(); - console.log(`โœ… FactoryBlox deployed at: ${factoryBlox.address}`); - const web3Factory = factoryBlox.constructor.web3 || global.web3; - await saveArtifactNetwork(FactoryBlox, factoryBlox.address, web3Factory, network); + // Step 5: Deploy CopyBlox (if enabled) - BaseStateMachine only, links EngineBlox + let copyBlox = null; + if (deployCopyBlox) { + console.log("\n๐Ÿ“ฆ Step 5: Deploying CopyBlox..."); + await deployer.link(sa, CopyBlox); + await deployer.deploy(CopyBlox); + copyBlox = await CopyBlox.deployed(); + console.log(`โœ… CopyBlox deployed at: ${copyBlox.address}`); + const web3Copy = copyBlox.constructor.web3 || global.web3; + await saveArtifactNetwork(CopyBlox, copyBlox.address, web3Copy, network); - // Initialize FactoryBlox (5 params) - console.log("๐Ÿ”ง Initializing FactoryBlox..."); + // Initialize CopyBlox (5 params) + console.log("๐Ÿ”ง Initializing CopyBlox..."); try { - await factoryBlox.initialize( + await copyBlox.initialize( accounts[0], // initialOwner accounts[1], // broadcaster accounts[2], // recovery 1, // timeLockPeriodInSeconds (1 second for fast testing) "0x0000000000000000000000000000000000000000" // eventForwarder (none) ); - console.log("โœ… FactoryBlox initialized successfully"); - } catch (error) { - console.log("โŒ FactoryBlox initialize failed:", error.message); - console.log("โš ๏ธ Contract deployed but not initialized."); - } - } else { - console.log("\n๐Ÿ“ฆ Step 6: Skipping FactoryBlox deployment (disabled)"); - } - - // Step 7: Deploy BloxchainWallet (if enabled) - Account-based, no definitions library; timeLock 1โ€“90 days - const ONE_DAY_SEC = 86400; - let bloxchainWallet = null; - if (deployWalletBlox) { - console.log("\n๐Ÿ“ฆ Step 7: Deploying BloxchainWallet..."); - await deployer.link(sa, BloxchainWallet); - await deployer.link(sod, BloxchainWallet); - await deployer.link(drbd, BloxchainWallet); - await deployer.link(gcd, BloxchainWallet); - await deployer.deploy(BloxchainWallet); - bloxchainWallet = await BloxchainWallet.deployed(); - console.log(`โœ… BloxchainWallet deployed at: ${bloxchainWallet.address}`); - const web3Wallet = bloxchainWallet.constructor.web3 || global.web3; - await saveArtifactNetwork(BloxchainWallet, bloxchainWallet.address, web3Wallet, network); - - // Initialize BloxchainWallet (5 params); timeLock must be between 1 and 90 days - console.log("๐Ÿ”ง Initializing BloxchainWallet..."); - try { - await bloxchainWallet.initialize( - accounts[0], // initialOwner - accounts[1], // broadcaster - accounts[2], // recovery - ONE_DAY_SEC, // timeLockPeriodInSeconds (min 1 day per contract) - "0x0000000000000000000000000000000000000000" // eventForwarder (none) - ); - console.log("โœ… BloxchainWallet initialized successfully"); + console.log("โœ… CopyBlox initialized successfully"); } catch (error) { - console.log("โŒ BloxchainWallet initialize failed:", error.message); + console.log("โŒ CopyBlox initialize failed:", error.message); console.log("โš ๏ธ Contract deployed but not initialized."); } } else { - console.log("\n๐Ÿ“ฆ Step 7: Skipping BloxchainWallet deployment (disabled)"); + console.log("\n๐Ÿ“ฆ Step 5: Skipping CopyBlox deployment (disabled)"); } console.log("\n๐ŸŽ‰ Migration 3 completed successfully!"); console.log("๐Ÿ“‹ Example Contracts Deployed & Initialized:"); if (simpleVault) console.log(` SimpleVault: ${simpleVault.address}`); if (simpleRWA20) console.log(` SimpleRWA20: ${simpleRWA20.address}`); - if (erc20Blox) console.log(` ERC20Blox: ${erc20Blox.address}`); - if (factoryBlox) console.log(` FactoryBlox: ${factoryBlox.address}`); - if (bloxchainWallet) console.log(` BloxchainWallet: ${bloxchainWallet.address}`); + if (copyBlox) console.log(` CopyBlox: ${copyBlox.address}`); // Save deployed addresses to file for auto mode fallback const fs = require('fs'); @@ -372,18 +265,6 @@ module.exports = async function(deployer, network, accounts) { deployedAt: new Date().toISOString() }; } - if (erc20BloxDefinitions) { - addresses[network].ERC20BloxDefinitions = { - address: erc20BloxDefinitions.address, - deployedAt: new Date().toISOString() - }; - } - if (factoryBloxDefinitions) { - addresses[network].FactoryBloxDefinitions = { - address: factoryBloxDefinitions.address, - deployedAt: new Date().toISOString() - }; - } if (simpleVault) { addresses[network].SimpleVault = { address: simpleVault.address, @@ -396,21 +277,9 @@ module.exports = async function(deployer, network, accounts) { deployedAt: new Date().toISOString() }; } - if (erc20Blox) { - addresses[network].ERC20Blox = { - address: erc20Blox.address, - deployedAt: new Date().toISOString() - }; - } - if (factoryBlox) { - addresses[network].FactoryBlox = { - address: factoryBlox.address, - deployedAt: new Date().toISOString() - }; - } - if (bloxchainWallet) { - addresses[network].BloxchainWallet = { - address: bloxchainWallet.address, + if (copyBlox) { + addresses[network].CopyBlox = { + address: copyBlox.address, deployedAt: new Date().toISOString() }; } @@ -427,17 +296,10 @@ module.exports = async function(deployer, network, accounts) { console.log("๐Ÿ“‹ Example-Specific Definitions:"); if (simpleVaultDefinitions) console.log(` SimpleVaultDefinitions: ${simpleVaultDefinitions.address}`); if (simpleRWA20Definitions) console.log(` SimpleRWA20Definitions: ${simpleRWA20Definitions.address}`); - if (erc20BloxDefinitions) console.log(` ERC20BloxDefinitions: ${erc20BloxDefinitions.address}`); - if (factoryBloxDefinitions) console.log(` FactoryBloxDefinitions: ${factoryBloxDefinitions.address}`); - console.log("๐Ÿ›ก๏ธ Guardian Contracts (Deployed & Initialized):"); - console.log(` GuardianAccountAbstraction: 0xf759A0e8F2fFBb5F5a9DD50f1106668FBE29bC93`); - console.log(` GuardianAccountAbstractionWithRoles: 0xA5682DF1987D214Fe4dfC3a262179eBDc205b525`); console.log("๐Ÿฆ Example Contracts (Deployed & Initialized):"); if (simpleVault) console.log(` SimpleVault: ${simpleVault.address}`); if (simpleRWA20) console.log(` SimpleRWA20: ${simpleRWA20.address}`); - if (erc20Blox) console.log(` ERC20Blox: ${erc20Blox.address}`); - if (factoryBlox) console.log(` FactoryBlox: ${factoryBlox.address}`); - if (bloxchainWallet) console.log(` BloxchainWallet: ${bloxchainWallet.address}`); + if (copyBlox) console.log(` CopyBlox: ${copyBlox.address}`); console.log("\nโœ… All contracts deployed and initialized successfully!"); console.log("๐ŸŽฏ Ready for comprehensive analyzer testing with fully functional contracts!"); console.log("๐Ÿ”ง Initialization Parameters:"); @@ -450,12 +312,10 @@ module.exports = async function(deployer, network, accounts) { console.log(` Token Symbol: SRWA`); console.log("\n๐Ÿ’ก Usage Examples:"); - console.log(" Deploy only SimpleVault: DEPLOY_SIMPLE_VAULT=true DEPLOY_SIMPLE_RWA20=false DEPLOY_ERC20_BLOX=false DEPLOY_FACTORY_BLOX=false DEPLOY_WALLET_BLOX=false truffle migrate"); - console.log(" Deploy only SimpleRWA20: DEPLOY_SIMPLE_VAULT=false DEPLOY_SIMPLE_RWA20=true DEPLOY_ERC20_BLOX=false DEPLOY_FACTORY_BLOX=false DEPLOY_WALLET_BLOX=false truffle migrate"); - console.log(" Deploy only ERC20Blox: DEPLOY_SIMPLE_VAULT=false DEPLOY_SIMPLE_RWA20=false DEPLOY_ERC20_BLOX=true DEPLOY_FACTORY_BLOX=false DEPLOY_WALLET_BLOX=false truffle migrate"); - console.log(" Deploy only FactoryBlox: DEPLOY_SIMPLE_VAULT=false DEPLOY_SIMPLE_RWA20=false DEPLOY_ERC20_BLOX=false DEPLOY_FACTORY_BLOX=true DEPLOY_WALLET_BLOX=false truffle migrate"); - console.log(" Deploy only BloxchainWallet: DEPLOY_SIMPLE_VAULT=false DEPLOY_SIMPLE_RWA20=false DEPLOY_ERC20_BLOX=false DEPLOY_FACTORY_BLOX=false DEPLOY_WALLET_BLOX=true truffle migrate"); - console.log(" Deploy all example contracts: DEPLOY_SIMPLE_VAULT=true DEPLOY_SIMPLE_RWA20=true DEPLOY_ERC20_BLOX=true DEPLOY_FACTORY_BLOX=true DEPLOY_WALLET_BLOX=true truffle migrate"); + console.log(" Deploy only SimpleVault: DEPLOY_SIMPLE_VAULT=true DEPLOY_SIMPLE_RWA20=false DEPLOY_COPYBLOX=false truffle migrate"); + console.log(" Deploy only SimpleRWA20: DEPLOY_SIMPLE_VAULT=false DEPLOY_SIMPLE_RWA20=true DEPLOY_COPYBLOX=false truffle migrate"); + console.log(" Deploy only CopyBlox: DEPLOY_SIMPLE_VAULT=false DEPLOY_SIMPLE_RWA20=false DEPLOY_COPYBLOX=true truffle migrate"); + console.log(" Deploy all example contracts: DEPLOY_SIMPLE_VAULT=true DEPLOY_SIMPLE_RWA20=true DEPLOY_COPYBLOX=true truffle migrate"); console.log(" Deploy none (default): truffle migrate"); } catch (error) { diff --git a/package-lock.json b/package-lock.json index 079406e3..80fd3b67 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,28 +1,28 @@ { "name": "Bloxchain", - "version": "1.0.0-alpha.12", + "version": "1.0.0-alpha.13", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "Bloxchain", - "version": "1.0.0-alpha.12", + "version": "1.0.0-alpha.13", "license": "MPL-2.0", "dependencies": { "@openzeppelin/contracts": "^5.4.0", "@openzeppelin/contracts-upgradeable": "^5.4.0" }, "devDependencies": { - "@commitlint/cli": "^20.3.1", + "@commitlint/cli": "^20.4.1", "@commitlint/config-conventional": "^20.3.1", "@nomicfoundation/hardhat-ethers": "^4.0.4", - "dotenv": "^17.2.3", - "hardhat": "^3.1.5", + "dotenv": "^17.3.1", + "hardhat": "^3.1.8", "husky": "^9.1.7", "prettier": "^3.8.1", - "prettier-plugin-solidity": "^2.1.0", - "release-please": "^17.1.3", - "viem": "^2.44.4" + "prettier-plugin-solidity": "^2.2.1", + "release-please": "^17.3.0", + "viem": "^2.46.1" } }, "node_modules/@adraffy/ens-normalize": { @@ -33,9 +33,9 @@ "license": "MIT" }, "node_modules/@babel/code-frame": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.28.6.tgz", - "integrity": "sha512-JYgintcMjRiCvS8mMECzaEn+m3PfoQiyqukOMCCVQtoJGYJw8j/8LBJEiqkHLkfwCcs74E3pbAUFNg7d9VNJ+Q==", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.0.tgz", + "integrity": "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==", "dev": true, "license": "MIT", "dependencies": { @@ -58,22 +58,24 @@ } }, "node_modules/@bytecodealliance/preview2-shim": { - "version": "0.17.6", + "version": "0.17.8", + "resolved": "https://registry.npmjs.org/@bytecodealliance/preview2-shim/-/preview2-shim-0.17.8.tgz", + "integrity": "sha512-wS5kg8u0KCML1UeHQPJ1IuOI24x/XLentCzsqPER1+gDNC5Cz2hG4G2blLOZap+3CEGhIhnJ9mmZYj6a2W0Lww==", "dev": true, "license": "(Apache-2.0 WITH LLVM-exception)" }, "node_modules/@commitlint/cli": { - "version": "20.3.1", - "resolved": "https://registry.npmjs.org/@commitlint/cli/-/cli-20.3.1.tgz", - "integrity": "sha512-NtInjSlyev/+SLPvx/ulz8hRE25Wf5S9dLNDcIwazq0JyB4/w1ROF/5nV0ObPTX8YpRaKYeKtXDYWqumBNHWsw==", + "version": "20.4.2", + "resolved": "https://registry.npmjs.org/@commitlint/cli/-/cli-20.4.2.tgz", + "integrity": "sha512-YjYSX2yj/WsVoxh9mNiymfFS2ADbg2EK4+1WAsMuckwKMCqJ5PDG0CJU/8GvmHWcv4VRB2V02KqSiecRksWqZQ==", "dev": true, "license": "MIT", "dependencies": { - "@commitlint/format": "^20.3.1", - "@commitlint/lint": "^20.3.1", - "@commitlint/load": "^20.3.1", - "@commitlint/read": "^20.3.1", - "@commitlint/types": "^20.3.1", + "@commitlint/format": "^20.4.0", + "@commitlint/lint": "^20.4.2", + "@commitlint/load": "^20.4.0", + "@commitlint/read": "^20.4.0", + "@commitlint/types": "^20.4.0", "tinyexec": "^1.0.0", "yargs": "^17.0.0" }, @@ -85,27 +87,27 @@ } }, "node_modules/@commitlint/config-conventional": { - "version": "20.3.1", - "resolved": "https://registry.npmjs.org/@commitlint/config-conventional/-/config-conventional-20.3.1.tgz", - "integrity": "sha512-NCzwvxepstBZbmVXsvg49s+shCxlJDJPWxXqONVcAtJH9wWrOlkMQw/zyl+dJmt8lyVopt5mwQ3mR5M2N2rUWg==", + "version": "20.4.2", + "resolved": "https://registry.npmjs.org/@commitlint/config-conventional/-/config-conventional-20.4.2.tgz", + "integrity": "sha512-rwkTF55q7Q+6dpSKUmJoScV0f3EpDlWKw2UPzklkLS4o5krMN1tPWAVOgHRtyUTMneIapLeQwaCjn44Td6OzBQ==", "dev": true, "license": "MIT", "dependencies": { - "@commitlint/types": "^20.3.1", - "conventional-changelog-conventionalcommits": "^7.0.2" + "@commitlint/types": "^20.4.0", + "conventional-changelog-conventionalcommits": "^9.1.0" }, "engines": { "node": ">=v18" } }, "node_modules/@commitlint/config-validator": { - "version": "20.3.1", - "resolved": "https://registry.npmjs.org/@commitlint/config-validator/-/config-validator-20.3.1.tgz", - "integrity": "sha512-ErVLC/IsHhcvxCyh+FXo7jy12/nkQySjWXYgCoQbZLkFp4hysov8KS6CdxBB0cWjbZWjvNOKBMNoUVqkmGmahw==", + "version": "20.4.0", + "resolved": "https://registry.npmjs.org/@commitlint/config-validator/-/config-validator-20.4.0.tgz", + "integrity": "sha512-zShmKTF+sqyNOfAE0vKcqnpvVpG0YX8F9G/ZIQHI2CoKyK+PSdladXMSns400aZ5/QZs+0fN75B//3Q5CHw++w==", "dev": true, "license": "MIT", "dependencies": { - "@commitlint/types": "^20.3.1", + "@commitlint/types": "^20.4.0", "ajv": "^8.11.0" }, "engines": { @@ -113,13 +115,13 @@ } }, "node_modules/@commitlint/ensure": { - "version": "20.3.1", - "resolved": "https://registry.npmjs.org/@commitlint/ensure/-/ensure-20.3.1.tgz", - "integrity": "sha512-h664FngOEd7bHAm0j8MEKq+qm2mH+V+hwJiIE2bWcw3pzJMlO0TPKtk0ATyRAtV6jQw+xviRYiIjjSjfajiB5w==", + "version": "20.4.1", + "resolved": "https://registry.npmjs.org/@commitlint/ensure/-/ensure-20.4.1.tgz", + "integrity": "sha512-WLQqaFx1pBooiVvBrA1YfJNFqZF8wS/YGOtr5RzApDbV9tQ52qT5VkTsY65hFTnXhW8PcDfZLaknfJTmPejmlw==", "dev": true, "license": "MIT", "dependencies": { - "@commitlint/types": "^20.3.1", + "@commitlint/types": "^20.4.0", "lodash.camelcase": "^4.3.0", "lodash.kebabcase": "^4.1.1", "lodash.snakecase": "^4.1.1", @@ -141,27 +143,27 @@ } }, "node_modules/@commitlint/format": { - "version": "20.3.1", - "resolved": "https://registry.npmjs.org/@commitlint/format/-/format-20.3.1.tgz", - "integrity": "sha512-jfsjGPFTd2Yti2YHwUH4SPRPbWKAJAwrfa3eNa9bXEdrXBb9mCwbIrgYX38LdEJK9zLJ3AsLBP4/FLEtxyu2AA==", + "version": "20.4.0", + "resolved": "https://registry.npmjs.org/@commitlint/format/-/format-20.4.0.tgz", + "integrity": "sha512-i3ki3WR0rgolFVX6r64poBHXM1t8qlFel1G1eCBvVgntE3fCJitmzSvH5JD/KVJN/snz6TfaX2CLdON7+s4WVQ==", "dev": true, "license": "MIT", "dependencies": { - "@commitlint/types": "^20.3.1", - "chalk": "^5.3.0" + "@commitlint/types": "^20.4.0", + "picocolors": "^1.1.1" }, "engines": { "node": ">=v18" } }, "node_modules/@commitlint/is-ignored": { - "version": "20.3.1", - "resolved": "https://registry.npmjs.org/@commitlint/is-ignored/-/is-ignored-20.3.1.tgz", - "integrity": "sha512-tWwAoh93QvAhxgp99CzCuHD86MgxE4NBtloKX+XxQxhfhSwHo7eloiar/yzx53YW9eqSLP95zgW2KDDk4/WX+A==", + "version": "20.4.1", + "resolved": "https://registry.npmjs.org/@commitlint/is-ignored/-/is-ignored-20.4.1.tgz", + "integrity": "sha512-In5EO4JR1lNsAv1oOBBO24V9ND1IqdAJDKZiEpdfjDl2HMasAcT7oA+5BKONv1pRoLG380DGPE2W2RIcUwdgLA==", "dev": true, "license": "MIT", "dependencies": { - "@commitlint/types": "^20.3.1", + "@commitlint/types": "^20.4.0", "semver": "^7.6.0" }, "engines": { @@ -169,47 +171,46 @@ } }, "node_modules/@commitlint/lint": { - "version": "20.3.1", - "resolved": "https://registry.npmjs.org/@commitlint/lint/-/lint-20.3.1.tgz", - "integrity": "sha512-LaOtrQ24+6SfUaWg8A+a+Wc77bvLbO5RIr6iy9F7CI3/0iq1uPEWgGRCwqWTuLGHkZDAcwaq0gZ01zpwZ1jCGw==", + "version": "20.4.2", + "resolved": "https://registry.npmjs.org/@commitlint/lint/-/lint-20.4.2.tgz", + "integrity": "sha512-buquzNRtFng6xjXvBU1abY/WPEEjCgUipNQrNmIWe8QuJ6LWLtei/LDBAzEe5ASm45+Q9L2Xi3/GVvlj50GAug==", "dev": true, "license": "MIT", "dependencies": { - "@commitlint/is-ignored": "^20.3.1", - "@commitlint/parse": "^20.3.1", - "@commitlint/rules": "^20.3.1", - "@commitlint/types": "^20.3.1" + "@commitlint/is-ignored": "^20.4.1", + "@commitlint/parse": "^20.4.1", + "@commitlint/rules": "^20.4.2", + "@commitlint/types": "^20.4.0" }, "engines": { "node": ">=v18" } }, "node_modules/@commitlint/load": { - "version": "20.3.1", - "resolved": "https://registry.npmjs.org/@commitlint/load/-/load-20.3.1.tgz", - "integrity": "sha512-YDD9XA2XhgYgbjju8itZ/weIvOOobApDqwlPYCX5NLO/cPtw2UMO5Cmn44Ks8RQULUVI5fUT6roKvyxcoLbNmw==", + "version": "20.4.0", + "resolved": "https://registry.npmjs.org/@commitlint/load/-/load-20.4.0.tgz", + "integrity": "sha512-Dauup/GfjwffBXRJUdlX/YRKfSVXsXZLnINXKz0VZkXdKDcaEILAi9oflHGbfydonJnJAbXEbF3nXPm9rm3G6A==", "dev": true, "license": "MIT", "dependencies": { - "@commitlint/config-validator": "^20.3.1", + "@commitlint/config-validator": "^20.4.0", "@commitlint/execute-rule": "^20.0.0", - "@commitlint/resolve-extends": "^20.3.1", - "@commitlint/types": "^20.3.1", - "chalk": "^5.3.0", + "@commitlint/resolve-extends": "^20.4.0", + "@commitlint/types": "^20.4.0", "cosmiconfig": "^9.0.0", "cosmiconfig-typescript-loader": "^6.1.0", - "lodash.isplainobject": "^4.0.6", - "lodash.merge": "^4.6.2", - "lodash.uniq": "^4.5.0" + "is-plain-obj": "^4.1.0", + "lodash.mergewith": "^4.6.2", + "picocolors": "^1.1.1" }, "engines": { "node": ">=v18" } }, "node_modules/@commitlint/message": { - "version": "20.0.0", - "resolved": "https://registry.npmjs.org/@commitlint/message/-/message-20.0.0.tgz", - "integrity": "sha512-gLX4YmKnZqSwkmSB9OckQUrI5VyXEYiv3J5JKZRxIp8jOQsWjZgHSG/OgEfMQBK9ibdclEdAyIPYggwXoFGXjQ==", + "version": "20.4.0", + "resolved": "https://registry.npmjs.org/@commitlint/message/-/message-20.4.0.tgz", + "integrity": "sha512-B5lGtvHgiLAIsK5nLINzVW0bN5hXv+EW35sKhYHE8F7V9Uz1fR4tx3wt7mobA5UNhZKUNgB/+ldVMQE6IHZRyA==", "dev": true, "license": "MIT", "engines": { @@ -217,29 +218,29 @@ } }, "node_modules/@commitlint/parse": { - "version": "20.3.1", - "resolved": "https://registry.npmjs.org/@commitlint/parse/-/parse-20.3.1.tgz", - "integrity": "sha512-TuUTdbLpyUNLgDzLDYlI2BeTE6V/COZbf3f8WwsV0K6eq/2nSpNTMw7wHtXb+YxeY9wwxBp/Ldad4P+YIxHJoA==", + "version": "20.4.1", + "resolved": "https://registry.npmjs.org/@commitlint/parse/-/parse-20.4.1.tgz", + "integrity": "sha512-XNtZjeRcFuAfUnhYrCY02+mpxwY4OmnvD3ETbVPs25xJFFz1nRo/25nHj+5eM+zTeRFvWFwD4GXWU2JEtoK1/w==", "dev": true, "license": "MIT", "dependencies": { - "@commitlint/types": "^20.3.1", - "conventional-changelog-angular": "^7.0.0", - "conventional-commits-parser": "^5.0.0" + "@commitlint/types": "^20.4.0", + "conventional-changelog-angular": "^8.1.0", + "conventional-commits-parser": "^6.2.1" }, "engines": { "node": ">=v18" } }, "node_modules/@commitlint/read": { - "version": "20.3.1", - "resolved": "https://registry.npmjs.org/@commitlint/read/-/read-20.3.1.tgz", - "integrity": "sha512-nCmJAdIg3OdNVUpQW0Idk/eF/vfOo2W2xzmvRmNeptLrzFK7qhwwl/kIwy1Q1LZrKHUFNj7PGNpIT5INbgZWzA==", + "version": "20.4.0", + "resolved": "https://registry.npmjs.org/@commitlint/read/-/read-20.4.0.tgz", + "integrity": "sha512-QfpFn6/I240ySEGv7YWqho4vxqtPpx40FS7kZZDjUJ+eHxu3azfhy7fFb5XzfTqVNp1hNoI3tEmiEPbDB44+cg==", "dev": true, "license": "MIT", "dependencies": { - "@commitlint/top-level": "^20.0.0", - "@commitlint/types": "^20.3.1", + "@commitlint/top-level": "^20.4.0", + "@commitlint/types": "^20.4.0", "git-raw-commits": "^4.0.0", "minimist": "^1.2.8", "tinyexec": "^1.0.0" @@ -249,14 +250,14 @@ } }, "node_modules/@commitlint/resolve-extends": { - "version": "20.3.1", - "resolved": "https://registry.npmjs.org/@commitlint/resolve-extends/-/resolve-extends-20.3.1.tgz", - "integrity": "sha512-iGTGeyaoDyHDEZNjD8rKeosjSNs8zYanmuowY4ful7kFI0dnY4b5QilVYaFQJ6IM27S57LAeH5sKSsOHy4bw5w==", + "version": "20.4.0", + "resolved": "https://registry.npmjs.org/@commitlint/resolve-extends/-/resolve-extends-20.4.0.tgz", + "integrity": "sha512-ay1KM8q0t+/OnlpqXJ+7gEFQNlUtSU5Gxr8GEwnVf2TPN3+ywc5DzL3JCxmpucqxfHBTFwfRMXxPRRnR5Ki20g==", "dev": true, "license": "MIT", "dependencies": { - "@commitlint/config-validator": "^20.3.1", - "@commitlint/types": "^20.3.1", + "@commitlint/config-validator": "^20.4.0", + "@commitlint/types": "^20.4.0", "global-directory": "^4.0.1", "import-meta-resolve": "^4.0.0", "lodash.mergewith": "^4.6.2", @@ -267,16 +268,16 @@ } }, "node_modules/@commitlint/rules": { - "version": "20.3.1", - "resolved": "https://registry.npmjs.org/@commitlint/rules/-/rules-20.3.1.tgz", - "integrity": "sha512-/uic4P+4jVNpqQxz02+Y6vvIC0A2J899DBztA1j6q3f3MOKwydlNrojSh0dQmGDxxT1bXByiRtDhgFnOFnM6Pg==", + "version": "20.4.2", + "resolved": "https://registry.npmjs.org/@commitlint/rules/-/rules-20.4.2.tgz", + "integrity": "sha512-oz83pnp5Yq6uwwTAabuVQPNlPfeD2Y5ZjMb7Wx8FSUlu4sLYJjbBWt8031Z0osCFPfHzAwSYrjnfDFKtuSMdKg==", "dev": true, "license": "MIT", "dependencies": { - "@commitlint/ensure": "^20.3.1", - "@commitlint/message": "^20.0.0", + "@commitlint/ensure": "^20.4.1", + "@commitlint/message": "^20.4.0", "@commitlint/to-lines": "^20.0.0", - "@commitlint/types": "^20.3.1" + "@commitlint/types": "^20.4.0" }, "engines": { "node": ">=v18" @@ -293,27 +294,27 @@ } }, "node_modules/@commitlint/top-level": { - "version": "20.0.0", - "resolved": "https://registry.npmjs.org/@commitlint/top-level/-/top-level-20.0.0.tgz", - "integrity": "sha512-drXaPSP2EcopukrUXvUXmsQMu3Ey/FuJDc/5oiW4heoCfoE5BdLQyuc7veGeE3aoQaTVqZnh4D5WTWe2vefYKg==", + "version": "20.4.0", + "resolved": "https://registry.npmjs.org/@commitlint/top-level/-/top-level-20.4.0.tgz", + "integrity": "sha512-NDzq8Q6jmFaIIBC/GG6n1OQEaHdmaAAYdrZRlMgW6glYWGZ+IeuXmiymDvQNXPc82mVxq2KiE3RVpcs+1OeDeA==", "dev": true, "license": "MIT", "dependencies": { - "find-up": "^7.0.0" + "escalade": "^3.2.0" }, "engines": { "node": ">=v18" } }, "node_modules/@commitlint/types": { - "version": "20.3.1", - "resolved": "https://registry.npmjs.org/@commitlint/types/-/types-20.3.1.tgz", - "integrity": "sha512-VmIFV/JkBRhDRRv7N5B7zEUkNZIx9Mp+8Pe65erz0rKycXLsi8Epcw0XJ+btSeRXgTzE7DyOyA9bkJ9mn/yqVQ==", + "version": "20.4.0", + "resolved": "https://registry.npmjs.org/@commitlint/types/-/types-20.4.0.tgz", + "integrity": "sha512-aO5l99BQJ0X34ft8b0h7QFkQlqxC6e7ZPVmBKz13xM9O8obDaM1Cld4sQlJDXXU/VFuUzQ30mVtHjVz74TuStw==", "dev": true, "license": "MIT", "dependencies": { - "@types/conventional-commits-parser": "^5.0.0", - "chalk": "^5.3.0" + "conventional-commits-parser": "^6.2.1", + "picocolors": "^1.1.1" }, "engines": { "node": ">=v18" @@ -330,8 +331,435 @@ "unist-util-visit-parents": "^3.1.1" } }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.3.tgz", + "integrity": "sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.3.tgz", + "integrity": "sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.3.tgz", + "integrity": "sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.3.tgz", + "integrity": "sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.3.tgz", + "integrity": "sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.3.tgz", + "integrity": "sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.3.tgz", + "integrity": "sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.3.tgz", + "integrity": "sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.3.tgz", + "integrity": "sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.3.tgz", + "integrity": "sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.3.tgz", + "integrity": "sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.3.tgz", + "integrity": "sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.3.tgz", + "integrity": "sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.3.tgz", + "integrity": "sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.3.tgz", + "integrity": "sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.3.tgz", + "integrity": "sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.3.tgz", + "integrity": "sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.3.tgz", + "integrity": "sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.3.tgz", + "integrity": "sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.3.tgz", + "integrity": "sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.3.tgz", + "integrity": "sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.3.tgz", + "integrity": "sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.3.tgz", + "integrity": "sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.3.tgz", + "integrity": "sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.3.tgz", + "integrity": "sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, "node_modules/@esbuild/win32-x64": { - "version": "0.27.2", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.3.tgz", + "integrity": "sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA==", "cpu": [ "x64" ], @@ -393,34 +821,40 @@ "jsep": "^0.4.0||^1.0.0" } }, - "node_modules/@noble/curves": { - "version": "1.4.2", + "node_modules/@noble/ciphers": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@noble/ciphers/-/ciphers-1.3.0.tgz", + "integrity": "sha512-2I0gnIVPtfnMw9ee9h1dJG7tp81+8Ob3OJb3Mv37rx5L40/b0i7djjCVvGOVqc9AEIQyvyu1i6ypKdFw8R8gQw==", "dev": true, "license": "MIT", - "dependencies": { - "@noble/hashes": "1.4.0" + "engines": { + "node": "^14.21.3 || >=16" }, "funding": { "url": "https://paulmillr.com/funding/" } }, - "node_modules/@noble/curves/node_modules/@noble/hashes": { - "version": "1.4.0", + "node_modules/@noble/curves": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.4.2.tgz", + "integrity": "sha512-TavHr8qycMChk8UwMld0ZDRvatedkzWfH8IiaeGCfymOP5i0hSCozz9vHOL0nkwk7HRMlFnAiKpS2jrUmSybcw==", "dev": true, "license": "MIT", - "engines": { - "node": ">= 16" + "dependencies": { + "@noble/hashes": "1.4.0" }, "funding": { "url": "https://paulmillr.com/funding/" } }, "node_modules/@noble/hashes": { - "version": "1.8.0", + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.4.0.tgz", + "integrity": "sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==", "dev": true, "license": "MIT", "engines": { - "node": "^14.21.3 || >=16" + "node": ">= 16" }, "funding": { "url": "https://paulmillr.com/funding/" @@ -517,6 +951,8 @@ }, "node_modules/@nomicfoundation/hardhat-errors": { "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-errors/-/hardhat-errors-3.0.6.tgz", + "integrity": "sha512-3x+OVdZv7Rgy3z6os9pB6kiHLxs6q0PCXHRu+WLZflr44PG9zW+7V9o+ehrUqmmivlHcIFr3Qh4M2wZVuoCYww==", "dev": true, "license": "MIT", "dependencies": { @@ -542,6 +978,8 @@ }, "node_modules/@nomicfoundation/hardhat-utils": { "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-utils/-/hardhat-utils-3.0.6.tgz", + "integrity": "sha512-AD/LPNdjXNFRrZcaAAewgJpdnHpPppZxo5p+x6wGMm5Hz4B3+oLf/LUzVn8qb4DDy9RE2c24l2F8vmL/w6ZuXg==", "dev": true, "license": "MIT", "dependencies": { @@ -564,6 +1002,8 @@ }, "node_modules/@nomicfoundation/hardhat-zod-utils": { "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-zod-utils/-/hardhat-zod-utils-3.0.1.tgz", + "integrity": "sha512-I6/pyYiS9p2lLkzQuedr1ScMocH+ew8l233xTi+LP92gjEiviJDxselpkzgU01MUM0t6BPpfP8yMO958LDEJVg==", "dev": true, "license": "MIT", "dependencies": { @@ -576,6 +1016,8 @@ }, "node_modules/@nomicfoundation/slang": { "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/slang/-/slang-1.3.1.tgz", + "integrity": "sha512-gh0+JDjazmevEYCcwVgtuyfBJcV1209gIORZNRjUxbGzbQN0MOhQO9T0ptkzHKCf854gUy27SMxPbAyAu63fvQ==", "dev": true, "license": "MIT", "dependencies": { @@ -584,6 +1026,8 @@ }, "node_modules/@nomicfoundation/solidity-analyzer": { "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer/-/solidity-analyzer-0.1.2.tgz", + "integrity": "sha512-q4n32/FNKIhQ3zQGGw5CvPF6GTvDCpYwIf7bEY/dZTZbgfDsHyjJwURxUJf3VQuuJj+fDIFl4+KkBVbw4Ef6jA==", "dev": true, "license": "MIT", "engines": { @@ -601,6 +1045,8 @@ }, "node_modules/@nomicfoundation/solidity-analyzer-darwin-arm64": { "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-darwin-arm64/-/solidity-analyzer-darwin-arm64-0.1.2.tgz", + "integrity": "sha512-JaqcWPDZENCvm++lFFGjrDd8mxtf+CtLd2MiXvMNTBD33dContTZ9TWETwNFwg7JTJT5Q9HEecH7FA+HTSsIUw==", "dev": true, "license": "MIT", "optional": true, @@ -610,6 +1056,8 @@ }, "node_modules/@nomicfoundation/solidity-analyzer-darwin-x64": { "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-darwin-x64/-/solidity-analyzer-darwin-x64-0.1.2.tgz", + "integrity": "sha512-fZNmVztrSXC03e9RONBT+CiksSeYcxI1wlzqyr0L7hsQlK1fzV+f04g2JtQ1c/Fe74ZwdV6aQBdd6Uwl1052sw==", "dev": true, "license": "MIT", "optional": true, @@ -619,6 +1067,8 @@ }, "node_modules/@nomicfoundation/solidity-analyzer-linux-arm64-gnu": { "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-linux-arm64-gnu/-/solidity-analyzer-linux-arm64-gnu-0.1.2.tgz", + "integrity": "sha512-3d54oc+9ZVBuB6nbp8wHylk4xh0N0Gc+bk+/uJae+rUgbOBwQSfuGIbAZt1wBXs5REkSmynEGcqx6DutoK0tPA==", "dev": true, "license": "MIT", "optional": true, @@ -628,6 +1078,8 @@ }, "node_modules/@nomicfoundation/solidity-analyzer-linux-arm64-musl": { "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-linux-arm64-musl/-/solidity-analyzer-linux-arm64-musl-0.1.2.tgz", + "integrity": "sha512-iDJfR2qf55vgsg7BtJa7iPiFAsYf2d0Tv/0B+vhtnI16+wfQeTbP7teookbGvAo0eJo7aLLm0xfS/GTkvHIucA==", "dev": true, "license": "MIT", "optional": true, @@ -637,6 +1089,8 @@ }, "node_modules/@nomicfoundation/solidity-analyzer-linux-x64-gnu": { "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-linux-x64-gnu/-/solidity-analyzer-linux-x64-gnu-0.1.2.tgz", + "integrity": "sha512-9dlHMAt5/2cpWyuJ9fQNOUXFB/vgSFORg1jpjX1Mh9hJ/MfZXlDdHQ+DpFCs32Zk5pxRBb07yGvSHk9/fezL+g==", "dev": true, "license": "MIT", "optional": true, @@ -646,6 +1100,8 @@ }, "node_modules/@nomicfoundation/solidity-analyzer-linux-x64-musl": { "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-linux-x64-musl/-/solidity-analyzer-linux-x64-musl-0.1.2.tgz", + "integrity": "sha512-GzzVeeJob3lfrSlDKQw2bRJ8rBf6mEYaWY+gW0JnTDHINA0s2gPR4km5RLIj1xeZZOYz4zRw+AEeYgLRqB2NXg==", "dev": true, "license": "MIT", "optional": true, @@ -655,6 +1111,8 @@ }, "node_modules/@nomicfoundation/solidity-analyzer-win32-x64-msvc": { "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-win32-x64-msvc/-/solidity-analyzer-win32-x64-msvc-0.1.2.tgz", + "integrity": "sha512-Fdjli4DCcFHb4Zgsz0uEJXZ2K7VEO+w5KVv7HmT7WO10iODdU9csC2az4jrhEsRtiR9Gfd74FlG0NYlw1BMdyA==", "dev": true, "license": "MIT", "optional": true, @@ -831,10 +1289,14 @@ }, "node_modules/@openzeppelin/contracts": { "version": "5.4.0", + "resolved": "https://registry.npmjs.org/@openzeppelin/contracts/-/contracts-5.4.0.tgz", + "integrity": "sha512-eCYgWnLg6WO+X52I16TZt8uEjbtdkgLC0SUX/xnAksjjrQI4Xfn4iBRoI5j55dmlOhDv1Y7BoR3cU7e3WWhC6A==", "license": "MIT" }, "node_modules/@openzeppelin/contracts-upgradeable": { "version": "5.4.0", + "resolved": "https://registry.npmjs.org/@openzeppelin/contracts-upgradeable/-/contracts-upgradeable-5.4.0.tgz", + "integrity": "sha512-STJKyDzUcYuB35Zub1JpWW58JxvrFFVgQ+Ykdr8A9PGXgtq/obF5uoh07k2XmFyPxfnZdPdBdhkJ/n2YxJ87HQ==", "license": "MIT", "peerDependencies": { "@openzeppelin/contracts": "5.4.0" @@ -842,6 +1304,8 @@ }, "node_modules/@scure/base": { "version": "1.1.9", + "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.1.9.tgz", + "integrity": "sha512-8YKhl8GHiNI/pU2VMaofa2Tor7PJRAjwQLBBuilkJ9L5+13yVbC7JO/wS7piioAvPSwR3JKM1IJ/u4xQzbcXKg==", "dev": true, "license": "MIT", "funding": { @@ -850,6 +1314,8 @@ }, "node_modules/@scure/bip32": { "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.4.0.tgz", + "integrity": "sha512-sVUpc0Vq3tXCkDGYVWGIZTRfnvu8LoTDaev7vbwh0omSvVORONr960MQWdKqJDCReIEmTj3PAr73O3aoxz7OPg==", "dev": true, "license": "MIT", "dependencies": { @@ -861,19 +1327,10 @@ "url": "https://paulmillr.com/funding/" } }, - "node_modules/@scure/bip32/node_modules/@noble/hashes": { - "version": "1.4.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 16" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, "node_modules/@scure/bip39": { "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.3.0.tgz", + "integrity": "sha512-disdg7gHuTDZtY+ZdkmLpPCk7fxZSu3gBiEGuoC1XYxv9cGx3Z6cpTggCgW6odSOOIXCiDjuGejW+aJKCY/pIQ==", "dev": true, "license": "MIT", "dependencies": { @@ -884,19 +1341,10 @@ "url": "https://paulmillr.com/funding/" } }, - "node_modules/@scure/bip39/node_modules/@noble/hashes": { - "version": "1.4.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 16" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, "node_modules/@sentry/core": { "version": "9.47.1", + "resolved": "https://registry.npmjs.org/@sentry/core/-/core-9.47.1.tgz", + "integrity": "sha512-KX62+qIt4xgy8eHKHiikfhz2p5fOciXd0Cl+dNzhgPFq8klq4MGMNaf148GB3M/vBqP4nw/eFvRMAayFCgdRQw==", "dev": true, "license": "MIT", "engines": { @@ -905,32 +1353,28 @@ }, "node_modules/@solidity-parser/parser": { "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@solidity-parser/parser/-/parser-0.20.2.tgz", + "integrity": "sha512-rbu0bzwNvMcwAjH86hiEAcOeRI2EeK8zCkHDrFykh/Al8mvJeFmjy3UrE7GYQjNwOgbGUUtCn5/k8CB8zIu7QA==", "dev": true, "license": "MIT" }, "node_modules/@streamparser/json": { "version": "0.0.22", + "resolved": "https://registry.npmjs.org/@streamparser/json/-/json-0.0.22.tgz", + "integrity": "sha512-b6gTSBjJ8G8SuO3Gbbj+zXbVx8NSs1EbpbMKpzGLWMdkR+98McH9bEjSz3+0mPJf68c5nxa3CrJHp5EQNXM6zQ==", "dev": true, "license": "MIT" }, "node_modules/@streamparser/json-node": { "version": "0.0.22", + "resolved": "https://registry.npmjs.org/@streamparser/json-node/-/json-node-0.0.22.tgz", + "integrity": "sha512-sJT2ptNRwqB1lIsQrQlCoWk5rF4tif9wDh+7yluAGijJamAhrHGYpFB/Zg3hJeceoZypi74ftXk8DHzwYpbZSg==", "dev": true, "license": "MIT", "dependencies": { "@streamparser/json": "^0.0.22" } }, - "node_modules/@types/conventional-commits-parser": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/@types/conventional-commits-parser/-/conventional-commits-parser-5.0.2.tgz", - "integrity": "sha512-BgT2szDXnVypgpNxOK8aL5SGjUdaQbC++WZNjF1Qge3Og2+zhHj+RWhmehLhYyvQwqAmvezruVfOf8+3m74W+g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/node": "*" - } - }, "node_modules/@types/minimist": { "version": "1.2.5", "resolved": "https://registry.npmjs.org/@types/minimist/-/minimist-1.2.5.tgz", @@ -939,13 +1383,14 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "25.0.10", - "resolved": "https://registry.npmjs.org/@types/node/-/node-25.0.10.tgz", - "integrity": "sha512-zWW5KPngR/yvakJgGOmZ5vTBemDoSqF3AcV/LrO5u5wTWyEAVVh+IT39G4gtyAkh3CtTZs8aX/yRM82OfzHJRg==", + "version": "25.3.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-25.3.0.tgz", + "integrity": "sha512-4K3bqJpXpqfg2XKGK9bpDTc6xO/xoUP/RBWS7AtRMug6zZFaRekiLzjVtAoZMquxoAbzBvy5nxQ7veS5eYzf8A==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { - "undici-types": "~7.16.0" + "undici-types": "~7.18.0" } }, "node_modules/@types/normalize-package-data": { @@ -998,6 +1443,8 @@ }, "node_modules/abitype": { "version": "1.2.3", + "resolved": "https://registry.npmjs.org/abitype/-/abitype-1.2.3.tgz", + "integrity": "sha512-Ofer5QUnuUdTFsBRwARMoWKOH1ND5ehwYhJ3OJ/BQO+StkwQjHw0XyVh4vDttzHB7QOFhPHa/o413PJ82gU/Tg==", "dev": true, "license": "MIT", "funding": { @@ -1018,6 +1465,8 @@ }, "node_modules/adm-zip": { "version": "0.4.16", + "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.4.16.tgz", + "integrity": "sha512-TFi4HBKSGfIKsK5YCkKaaFG2m4PEDyViZmEwof3MTIgzimHLto6muaHVpbrljdIvIrFZzEq/p4nafOeLcYegrg==", "dev": true, "license": "MIT", "engines": { @@ -1060,6 +1509,8 @@ }, "node_modules/ansi-colors": { "version": "4.1.3", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", + "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", "dev": true, "license": "MIT", "engines": { @@ -1068,6 +1519,8 @@ }, "node_modules/ansi-regex": { "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "dev": true, "license": "MIT", "engines": { @@ -1125,11 +1578,14 @@ } }, "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", "dev": true, - "license": "MIT" + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } }, "node_modules/before-after-hook": { "version": "2.2.3", @@ -1146,13 +1602,16 @@ "license": "ISC" }, "node_modules/brace-expansion": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", - "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.3.tgz", + "integrity": "sha512-fy6KJm2RawA5RcHkLa1z/ScpBeA762UF9KmZQxwIbDtRJrgLzM10depAiEQ+CXYcoiqW1/m96OAAoke2nE9EeA==", "dev": true, "license": "MIT", "dependencies": { - "balanced-match": "^1.0.0" + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" } }, "node_modules/callsites": { @@ -1195,6 +1654,8 @@ }, "node_modules/chalk": { "version": "5.6.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz", + "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==", "dev": true, "license": "MIT", "engines": { @@ -1206,6 +1667,8 @@ }, "node_modules/chokidar": { "version": "4.0.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", + "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", "dev": true, "license": "MIT", "dependencies": { @@ -1327,37 +1790,30 @@ "dot-prop": "^5.1.0" } }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true, - "license": "MIT" - }, "node_modules/conventional-changelog-angular": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/conventional-changelog-angular/-/conventional-changelog-angular-7.0.0.tgz", - "integrity": "sha512-ROjNchA9LgfNMTTFSIWPzebCwOGFdgkEq45EnvvrmSLvCtAw0HSmrCs7/ty+wAeYUZyNay0YMUNYFTRL72PkBQ==", + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/conventional-changelog-angular/-/conventional-changelog-angular-8.1.0.tgz", + "integrity": "sha512-GGf2Nipn1RUCAktxuVauVr1e3r8QrLP/B0lEUsFktmGqc3ddbQkhoJZHJctVU829U1c6mTSWftrVOCHaL85Q3w==", "dev": true, "license": "ISC", "dependencies": { "compare-func": "^2.0.0" }, "engines": { - "node": ">=16" + "node": ">=18" } }, "node_modules/conventional-changelog-conventionalcommits": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/conventional-changelog-conventionalcommits/-/conventional-changelog-conventionalcommits-7.0.2.tgz", - "integrity": "sha512-NKXYmMR/Hr1DevQegFB4MwfM5Vv0m4UIxKZTTYuD98lpTknaZlSRrDOG4X7wIXpGkfsYxZTghUN+Qq+T0YQI7w==", + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/conventional-changelog-conventionalcommits/-/conventional-changelog-conventionalcommits-9.1.0.tgz", + "integrity": "sha512-MnbEysR8wWa8dAEvbj5xcBgJKQlX/m0lhS8DsyAAWDHdfs2faDJxTgzRYlRYpXSe7UiKrIIlB4TrBKU9q9DgkA==", "dev": true, "license": "ISC", "dependencies": { "compare-func": "^2.0.0" }, "engines": { - "node": ">=16" + "node": ">=18" } }, "node_modules/conventional-changelog-writer": { @@ -1446,22 +1902,19 @@ } }, "node_modules/conventional-commits-parser": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/conventional-commits-parser/-/conventional-commits-parser-5.0.0.tgz", - "integrity": "sha512-ZPMl0ZJbw74iS9LuX9YIAiW8pfM5p3yh2o/NbXHbkFuZzY5jvdi5jFycEOkmBW5H5I7nA+D6f3UcsCLP2vvSEA==", + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/conventional-commits-parser/-/conventional-commits-parser-6.2.1.tgz", + "integrity": "sha512-20pyHgnO40rvfI0NGF/xiEoFMkXDtkF8FwHvk5BokoFoCuTQRI8vrNCNFWUOfuolKJMm1tPCHc8GgYEtr1XRNA==", "dev": true, "license": "MIT", "dependencies": { - "is-text-path": "^2.0.0", - "JSONStream": "^1.3.5", - "meow": "^12.0.1", - "split2": "^4.0.0" + "meow": "^13.0.0" }, "bin": { - "conventional-commits-parser": "cli.mjs" + "conventional-commits-parser": "dist/cli/index.js" }, "engines": { - "node": ">=16" + "node": ">=18" } }, "node_modules/cosmiconfig": { @@ -1564,6 +2017,8 @@ }, "node_modules/debug": { "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", "dev": true, "license": "MIT", "dependencies": { @@ -1715,7 +2170,9 @@ } }, "node_modules/dotenv": { - "version": "17.2.3", + "version": "17.3.1", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.3.1.tgz", + "integrity": "sha512-IO8C/dzEb6O3F9/twg6ZLXz164a2fhTnEWb95H23Dm4OuN+92NmEAlTrupP9VW6Jm3sO26tQlqyvyi4CsnY9GA==", "dev": true, "license": "BSD-2-Clause", "engines": { @@ -1734,6 +2191,8 @@ }, "node_modules/enquirer": { "version": "2.4.1", + "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.4.1.tgz", + "integrity": "sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==", "dev": true, "license": "MIT", "dependencies": { @@ -1759,6 +2218,8 @@ }, "node_modules/env-paths": { "version": "2.2.1", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", "dev": true, "license": "MIT", "engines": { @@ -1776,7 +2237,9 @@ } }, "node_modules/esbuild": { - "version": "0.27.2", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.3.tgz", + "integrity": "sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==", "dev": true, "hasInstallScript": true, "license": "MIT", @@ -1787,32 +2250,32 @@ "node": ">=18" }, "optionalDependencies": { - "@esbuild/aix-ppc64": "0.27.2", - "@esbuild/android-arm": "0.27.2", - "@esbuild/android-arm64": "0.27.2", - "@esbuild/android-x64": "0.27.2", - "@esbuild/darwin-arm64": "0.27.2", - "@esbuild/darwin-x64": "0.27.2", - "@esbuild/freebsd-arm64": "0.27.2", - "@esbuild/freebsd-x64": "0.27.2", - "@esbuild/linux-arm": "0.27.2", - "@esbuild/linux-arm64": "0.27.2", - "@esbuild/linux-ia32": "0.27.2", - "@esbuild/linux-loong64": "0.27.2", - "@esbuild/linux-mips64el": "0.27.2", - "@esbuild/linux-ppc64": "0.27.2", - "@esbuild/linux-riscv64": "0.27.2", - "@esbuild/linux-s390x": "0.27.2", - "@esbuild/linux-x64": "0.27.2", - "@esbuild/netbsd-arm64": "0.27.2", - "@esbuild/netbsd-x64": "0.27.2", - "@esbuild/openbsd-arm64": "0.27.2", - "@esbuild/openbsd-x64": "0.27.2", - "@esbuild/openharmony-arm64": "0.27.2", - "@esbuild/sunos-x64": "0.27.2", - "@esbuild/win32-arm64": "0.27.2", - "@esbuild/win32-ia32": "0.27.2", - "@esbuild/win32-x64": "0.27.2" + "@esbuild/aix-ppc64": "0.27.3", + "@esbuild/android-arm": "0.27.3", + "@esbuild/android-arm64": "0.27.3", + "@esbuild/android-x64": "0.27.3", + "@esbuild/darwin-arm64": "0.27.3", + "@esbuild/darwin-x64": "0.27.3", + "@esbuild/freebsd-arm64": "0.27.3", + "@esbuild/freebsd-x64": "0.27.3", + "@esbuild/linux-arm": "0.27.3", + "@esbuild/linux-arm64": "0.27.3", + "@esbuild/linux-ia32": "0.27.3", + "@esbuild/linux-loong64": "0.27.3", + "@esbuild/linux-mips64el": "0.27.3", + "@esbuild/linux-ppc64": "0.27.3", + "@esbuild/linux-riscv64": "0.27.3", + "@esbuild/linux-s390x": "0.27.3", + "@esbuild/linux-x64": "0.27.3", + "@esbuild/netbsd-arm64": "0.27.3", + "@esbuild/netbsd-x64": "0.27.3", + "@esbuild/openbsd-arm64": "0.27.3", + "@esbuild/openbsd-x64": "0.27.3", + "@esbuild/openharmony-arm64": "0.27.3", + "@esbuild/sunos-x64": "0.27.3", + "@esbuild/win32-arm64": "0.27.3", + "@esbuild/win32-ia32": "0.27.3", + "@esbuild/win32-x64": "0.27.3" } }, "node_modules/escalade": { @@ -1837,6 +2300,8 @@ }, "node_modules/ethereum-cryptography": { "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-2.2.1.tgz", + "integrity": "sha512-r/W8lkHSiTLxUxW8Rf3u4HGB0xQweG2RyETjywylKZSzLWoWAijRz8WCuOtJ6wah+avllXBqZuk29HCCvhEIRg==", "dev": true, "license": "MIT", "dependencies": { @@ -1846,17 +2311,6 @@ "@scure/bip39": "1.3.0" } }, - "node_modules/ethereum-cryptography/node_modules/@noble/hashes": { - "version": "1.4.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 16" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, "node_modules/ethers": { "version": "6.16.0", "resolved": "https://registry.npmjs.org/ethers/-/ethers-6.16.0.tgz", @@ -1929,33 +2383,6 @@ "dev": true, "license": "MIT" }, - "node_modules/ethers/node_modules/ws": { - "version": "8.17.1", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz", - "integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": ">=5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - }, - "node_modules/eventemitter3": { - "version": "5.0.1", - "dev": true, - "license": "MIT" - }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -1965,6 +2392,8 @@ }, "node_modules/fast-equals": { "version": "5.4.0", + "resolved": "https://registry.npmjs.org/fast-equals/-/fast-equals-5.4.0.tgz", + "integrity": "sha512-jt2DW/aNFNwke7AUd+Z+e6pz39KO5rzdbbFCg2sGafS4mk13MI7Z8O5z9cADNn5lhGODIgLwug6TZO2ctf7kcw==", "dev": true, "license": "MIT", "engines": { @@ -2005,31 +2434,17 @@ } }, "node_modules/find-up": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-7.0.0.tgz", - "integrity": "sha512-YyZM99iHrqLKjmt4LJDj58KI+fYyufRLBSYcqycxf//KpBk9FoewoGX0450m9nB44qrZnovzC2oeP5hUibxc/g==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", "dev": true, "license": "MIT", "dependencies": { - "locate-path": "^7.2.0", - "path-exists": "^5.0.0", - "unicorn-magic": "^0.1.0" - }, - "engines": { - "node": ">=18" + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/find-up/node_modules/path-exists": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-5.0.0.tgz", - "integrity": "sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ==", - "dev": true, - "license": "MIT", "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + "node": ">=8" } }, "node_modules/fs.realpath": { @@ -2039,6 +2454,21 @@ "dev": true, "license": "ISC" }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, "node_modules/function-bind": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", @@ -2060,7 +2490,9 @@ } }, "node_modules/get-tsconfig": { - "version": "4.13.0", + "version": "4.13.6", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.13.6.tgz", + "integrity": "sha512-shZT/QMiSHc/YBLxxOkMtgSid5HFoauqCE3/exfsEcwg1WkeqjG+V40yBbBrsD+jW2HDXcs28xOfcbm2jI8Ddw==", "dev": true, "license": "MIT", "dependencies": { @@ -2085,14 +2517,27 @@ "git-raw-commits": "cli.mjs" }, "engines": { - "node": ">=16" + "node": ">=16" + } + }, + "node_modules/git-raw-commits/node_modules/meow": { + "version": "12.1.1", + "resolved": "https://registry.npmjs.org/meow/-/meow-12.1.1.tgz", + "integrity": "sha512-BhXM0Au22RwUneMPwSCnyhTOizdWoIEPU9sp0Aqa1PnDMR5Wv2FGXYDjuzJEIX+Eo2Rb8xuYe5jrnm5QowQFkw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=16.10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/glob": { "version": "7.2.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Glob versions prior to v9 are no longer supported", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", "dev": true, "license": "ISC", "dependencies": { @@ -2110,30 +2555,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/glob/node_modules/brace-expansion": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", - "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/glob/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, "node_modules/global-directory": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/global-directory/-/global-directory-4.0.1.tgz", @@ -2183,9 +2604,9 @@ } }, "node_modules/hardhat": { - "version": "3.1.8", - "resolved": "https://registry.npmjs.org/hardhat/-/hardhat-3.1.8.tgz", - "integrity": "sha512-VB1AQBEWgVQp7hd48zt4lb1bv5ndF9B05LQSaunOfu1RMjF3HErkiWFBbBPt0ZDUDv5ab+rgWnwCYwOeThFeHw==", + "version": "3.1.9", + "resolved": "https://registry.npmjs.org/hardhat/-/hardhat-3.1.9.tgz", + "integrity": "sha512-LCThGBbROzRiI0RwD85i61bYM380ZWwVZ5XRHsY/ADUWnoMKIRYN835f4rQxT2qkVvDnZB0jbmU3RRS/MPy7Gw==", "dev": true, "license": "MIT", "dependencies": { @@ -2214,6 +2635,28 @@ "hardhat": "dist/src/cli.js" } }, + "node_modules/hardhat/node_modules/ws": { + "version": "8.19.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.19.0.tgz", + "integrity": "sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, "node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -2247,6 +2690,19 @@ "he": "bin/he" } }, + "node_modules/hosted-git-info": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz", + "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==", + "dev": true, + "license": "ISC", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/http-proxy-agent": { "version": "7.0.2", "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", @@ -2412,30 +2868,22 @@ } }, "node_modules/is-plain-obj": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", - "integrity": "sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", + "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", "dev": true, "license": "MIT", "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-text-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-text-path/-/is-text-path-2.0.0.tgz", - "integrity": "sha512-+oDTluR6WEjdXEJMnC2z6A4FRwFoYuvShVVEGsS7ewc0UTi2QtAKMDJuL4BDEVt+5T7MjFo12RP8ghOM75oKJw==", - "dev": true, - "license": "MIT", - "dependencies": { - "text-extensions": "^2.0.0" + "node": ">=12" }, - "engines": { - "node": ">=8" + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/isows": { "version": "1.0.7", + "resolved": "https://registry.npmjs.org/isows/-/isows-1.0.7.tgz", + "integrity": "sha512-I1fSfDCZL5P0v33sVqeTDSpcstAg/N+wF5HS033mogOVIp4B+oHC7oOCsA3axAbBSGTJ8QubbNmnIRN/h8U7hg==", "dev": true, "funding": [ { @@ -2504,6 +2952,8 @@ }, "node_modules/json-stream-stringify": { "version": "3.1.6", + "resolved": "https://registry.npmjs.org/json-stream-stringify/-/json-stream-stringify-3.1.6.tgz", + "integrity": "sha512-x7fpwxOkbhFCaJDJ8vb1fBY3DdSa4AlITaz+HHILQJzdPMnHEFjxPwVUi1ALIbcIxDE0PNe/0i7frnY8QnBQog==", "dev": true, "license": "MIT", "engines": { @@ -2517,20 +2967,10 @@ "dev": true, "license": "ISC" }, - "node_modules/jsonparse": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", - "integrity": "sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==", - "dev": true, - "engines": [ - "node >= 0.2.0" - ], - "license": "MIT" - }, "node_modules/jsonpath-plus": { - "version": "10.3.0", - "resolved": "https://registry.npmjs.org/jsonpath-plus/-/jsonpath-plus-10.3.0.tgz", - "integrity": "sha512-8TNmfeTCk2Le33A3vRRwtuworG/L5RrgMvdjhKZxvyShO+mBu2fP50OWUjRLNtvw344DdDarFh9buFAZs5ujeA==", + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/jsonpath-plus/-/jsonpath-plus-10.4.0.tgz", + "integrity": "sha512-T92WWatJXmhBbKsgH/0hl+jxjdXrifi5IKeMY02DWggRxX0UElcbVzPlmgLTbvsPeW1PasQ6xE2Q75stkhGbsA==", "dev": true, "license": "MIT", "dependencies": { @@ -2546,23 +2986,6 @@ "node": ">=18.0.0" } }, - "node_modules/JSONStream": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.5.tgz", - "integrity": "sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==", - "dev": true, - "license": "(MIT OR Apache-2.0)", - "dependencies": { - "jsonparse": "^1.2.0", - "through": ">=2.2.7 <3" - }, - "bin": { - "JSONStream": "bin.js" - }, - "engines": { - "node": "*" - } - }, "node_modules/kind-of": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", @@ -2581,19 +3004,16 @@ "license": "MIT" }, "node_modules/locate-path": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-7.2.0.tgz", - "integrity": "sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", "dev": true, "license": "MIT", "dependencies": { - "p-locate": "^6.0.0" + "p-locate": "^4.1.0" }, "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=8" } }, "node_modules/lodash.camelcase": { @@ -2610,13 +3030,6 @@ "dev": true, "license": "MIT" }, - "node_modules/lodash.isplainobject": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", - "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", - "dev": true, - "license": "MIT" - }, "node_modules/lodash.kebabcase": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/lodash.kebabcase/-/lodash.kebabcase-4.1.1.tgz", @@ -2624,13 +3037,6 @@ "dev": true, "license": "MIT" }, - "node_modules/lodash.merge": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true, - "license": "MIT" - }, "node_modules/lodash.mergewith": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.mergewith/-/lodash.mergewith-4.6.2.tgz", @@ -2652,13 +3058,6 @@ "dev": true, "license": "MIT" }, - "node_modules/lodash.uniq": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", - "integrity": "sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==", - "dev": true, - "license": "MIT" - }, "node_modules/lodash.upperfirst": { "version": "4.3.1", "resolved": "https://registry.npmjs.org/lodash.upperfirst/-/lodash.upperfirst-4.3.1.tgz", @@ -2693,13 +3092,13 @@ } }, "node_modules/meow": { - "version": "12.1.1", - "resolved": "https://registry.npmjs.org/meow/-/meow-12.1.1.tgz", - "integrity": "sha512-BhXM0Au22RwUneMPwSCnyhTOizdWoIEPU9sp0Aqa1PnDMR5Wv2FGXYDjuzJEIX+Eo2Rb8xuYe5jrnm5QowQFkw==", + "version": "13.2.0", + "resolved": "https://registry.npmjs.org/meow/-/meow-13.2.0.tgz", + "integrity": "sha512-pxQJQzB6djGPXh08dacEloMFopsOqGVRKFPYvPOt9XDZ1HasbgDZA74CJGreSU4G3Ak7EFJGoiH2auq+yXISgA==", "dev": true, "license": "MIT", "engines": { - "node": ">=16.10" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -2707,6 +3106,8 @@ }, "node_modules/micro-eth-signer": { "version": "0.14.0", + "resolved": "https://registry.npmjs.org/micro-eth-signer/-/micro-eth-signer-0.14.0.tgz", + "integrity": "sha512-5PLLzHiVYPWClEvZIXXFu5yutzpadb73rnQCpUqIHu3No3coFuWQNfE5tkBQJ7djuLYl6aRLaS0MgWJYGoqiBw==", "dev": true, "license": "MIT", "dependencies": { @@ -2717,6 +3118,8 @@ }, "node_modules/micro-eth-signer/node_modules/@noble/curves": { "version": "1.8.2", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.8.2.tgz", + "integrity": "sha512-vnI7V6lFNe0tLAuJMu+2sX+FcL14TaCWy1qiczg1VwRmPrpQCdq5ESXQMqUc2tluRNf6irBXrWbl1mGN8uaU/g==", "dev": true, "license": "MIT", "dependencies": { @@ -2731,6 +3134,8 @@ }, "node_modules/micro-eth-signer/node_modules/@noble/hashes": { "version": "1.7.2", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.7.2.tgz", + "integrity": "sha512-biZ0NUSxyjLLqo6KxEJ1b+C2NAx0wtDoFvCaXHGgUkeHzf3Xc1xKumFKREuT7f7DARNZ/slvYUwFG6B0f2b6hQ==", "dev": true, "license": "MIT", "engines": { @@ -2742,6 +3147,8 @@ }, "node_modules/micro-packed": { "version": "0.7.3", + "resolved": "https://registry.npmjs.org/micro-packed/-/micro-packed-0.7.3.tgz", + "integrity": "sha512-2Milxs+WNC00TRlem41oRswvw31146GiSaoCT7s3Xi2gMUglW5QBeqlQaZeHr5tJx9nm3i57LNXPqxOOaWtTYg==", "dev": true, "license": "MIT", "dependencies": { @@ -2753,6 +3160,8 @@ }, "node_modules/micro-packed/node_modules/@scure/base": { "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.2.6.tgz", + "integrity": "sha512-g/nm5FgUa//MCj1gV09zTJTaM6KBAHqLN907YVQqf7zC49+DcO4B1so4ZX07Ef10Twr6nuqYEH9GEggFXA4Fmg==", "dev": true, "license": "MIT", "funding": { @@ -2770,16 +3179,19 @@ } }, "node_modules/minimatch": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", - "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.2.tgz", + "integrity": "sha512-+G4CpNBxa5MprY+04MbgOw1v7So6n5JY166pFi9KfYwT78fxScCeSNQSNzp6dpPSW2rONOps6Ocam1wFhCgoVw==", "dev": true, - "license": "ISC", + "license": "BlueOak-1.0.0", "dependencies": { - "brace-expansion": "^2.0.1" + "brace-expansion": "^5.0.2" }, "engines": { - "node": ">=10" + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, "node_modules/minimist": { @@ -2807,6 +3219,16 @@ "node": ">= 6" } }, + "node_modules/minimist-options/node_modules/is-plain-obj": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", + "integrity": "sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/modify-values": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/modify-values/-/modify-values-1.0.1.tgz", @@ -2819,6 +3241,8 @@ }, "node_modules/ms": { "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "dev": true, "license": "MIT" }, @@ -2856,19 +3280,6 @@ "node": ">=10" } }, - "node_modules/normalize-package-data/node_modules/hosted-git-info": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz", - "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==", - "dev": true, - "license": "ISC", - "dependencies": { - "lru-cache": "^6.0.0" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/nth-check": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", @@ -2893,7 +3304,9 @@ } }, "node_modules/ox": { - "version": "0.11.3", + "version": "0.12.4", + "resolved": "https://registry.npmjs.org/ox/-/ox-0.12.4.tgz", + "integrity": "sha512-+P+C7QzuwPV8lu79dOwjBKfB2CbnbEXe/hfyyrff1drrO1nOOj3Hc87svHfcW1yneRr3WXaKr6nz11nq+/DF9Q==", "dev": true, "funding": [ { @@ -2923,13 +3336,20 @@ }, "node_modules/ox/node_modules/@adraffy/ens-normalize": { "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@adraffy/ens-normalize/-/ens-normalize-1.11.1.tgz", + "integrity": "sha512-nhCBV3quEgesuf7c7KYfperqSS14T8bYuvJ8PcLJp6znkZpFc0AuW4qBtr8eKVyPPe/8RSr7sglCWPU5eaxwKQ==", "dev": true, "license": "MIT" }, - "node_modules/ox/node_modules/@noble/ciphers": { - "version": "1.3.0", + "node_modules/ox/node_modules/@noble/curves": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.9.1.tgz", + "integrity": "sha512-k11yZxZg+t+gWvBbIswW0yoJlu8cHOC7dhunwOzoWH/mXGBiYyR4YY6hAEK/3EUs4UpB8la1RfdRpeGsFHkWsA==", "dev": true, "license": "MIT", + "dependencies": { + "@noble/hashes": "1.8.0" + }, "engines": { "node": "^14.21.3 || >=16" }, @@ -2937,13 +3357,12 @@ "url": "https://paulmillr.com/funding/" } }, - "node_modules/ox/node_modules/@noble/curves": { - "version": "1.9.1", + "node_modules/ox/node_modules/@noble/hashes": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.8.0.tgz", + "integrity": "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==", "dev": true, "license": "MIT", - "dependencies": { - "@noble/hashes": "1.8.0" - }, "engines": { "node": "^14.21.3 || >=16" }, @@ -2953,6 +3372,8 @@ }, "node_modules/ox/node_modules/@scure/base": { "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.2.6.tgz", + "integrity": "sha512-g/nm5FgUa//MCj1gV09zTJTaM6KBAHqLN907YVQqf7zC49+DcO4B1so4ZX07Ef10Twr6nuqYEH9GEggFXA4Fmg==", "dev": true, "license": "MIT", "funding": { @@ -2961,6 +3382,8 @@ }, "node_modules/ox/node_modules/@scure/bip32": { "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.7.0.tgz", + "integrity": "sha512-E4FFX/N3f4B80AKWp5dP6ow+flD1LQZo/w8UnLGYZO674jS6YnYeepycOOksv+vLPSpgN35wgKgy+ybfTb2SMw==", "dev": true, "license": "MIT", "dependencies": { @@ -2974,6 +3397,8 @@ }, "node_modules/ox/node_modules/@scure/bip39": { "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.6.0.tgz", + "integrity": "sha512-+lF0BbLiJNwVlev4eKelw1WWLaiKXw7sSl8T6FvBlWkdX+94aGJ4o8XjUdlyhTCjd8c+B3KT3JfS8P0bLRNU6A==", "dev": true, "license": "MIT", "dependencies": { @@ -2984,40 +3409,46 @@ "url": "https://paulmillr.com/funding/" } }, + "node_modules/ox/node_modules/eventemitter3": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", + "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==", + "dev": true, + "license": "MIT" + }, "node_modules/p-limit": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-4.0.0.tgz", - "integrity": "sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", "dev": true, "license": "MIT", "dependencies": { - "yocto-queue": "^1.0.0" + "p-try": "^2.0.0" }, "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + "node": ">=6" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/p-locate": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-6.0.0.tgz", - "integrity": "sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", "dev": true, "license": "MIT", "dependencies": { - "p-limit": "^4.0.0" + "p-limit": "^2.2.0" }, "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=8" } }, "node_modules/p-map": { "version": "7.0.4", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-7.0.4.tgz", + "integrity": "sha512-tkAQEw8ysMzmkhgw8k+1U/iPhWNhykKnSk4Rd5zLoPJCuJaGRPo6YposrZgaxHKzDHdDWWZvE/Sk7hsL2X/CpQ==", "dev": true, "license": "MIT", "engines": { @@ -3119,6 +3550,8 @@ }, "node_modules/prettier": { "version": "3.8.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.8.1.tgz", + "integrity": "sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg==", "dev": true, "license": "MIT", "bin": { @@ -3133,6 +3566,8 @@ }, "node_modules/prettier-plugin-solidity": { "version": "2.2.1", + "resolved": "https://registry.npmjs.org/prettier-plugin-solidity/-/prettier-plugin-solidity-2.2.1.tgz", + "integrity": "sha512-LOHfxECJ/gHsY7qi4D7vanz8cVsCf6yFotBapJ5O0qaX0ZR1sGUzbWfMd4JeQYOItFl+wXW9IcjZOdfr6bmSvQ==", "dev": true, "license": "MIT", "dependencies": { @@ -3191,62 +3626,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/read-pkg-up/node_modules/find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "license": "MIT", - "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/read-pkg-up/node_modules/locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "license": "MIT", - "dependencies": { - "p-locate": "^4.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/read-pkg-up/node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "license": "MIT", - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/read-pkg-up/node_modules/p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "license": "MIT", - "dependencies": { - "p-limit": "^2.2.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/read-pkg-up/node_modules/type-fest": { "version": "0.8.1", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", @@ -3299,6 +3678,8 @@ }, "node_modules/readdirp": { "version": "4.1.2", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", + "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", "dev": true, "license": "MIT", "engines": { @@ -3324,9 +3705,9 @@ } }, "node_modules/release-please": { - "version": "17.2.0", - "resolved": "https://registry.npmjs.org/release-please/-/release-please-17.2.0.tgz", - "integrity": "sha512-DIB8gXH+GBwy1MvkJ/xUceVPW+10OOQagNBaOB/V3B8hHbfsVbQjwEL0Hu6zTRsqve9wRvqE48mKtwjaXIxupA==", + "version": "17.3.0", + "resolved": "https://registry.npmjs.org/release-please/-/release-please-17.3.0.tgz", + "integrity": "sha512-dB7HsFUpAvU1Wj9RGCINUz8Zi2qQDZiGbDEEVnJ7baNfJmk5XdYhuUFL6RcuDGjReGhp1gzY8Tc2g7vHlM4zpg==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -3466,6 +3847,8 @@ }, "node_modules/resolve-pkg-maps": { "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", "dev": true, "license": "MIT", "funding": { @@ -3474,6 +3857,8 @@ }, "node_modules/resolve.exports": { "version": "2.0.3", + "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.3.tgz", + "integrity": "sha512-OcXjMsGdhL4XnbShKpAcSqPMzQoYkYyhbEaeSko47MjRP9NfEQMhZkXL1DoFlt9LWQn4YttrdnV6X2OiyzBi+A==", "dev": true, "license": "MIT", "engines": { @@ -3492,11 +3877,15 @@ }, "node_modules/rfdc": { "version": "1.4.1", + "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz", + "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==", "dev": true, "license": "MIT" }, "node_modules/semver": { - "version": "7.7.3", + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", "dev": true, "license": "ISC", "bin": { @@ -3546,9 +3935,9 @@ } }, "node_modules/spdx-license-ids": { - "version": "3.0.22", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.22.tgz", - "integrity": "sha512-4PRT4nh1EImPbt2jASOKHX7PB7I+e4IWNLvkKFDxNhJlfjbYlleYQh285Z/3mPTHSAK/AvdMmw5BNNuYH8ShgQ==", + "version": "3.0.23", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.23.tgz", + "integrity": "sha512-CWLcCCH7VLu13TgOH+r8p1O/Znwhqv/dbb6lqWy67G+pT1kHmeD/+V36AVb/vq8QMIQwVShJ6Ssl5FPh0fuSdw==", "dev": true, "license": "CC0-1.0" }, @@ -3592,6 +3981,8 @@ }, "node_modules/strip-ansi": { "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, "license": "MIT", "dependencies": { @@ -3640,19 +4031,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/text-extensions": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/text-extensions/-/text-extensions-2.4.0.tgz", - "integrity": "sha512-te/NtwBwfiNRLf9Ijqx3T0nlqZiQ2XrrtBvu+cLL8ZRrGkO0NHTug8MYFKyoSrv/sHTaSKfilUkizV6XhxMJ3g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/through": { "version": "2.3.8", "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", @@ -3689,6 +4067,8 @@ }, "node_modules/tsx": { "version": "4.21.0", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.21.0.tgz", + "integrity": "sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==", "dev": true, "license": "MIT", "dependencies": { @@ -3749,6 +4129,8 @@ }, "node_modules/undici": { "version": "6.23.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-6.23.0.tgz", + "integrity": "sha512-VfQPToRA5FZs/qJxLIinmU59u0r7LXqoJkCzinq3ckNJp3vKEh7jTWN589YQ5+aoAC/TGRLyJLCPKcLQbM8r9g==", "dev": true, "license": "MIT", "engines": { @@ -3756,24 +4138,12 @@ } }, "node_modules/undici-types": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz", - "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==", - "dev": true, - "license": "MIT" - }, - "node_modules/unicorn-magic": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.1.0.tgz", - "integrity": "sha512-lRfVq8fE8gz6QMBuDM6a+LO3IAzTi05H6gCVaUpir2E1Rwpo4ZUog45KpNXKC/Mn3Yb9UDuHumeFTo9iV/D9FQ==", + "version": "7.18.2", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.18.2.tgz", + "integrity": "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==", "dev": true, "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } + "peer": true }, "node_modules/unist-util-is": { "version": "4.1.0", @@ -3836,7 +4206,9 @@ } }, "node_modules/viem": { - "version": "2.45.0", + "version": "2.46.2", + "resolved": "https://registry.npmjs.org/viem/-/viem-2.46.2.tgz", + "integrity": "sha512-w8Qv5Vyo7TfXcH3vgmxRa1NRvzJCDy2aSGSRsJn3503nC/qVbgEQ+n3aj/CkqWXbloudZh97h5o5aQrQSVGy0w==", "dev": true, "funding": [ { @@ -3852,7 +4224,7 @@ "@scure/bip39": "1.6.0", "abitype": "1.2.3", "isows": "1.0.7", - "ox": "0.11.3", + "ox": "0.12.4", "ws": "8.18.3" }, "peerDependencies": { @@ -3866,6 +4238,8 @@ }, "node_modules/viem/node_modules/@noble/curves": { "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.9.1.tgz", + "integrity": "sha512-k11yZxZg+t+gWvBbIswW0yoJlu8cHOC7dhunwOzoWH/mXGBiYyR4YY6hAEK/3EUs4UpB8la1RfdRpeGsFHkWsA==", "dev": true, "license": "MIT", "dependencies": { @@ -3878,8 +4252,23 @@ "url": "https://paulmillr.com/funding/" } }, + "node_modules/viem/node_modules/@noble/hashes": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.8.0.tgz", + "integrity": "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, "node_modules/viem/node_modules/@scure/base": { "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.2.6.tgz", + "integrity": "sha512-g/nm5FgUa//MCj1gV09zTJTaM6KBAHqLN907YVQqf7zC49+DcO4B1so4ZX07Ef10Twr6nuqYEH9GEggFXA4Fmg==", "dev": true, "license": "MIT", "funding": { @@ -3888,6 +4277,8 @@ }, "node_modules/viem/node_modules/@scure/bip32": { "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.7.0.tgz", + "integrity": "sha512-E4FFX/N3f4B80AKWp5dP6ow+flD1LQZo/w8UnLGYZO674jS6YnYeepycOOksv+vLPSpgN35wgKgy+ybfTb2SMw==", "dev": true, "license": "MIT", "dependencies": { @@ -3901,6 +4292,8 @@ }, "node_modules/viem/node_modules/@scure/bip39": { "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.6.0.tgz", + "integrity": "sha512-+lF0BbLiJNwVlev4eKelw1WWLaiKXw7sSl8T6FvBlWkdX+94aGJ4o8XjUdlyhTCjd8c+B3KT3JfS8P0bLRNU6A==", "dev": true, "license": "MIT", "dependencies": { @@ -3913,6 +4306,8 @@ }, "node_modules/viem/node_modules/ws": { "version": "8.18.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz", + "integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==", "dev": true, "license": "MIT", "engines": { @@ -3964,7 +4359,9 @@ "license": "ISC" }, "node_modules/ws": { - "version": "8.18.0", + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz", + "integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==", "dev": true, "license": "MIT", "engines": { @@ -4055,21 +4452,10 @@ "node": ">=12" } }, - "node_modules/yocto-queue": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.2.2.tgz", - "integrity": "sha512-4LCcse/U2MHZ63HAJVE+v71o7yOdIe4cZ70Wpf8D/IyjDKYQLV5GD46B+hSTjJsvV5PztjvHoU580EftxjDZFQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12.20" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/zod": { "version": "3.25.76", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", + "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", "dev": true, "license": "MIT", "funding": { diff --git a/package.json b/package.json index 34e70493..55c73380 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "Bloxchain", - "version": "1.0.0-alpha.12", + "version": "1.0.0-alpha.13", "description": "Library engine for building enterprise grade decentralized permissioned applications", "type": "module", "main": "truffle-config.cjs", @@ -28,7 +28,8 @@ "test:foundry:invariant": "forge test --invariant-runs 1000", "deploy:truffle": "npx truffle migrate --network development --reset --config truffle-config.cjs && node scripts/extract-abi.cjs", "deploy:hardhat": "hardhat run scripts/deploy.js", - "deploy:hardhat:foundation": "hardhat run scripts/deploy-foundation-libraries.js --network sepolia", + "deploy:hardhat:foundation": "hardhat run scripts/deployment/deploy-foundation-libraries.js --network sepolia", + "create-wallet": "node scripts/deployment/create-wallet-copyblox.js", "test:sanity": "node scripts/sanity/run-all-tests.cjs", "test:sanity:core": "node scripts/sanity/run-all-tests.cjs --core", "test:sanity:examples": "node scripts/sanity/run-all-tests.cjs --examples", @@ -44,8 +45,8 @@ "build:sdk:clean": "cd sdk/typescript && npm run clean && npm run build", "generate:contracts-lock": "cd package && npm install --package-lock-only", "release:prepare": "node scripts/release-prepare.cjs", - "publish:contracts": "npm run release:prepare && cd package && npm publish --tag alpha.12", - "publish:sdk": "npm run release:sync-versions && npm run extract-abi && npm run build:sdk && cd sdk/typescript && npm publish --tag alpha.12", + "publish:contracts": "npm run release:prepare && cd package && npm publish --tag alpha.13", + "publish:sdk": "npm run release:sync-versions && npm run extract-abi && npm run build:sdk && cd sdk/typescript && npm publish --tag alpha.13", "docgen": "npm run compile:hardhat && cd docgen && npm run docgen", "docgen:install": "cd docgen && npm install", "format": "prettier --config .prettierrc --write \"contracts/**/*.sol\"", @@ -59,20 +60,23 @@ ], "author": "Particle Crypto Security", "license": "MPL-2.0", + "overrides": { + "minimatch": ">=10.2.1" + }, "dependencies": { "@openzeppelin/contracts": "^5.4.0", "@openzeppelin/contracts-upgradeable": "^5.4.0" }, "devDependencies": { - "@commitlint/cli": "^20.3.1", + "@commitlint/cli": "^20.4.1", "@commitlint/config-conventional": "^20.3.1", "@nomicfoundation/hardhat-ethers": "^4.0.4", - "dotenv": "^17.2.3", - "hardhat": "^3.1.5", + "dotenv": "^17.3.1", + "hardhat": "^3.1.8", "husky": "^9.1.7", "prettier": "^3.8.1", - "prettier-plugin-solidity": "^2.1.0", - "release-please": "^17.1.3", - "viem": "^2.44.4" + "prettier-plugin-solidity": "^2.2.1", + "release-please": "^17.3.0", + "viem": "^2.46.1" } } diff --git a/package/README.md b/package/README.md index c672828a..f3dfbda7 100644 --- a/package/README.md +++ b/package/README.md @@ -50,7 +50,7 @@ import "@bloxchain/contracts/core/lib/interfaces/IDefinition.sol"; ### Templates and examples -Templates (e.g. BareBlox, SecureBlox, AccountBlox) and example applications (SimpleVault, SimpleRWA20) live in the main repository under `contracts/examples/`. They are not included in this npm package. See the [main repo](https://github.com/PracticalParticle/Bloxchain-Protocol) for full documentation and examples. +Templates (e.g. AccountBlox, CopyBlox) and example applications (SimpleVault, SimpleRWA20) live in the main repository under `contracts/examples/`. They are not included in this npm package. See the [main repo](https://github.com/PracticalParticle/Bloxchain-Protocol) for full documentation and examples. ## Dependencies diff --git a/package/package.json b/package/package.json index e1fc534e..d1d0ffff 100644 --- a/package/package.json +++ b/package/package.json @@ -1,6 +1,6 @@ { "name": "@bloxchain/contracts", - "version": "1.0.0-alpha.12", + "version": "1.0.0-alpha.13", "description": "Library engine for building enterprise grade decentralized permissioned applications", "files": [ "core", @@ -46,4 +46,4 @@ "engines": { "node": ">=18.0.0" } -} \ No newline at end of file +} diff --git a/package/scripts/prepublish-contracts.cjs b/package/scripts/prepublish-contracts.cjs index c16de45c..d1fdd9fb 100644 --- a/package/scripts/prepublish-contracts.cjs +++ b/package/scripts/prepublish-contracts.cjs @@ -91,12 +91,77 @@ if (fs.existsSync(destAbiDir)) { fs.rmSync(destAbiDir, { recursive: true, force: true }); } -// Copy ABIs (excluding examples and experimental) -copyDir(sourceAbiDir, destAbiDir, excludedDirs); -console.log('โœ… ABIs copied (excluding examples and experimental)\n'); +copyDir(sourceAbiDir, destAbiDir, []); +console.log('โœ… ABIs copied\n'); + +// Step 4: Remove ABIs that don't have a contract in the package +// Only keep ABIs whose contract name exists in core, standards, or components (no examples). +const packagedContractNames = collectPackagedContractNames(); +console.log('๐Ÿ“‹ Step 4: Pruning ABIs not packaged with contracts...'); +const removed = pruneUnpackagedAbis(destAbiDir, packagedContractNames); +if (removed.length > 0) { + console.log(` Removed ${removed.length} ABI(s) with no packaged contract: ${removed.join(', ')}`); +} +const remaining = fs.existsSync(destAbiDir) ? fs.readdirSync(destAbiDir).filter(f => f.endsWith('.abi.json')).length : 0; +console.log(` Packaged ABIs remaining: ${remaining}`); +console.log('โœ… ABI prune complete\n'); console.log('โœ… Package ready for publishing!\n'); +/** + * Collect contract names (basename of .sol files) from the source dirs that get copied + * into the package: core, standards, components. Excludes examples and experimental. + */ +function collectPackagedContractNames() { + const names = new Set(); + const dirs = [ + coreSrc, + fs.existsSync(standardsSrc) ? standardsSrc : null, + fs.existsSync(componentsSrc) ? componentsSrc : null + ].filter(Boolean); + + function walk(dir, excludeDirs = []) { + if (!fs.existsSync(dir)) return; + const entries = fs.readdirSync(dir, { withFileTypes: true }); + for (const entry of entries) { + const full = path.join(dir, entry.name); + if (entry.isDirectory()) { + if (!excludeDirs.includes(entry.name)) { + walk(full, excludeDirs); + } + } else if (entry.name.endsWith('.sol')) { + names.add(path.basename(entry.name, '.sol')); + } + } + } + + for (const d of dirs) { + walk(d, excludedDirs); + } + return names; +} + +/** + * Remove any file in destAbiDir that is *.abi.json and whose contract name + * (stem) is not in packagedContractNames. Returns list of removed filenames. + */ +function pruneUnpackagedAbis(destAbiDir, packagedContractNames) { + const removed = []; + if (!fs.existsSync(destAbiDir)) return removed; + + const files = fs.readdirSync(destAbiDir); + for (const file of files) { + if (!file.endsWith('.abi.json')) continue; + const stem = file.replace(/\.abi\.json$/, ''); + if (!packagedContractNames.has(stem)) { + const full = path.join(destAbiDir, file); + fs.unlinkSync(full); + removed.push(file); + } + } + return removed; +} + // Helper function to copy directory recursively // excludedDirs: array of directory names to skip (e.g., ['examples', 'experimental']) function copyDir(src, dest, excludedDirs = []) { diff --git a/scripts/deploy-foundation-libraries.js b/scripts/deploy-foundation-libraries.js deleted file mode 100644 index 50863ff8..00000000 --- a/scripts/deploy-foundation-libraries.js +++ /dev/null @@ -1,96 +0,0 @@ -/** - * Hardhat deployment script: Foundation libraries (production / public network). - * Deploys: EngineBlox, SecureOwnableDefinitions, RuntimeRBACDefinitions, GuardControllerDefinitions. - * Aligns with migrations/1_deploy_foundation_libraries.cjs and foundry.toml compiler config. - * Uses viem (Hardhat 3 default) for deployment. - * - * Output: Writes deployed addresses to deployed-addresses.json (merged by network). - * - * Usage: - * Copy env.deployment.example to .env.deployment and set DEPLOY_RPC_URL, DEPLOY_PRIVATE_KEY. - * npx hardhat run scripts/deploy-foundation-libraries.js --network sepolia - */ - -import { network } from "hardhat"; -import fs from "fs"; -import path from "path"; -import { fileURLToPath } from "url"; - -const __dirname = path.dirname(fileURLToPath(import.meta.url)); -const ROOT_DIR = path.join(__dirname, ".."); -const ADDRESSES_FILE = path.join(ROOT_DIR, "deployed-addresses.json"); - -const FOUNDATION_CONTRACTS = [ - "EngineBlox", - "SecureOwnableDefinitions", - "RuntimeRBACDefinitions", - "GuardControllerDefinitions", -]; - -async function main() { - const conn = await network.connect(); - const { networkName } = conn; - const viem = conn.viem; - if (!viem) { - throw new Error( - "Deployment requires Hardhat viem (conn.viem). " + - "Ensure the Hardhat viem toolbox is configured and the network is connected. " + - "Install it with: npm install --save-dev @nomicfoundation/hardhat-toolbox-viem" - ); - } - - const wallet = await viem.getWalletClient(); - const deployerAddress = wallet?.account ? wallet.account.address : "N/A"; - console.log(`\n๐Ÿš€ Deploying Foundation Libraries on ${networkName} (viem)`); - console.log(`๐Ÿ“‹ Deployer: ${deployerAddress}\n`); - - const addresses = {}; - const deployed = {}; - - for (const contractName of FOUNDATION_CONTRACTS) { - console.log(`๐Ÿ“ฆ Deploying ${contractName}...`); - const lib = await viem.deployContract(contractName); - if (!lib) { - throw new Error(`deployContract("${contractName}") returned undefined. Run "npx hardhat compile" and ensure the contract artifact exists.`); - } - const addr = lib.address ?? lib.contractAddress; - if (!addr) { - throw new Error(`deployContract("${contractName}") returned contract with no address. Keys: ${Object.keys(lib).join(", ")}`); - } - deployed[contractName] = addr; - console.log(` โœ… ${contractName}: ${addr}`); - } - - const now = new Date().toISOString(); - const networkKey = networkName; - - for (const [name, address] of Object.entries(deployed)) { - if (!addresses[networkKey]) addresses[networkKey] = {}; - addresses[networkKey][name] = { address, deployedAt: now }; - } - - let existing = {}; - if (fs.existsSync(ADDRESSES_FILE)) { - try { - existing = JSON.parse(fs.readFileSync(ADDRESSES_FILE, "utf8")); - } catch (e) { - console.warn(`โš ๏ธ ${ADDRESSES_FILE} exists but is not valid JSON; using empty object. Error:`, e?.message ?? e); - } - } - for (const net of Object.keys(addresses)) { - existing[net] = { ...(existing[net] || {}), ...addresses[net] }; - } - fs.writeFileSync(ADDRESSES_FILE, JSON.stringify(existing, null, 2)); - - console.log("\n๐ŸŽ‰ Foundation libraries deployment complete."); - console.log("๐Ÿ“‹ Deployed addresses (logged to deployed-addresses.json):"); - for (const [name, addr] of Object.entries(deployed)) { - console.log(` ${name}: ${addr}`); - } - console.log(`\n๐Ÿ’พ All deployed addresses saved to: ${path.resolve(ADDRESSES_FILE)}`); -} - -main().catch((err) => { - console.error(err); - process.exit(1); -}); diff --git a/scripts/deployment/create-wallet-copyblox.js b/scripts/deployment/create-wallet-copyblox.js new file mode 100644 index 00000000..cdd4a029 --- /dev/null +++ b/scripts/deployment/create-wallet-copyblox.js @@ -0,0 +1,176 @@ +/** + * Interactive script: create a new wallet (clone) via CopyBlox. + * Uses the deployer key from .env.deployment. Prompts for: + * - Network (default from DEPLOY_NETWORK_NAME or sepolia) + * - Choice: basic wallet (AccountBlox clone) or custom blox (user provides implementation address) + * - Initialization: initialOwner, broadcaster, recovery, timeLockPeriodSec + * Then calls CopyBlox.cloneBlox(...) and prints the new clone address. + * + * Usage (from repo root): + * node scripts/deployment/create-wallet-copyblox.js + * npm run create-wallet + * Non-interactive (defaults): CREATE_WALLET_USE_DEFAULTS=1 node scripts/deployment/create-wallet-copyblox.js + * Ensure .env.deployment has DEPLOY_RPC_URL, DEPLOY_PRIVATE_KEY, and optionally DEPLOY_NETWORK_NAME. + */ + +import { createInterface } from "readline"; +import { config } from "dotenv"; +import fs from "fs"; +import path from "path"; +import { fileURLToPath } from "url"; + +const __dirname = path.dirname(fileURLToPath(import.meta.url)); +const ROOT_DIR = path.join(__dirname, "..", ".."); +const ENV_DEPLOYMENT = path.join(ROOT_DIR, ".env.deployment"); +const ADDRESSES_FILE = path.join(ROOT_DIR, "deployed-addresses.json"); +const COPYBLOX_ARTIFACT_PATH = path.join( + ROOT_DIR, + "artifacts", + "contracts", + "examples", + "applications", + "CopyBlox", + "CopyBlox.sol", + "CopyBlox.json" +); + +config({ path: ENV_DEPLOYMENT }); + +function question(rl, prompt, defaultValue = "") { + const p = defaultValue !== "" ? `${prompt} [${defaultValue}]: ` : `${prompt}: `; + return new Promise((resolve) => rl.question(p, (answer) => resolve((answer && answer.trim()) || defaultValue))); +} + +function isAddress(s) { + return /^0x[a-fA-F0-9]{40}$/.test(s); +} + +async function main() { + const useDefaults = process.env.CREATE_WALLET_USE_DEFAULTS === "1" || process.env.CREATE_WALLET_USE_DEFAULTS === "true"; + const rl = useDefaults ? null : createInterface({ input: process.stdin, output: process.stdout }); + + const ask = async (prompt, defaultValue) => (rl ? question(rl, prompt, defaultValue) : Promise.resolve(defaultValue)); + + console.log("\n๐Ÿช™ Create a new wallet with CopyBlox\n"); + console.log("This script uses your .env.deployment deployer key to call CopyBlox.cloneBlox()."); + console.log("You can deploy a basic wallet (AccountBlox) or clone any other compatible blox.\n"); + + if (!process.env.DEPLOY_PRIVATE_KEY || !process.env.DEPLOY_RPC_URL) { + console.error("Missing DEPLOY_PRIVATE_KEY or DEPLOY_RPC_URL in .env.deployment."); + if (rl) rl.close(); + process.exit(1); + } + + if (!fs.existsSync(ADDRESSES_FILE)) { + console.error("deployed-addresses.json not found. Deploy foundation and CopyBlox first."); + if (rl) rl.close(); + process.exit(1); + } + const addressesByNetwork = JSON.parse(fs.readFileSync(ADDRESSES_FILE, "utf8")); + const networkList = Object.keys(addressesByNetwork).filter( + (n) => addressesByNetwork[n].CopyBlox?.address && addressesByNetwork[n].AccountBlox?.address + ); + if (networkList.length === 0) { + console.error("No network in deployed-addresses.json has both CopyBlox and AccountBlox. Deploy them first."); + if (rl) rl.close(); + process.exit(1); + } + + const defaultNetwork = process.env.DEPLOY_NETWORK_NAME || "sepolia"; + const networkPrompt = networkList.includes(defaultNetwork) + ? `Network (${networkList.join(", ")})` + : `Network (${networkList.join(", ")})`; + let network = await ask(networkPrompt, defaultNetwork); + if (!addressesByNetwork[network]) { + network = networkList[0]; + console.log(`Using network: ${network}`); + } + const copyBloxAddress = addressesByNetwork[network].CopyBlox?.address; + const accountBloxAddress = addressesByNetwork[network].AccountBlox?.address; + if (!copyBloxAddress || !accountBloxAddress) { + console.error(`Network "${network}" is missing CopyBlox or AccountBlox in deployed-addresses.json.`); + if (rl) rl.close(); + process.exit(1); + } + + console.log("\nChoose what to clone:"); + console.log(" 1) Basic wallet (AccountBlox) โ€“ recommended for getting started"); + console.log(" 2) Custom blox (you provide the implementation contract address)"); + const choice = await ask("Enter 1 or 2", "1"); + let bloxAddress; + if (choice === "2") { + bloxAddress = await ask("Blox implementation address (0x...)"); + if (!isAddress(bloxAddress)) { + console.error("Invalid address."); + if (rl) rl.close(); + process.exit(1); + } + } else { + bloxAddress = accountBloxAddress; + console.log(`Using AccountBlox: ${bloxAddress}`); + } + + const chainId = parseInt(process.env.DEPLOY_CHAIN_ID || "11155111", 10); + const rpc = process.env.DEPLOY_RPC_URL; + const pk = process.env.DEPLOY_PRIVATE_KEY.startsWith("0x") ? process.env.DEPLOY_PRIVATE_KEY : `0x${process.env.DEPLOY_PRIVATE_KEY}`; + const { createWalletClient, createPublicClient, http } = await import("viem"); + const { privateKeyToAccount } = await import("viem/accounts"); + const { waitForTransactionReceipt } = await import("viem/actions"); + const chain = + chainId === 11155111 + ? (await import("viem/chains")).sepolia + : { id: chainId, name: "Custom", nativeCurrency: { decimals: 18, name: "Ether", symbol: "ETH" }, rpcUrls: { default: { http: [rpc] } } }; + const deployerAccount = privateKeyToAccount(pk); + const walletClient = createWalletClient({ account: deployerAccount, chain, transport: http(rpc) }); + const publicClient = createPublicClient({ chain, transport: http(rpc) }); + const deployerAddr = deployerAccount.address; + + if (useDefaults) console.log("Using defaults (CREATE_WALLET_USE_DEFAULTS): owner=broadcaster=recovery=deployer, timeLock=1"); + console.log("\nInitialization parameters (press Enter to use default):"); + const initialOwner = await ask("Initial owner address", deployerAddr); + const broadcaster = await ask("Broadcaster address", deployerAddr); + const recovery = await ask("Recovery address", deployerAddr); + const timeLockSecStr = await ask("Time lock period (seconds)", "1"); + const timeLockPeriodSec = BigInt(timeLockSecStr || "1"); + + if (!isAddress(initialOwner) || !isAddress(broadcaster) || !isAddress(recovery)) { + console.error("Owner, broadcaster, and recovery must be valid 0x... addresses."); + if (rl) rl.close(); + process.exit(1); + } + + if (rl) rl.close(); + + const copyBloxArtifact = JSON.parse(fs.readFileSync(COPYBLOX_ARTIFACT_PATH, "utf8")); + const abi = copyBloxArtifact.abi; + + console.log("\n๐Ÿ“ค Calling CopyBlox.cloneBlox()..."); + const hash = await walletClient.writeContract({ + address: copyBloxAddress, + abi, + functionName: "cloneBlox", + args: [bloxAddress, initialOwner, broadcaster, recovery, timeLockPeriodSec], + account: deployerAccount, + }); + console.log(` Tx hash: ${hash}`); + const receipt = await waitForTransactionReceipt(publicClient, { hash }); + const bloxClonedLog = receipt.logs?.find( + (l) => l.address?.toLowerCase() === copyBloxAddress.toLowerCase() && l.topics?.length === 4 + ); + const topicClone = bloxClonedLog?.topics?.[2]; + const cloneFromTopic = topicClone ? "0x" + (topicClone.length === 66 ? topicClone.slice(26) : topicClone.slice(-40)).toLowerCase() : null; + if (cloneFromTopic) { + console.log("\nโœ… New wallet (clone) deployed:"); + console.log(` Address: ${cloneFromTopic}`); + if (chainId === 11155111) { + console.log(` Explorer: https://sepolia.etherscan.io/address/${cloneFromTopic}`); + } + } else { + console.log("\nโœ… Clone transaction confirmed. Check CopyBlox.getCloneAtIndex(getCloneCount()-1) for the new address."); + } +} + +main().catch((err) => { + console.error(err); + process.exit(1); +}); diff --git a/scripts/deployment/deploy-example-copyblox.js b/scripts/deployment/deploy-example-copyblox.js new file mode 100644 index 00000000..0089ad0b --- /dev/null +++ b/scripts/deployment/deploy-example-copyblox.js @@ -0,0 +1,180 @@ +/** + * Hardhat deployment script: Example contracts (CopyBlox only). + * Deploys CopyBlox (linked to EngineBlox) and initializes it. + * Requires foundation libraries (at least EngineBlox) and optionally AccountBlox to be + * already deployed on the same network; reads addresses from deployed-addresses.json. + * + * Aligns with migrations/3_deploy_example_contracts.cjs (CopyBlox step). + * Uses viem (Hardhat 3 default) for deployment. + * + * Output: Merges CopyBlox address into deployed-addresses.json under the network key. + * + * Usage: + * Ensure foundation is deployed first: npx hardhat run scripts/deployment/deploy-foundation-libraries.js --network sepolia + * Then: npx hardhat run scripts/deployment/deploy-example-copyblox.js --network sepolia + */ + +import { network } from "hardhat"; +import fs from "fs"; +import path from "path"; +import { fileURLToPath } from "url"; + +const __dirname = path.dirname(fileURLToPath(import.meta.url)); +const ROOT_DIR = path.join(__dirname, "..", ".."); +const ADDRESSES_FILE = path.join(ROOT_DIR, "deployed-addresses.json"); + +const COPYBLOX_ARTIFACT_PATH = path.join( + ROOT_DIR, + "artifacts", + "contracts", + "examples", + "applications", + "CopyBlox", + "CopyBlox.sol", + "CopyBlox.json" +); + +/** + * Link library addresses into contract bytecode using artifact linkReferences. + */ +function linkBytecode(bytecode, linkReferences, libraryAddresses) { + let code = bytecode.replace(/^0x/, ""); + for (const [, libs] of Object.entries(linkReferences || {})) { + for (const [libName, refs] of Object.entries(libs)) { + const addr = libraryAddresses[libName]; + if (!addr) throw new Error(`Missing library address for ${libName}`); + const addrHex = addr.replace(/^0x/, "").toLowerCase().padStart(40, "0").slice(-40); + for (const { start, length } of refs) { + const startChar = start * 2; + const endChar = startChar + length * 2; + code = code.slice(0, startChar) + addrHex + code.slice(endChar); + } + } + } + return "0x" + code; +} + +async function main() { + const conn = await network.connect(); + const { networkName } = conn; + const viem = conn.viem; + if (!viem) { + throw new Error( + "Deployment requires Hardhat viem (conn.viem). " + + "Ensure the Hardhat viem toolbox is configured. " + + "Install it with: npm install --save-dev @nomicfoundation/hardhat-toolbox-viem" + ); + } + + let walletClient = await viem.getWalletClient(); + let deployerAccount = walletClient?.account; + let publicClient = await viem.getPublicClient?.() ?? null; + if (!deployerAccount) { + const pk = process.env.DEPLOY_PRIVATE_KEY; + const rpc = process.env.DEPLOY_RPC_URL; + if (!pk || !rpc) { + throw new Error( + "Wallet client has no account. Set DEPLOY_PRIVATE_KEY and DEPLOY_RPC_URL in .env.deployment for HTTP networks." + ); + } + const { createWalletClient, createPublicClient, http } = await import("viem"); + const { privateKeyToAccount } = await import("viem/accounts"); + const chainId = parseInt(process.env.DEPLOY_CHAIN_ID || "11155111", 10); + const chain = + chainId === 11155111 + ? (await import("viem/chains")).sepolia + : { id: chainId, name: "Custom", nativeCurrency: { decimals: 18, name: "Ether", symbol: "ETH" }, rpcUrls: { default: { http: [rpc] } } }; + deployerAccount = privateKeyToAccount(pk.startsWith("0x") ? pk : `0x${pk}`); + walletClient = createWalletClient({ account: deployerAccount, chain, transport: http(rpc) }); + publicClient = createPublicClient({ chain, transport: http(rpc) }); + } + if (!publicClient) { + const rpc = process.env.DEPLOY_RPC_URL; + const chainId = parseInt(process.env.DEPLOY_CHAIN_ID || "11155111", 10); + const chain = chainId === 11155111 ? (await import("viem/chains")).sepolia : { id: chainId, name: "Custom", nativeCurrency: { decimals: 18, name: "Ether", symbol: "ETH" }, rpcUrls: { default: { http: [rpc] } } }; + const { createPublicClient, http } = await import("viem"); + publicClient = createPublicClient({ chain, transport: http(rpc || "http://127.0.0.1:8545") }); + } + const { waitForTransactionReceipt } = await import("viem/actions"); + const deployerAddress = deployerAccount.address; + + console.log(`\n๐Ÿš€ Deploying example (CopyBlox) on ${networkName} (viem)`); + console.log(`๐Ÿ“‹ Deployer: ${deployerAddress}\n`); + + // Load existing deployed addresses for this network (need EngineBlox) + if (!fs.existsSync(ADDRESSES_FILE)) { + throw new Error( + `No deployed-addresses.json found at ${ADDRESSES_FILE}. Deploy foundation first (deploy-foundation-libraries.js).` + ); + } + const existing = JSON.parse(fs.readFileSync(ADDRESSES_FILE, "utf8")); + const networkAddresses = existing[networkName]; + if (!networkAddresses?.EngineBlox?.address) { + throw new Error( + `EngineBlox not found for network "${networkName}" in deployed-addresses.json. Deploy foundation first.` + ); + } + const engineBloxAddress = networkAddresses.EngineBlox.address; + + // Deploy CopyBlox (links only EngineBlox) + console.log(`๐Ÿ“ฆ Deploying CopyBlox (linked to EngineBlox)...`); + if (!fs.existsSync(COPYBLOX_ARTIFACT_PATH)) { + throw new Error( + `CopyBlox artifact not found at ${COPYBLOX_ARTIFACT_PATH}. Run "npx hardhat compile".` + ); + } + const copyBloxArtifact = JSON.parse(fs.readFileSync(COPYBLOX_ARTIFACT_PATH, "utf8")); + const linkedBytecode = linkBytecode( + copyBloxArtifact.bytecode, + copyBloxArtifact.linkReferences, + { EngineBlox: engineBloxAddress } + ); + const { deployContract } = await import("viem/actions"); + const copyBloxHash = await deployContract(walletClient, { + abi: copyBloxArtifact.abi, + bytecode: linkedBytecode, + account: deployerAccount, + args: [], + }); + const copyBloxReceipt = await waitForTransactionReceipt(publicClient, { hash: copyBloxHash }); + const copyBloxAddress = copyBloxReceipt.contractAddress; + if (!copyBloxAddress) { + throw new Error(`CopyBlox deployment tx ${copyBloxHash} did not return contractAddress.`); + } + console.log(` โœ… CopyBlox: ${copyBloxAddress}`); + + // Initialize CopyBlox (dev-friendly: same address for owner/broadcaster/recovery, 1s timelock) + const ZERO_ADDRESS = "0x0000000000000000000000000000000000000000"; + console.log(`๐Ÿ”ง Initializing CopyBlox (deployer as owner/broadcaster/recovery, 1s timelock)...`); + console.warn(` โš ๏ธ Dev config: role separation disabled and short timelock. For production use distinct roles and a longer timeLockPeriodSec.`); + const initHash = await walletClient.writeContract({ + address: copyBloxAddress, + abi: copyBloxArtifact.abi, + functionName: "initialize", + args: [ + deployerAccount.address, // initialOwner + deployerAccount.address, // broadcaster + deployerAccount.address, // recovery + 1n, // timeLockPeriodSec + ZERO_ADDRESS, // eventForwarder (none) + ], + account: deployerAccount, + }); + await waitForTransactionReceipt(publicClient, { hash: initHash }); + console.log(` โœ… CopyBlox initialized (tx: ${initHash})`); + + const now = new Date().toISOString(); + const addresses = { [networkName]: { CopyBlox: { address: copyBloxAddress, deployedAt: now } } }; + const existingReread = JSON.parse(fs.readFileSync(ADDRESSES_FILE, "utf8")); + existingReread[networkName] = { ...(existingReread[networkName] || {}), ...addresses[networkName] }; + fs.writeFileSync(ADDRESSES_FILE, JSON.stringify(existingReread, null, 2)); + + console.log("\n๐ŸŽ‰ Example (CopyBlox) deployment complete."); + console.log(` CopyBlox: ${copyBloxAddress}`); + console.log(`\n๐Ÿ’พ Addresses saved to: ${path.resolve(ADDRESSES_FILE)}`); +} + +main().catch((err) => { + console.error(err); + process.exit(1); +}); diff --git a/scripts/deployment/deploy-foundation-libraries.js b/scripts/deployment/deploy-foundation-libraries.js new file mode 100644 index 00000000..a1099685 --- /dev/null +++ b/scripts/deployment/deploy-foundation-libraries.js @@ -0,0 +1,209 @@ +/** + * Hardhat deployment script: Foundation libraries (production / public network). + * Deploys: EngineBlox, SecureOwnableDefinitions, RuntimeRBACDefinitions, GuardControllerDefinitions, AccountBlox. + * Aligns with migrations/1_deploy_foundation_libraries.cjs, 2_deploy_guardian_contracts.cjs and foundry.toml compiler config. + * Uses viem (Hardhat 3 default) for deployment. + * + * AccountBlox is deployed after the four libraries and linked to them, then initialized with the deployer as owner/broadcaster/recovery so the implementation cannot be taken by others (safe for use as clone source). + * + * Output: Writes deployed addresses to deployed-addresses.json (merged by network). + * + * Usage: + * Copy env.deployment.example to .env.deployment and set DEPLOY_RPC_URL, DEPLOY_PRIVATE_KEY. + * npx hardhat run scripts/deployment/deploy-foundation-libraries.js --network sepolia + */ + +import { network } from "hardhat"; +import fs from "fs"; +import path from "path"; +import { fileURLToPath } from "url"; + +const __dirname = path.dirname(fileURLToPath(import.meta.url)); +const ROOT_DIR = path.join(__dirname, "..", ".."); +const ADDRESSES_FILE = path.join(ROOT_DIR, "deployed-addresses.json"); + +const FOUNDATION_LIBRARIES = [ + "EngineBlox", + "SecureOwnableDefinitions", + "RuntimeRBACDefinitions", + "GuardControllerDefinitions", +]; + +const ACCOUNTBLOX_ARTIFACT_PATH = path.join( + ROOT_DIR, + "artifacts", + "contracts", + "examples", + "templates", + "AccountBlox.sol", + "AccountBlox.json" +); + +/** + * Link library addresses into contract bytecode using artifact linkReferences. + * @param {string} bytecode - Hex bytecode (with or without 0x) + * @param {{ [source: string]: { [lib: string]: Array<{ start: number, length: number }> } }} linkReferences + * @param {{ [name: string]: string }} libraryAddresses - Map of library contract name to deployed address + * @returns {string} Linked bytecode (with 0x prefix) + */ +function linkBytecode(bytecode, linkReferences, libraryAddresses) { + let code = bytecode.replace(/^0x/, ""); + for (const [, libs] of Object.entries(linkReferences || {})) { + for (const [libName, refs] of Object.entries(libs)) { + const addr = libraryAddresses[libName]; + if (!addr) throw new Error(`Missing library address for ${libName}`); + const addrHex = addr.replace(/^0x/, "").toLowerCase().padStart(40, "0").slice(-40); + for (const { start, length } of refs) { + const startChar = start * 2; + const endChar = startChar + length * 2; + code = code.slice(0, startChar) + addrHex + code.slice(endChar); + } + } + } + return "0x" + code; +} + +async function main() { + const conn = await network.connect(); + const { networkName } = conn; + const viem = conn.viem; + if (!viem) { + throw new Error( + "Deployment requires Hardhat viem (conn.viem). " + + "Ensure the Hardhat viem toolbox is configured and the network is connected. " + + "Install it with: npm install --save-dev @nomicfoundation/hardhat-toolbox-viem" + ); + } + + let walletClient = await viem.getWalletClient(); + let deployerAccount = walletClient?.account; + let publicClient = await viem.getPublicClient?.() ?? null; + if (!deployerAccount) { + const pk = process.env.DEPLOY_PRIVATE_KEY; + const rpc = process.env.DEPLOY_RPC_URL; + if (!pk || !rpc) { + throw new Error( + "Wallet client has no account. Set DEPLOY_PRIVATE_KEY and DEPLOY_RPC_URL in .env.deployment for HTTP networks." + ); + } + const { createWalletClient, createPublicClient, http } = await import("viem"); + const { privateKeyToAccount } = await import("viem/accounts"); + const chainId = parseInt(process.env.DEPLOY_CHAIN_ID || "11155111", 10); + const chain = + chainId === 11155111 + ? (await import("viem/chains")).sepolia + : { id: chainId, name: "Custom", nativeCurrency: { decimals: 18, name: "Ether", symbol: "ETH" }, rpcUrls: { default: { http: [rpc] } } }; + deployerAccount = privateKeyToAccount(pk.startsWith("0x") ? pk : `0x${pk}`); + walletClient = createWalletClient({ account: deployerAccount, chain, transport: http(rpc) }); + publicClient = createPublicClient({ chain, transport: http(rpc) }); + } + if (!publicClient) { + const rpc = process.env.DEPLOY_RPC_URL; + const chainId = parseInt(process.env.DEPLOY_CHAIN_ID || "11155111", 10); + const chain = chainId === 11155111 ? (await import("viem/chains")).sepolia : { id: chainId, name: "Custom", nativeCurrency: { decimals: 18, name: "Ether", symbol: "ETH" }, rpcUrls: { default: { http: [rpc] } } }; + const { createPublicClient, http } = await import("viem"); + publicClient = createPublicClient({ chain, transport: http(rpc || "http://127.0.0.1:8545") }); + } + const { waitForTransactionReceipt } = await import("viem/actions"); + const deployerAddress = deployerAccount.address; + console.log(`\n๐Ÿš€ Deploying Foundation Libraries on ${networkName} (viem)`); + console.log(`๐Ÿ“‹ Deployer: ${deployerAddress}\n`); + + const addresses = {}; + const deployed = {}; + + for (const contractName of FOUNDATION_LIBRARIES) { + console.log(`๐Ÿ“ฆ Deploying ${contractName}...`); + const lib = await viem.deployContract(contractName); + if (!lib) { + throw new Error(`deployContract("${contractName}") returned undefined. Run "npx hardhat compile" and ensure the contract artifact exists.`); + } + const addr = lib.address ?? lib.contractAddress; + if (!addr) { + throw new Error(`deployContract("${contractName}") returned contract with no address. Keys: ${Object.keys(lib).join(", ")}`); + } + deployed[contractName] = addr; + console.log(` โœ… ${contractName}: ${addr}`); + } + + // Deploy AccountBlox with libraries linked + console.log(`๐Ÿ“ฆ Deploying AccountBlox (linked to foundation libraries)...`); + if (!fs.existsSync(ACCOUNTBLOX_ARTIFACT_PATH)) { + throw new Error( + `AccountBlox artifact not found at ${ACCOUNTBLOX_ARTIFACT_PATH}. Run "npx hardhat compile".` + ); + } + const accountBloxArtifact = JSON.parse(fs.readFileSync(ACCOUNTBLOX_ARTIFACT_PATH, "utf8")); + const linkedBytecode = linkBytecode( + accountBloxArtifact.bytecode, + accountBloxArtifact.linkReferences, + deployed + ); + const { deployContract } = await import("viem/actions"); + const accountBloxHash = await deployContract(walletClient, { + abi: accountBloxArtifact.abi, + bytecode: linkedBytecode, + account: deployerAccount, + args: [], + }); + const accountBloxReceipt = await waitForTransactionReceipt(publicClient, { hash: accountBloxHash }); + const accountBloxAddress = accountBloxReceipt.contractAddress; + if (!accountBloxAddress) { + throw new Error(`AccountBlox deployment tx ${accountBloxHash} did not return contractAddress.`); + } + deployed.AccountBlox = accountBloxAddress; + console.log(` โœ… AccountBlox: ${accountBloxAddress}`); + + // Save deployed addresses before initialization so a failed init does not lose them + const now = new Date().toISOString(); + const networkKey = networkName; + const addresses = {}; + for (const [name, address] of Object.entries(deployed)) { + if (!addresses[networkKey]) addresses[networkKey] = {}; + addresses[networkKey][name] = { address, deployedAt: now }; + } + let existing = {}; + if (fs.existsSync(ADDRESSES_FILE)) { + try { + existing = JSON.parse(fs.readFileSync(ADDRESSES_FILE, "utf8")); + } catch (e) { + console.warn(`โš ๏ธ ${ADDRESSES_FILE} exists but is not valid JSON; using empty object. Error:`, e?.message ?? e); + } + } + for (const net of Object.keys(addresses)) { + existing[net] = { ...(existing[net] || {}), ...addresses[net] }; + } + fs.writeFileSync(ADDRESSES_FILE, JSON.stringify(existing, null, 2)); + console.log(` ๐Ÿ’พ Deployed addresses saved (pre-init)`); + + // Initialize the implementation so it cannot be taken by others (one-shot initializer) + const ZERO_ADDRESS = "0x0000000000000000000000000000000000000000"; + console.log(`๐Ÿ”ง Initializing AccountBlox (deployer as owner/broadcaster/recovery)...`); + const initHash = await walletClient.writeContract({ + address: accountBloxAddress, + abi: accountBloxArtifact.abi, + functionName: "initialize", + args: [ + deployerAccount.address, // initialOwner + deployerAccount.address, // broadcaster + deployerAccount.address, // recovery + 1n, // timeLockPeriodSec + ZERO_ADDRESS, // eventForwarder (none) + ], + account: deployerAccount, + }); + await waitForTransactionReceipt(publicClient, { hash: initHash }); + console.log(` โœ… AccountBlox initialized (tx: ${initHash})`); + + console.log("\n๐ŸŽ‰ Foundation libraries deployment complete."); + console.log("๐Ÿ“‹ Deployed addresses (logged to deployed-addresses.json):"); + for (const [name, addr] of Object.entries(deployed)) { + console.log(` ${name}: ${addr}`); + } + console.log(`\n๐Ÿ’พ All deployed addresses saved to: ${path.resolve(ADDRESSES_FILE)}`); +} + +main().catch((err) => { + console.error(err); + process.exit(1); +}); diff --git a/scripts/extract-abi.cjs b/scripts/extract-abi.cjs index f6f9648f..45129445 100644 --- a/scripts/extract-abi.cjs +++ b/scripts/extract-abi.cjs @@ -17,14 +17,12 @@ const contractsToProcess = [ 'GuardController', 'GuardControllerDefinitions', 'IDefinition', - 'BareBlox', - 'SecureBlox', - 'RoleBlox', 'AccountBlox', 'SimpleVault', 'SimpleVaultDefinitions', 'SimpleRWA20', - 'SimpleRWA20Definitions' + 'SimpleRWA20Definitions', + 'CopyBlox' ]; // Define the source and destination folders diff --git a/scripts/get-deployed-addresses.cjs b/scripts/get-deployed-addresses.cjs index 0669491f..ad19b0f0 100644 --- a/scripts/get-deployed-addresses.cjs +++ b/scripts/get-deployed-addresses.cjs @@ -5,7 +5,7 @@ const fs = require('fs'); const path = require('path'); // Load environment variables -require('dotenv').config(); +require('dotenv').config({ quiet: true }); /** * @dev Extracts deployed contract addresses from Truffle migration artifacts @@ -182,8 +182,7 @@ function displayEnvironmentConfig(addresses) { RUNTIME_RBAC_DEFINITIONS_ADDRESS: process.env.RUNTIME_RBAC_DEFINITIONS_ADDRESS || 'Not set' }, guardianContracts: { - SECUREBLOX_ADDRESS: process.env.SECUREBLOX_ADDRESS || 'Not set', - ROLEBLOX_ADDRESS: process.env.ROLEBLOX_ADDRESS || 'Not set' + ACCOUNTBLOX_ADDRESS: process.env.ACCOUNTBLOX_ADDRESS || 'Not set' }, exampleContracts: { SIMPLE_VAULT_ADDRESS: process.env.SIMPLE_VAULT_ADDRESS || 'Not set', @@ -231,8 +230,7 @@ function displayEnvironmentConfig(addresses) { if (latestContracts) { const verifications = [ - { env: 'SECUREBLOX_ADDRESS', artifact: latestContracts.SecureBlox }, - { env: 'ROLEBLOX_ADDRESS', artifact: latestContracts.RoleBlox }, + { env: 'ACCOUNTBLOX_ADDRESS', artifact: latestContracts.AccountBlox }, { env: 'SIMPLE_VAULT_ADDRESS', artifact: latestContracts.SimpleVault }, { env: 'SIMPLE_RWA20_ADDRESS', artifact: latestContracts.SimpleRWA20 } ]; @@ -253,7 +251,7 @@ function displayEnvironmentConfig(addresses) { console.log('```javascript'); console.log('require(\'dotenv\').config();'); console.log(''); - console.log('const secureBloxAddress = process.env.SECUREBLOX_ADDRESS;'); + console.log('const accountBloxAddress = process.env.ACCOUNTBLOX_ADDRESS;'); console.log('const vaultAddress = process.env.SIMPLE_VAULT_ADDRESS;'); console.log('// etc...'); console.log('```'); diff --git a/scripts/sanity-sdk/base/test-config.ts b/scripts/sanity-sdk/base/test-config.ts index bedd66d1..f5ac5b69 100644 --- a/scripts/sanity-sdk/base/test-config.ts +++ b/scripts/sanity-sdk/base/test-config.ts @@ -11,7 +11,7 @@ import * as path from 'path'; import { fileURLToPath } from 'url'; const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); -dotenv.config({ path: path.join(__dirname, '../../../.env'), override: true }); +dotenv.config({ path: path.join(__dirname, '../../../.env'), override: true, quiet: true }); export interface TestConfig { testMode: 'auto' | 'manual'; diff --git a/scripts/sanity-sdk/load-env.ts b/scripts/sanity-sdk/load-env.ts index c95e8103..5b5e1424 100644 --- a/scripts/sanity-sdk/load-env.ts +++ b/scripts/sanity-sdk/load-env.ts @@ -9,4 +9,4 @@ import * as path from 'path'; // Load from cwd (project root when run via "npm run test:sanity-sdk") so RPC always comes from .env const envPath = path.join(process.cwd(), '.env'); -dotenv.config({ path: envPath, override: true }); +dotenv.config({ path: envPath, override: true, quiet: true }); diff --git a/scripts/sanity/README.md b/scripts/sanity/README.md index 9501d4ef..23ec82e6 100644 --- a/scripts/sanity/README.md +++ b/scripts/sanity/README.md @@ -45,7 +45,7 @@ node scripts/sanity/run-all-tests.cjs --simple-rwa20 ## Contract Configuration -All sanity tests use a **single account contract** (AccountBlox). In manual mode set `ACCOUNTBLOX_ADDRESS` in `.env`. In auto mode, the address is read from Truffle artifacts (AccountBlox). SecureBlox and RoleBlox are no longer used by sanity tests. +All sanity tests use a **single account contract** (AccountBlox). In manual mode set `ACCOUNTBLOX_ADDRESS` in `.env`. In auto mode, the address is read from **Truffle build artifacts** at `build/contracts/` (e.g. `build/contracts/AccountBlox.json`), which is separate from Hardhat deployment artifacts at `artifacts/contracts/`. Ensure Truffle has been run (`npm run compile:truffle` / migrations) so `build/contracts/` is populated, or use manual mode with addresses from Hardhat deployment. ## Individual Test Suites diff --git a/scripts/sanity/copy-blox/README.md b/scripts/sanity/copy-blox/README.md new file mode 100644 index 00000000..dea7b0d7 --- /dev/null +++ b/scripts/sanity/copy-blox/README.md @@ -0,0 +1,115 @@ +# CopyBlox Sanity Tests + +Sanity tests for the **CopyBlox** example contract: clone a blox (EIP-1167) and initialize it with owner/broadcaster/recovery. + +## Overview + +CopyBlox provides: + +- Clone any blox that implements `IBaseStateMachine` via EIP-1167 minimal proxy +- Initialize the clone with `initialOwner`, `broadcaster`, `recovery`, and `timeLockPeriodSec` +- Set the cloneโ€™s event forwarder to the CopyBlox instance +- Registry: `getCloneCount`, `getCloneAtIndex`, `isClone` + +These tests use CopyBlox to **clone AccountBlox** and assert clone address, registry, and clone state (owner, broadcaster, recovery). + +## Test Structure + +- **`base-test.cjs`** โ€“ Base class: RPC URL, TEST_MODE (auto/manual), CopyBlox + AccountBlox addresses, wallets +- **`clone-account-blox-tests.cjs`** โ€“ Clone AccountBlox and verify clone count, registry, and clone roles +- **`run-tests.cjs`** โ€“ Runner for `--all` or `--clone-account-blox` +- **`README.md`** โ€“ This file + +## Usage + +### Prerequisites + +1. CopyBlox and AccountBlox deployed (e.g. migration 3 with `DEPLOY_COPYBLOX=true`). +2. `.env` (or env) set as below for the mode you use. +3. For **auto**: Ganache (or compatible chain) on the RPC URL; Truffle artifacts in `build/contracts`. +4. For **manual**: RPC URL and all addresses/keys set in env. + +### Running tests + +```bash +# From repo root +node scripts/sanity/copy-blox/run-tests.cjs --all + +# Only clone-account-blox suite +node scripts/sanity/copy-blox/run-tests.cjs --clone-account-blox + +# Help +node scripts/sanity/copy-blox/run-tests.cjs --help +``` + +### Environment variables + +#### Auto mode (Ganache + Truffle artifacts) + +- `TEST_MODE=auto` +- RPC: `RPC_URL` or `REMOTE_HOST`/`REMOTE_PORT`/`REMOTE_PROTOCOL`, or default `http://localhost:8545` +- CopyBlox and AccountBlox addresses are read from `build/contracts/CopyBlox.json` and `AccountBlox.json` for the current network ID. +- Wallets: Ganache deterministic keys (no extra env). + +#### Manual mode (remote or custom chain) + +- `TEST_MODE=manual` +- `COPYBLOX_ADDRESS` โ€“ CopyBlox contract address +- `ACCOUNTBLOX_ADDRESS` โ€“ AccountBlox implementation to clone +- RPC: same as above (`RPC_URL` or `REMOTE_*` or default localhost) +- Wallets (used as cloneโ€™s owner/broadcaster/recovery): + - `OWNER_PRIVATE_KEY`, `BROADCASTER_PRIVATE_KEY`, `RECOVERY_PRIVATE_KEY` + - Or `TEST_WALLET_1_PRIVATE_KEY`, `TEST_WALLET_2_PRIVATE_KEY`, `TEST_WALLET_3_PRIVATE_KEY` + +Example `.env` (manual): + +```bash +TEST_MODE=manual +COPYBLOX_ADDRESS=0x... +ACCOUNTBLOX_ADDRESS=0x... +OWNER_PRIVATE_KEY=0x... +BROADCASTER_PRIVATE_KEY=0x... +RECOVERY_PRIVATE_KEY=0x... + +# Optional: remote chain +REMOTE_HOST=your-remote-host.com +REMOTE_PORT=8545 +REMOTE_PROTOCOL=https +# Or: RPC_URL=https://... +``` + +## Test flow + +1. **Initial clone count** โ€“ `getCloneCount()` (0 or existing). +2. **Clone AccountBlox** โ€“ `cloneBlox(accountBlox, owner, broadcaster, recovery, timeLockPeriodSec)`; capture clone address from events or `getCloneAtIndex(0)`. +3. **Clone state and registry** โ€“ `isClone(clone)`, `getCloneAtIndex(0)`, then on the clone contract: `owner()`, `getBroadcaster()`, `getRecovery()` match the passed addresses. +4. **Second clone** โ€“ Call `cloneBlox` again; assert `getCloneCount()` increases by 1 and `getCloneAtIndex(previousCount)` is the new clone. + +## Contract features covered + +- Clone creation via CopyBlox +- Clone registry: `getCloneCount`, `getCloneAtIndex`, `isClone` +- Clone initialization: owner, broadcaster, recovery on the cloned AccountBlox + +## Integration with master runner + +From the sanity root: + +```bash +node scripts/sanity/run-all-tests.cjs --copy-blox +node scripts/sanity/run-all-tests.cjs --examples # includes copy-blox +``` + +## Troubleshooting + +- **CopyBlox ABI not found** + Run `npm run compile:truffle` and, if needed, `npm run extract-abi` so `abi/CopyBlox.abi.json` exists (or ensure `build/contracts/CopyBlox.json` exists). + +- **AccountBlox / CopyBlox address not found (auto)** + Ensure CopyBlox and AccountBlox are deployed on the same network as the RPC (e.g. run migrations with `DEPLOY_COPYBLOX=true`) and `build/contracts` is up to date. + +- **Manual: "COPYBLOX_ADDRESS / ACCOUNTBLOX_ADDRESS not set"** + Set both in `.env` when using `TEST_MODE=manual`. + +- **Remote chain** + Use `RPC_URL` or `REMOTE_HOST`/`REMOTE_PORT`/`REMOTE_PROTOCOL` and ensure the node is reachable and network ID matches your deployments. diff --git a/scripts/sanity/copy-blox/base-test.cjs b/scripts/sanity/copy-blox/base-test.cjs new file mode 100644 index 00000000..1de21e0a --- /dev/null +++ b/scripts/sanity/copy-blox/base-test.cjs @@ -0,0 +1,310 @@ +/** + * Base Test Class for CopyBlox Tests + * Provides common functionality: CopyBlox + AccountBlox addresses, wallets, cloneBlox flow + */ + +const Web3 = require('web3'); +const fs = require('fs'); +const path = require('path'); + +// Load environment variables from the project root +require('dotenv').config({ path: path.join(__dirname, '../../../.env'), quiet: true }); + +function getWeb3Url() { + if (process.env.RPC_URL) { + return process.env.RPC_URL; + } + if (process.env.REMOTE_HOST) { + const protocol = process.env.REMOTE_PROTOCOL || 'https'; + const port = process.env.REMOTE_PORT || 8545; + return `${protocol}://${process.env.REMOTE_HOST}:${port}`; + } + return 'http://localhost:8545'; +} + +class BaseCopyBloxTest { + constructor(testName) { + this.testName = testName; + this.web3 = new Web3(getWeb3Url()); + + this.testMode = process.env.TEST_MODE || 'manual'; + console.log(`๐Ÿ”ง Test Mode: ${this.testMode.toUpperCase()}`); + + // CopyBlox contract (main contract under test) + this.contractAddress = null; + this.contractABI = this.loadCopyBloxABI(); + this.contract = null; + + // AccountBlox address (the blox we clone) + this.accountBloxAddress = null; + + // Wallets used as initialOwner, broadcaster, recovery for cloned blox + this.wallets = {}; + + // Timelock period used when cloning (seconds) + this.timeLockPeriodSec = 60; + + this.testResults = { + totalTests: 0, + passedTests: 0, + failedTests: 0, + startTime: null, + endTime: null + }; + } + + /** + * Load CopyBlox ABI from abi/CopyBlox.abi.json or build/contracts/CopyBlox.json + */ + loadCopyBloxABI() { + const abiPath = path.join(__dirname, '../../../abi', 'CopyBlox.abi.json'); + const artifactPath = path.join(__dirname, '../../../build/contracts', 'CopyBlox.json'); + if (fs.existsSync(abiPath)) { + return JSON.parse(fs.readFileSync(abiPath, 'utf8')); + } + if (fs.existsSync(artifactPath)) { + const artifact = JSON.parse(fs.readFileSync(artifactPath, 'utf8')); + return artifact.abi || []; + } + throw new Error('CopyBlox ABI not found. Run "npm run compile:truffle" and optionally "npm run extract-abi".'); + } + + loadABI(contractName) { + const abiPath = path.join(__dirname, '../../../abi', `${contractName}.abi.json`); + if (!fs.existsSync(abiPath)) { + throw new Error(`${contractName} ABI not found at ${abiPath}. Run "npm run compile:truffle" and optionally "npm run extract-abi".`); + } + return JSON.parse(fs.readFileSync(abiPath, 'utf8')); + } + + async initializeAutoMode() { + console.log('๐Ÿค– AUTO MODE: Fetching CopyBlox, AccountBlox addresses and Ganache accounts...'); + + try { + this.contractAddress = await this.getContractAddressFromArtifacts('CopyBlox'); + if (!this.contractAddress) { + throw new Error('Could not find CopyBlox address in Truffle artifacts'); + } + this.accountBloxAddress = await this.getContractAddressFromArtifacts('AccountBlox'); + if (!this.accountBloxAddress) { + throw new Error('Could not find AccountBlox address in Truffle artifacts'); + } + + console.log(`๐Ÿ“‹ CopyBlox Address: ${this.contractAddress}`); + console.log(`๐Ÿ“‹ AccountBlox Address (to clone): ${this.accountBloxAddress}`); + + await this.initializeGanacheWallets(); + console.log('โœ… Auto mode initialization completed'); + } catch (error) { + console.error('โŒ Auto mode initialization failed:', error.message); + throw new Error(`Auto mode failed: ${error.message}`); + } + } + + async initializeManualMode() { + console.log('๐Ÿ‘ค MANUAL MODE: Using provided contract addresses and private keys...'); + + try { + this.contractAddress = process.env.COPYBLOX_ADDRESS; + this.accountBloxAddress = process.env.ACCOUNTBLOX_ADDRESS; + + if (!this.contractAddress) { + throw new Error('COPYBLOX_ADDRESS not set in environment variables'); + } + if (!this.accountBloxAddress) { + throw new Error('ACCOUNTBLOX_ADDRESS not set in environment variables'); + } + + console.log(`๐Ÿ“‹ CopyBlox Address: ${this.contractAddress}`); + console.log(`๐Ÿ“‹ AccountBlox Address (to clone): ${this.accountBloxAddress}`); + + const ownerKey = process.env.OWNER_PRIVATE_KEY || process.env.TEST_WALLET_1_PRIVATE_KEY; + const broadcasterKey = process.env.BROADCASTER_PRIVATE_KEY || process.env.TEST_WALLET_2_PRIVATE_KEY; + const recoveryKey = process.env.RECOVERY_PRIVATE_KEY || process.env.TEST_WALLET_3_PRIVATE_KEY; + + if (!ownerKey || !broadcasterKey || !recoveryKey) { + throw new Error( + 'Set OWNER_PRIVATE_KEY, BROADCASTER_PRIVATE_KEY, RECOVERY_PRIVATE_KEY (or TEST_WALLET_1/2/3_PRIVATE_KEY) for manual mode' + ); + } + + this.wallets = { + owner: this.web3.eth.accounts.privateKeyToAccount(ownerKey), + broadcaster: this.web3.eth.accounts.privateKeyToAccount(broadcasterKey), + recovery: this.web3.eth.accounts.privateKeyToAccount(recoveryKey) + }; + + Object.values(this.wallets).forEach(wallet => { + this.web3.eth.accounts.wallet.add(wallet); + }); + console.log('โœ… Manual mode initialization completed'); + } catch (error) { + console.error('โŒ Manual mode initialization failed:', error.message); + throw new Error(`Manual mode failed: ${error.message}`); + } + } + + async initializeGanacheWallets() { + console.log('๐Ÿ”‘ Fetching Ganache accounts...'); + + try { + const rpcUrl = getWeb3Url(); + const isLocal = /localhost|127\.0\.0\.1/i.test(rpcUrl); + if (!isLocal) { + throw new Error( + 'Ganache auto mode with hardcoded keys is only allowed for local RPC (localhost/127.0.0.1). ' + + `Current RPC_URL or REMOTE_HOST points to: ${rpcUrl}. Use TEST_MODE=manual with your own keys for remote networks.` + ); + } + + const accounts = await this.web3.eth.getAccounts(); + if (accounts.length < 3) { + throw new Error('Not enough Ganache accounts available (need at least 3)'); + } + + const ganachePrivateKeys = [ + '0x4f3edf983ac636a65a842ce7c78d9aa706d3b113bce9c46f30d7d21715b23b1d', + '0x6cbed15c793ce57650b9877cf6fa156fbef513c4e6134f022a85b1ffdd59b2a1', + '0x6370fd033278c143179d81c5526140625662b8daa446c22ee2d73db3707e620c' + ]; + + const ownerAccount = this.web3.eth.accounts.privateKeyToAccount(ganachePrivateKeys[0]); + if (ownerAccount.address.toLowerCase() !== accounts[0].toLowerCase()) { + throw new Error( + 'Ganache accounts do not match hardcoded keys (wrong mnemonic or HD path). ' + + `Expected accounts[0]=${ownerAccount.address}, got ${accounts[0]}. Use default Ganache mnemonic or TEST_MODE=manual.` + ); + } + + this.wallets = { + owner: ownerAccount, + broadcaster: this.web3.eth.accounts.privateKeyToAccount(ganachePrivateKeys[1]), + recovery: this.web3.eth.accounts.privateKeyToAccount(ganachePrivateKeys[2]) + }; + + Object.values(this.wallets).forEach(wallet => { + this.web3.eth.accounts.wallet.add(wallet); + }); + console.log(`โœ… Initialized ${Object.keys(this.wallets).length} wallets from Ganache`); + } catch (error) { + console.error('โŒ Failed to initialize Ganache wallets:', error.message); + throw error; + } + } + + async getContractAddressFromArtifacts(contractName) { + try { + const artifactsPath = path.join(__dirname, '../../../build/contracts', `${contractName}.json`); + const artifacts = JSON.parse(fs.readFileSync(artifactsPath, 'utf8')); + const networkId = await this.web3.eth.net.getId(); + if (artifacts.networks && artifacts.networks[networkId]) { + return artifacts.networks[networkId].address; + } + return null; + } catch (error) { + console.error(`โŒ Failed to get contract address for ${contractName}:`, error.message); + return null; + } + } + + async initialize() { + console.log(`\n๐Ÿš€ Initializing ${this.testName}...`); + + try { + if (this.testMode === 'auto') { + await this.initializeAutoMode(); + } else { + await this.initializeManualMode(); + } + + this.contract = new this.web3.eth.Contract(this.contractABI, this.contractAddress); + console.log('โœ… Initialization completed successfully'); + } catch (error) { + console.error('โŒ Initialization failed:', error.message); + throw error; + } + } + + async startTest(testDescription) { + this.testResults.totalTests++; + console.log(`\n๐Ÿงช Test ${this.testResults.totalTests}: ${testDescription}`); + console.log('โ”€'.repeat(60)); + } + + async passTest(testDescription, details = '') { + this.testResults.passedTests++; + console.log(`โœ… PASSED: ${testDescription}`); + if (details) { + console.log(` ${details}`); + } + } + + async failTest(testDescription, error) { + this.testResults.failedTests++; + console.log(`โŒ FAILED: ${testDescription}`); + console.log(` Error: ${error.message || error}`); + if (error.reason) { + console.log(` Reason: ${error.reason}`); + } + } + + async executeTransaction(method, params = [], options = {}) { + const txOptions = { + from: options.from || this.wallets.owner.address, + ...options + }; + const tx = method(...params); + const gas = await tx.estimateGas(txOptions); + txOptions.gas = gas; + return tx.send(txOptions); + } + + async callMethod(method, params = [], options = {}) { + const callOptions = { + from: options.from || this.wallets.owner.address, + ...options + }; + return method(...params).call(callOptions); + } + + printTestResults() { + console.log('\n๐Ÿ“Š Test Results Summary'); + console.log('โ•'.repeat(50)); + console.log(`Total Tests: ${this.testResults.totalTests}`); + console.log(`Passed: ${this.testResults.passedTests}`); + console.log(`Failed: ${this.testResults.failedTests}`); + const rate = this.testResults.totalTests > 0 + ? ((this.testResults.passedTests / this.testResults.totalTests) * 100).toFixed(1) + : '0'; + console.log(`Success Rate: ${rate}%`); + if (this.testResults.startTime && this.testResults.endTime) { + const duration = (this.testResults.endTime - this.testResults.startTime) / 1000; + console.log(`Duration: ${duration.toFixed(2)} seconds`); + } + console.log('โ•'.repeat(50)); + } + + async runTests() { + this.testResults.startTime = Date.now(); + console.log(`\n๐Ÿš€ Starting ${this.testName} Tests`); + console.log('โ•'.repeat(60)); + + try { + await this.initialize(); + await this.executeTests(); + } catch (error) { + console.error(`โŒ Test suite failed: ${error.message}`); + this.testResults.totalTests++; + this.testResults.failedTests++; + } finally { + this.testResults.endTime = Date.now(); + this.printTestResults(); + } + } + + async executeTests() { + throw new Error('executeTests() must be implemented by subclasses'); + } +} + +module.exports = BaseCopyBloxTest; diff --git a/scripts/sanity/copy-blox/clone-account-blox-tests.cjs b/scripts/sanity/copy-blox/clone-account-blox-tests.cjs new file mode 100644 index 00000000..ce9e0f9c --- /dev/null +++ b/scripts/sanity/copy-blox/clone-account-blox-tests.cjs @@ -0,0 +1,201 @@ +/** + * CopyBlox Sanity: Clone AccountBlox + * Uses CopyBlox to clone the AccountBlox implementation and verifies clone state + */ + +const path = require('path'); +const BaseCopyBloxTest = require('./base-test.cjs'); + +class CloneAccountBloxTests extends BaseCopyBloxTest { + constructor() { + super('CopyBlox Clone AccountBlox'); + } + + async executeTests() { + await this.testInitialCloneCount(); + await this.testCloneAccountBlox(); + await this.testCloneStateAndRegistry(); + await this.testSecondCloneIncrementsCount(); + } + + async testInitialCloneCount() { + await this.startTest('Verify initial clone count is zero or existing'); + + try { + const count = await this.callMethod(this.contract.methods.getCloneCount); + console.log(` getCloneCount(): ${count}`); + await this.passTest('Initial clone count', `Count = ${count}`); + } catch (error) { + await this.failTest('Initial clone count', error); + } + } + + async testCloneAccountBlox() { + await this.startTest('Clone AccountBlox via CopyBlox.cloneBlox'); + + try { + const initialOwner = this.wallets.owner.address; + const broadcaster = this.wallets.broadcaster.address; + const recovery = this.wallets.recovery.address; + + const tx = await this.executeTransaction( + this.contract.methods.cloneBlox, + [ + this.accountBloxAddress, + initialOwner, + broadcaster, + recovery, + this.timeLockPeriodSec + ] + ); + + console.log(` Transaction hash: ${tx.transactionHash}`); + console.log(` Blox (original): ${this.accountBloxAddress}`); + console.log(` initialOwner: ${initialOwner}`); + console.log(` broadcaster: ${broadcaster}`); + console.log(` recovery: ${recovery}`); + console.log(` timeLockPeriodSec: ${this.timeLockPeriodSec}`); + + // Decode BloxCloned event to get clone address + const events = tx.events; + let cloneAddress = null; + if (events && events.BloxCloned) { + const e = Array.isArray(events.BloxCloned) ? events.BloxCloned[0] : events.BloxCloned; + cloneAddress = e.returnValues.clone; + } + if (!cloneAddress && events) { + const keys = Object.keys(events); + for (const k of keys) { + const v = events[k]; + const arr = Array.isArray(v) ? v : [v]; + for (const item of arr) { + if (item.returnValues && item.returnValues.clone) { + cloneAddress = item.returnValues.clone; + break; + } + } + if (cloneAddress) break; + } + } + + if (!cloneAddress) { + // Fallback: get clone at last index (most recently created) + const count = await this.callMethod(this.contract.methods.getCloneCount); + if (count > 0) { + const lastIndex = String(Number(count) - 1); + cloneAddress = await this.callMethod(this.contract.methods.getCloneAtIndex, [lastIndex]); + } + } + + if (!cloneAddress || cloneAddress === '0x0000000000000000000000000000000000000000') { + throw new Error('Could not determine clone address from tx events or getCloneAtIndex(lastIndex)'); + } + + this.lastCloneAddress = cloneAddress; + console.log(` Clone address: ${cloneAddress}`); + await this.passTest('Clone AccountBlox', `Clone at ${cloneAddress}`); + } catch (error) { + await this.failTest('Clone AccountBlox', error); + throw error; + } + } + + async testCloneStateAndRegistry() { + if (!this.lastCloneAddress) { + console.log(' Skipped (no clone from previous test)'); + return; + } + await this.startTest('Verify clone state and CopyBlox registry'); + + try { + const cloneAddress = this.lastCloneAddress; + + const isClone = await this.callMethod(this.contract.methods.isClone, [cloneAddress]); + if (!isClone) { + throw new Error(`isClone(${cloneAddress}) expected true, got false`); + } + console.log(` isClone(clone): true`); + + const count = await this.callMethod(this.contract.methods.getCloneCount); + const lastIndex = String(Number(count) - 1); + const atLastIndex = await this.callMethod(this.contract.methods.getCloneAtIndex, [lastIndex]); + if (atLastIndex.toLowerCase() !== cloneAddress.toLowerCase()) { + throw new Error(`getCloneAtIndex(${lastIndex}) expected ${cloneAddress}, got ${atLastIndex}`); + } + console.log(` getCloneCount(): ${count}`); + console.log(` getCloneAtIndex(${lastIndex}): ${atLastIndex}`); + + // Verify cloned blox has correct owner, broadcaster, recovery (AccountBlox interface) + const accountBloxABI = this.loadABI('AccountBlox'); + const cloneContract = new this.web3.eth.Contract(accountBloxABI, cloneAddress); + + const owner = await cloneContract.methods.owner().call(); + const broadcasters = await cloneContract.methods.getBroadcasters().call(); + const broadcaster = Array.isArray(broadcasters) && broadcasters.length > 0 + ? broadcasters[0] + : (typeof broadcasters === 'string' ? broadcasters : null); + if (broadcaster == null || (typeof broadcaster !== 'string')) { + throw new Error(`Clone getBroadcasters() returned no broadcaster (expected at least one). Got: ${JSON.stringify(broadcasters)}`); + } + const recovery = await cloneContract.methods.getRecovery().call(); + + const expectedOwner = this.wallets.owner.address; + const expectedBroadcaster = this.wallets.broadcaster.address; + const expectedRecovery = this.wallets.recovery.address; + + if (owner.toLowerCase() !== expectedOwner.toLowerCase()) { + throw new Error(`Clone owner expected ${expectedOwner}, got ${owner}`); + } + if (broadcaster.toLowerCase() !== expectedBroadcaster.toLowerCase()) { + throw new Error(`Clone broadcaster expected ${expectedBroadcaster}, got ${broadcaster}`); + } + if (recovery.toLowerCase() !== expectedRecovery.toLowerCase()) { + throw new Error(`Clone recovery expected ${expectedRecovery}, got ${recovery}`); + } + + console.log(` Clone owner: ${owner}`); + console.log(` Clone broadcaster: ${broadcaster}`); + console.log(` Clone recovery: ${recovery}`); + await this.passTest('Clone state and registry', 'Clone is registered and initialized correctly'); + } catch (error) { + await this.failTest('Clone state and registry', error); + } + } + + async testSecondCloneIncrementsCount() { + await this.startTest('Second clone increments getCloneCount'); + + try { + const countBefore = await this.callMethod(this.contract.methods.getCloneCount); + + await this.executeTransaction( + this.contract.methods.cloneBlox, + [ + this.accountBloxAddress, + this.wallets.owner.address, + this.wallets.broadcaster.address, + this.wallets.recovery.address, + this.timeLockPeriodSec + ] + ); + + const countAfter = await this.callMethod(this.contract.methods.getCloneCount); + const expected = Number(countBefore) + 1; + if (Number(countAfter) !== expected) { + throw new Error(`getCloneCount expected ${expected}, got ${countAfter}`); + } + + const secondClone = await this.callMethod(this.contract.methods.getCloneAtIndex, [String(countBefore)]); + if (!secondClone || secondClone === '0x0000000000000000000000000000000000000000') { + throw new Error('getCloneAtIndex(countBefore) should return second clone address'); + } + console.log(` getCloneCount before: ${countBefore}, after: ${countAfter}`); + console.log(` Second clone: ${secondClone}`); + await this.passTest('Second clone increments count', `Count: ${countBefore} -> ${countAfter}`); + } catch (error) { + await this.failTest('Second clone increments count', error); + } + } +} + +module.exports = CloneAccountBloxTests; diff --git a/scripts/sanity/copy-blox/run-tests.cjs b/scripts/sanity/copy-blox/run-tests.cjs new file mode 100644 index 00000000..fca06069 --- /dev/null +++ b/scripts/sanity/copy-blox/run-tests.cjs @@ -0,0 +1,157 @@ +/** + * CopyBlox Test Runner + * Runs CopyBlox sanity tests (clone AccountBlox and verify) + */ + +const CloneAccountBloxTests = require('./clone-account-blox-tests.cjs'); + +class CopyBloxTestRunner { + constructor() { + this.testSuites = { + 'clone-account-blox': CloneAccountBloxTests + }; + + this.results = { + totalSuites: 0, + passedSuites: 0, + failedSuites: 0, + startTime: null, + endTime: null + }; + } + + printUsage() { + console.log('๐Ÿ”ง CopyBlox Test Runner'); + console.log('='.repeat(50)); + console.log('Usage: node run-tests.cjs [options]'); + console.log(); + console.log('Options:'); + console.log(' --all Run all test suites'); + console.log(' --clone-account-blox Run clone AccountBlox tests only'); + console.log(' --help Show this help message'); + console.log(); + console.log('Examples:'); + console.log(' node run-tests.cjs --all'); + console.log(' node run-tests.cjs --clone-account-blox'); + console.log(); + console.log('Environment Variables:'); + console.log(' TEST_MODE=auto|manual Test mode (default: manual)'); + console.log(' COPYBLOX_ADDRESS CopyBlox contract (manual mode)'); + console.log(' ACCOUNTBLOX_ADDRESS AccountBlox to clone (manual mode)'); + console.log(' OWNER_PRIVATE_KEY Owner key for clone roles (manual mode)'); + console.log(' BROADCASTER_PRIVATE_KEY Broadcaster key (manual mode)'); + console.log(' RECOVERY_PRIVATE_KEY Recovery key (manual mode)'); + console.log(' Or TEST_WALLET_1/2/3_PRIVATE_KEY as fallback'); + console.log(); + } + + async runTestSuite(suiteName, TestClass) { + console.log(`\n๐Ÿš€ Running ${suiteName} tests...`); + console.log('โ•'.repeat(60)); + + const testSuite = new TestClass(); + await testSuite.runTests(); + // BaseCopyBloxTest.runTests() catches errors internally and never re-throws; check testResults + const failedTests = testSuite.testResults?.failedTests ?? 0; + if (failedTests > 0) { + this.results.failedSuites++; + console.error(`โŒ ${suiteName} tests failed (${failedTests} failed test(s))`); + } else { + this.results.passedSuites++; + console.log(`โœ… ${suiteName} tests completed successfully`); + } + } + + async runAllTests() { + console.log('๐Ÿš€ Running ALL CopyBlox test suites...'); + console.log('โ•'.repeat(60)); + + this.results.startTime = Date.now(); + for (const [suiteName, TestClass] of Object.entries(this.testSuites)) { + this.results.totalSuites++; + await this.runTestSuite(suiteName, TestClass); + } + this.results.endTime = Date.now(); + this.printResults(); + } + + async runSpecificTests(requestedSuites) { + console.log(`๐Ÿš€ Running specific test suites: ${requestedSuites.join(', ')}`); + console.log('โ•'.repeat(60)); + + this.results.startTime = Date.now(); + for (const suiteName of requestedSuites) { + if (this.testSuites[suiteName]) { + this.results.totalSuites++; + await this.runTestSuite(suiteName, this.testSuites[suiteName]); + } else { + this.results.totalSuites++; + this.results.failedSuites++; + console.error(`โŒ Unknown test suite: ${suiteName}`); + console.log(`Available suites: ${Object.keys(this.testSuites).join(', ')}`); + } + } + this.results.endTime = Date.now(); + this.printResults(); + } + + printResults() { + console.log('\n๐Ÿ“Š Overall Test Results'); + console.log('โ•'.repeat(60)); + console.log(`Total Test Suites: ${this.results.totalSuites}`); + console.log(`Passed Suites: ${this.results.passedSuites}`); + console.log(`Failed Suites: ${this.results.failedSuites}`); + if (this.results.totalSuites > 0) { + const successRate = (this.results.passedSuites / this.results.totalSuites) * 100; + console.log(`Success Rate: ${successRate.toFixed(1)}%`); + } + if (this.results.startTime && this.results.endTime) { + const duration = (this.results.endTime - this.results.startTime) / 1000; + console.log(`Total Duration: ${duration.toFixed(2)} seconds`); + } + console.log('โ•'.repeat(60)); + if (this.results.failedSuites === 0) { + console.log('๐ŸŽ‰ All test suites passed successfully!'); + } else { + console.log('โš ๏ธ Some test suites failed. Check the logs above for details.'); + } + } + + async run() { + const args = process.argv.slice(2); + + if (args.length === 0 || args.includes('--help')) { + this.printUsage(); + return; + } + + if (args.includes('--all')) { + await this.runAllTests(); + } else { + const requestedSuites = args + .filter(arg => arg !== '--help') + .map(arg => arg.replace(/^--/, '')) + .filter(Boolean); + if (requestedSuites.length > 0) { + await this.runSpecificTests(requestedSuites); + } else { + console.log('โŒ No test suites specified'); + this.printUsage(); + } + } + } +} + +if (require.main === module) { + const runner = new CopyBloxTestRunner(); + runner.run() + .then(() => { + process.exit(runner.results.failedSuites > 0 ? 1 : 0); + }) + .catch(error => { + console.error('โŒ Test runner failed:', error); + process.exit(1); + }); +} + +module.exports = CopyBloxTestRunner; diff --git a/scripts/sanity/guard-controller/base-test.cjs b/scripts/sanity/guard-controller/base-test.cjs index 6a4e0506..bdacbb67 100644 --- a/scripts/sanity/guard-controller/base-test.cjs +++ b/scripts/sanity/guard-controller/base-test.cjs @@ -52,7 +52,7 @@ try { } // Load environment variables from the project root -require('dotenv').config({ path: path.join(__dirname, '../../../.env') }); +require('dotenv').config({ path: path.join(__dirname, '../../../.env'), quiet: true }); // Helper function to get RPC URL dynamically function getWeb3Url() { diff --git a/scripts/sanity/run-all-tests.cjs b/scripts/sanity/run-all-tests.cjs index b9382d9f..a6d6f3c9 100644 --- a/scripts/sanity/run-all-tests.cjs +++ b/scripts/sanity/run-all-tests.cjs @@ -17,7 +17,8 @@ class SanityTestRunner { this.exampleTests = { 'simple-vault': path.resolve(__dirname, 'simple-vault', 'run-tests.cjs'), - 'simple-rwa20': path.resolve(__dirname, 'simple-rwa20', 'run-tests.cjs') + 'simple-rwa20': path.resolve(__dirname, 'simple-rwa20', 'run-tests.cjs'), + 'copy-blox': path.resolve(__dirname, 'copy-blox', 'run-tests.cjs') }; this.results = { @@ -43,6 +44,7 @@ class SanityTestRunner { console.log(' --guard-controller Run guard-controller tests only'); console.log(' --simple-vault Run simple-vault tests only'); console.log(' --simple-rwa20 Run simple-rwa20 tests only'); + console.log(' --copy-blox Run copy-blox tests only'); console.log(' --help Show this help message'); console.log(); console.log('Examples:'); diff --git a/scripts/sanity/runtime-rbac/base-test.cjs b/scripts/sanity/runtime-rbac/base-test.cjs index b0d97314..a0b59bb7 100644 --- a/scripts/sanity/runtime-rbac/base-test.cjs +++ b/scripts/sanity/runtime-rbac/base-test.cjs @@ -9,7 +9,7 @@ const path = require('path'); const EIP712Signer = require('../utils/eip712-signing.cjs'); // Load environment variables from the project root -require('dotenv').config({ path: path.join(__dirname, '../../../.env') }); +require('dotenv').config({ path: path.join(__dirname, '../../../.env'), quiet: true }); // Helper function to get RPC URL dynamically function getWeb3Url() { diff --git a/scripts/sanity/secure-ownable/README.md b/scripts/sanity/secure-ownable/README.md index 8b137188..397a3556 100644 --- a/scripts/sanity/secure-ownable/README.md +++ b/scripts/sanity/secure-ownable/README.md @@ -130,7 +130,7 @@ node run-tests.js --help - Node.js with Web3.js - Access to deployed SecureOwnable contract - Environment variables configured in `.env` file: - - `SECUREBLOX_ADDRESS` + - `ACCOUNTBLOX_ADDRESS` (manual mode; auto mode uses Truffle artifacts) - `TEST_WALLET_1_PRIVATE_KEY` through `TEST_WALLET_5_PRIVATE_KEY` - `REMOTE_HOST` and `REMOTE_PORT` (if using remote blockchain) diff --git a/scripts/sanity/secure-ownable/base-test.cjs b/scripts/sanity/secure-ownable/base-test.cjs index 7f3696b8..7b4ea5ff 100644 --- a/scripts/sanity/secure-ownable/base-test.cjs +++ b/scripts/sanity/secure-ownable/base-test.cjs @@ -9,7 +9,7 @@ const path = require('path'); const EIP712Signer = require('../utils/eip712-signing.cjs'); // Load environment variables from the project root -require('dotenv').config({ path: path.join(__dirname, '../../../.env') }); +require('dotenv').config({ path: path.join(__dirname, '../../../.env'), quiet: true }); // Helper function to get RPC URL dynamically function getWeb3Url() { diff --git a/scripts/sanity/simple-rwa20/base-test.cjs b/scripts/sanity/simple-rwa20/base-test.cjs index 0d31d0c5..d8a9228c 100644 --- a/scripts/sanity/simple-rwa20/base-test.cjs +++ b/scripts/sanity/simple-rwa20/base-test.cjs @@ -9,7 +9,7 @@ const path = require('path'); const SimpleRWA20EIP712Signer = require('./simple-rwa20-eip712-signer.cjs'); // Load environment variables from the project root -require('dotenv').config({ path: path.join(__dirname, '../../../.env') }); +require('dotenv').config({ path: path.join(__dirname, '../../../.env'), quiet: true }); // Helper function to get RPC URL dynamically function getWeb3Url() { diff --git a/scripts/sanity/simple-vault/base-test.cjs b/scripts/sanity/simple-vault/base-test.cjs index 9ce75886..0221ff4f 100644 --- a/scripts/sanity/simple-vault/base-test.cjs +++ b/scripts/sanity/simple-vault/base-test.cjs @@ -9,7 +9,7 @@ const path = require('path'); const EIP712Signer = require('../utils/eip712-signing.cjs'); // Load environment variables from the project root -require('dotenv').config({ path: path.join(__dirname, '../../../.env') }); +require('dotenv').config({ path: path.join(__dirname, '../../../.env'), quiet: true }); // Helper function to get RPC URL dynamically function getWeb3Url() { diff --git a/scripts/sanity/utils/eip712-signing.cjs b/scripts/sanity/utils/eip712-signing.cjs index bc13345a..6718235a 100644 --- a/scripts/sanity/utils/eip712-signing.cjs +++ b/scripts/sanity/utils/eip712-signing.cjs @@ -1,6 +1,6 @@ const Web3 = require('web3'); const fs = require('fs'); -require('dotenv').config(); +require('dotenv').config({ quiet: true }); // Helper function to get RPC URL dynamically function getWeb3Url() { diff --git a/abi/SecureBlox.abi.json b/sdk/typescript/abi/CopyBlox.abi.json similarity index 50% rename from abi/SecureBlox.abi.json rename to sdk/typescript/abi/CopyBlox.abi.json index 263283df..2fe439e5 100644 --- a/abi/SecureBlox.abi.json +++ b/sdk/typescript/abi/CopyBlox.abi.json @@ -1,29 +1,34 @@ [ + { + "inputs": [], + "name": "FailedDeployment", + "type": "error" + }, { "inputs": [ { "internalType": "uint256", - "name": "array1Length", + "name": "balance", "type": "uint256" }, { "internalType": "uint256", - "name": "array2Length", + "name": "needed", "type": "uint256" } ], - "name": "ArrayLengthMismatch", + "name": "InsufficientBalance", "type": "error" }, { "inputs": [ { - "internalType": "bytes4", - "name": "functionSelector", - "type": "bytes4" + "internalType": "address", + "name": "provided", + "type": "address" } ], - "name": "ContractFunctionMustBeProtected", + "name": "InvalidAddress", "type": "error" }, { @@ -31,6 +36,17 @@ "name": "InvalidInitialization", "type": "error" }, + { + "inputs": [ + { + "internalType": "address", + "name": "item", + "type": "address" + } + ], + "name": "InvalidOperation", + "type": "error" + }, { "inputs": [ { @@ -64,24 +80,13 @@ "type": "error" }, { - "inputs": [ - { - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "internalType": "address", - "name": "contractAddress", - "type": "address" - } - ], - "name": "OnlyCallableByContract", + "inputs": [], + "name": "NotSupported", "type": "error" }, { "inputs": [], - "name": "PendingSecureRequest", + "name": "OperationFailed", "type": "error" }, { @@ -117,57 +122,84 @@ "type": "error" }, { + "anonymous": false, "inputs": [ { + "indexed": true, + "internalType": "address", + "name": "original", + "type": "address" + }, + { + "indexed": true, "internalType": "address", - "name": "caller", + "name": "clone", "type": "address" }, { + "indexed": true, "internalType": "address", - "name": "owner", + "name": "initialOwner", "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "cloneNumber", + "type": "uint256" } ], - "name": "RestrictedOwner", - "type": "error" + "name": "BloxCloned", + "type": "event" }, { + "anonymous": false, "inputs": [ { + "indexed": true, "internalType": "address", - "name": "caller", + "name": "cloneAddress", "type": "address" }, { - "internalType": "address", - "name": "owner", - "type": "address" + "indexed": true, + "internalType": "uint256", + "name": "txId", + "type": "uint256" }, { - "internalType": "address", - "name": "recovery", - "type": "address" - } - ], - "name": "RestrictedOwnerRecovery", - "type": "error" - }, - { - "inputs": [ + "indexed": true, + "internalType": "bytes4", + "name": "functionSelector", + "type": "bytes4" + }, + { + "indexed": false, + "internalType": "enum EngineBlox.TxStatus", + "name": "status", + "type": "uint8" + }, { + "indexed": false, "internalType": "address", - "name": "caller", + "name": "requester", "type": "address" }, { + "indexed": false, "internalType": "address", - "name": "recovery", + "name": "target", "type": "address" + }, + { + "indexed": false, + "internalType": "bytes32", + "name": "operationType", + "type": "bytes32" } ], - "name": "RestrictedRecovery", - "type": "error" + "name": "CloneEventForwarded", + "type": "event" }, { "anonymous": false, @@ -201,6 +233,10 @@ "name": "Initialized", "type": "event" }, + { + "stateMutability": "payable", + "type": "fallback" + }, { "inputs": [ { @@ -287,63 +323,6 @@ "stateMutability": "view", "type": "function" }, - { - "inputs": [ - { - "internalType": "address", - "name": "newBroadcaster", - "type": "address" - }, - { - "internalType": "uint256", - "name": "location", - "type": "uint256" - } - ], - "name": "executeBroadcasterUpdate", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "newRecoveryAddress", - "type": "address" - } - ], - "name": "executeRecoveryUpdate", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "newTimeLockPeriodSec", - "type": "uint256" - } - ], - "name": "executeTimeLockUpdate", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "newOwner", - "type": "address" - } - ], - "name": "executeTransferOwnership", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, { "inputs": [ { @@ -1500,1029 +1479,85 @@ "stateMutability": "view", "type": "function" }, + { + "stateMutability": "payable", + "type": "receive" + }, { "inputs": [ { - "components": [ - { - "components": [ - { - "internalType": "uint256", - "name": "txId", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "releaseTime", - "type": "uint256" - }, - { - "internalType": "enum EngineBlox.TxStatus", - "name": "status", - "type": "uint8" - }, - { - "components": [ - { - "internalType": "address", - "name": "requester", - "type": "address" - }, - { - "internalType": "address", - "name": "target", - "type": "address" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "gasLimit", - "type": "uint256" - }, - { - "internalType": "bytes32", - "name": "operationType", - "type": "bytes32" - }, - { - "internalType": "bytes4", - "name": "executionSelector", - "type": "bytes4" - }, - { - "internalType": "bytes", - "name": "executionParams", - "type": "bytes" - } - ], - "internalType": "struct EngineBlox.TxParams", - "name": "params", - "type": "tuple" - }, - { - "internalType": "bytes32", - "name": "message", - "type": "bytes32" - }, - { - "internalType": "bytes", - "name": "result", - "type": "bytes" - }, - { - "components": [ - { - "internalType": "address", - "name": "recipient", - "type": "address" - }, - { - "internalType": "uint256", - "name": "nativeTokenAmount", - "type": "uint256" - }, - { - "internalType": "address", - "name": "erc20TokenAddress", - "type": "address" - }, - { - "internalType": "uint256", - "name": "erc20TokenAmount", - "type": "uint256" - } - ], - "internalType": "struct EngineBlox.PaymentDetails", - "name": "payment", - "type": "tuple" - } - ], - "internalType": "struct EngineBlox.TxRecord", - "name": "txRecord", - "type": "tuple" - }, - { - "components": [ - { - "internalType": "uint256", - "name": "chainId", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "nonce", - "type": "uint256" - }, - { - "internalType": "address", - "name": "handlerContract", - "type": "address" - }, - { - "internalType": "bytes4", - "name": "handlerSelector", - "type": "bytes4" - }, - { - "internalType": "enum EngineBlox.TxAction", - "name": "action", - "type": "uint8" - }, - { - "internalType": "uint256", - "name": "deadline", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "maxGasPrice", - "type": "uint256" - }, - { - "internalType": "address", - "name": "signer", - "type": "address" - } - ], - "internalType": "struct EngineBlox.MetaTxParams", - "name": "params", - "type": "tuple" - }, - { - "internalType": "bytes32", - "name": "message", - "type": "bytes32" - }, - { - "internalType": "bytes", - "name": "signature", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "data", - "type": "bytes" - } - ], - "internalType": "struct EngineBlox.MetaTransaction", - "name": "metaTx", - "type": "tuple" - } - ], - "name": "transferOwnershipApprovalWithMetaTx", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "txId", - "type": "uint256" - } - ], - "name": "transferOwnershipCancellation", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "components": [ - { - "internalType": "uint256", - "name": "txId", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "releaseTime", - "type": "uint256" - }, - { - "internalType": "enum EngineBlox.TxStatus", - "name": "status", - "type": "uint8" - }, - { - "components": [ - { - "internalType": "address", - "name": "requester", - "type": "address" - }, - { - "internalType": "address", - "name": "target", - "type": "address" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "gasLimit", - "type": "uint256" - }, - { - "internalType": "bytes32", - "name": "operationType", - "type": "bytes32" - }, - { - "internalType": "bytes4", - "name": "executionSelector", - "type": "bytes4" - }, - { - "internalType": "bytes", - "name": "executionParams", - "type": "bytes" - } - ], - "internalType": "struct EngineBlox.TxParams", - "name": "params", - "type": "tuple" - }, - { - "internalType": "bytes32", - "name": "message", - "type": "bytes32" - }, - { - "internalType": "bytes", - "name": "result", - "type": "bytes" - }, - { - "components": [ - { - "internalType": "address", - "name": "recipient", - "type": "address" - }, - { - "internalType": "uint256", - "name": "nativeTokenAmount", - "type": "uint256" - }, - { - "internalType": "address", - "name": "erc20TokenAddress", - "type": "address" - }, - { - "internalType": "uint256", - "name": "erc20TokenAmount", - "type": "uint256" - } - ], - "internalType": "struct EngineBlox.PaymentDetails", - "name": "payment", - "type": "tuple" - } - ], - "internalType": "struct EngineBlox.TxRecord", - "name": "txRecord", - "type": "tuple" - }, - { - "components": [ - { - "internalType": "uint256", - "name": "chainId", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "nonce", - "type": "uint256" - }, - { - "internalType": "address", - "name": "handlerContract", - "type": "address" - }, - { - "internalType": "bytes4", - "name": "handlerSelector", - "type": "bytes4" - }, - { - "internalType": "enum EngineBlox.TxAction", - "name": "action", - "type": "uint8" - }, - { - "internalType": "uint256", - "name": "deadline", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "maxGasPrice", - "type": "uint256" - }, - { - "internalType": "address", - "name": "signer", - "type": "address" - } - ], - "internalType": "struct EngineBlox.MetaTxParams", - "name": "params", - "type": "tuple" - }, - { - "internalType": "bytes32", - "name": "message", - "type": "bytes32" - }, - { - "internalType": "bytes", - "name": "signature", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "data", - "type": "bytes" - } - ], - "internalType": "struct EngineBlox.MetaTransaction", - "name": "metaTx", - "type": "tuple" - } - ], - "name": "transferOwnershipCancellationWithMetaTx", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "txId", - "type": "uint256" - } - ], - "name": "transferOwnershipDelayedApproval", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "transferOwnershipRequest", - "outputs": [ - { - "internalType": "uint256", - "name": "txId", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "components": [ - { - "internalType": "uint256", - "name": "txId", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "releaseTime", - "type": "uint256" - }, - { - "internalType": "enum EngineBlox.TxStatus", - "name": "status", - "type": "uint8" - }, - { - "components": [ - { - "internalType": "address", - "name": "requester", - "type": "address" - }, - { - "internalType": "address", - "name": "target", - "type": "address" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "gasLimit", - "type": "uint256" - }, - { - "internalType": "bytes32", - "name": "operationType", - "type": "bytes32" - }, - { - "internalType": "bytes4", - "name": "executionSelector", - "type": "bytes4" - }, - { - "internalType": "bytes", - "name": "executionParams", - "type": "bytes" - } - ], - "internalType": "struct EngineBlox.TxParams", - "name": "params", - "type": "tuple" - }, - { - "internalType": "bytes32", - "name": "message", - "type": "bytes32" - }, - { - "internalType": "bytes", - "name": "result", - "type": "bytes" - }, - { - "components": [ - { - "internalType": "address", - "name": "recipient", - "type": "address" - }, - { - "internalType": "uint256", - "name": "nativeTokenAmount", - "type": "uint256" - }, - { - "internalType": "address", - "name": "erc20TokenAddress", - "type": "address" - }, - { - "internalType": "uint256", - "name": "erc20TokenAmount", - "type": "uint256" - } - ], - "internalType": "struct EngineBlox.PaymentDetails", - "name": "payment", - "type": "tuple" - } - ], - "internalType": "struct EngineBlox.TxRecord", - "name": "txRecord", - "type": "tuple" - }, - { - "components": [ - { - "internalType": "uint256", - "name": "chainId", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "nonce", - "type": "uint256" - }, - { - "internalType": "address", - "name": "handlerContract", - "type": "address" - }, - { - "internalType": "bytes4", - "name": "handlerSelector", - "type": "bytes4" - }, - { - "internalType": "enum EngineBlox.TxAction", - "name": "action", - "type": "uint8" - }, - { - "internalType": "uint256", - "name": "deadline", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "maxGasPrice", - "type": "uint256" - }, - { - "internalType": "address", - "name": "signer", - "type": "address" - } - ], - "internalType": "struct EngineBlox.MetaTxParams", - "name": "params", - "type": "tuple" - }, - { - "internalType": "bytes32", - "name": "message", - "type": "bytes32" - }, - { - "internalType": "bytes", - "name": "signature", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "data", - "type": "bytes" - } - ], - "internalType": "struct EngineBlox.MetaTransaction", - "name": "metaTx", - "type": "tuple" - } - ], - "name": "updateBroadcasterApprovalWithMetaTx", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "txId", - "type": "uint256" - } - ], - "name": "updateBroadcasterCancellation", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "components": [ - { - "internalType": "uint256", - "name": "txId", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "releaseTime", - "type": "uint256" - }, - { - "internalType": "enum EngineBlox.TxStatus", - "name": "status", - "type": "uint8" - }, - { - "components": [ - { - "internalType": "address", - "name": "requester", - "type": "address" - }, - { - "internalType": "address", - "name": "target", - "type": "address" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "gasLimit", - "type": "uint256" - }, - { - "internalType": "bytes32", - "name": "operationType", - "type": "bytes32" - }, - { - "internalType": "bytes4", - "name": "executionSelector", - "type": "bytes4" - }, - { - "internalType": "bytes", - "name": "executionParams", - "type": "bytes" - } - ], - "internalType": "struct EngineBlox.TxParams", - "name": "params", - "type": "tuple" - }, - { - "internalType": "bytes32", - "name": "message", - "type": "bytes32" - }, - { - "internalType": "bytes", - "name": "result", - "type": "bytes" - }, - { - "components": [ - { - "internalType": "address", - "name": "recipient", - "type": "address" - }, - { - "internalType": "uint256", - "name": "nativeTokenAmount", - "type": "uint256" - }, - { - "internalType": "address", - "name": "erc20TokenAddress", - "type": "address" - }, - { - "internalType": "uint256", - "name": "erc20TokenAmount", - "type": "uint256" - } - ], - "internalType": "struct EngineBlox.PaymentDetails", - "name": "payment", - "type": "tuple" - } - ], - "internalType": "struct EngineBlox.TxRecord", - "name": "txRecord", - "type": "tuple" - }, - { - "components": [ - { - "internalType": "uint256", - "name": "chainId", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "nonce", - "type": "uint256" - }, - { - "internalType": "address", - "name": "handlerContract", - "type": "address" - }, - { - "internalType": "bytes4", - "name": "handlerSelector", - "type": "bytes4" - }, - { - "internalType": "enum EngineBlox.TxAction", - "name": "action", - "type": "uint8" - }, - { - "internalType": "uint256", - "name": "deadline", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "maxGasPrice", - "type": "uint256" - }, - { - "internalType": "address", - "name": "signer", - "type": "address" - } - ], - "internalType": "struct EngineBlox.MetaTxParams", - "name": "params", - "type": "tuple" - }, - { - "internalType": "bytes32", - "name": "message", - "type": "bytes32" - }, - { - "internalType": "bytes", - "name": "signature", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "data", - "type": "bytes" - } - ], - "internalType": "struct EngineBlox.MetaTransaction", - "name": "metaTx", - "type": "tuple" - } - ], - "name": "updateBroadcasterCancellationWithMetaTx", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "txId", - "type": "uint256" - } - ], - "name": "updateBroadcasterDelayedApproval", - "outputs": [ + "internalType": "address", + "name": "initialOwner", + "type": "address" + }, { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ + "internalType": "address", + "name": "broadcaster", + "type": "address" + }, { "internalType": "address", - "name": "newBroadcaster", + "name": "recovery", "type": "address" }, { "internalType": "uint256", - "name": "location", + "name": "timeLockPeriodSec", "type": "uint256" - } - ], - "name": "updateBroadcasterRequest", - "outputs": [ + }, { - "internalType": "uint256", - "name": "txId", - "type": "uint256" + "internalType": "address", + "name": "eventForwarder", + "type": "address" } ], + "name": "initialize", + "outputs": [], "stateMutability": "nonpayable", "type": "function" }, - { - "inputs": [ - { - "components": [ - { - "components": [ - { - "internalType": "uint256", - "name": "txId", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "releaseTime", - "type": "uint256" - }, - { - "internalType": "enum EngineBlox.TxStatus", - "name": "status", - "type": "uint8" - }, - { - "components": [ - { - "internalType": "address", - "name": "requester", - "type": "address" - }, - { - "internalType": "address", - "name": "target", - "type": "address" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "gasLimit", - "type": "uint256" - }, - { - "internalType": "bytes32", - "name": "operationType", - "type": "bytes32" - }, - { - "internalType": "bytes4", - "name": "executionSelector", - "type": "bytes4" - }, - { - "internalType": "bytes", - "name": "executionParams", - "type": "bytes" - } - ], - "internalType": "struct EngineBlox.TxParams", - "name": "params", - "type": "tuple" - }, - { - "internalType": "bytes32", - "name": "message", - "type": "bytes32" - }, - { - "internalType": "bytes", - "name": "result", - "type": "bytes" - }, - { - "components": [ - { - "internalType": "address", - "name": "recipient", - "type": "address" - }, - { - "internalType": "uint256", - "name": "nativeTokenAmount", - "type": "uint256" - }, - { - "internalType": "address", - "name": "erc20TokenAddress", - "type": "address" - }, - { - "internalType": "uint256", - "name": "erc20TokenAmount", - "type": "uint256" - } - ], - "internalType": "struct EngineBlox.PaymentDetails", - "name": "payment", - "type": "tuple" - } - ], - "internalType": "struct EngineBlox.TxRecord", - "name": "txRecord", - "type": "tuple" - }, - { - "components": [ - { - "internalType": "uint256", - "name": "chainId", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "nonce", - "type": "uint256" - }, - { - "internalType": "address", - "name": "handlerContract", - "type": "address" - }, - { - "internalType": "bytes4", - "name": "handlerSelector", - "type": "bytes4" - }, - { - "internalType": "enum EngineBlox.TxAction", - "name": "action", - "type": "uint8" - }, - { - "internalType": "uint256", - "name": "deadline", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "maxGasPrice", - "type": "uint256" - }, - { - "internalType": "address", - "name": "signer", - "type": "address" - } - ], - "internalType": "struct EngineBlox.MetaTxParams", - "name": "params", - "type": "tuple" - }, - { - "internalType": "bytes32", - "name": "message", - "type": "bytes32" - }, - { - "internalType": "bytes", - "name": "signature", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "data", - "type": "bytes" - } - ], - "internalType": "struct EngineBlox.MetaTransaction", - "name": "metaTx", - "type": "tuple" + { + "inputs": [ + { + "internalType": "address", + "name": "bloxAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "initialOwner", + "type": "address" + }, + { + "internalType": "address", + "name": "broadcaster", + "type": "address" + }, + { + "internalType": "address", + "name": "recovery", + "type": "address" + }, + { + "internalType": "uint256", + "name": "timeLockPeriodSec", + "type": "uint256" + } + ], + "name": "cloneBlox", + "outputs": [ + { + "internalType": "address", + "name": "cloneAddress", + "type": "address" } ], - "name": "updateRecoveryRequestAndApprove", + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "getCloneCount", "outputs": [ { "internalType": "uint256", @@ -2530,222 +1565,81 @@ "type": "uint256" } ], - "stateMutability": "nonpayable", + "stateMutability": "view", "type": "function" }, { "inputs": [ { - "components": [ - { - "components": [ - { - "internalType": "uint256", - "name": "txId", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "releaseTime", - "type": "uint256" - }, - { - "internalType": "enum EngineBlox.TxStatus", - "name": "status", - "type": "uint8" - }, - { - "components": [ - { - "internalType": "address", - "name": "requester", - "type": "address" - }, - { - "internalType": "address", - "name": "target", - "type": "address" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "gasLimit", - "type": "uint256" - }, - { - "internalType": "bytes32", - "name": "operationType", - "type": "bytes32" - }, - { - "internalType": "bytes4", - "name": "executionSelector", - "type": "bytes4" - }, - { - "internalType": "bytes", - "name": "executionParams", - "type": "bytes" - } - ], - "internalType": "struct EngineBlox.TxParams", - "name": "params", - "type": "tuple" - }, - { - "internalType": "bytes32", - "name": "message", - "type": "bytes32" - }, - { - "internalType": "bytes", - "name": "result", - "type": "bytes" - }, - { - "components": [ - { - "internalType": "address", - "name": "recipient", - "type": "address" - }, - { - "internalType": "uint256", - "name": "nativeTokenAmount", - "type": "uint256" - }, - { - "internalType": "address", - "name": "erc20TokenAddress", - "type": "address" - }, - { - "internalType": "uint256", - "name": "erc20TokenAmount", - "type": "uint256" - } - ], - "internalType": "struct EngineBlox.PaymentDetails", - "name": "payment", - "type": "tuple" - } - ], - "internalType": "struct EngineBlox.TxRecord", - "name": "txRecord", - "type": "tuple" - }, - { - "components": [ - { - "internalType": "uint256", - "name": "chainId", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "nonce", - "type": "uint256" - }, - { - "internalType": "address", - "name": "handlerContract", - "type": "address" - }, - { - "internalType": "bytes4", - "name": "handlerSelector", - "type": "bytes4" - }, - { - "internalType": "enum EngineBlox.TxAction", - "name": "action", - "type": "uint8" - }, - { - "internalType": "uint256", - "name": "deadline", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "maxGasPrice", - "type": "uint256" - }, - { - "internalType": "address", - "name": "signer", - "type": "address" - } - ], - "internalType": "struct EngineBlox.MetaTxParams", - "name": "params", - "type": "tuple" - }, - { - "internalType": "bytes32", - "name": "message", - "type": "bytes32" - }, - { - "internalType": "bytes", - "name": "signature", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "data", - "type": "bytes" - } - ], - "internalType": "struct EngineBlox.MetaTransaction", - "name": "metaTx", - "type": "tuple" + "internalType": "uint256", + "name": "index", + "type": "uint256" } ], - "name": "updateTimeLockRequestAndApprove", + "name": "getCloneAtIndex", "outputs": [ { - "internalType": "uint256", + "internalType": "address", "name": "", - "type": "uint256" + "type": "address" } ], - "stateMutability": "nonpayable", + "stateMutability": "view", "type": "function" }, { "inputs": [ { "internalType": "address", - "name": "initialOwner", + "name": "cloneAddress", "type": "address" + } + ], + "name": "isClone", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "txId", + "type": "uint256" }, { - "internalType": "address", - "name": "broadcaster", - "type": "address" + "internalType": "bytes4", + "name": "functionSelector", + "type": "bytes4" }, { - "internalType": "address", - "name": "recovery", - "type": "address" + "internalType": "enum EngineBlox.TxStatus", + "name": "status", + "type": "uint8" }, { - "internalType": "uint256", - "name": "timeLockPeriodSec", - "type": "uint256" + "internalType": "address", + "name": "requester", + "type": "address" }, { "internalType": "address", - "name": "eventForwarder", + "name": "target", "type": "address" + }, + { + "internalType": "bytes32", + "name": "operationType", + "type": "bytes32" } ], - "name": "initialize", + "name": "forwardTxEvent", "outputs": [], "stateMutability": "nonpayable", "type": "function" diff --git a/sdk/typescript/docs/bloxchain-architecture.md b/sdk/typescript/docs/bloxchain-architecture.md index 6a3be5db..8b5ecc3b 100644 --- a/sdk/typescript/docs/bloxchain-architecture.md +++ b/sdk/typescript/docs/bloxchain-architecture.md @@ -120,11 +120,7 @@ struct SecureOperationState { ### Layer 4: Template Contracts **Purpose**: Provide ready-to-use template implementations -- **`BareBlox.sol`**: Minimal implementation using only BaseStateMachine -- **`SecureBlox.sol`**: Basic implementation using SecureOwnable -- **`RoleBlox.sol`**: Implementation combining SecureOwnable and RuntimeRBAC - **`AccountBlox.sol`**: Complete implementation with GuardController, RuntimeRBAC, and SecureOwnable -- **`MachineBlox.sol`**: Full-featured implementation with GuardController, RuntimeRBAC, SecureOwnable, and HookManager ### Layer 5: Application Contracts **Purpose**: DApp-specific implementations using Bloxchain security diff --git a/sdk/typescript/package.json b/sdk/typescript/package.json index 455a326d..a810475d 100644 --- a/sdk/typescript/package.json +++ b/sdk/typescript/package.json @@ -1,6 +1,6 @@ { "name": "@bloxchain/sdk", - "version": "1.0.0-alpha.12", + "version": "1.0.0-alpha.13", "description": "Library engine for building enterprise grade decentralized permissioned applications", "type": "module", "main": "./dist/index.js", diff --git a/test/foundry/CommonBase.sol b/test/foundry/CommonBase.sol index 43f95632..25004b86 100644 --- a/test/foundry/CommonBase.sol +++ b/test/foundry/CommonBase.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: MPL-2.0 pragma solidity 0.8.34; import "forge-std/Test.sol"; @@ -7,8 +7,6 @@ import "../../contracts/core/access/interface/IRuntimeRBAC.sol"; import "../../contracts/core/access/lib/definitions/RuntimeRBACDefinitions.sol"; import "../../contracts/core/execution/lib/definitions/GuardControllerDefinitions.sol"; import "../../contracts/core/security/lib/definitions/SecureOwnableDefinitions.sol"; -import "../../contracts/examples/templates/SecureBlox.sol"; -import "../../contracts/examples/templates/RoleBlox.sol"; import "../../contracts/examples/templates/AccountBlox.sol"; import "./helpers/MockContracts.sol"; import "./helpers/TestHelpers.sol"; @@ -29,9 +27,7 @@ contract CommonBase is Test { address public user4; address public user5; - // Deployed contracts - SecureBlox public secureBlox; - RoleBlox public roleBlox; + // Deployed contracts (AccountBlox provides SecureOwnable + RuntimeRBAC + GuardController) AccountBlox public accountBlox; // Mock contracts @@ -91,28 +87,6 @@ contract CommonBase is Test { mockEventForwarder = new MockEventForwarder(); metaTxSigner = new MetaTxSigner(); - // Deploy and initialize SecureBlox - secureBlox = new SecureBlox(); - vm.prank(owner); - secureBlox.initialize( - owner, - broadcaster, - recovery, - DEFAULT_TIMELOCK_PERIOD, - address(mockEventForwarder) - ); - - // Deploy and initialize RoleBlox - roleBlox = new RoleBlox(); - vm.prank(owner); - roleBlox.initialize( - owner, - broadcaster, - recovery, - DEFAULT_TIMELOCK_PERIOD, - address(mockEventForwarder) - ); - // Deploy and initialize AccountBlox accountBlox = new AccountBlox(); vm.prank(owner); diff --git a/test/foundry/fuzz/ComprehensiveAccessControlFuzz.t.sol b/test/foundry/fuzz/ComprehensiveAccessControlFuzz.t.sol index dc714603..2ce3e8a2 100644 --- a/test/foundry/fuzz/ComprehensiveAccessControlFuzz.t.sol +++ b/test/foundry/fuzz/ComprehensiveAccessControlFuzz.t.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: MPL-2.0 pragma solidity 0.8.34; import "../CommonBase.sol"; @@ -69,9 +69,9 @@ contract ComprehensiveAccessControlFuzzTest is CommonBase { ); vm.prank(broadcaster); - uint256 _txId = roleBlox.roleConfigBatchRequestAndApprove(metaTx); + uint256 _txId = accountBlox.roleConfigBatchRequestAndApprove(metaTx); vm.prank(broadcaster); - EngineBlox.TxRecord memory txRecord = roleBlox.getTransaction(_txId); + EngineBlox.TxRecord memory txRecord = accountBlox.getTransaction(_txId); assertEq(uint8(txRecord.status), uint8(EngineBlox.TxStatus.FAILED)); bytes memory expectedError = abi.encodeWithSelector( @@ -96,7 +96,7 @@ contract ComprehensiveAccessControlFuzzTest is CommonBase { if (protectedRoleHash == OWNER_ROLE) { walletToRevoke = owner; } else if (protectedRoleHash == BROADCASTER_ROLE) { - address[] memory broadcasters = roleBlox.getBroadcasters(); + address[] memory broadcasters = accountBlox.getBroadcasters(); vm.assume(broadcasters.length > 0); walletToRevoke = broadcasters[0]; // Only test if it's the last wallet @@ -115,9 +115,9 @@ contract ComprehensiveAccessControlFuzzTest is CommonBase { ); vm.prank(broadcaster); - uint256 _txId = roleBlox.roleConfigBatchRequestAndApprove(metaTx); + uint256 _txId = accountBlox.roleConfigBatchRequestAndApprove(metaTx); vm.prank(broadcaster); - EngineBlox.TxRecord memory txRecord = roleBlox.getTransaction(_txId); + EngineBlox.TxRecord memory txRecord = accountBlox.getTransaction(_txId); assertEq(uint8(txRecord.status), uint8(EngineBlox.TxStatus.FAILED)); } @@ -137,9 +137,9 @@ contract ComprehensiveAccessControlFuzzTest is CommonBase { ); vm.prank(broadcaster); - uint256 _txId = roleBlox.roleConfigBatchRequestAndApprove(metaTx); + uint256 _txId = accountBlox.roleConfigBatchRequestAndApprove(metaTx); vm.prank(broadcaster); - EngineBlox.TxRecord memory txRecord = roleBlox.getTransaction(_txId); + EngineBlox.TxRecord memory txRecord = accountBlox.getTransaction(_txId); assertEq(uint8(txRecord.status), uint8(EngineBlox.TxStatus.FAILED)); } @@ -168,9 +168,9 @@ contract ComprehensiveAccessControlFuzzTest is CommonBase { ); vm.prank(broadcaster); - uint256 _txId = roleBlox.roleConfigBatchRequestAndApprove(metaTx); + uint256 _txId = accountBlox.roleConfigBatchRequestAndApprove(metaTx); vm.prank(broadcaster); - EngineBlox.TxRecord memory txRecord = roleBlox.getTransaction(_txId); + EngineBlox.TxRecord memory txRecord = accountBlox.getTransaction(_txId); assertEq(uint8(txRecord.status), uint8(EngineBlox.TxStatus.FAILED)); bytes memory expectedError = abi.encodeWithSelector( @@ -281,7 +281,7 @@ contract ComprehensiveAccessControlFuzzTest is CommonBase { // Store initial role count (requires permissions) vm.prank(owner); - bytes32[] memory initialRoles = roleBlox.getSupportedRoles(); + bytes32[] memory initialRoles = accountBlox.getSupportedRoles(); uint256 initialRoleCount = initialRoles.length; // Create batch with valid action followed by invalid action (protected role modification) @@ -308,9 +308,9 @@ contract ComprehensiveAccessControlFuzzTest is CommonBase { ); vm.prank(broadcaster); - uint256 _txId = roleBlox.roleConfigBatchRequestAndApprove(metaTx); + uint256 _txId = accountBlox.roleConfigBatchRequestAndApprove(metaTx); vm.prank(broadcaster); - EngineBlox.TxRecord memory txRecord = roleBlox.getTransaction(_txId); + EngineBlox.TxRecord memory txRecord = accountBlox.getTransaction(_txId); // CRITICAL: Verify batch is atomic - Action 1 should NOT succeed if Action 2 fails assertEq(uint8(txRecord.status), uint8(EngineBlox.TxStatus.FAILED), "Batch with invalid action should fail"); @@ -318,7 +318,7 @@ contract ComprehensiveAccessControlFuzzTest is CommonBase { // Verify Action 1 was NOT executed (role should not exist) // This tests atomicity - getSupportedRoles requires permissions vm.prank(owner); - bytes32[] memory finalRoles = roleBlox.getSupportedRoles(); + bytes32[] memory finalRoles = accountBlox.getSupportedRoles(); uint256 finalRoleCount = finalRoles.length; // Role count should not increase (atomicity) @@ -369,9 +369,9 @@ contract ComprehensiveAccessControlFuzzTest is CommonBase { ); vm.prank(broadcaster); - uint256 _txId = roleBlox.roleConfigBatchRequestAndApprove(metaTx); + uint256 _txId = accountBlox.roleConfigBatchRequestAndApprove(metaTx); vm.prank(broadcaster); - EngineBlox.TxRecord memory txRecord = roleBlox.getTransaction(_txId); + EngineBlox.TxRecord memory txRecord = accountBlox.getTransaction(_txId); // All should fail assertEq(uint8(txRecord.status), uint8(EngineBlox.TxStatus.FAILED)); @@ -420,7 +420,7 @@ contract ComprehensiveAccessControlFuzzTest is CommonBase { ); vm.prank(broadcaster); - roleBlox.roleConfigBatchRequestAndApprove(createMetaTx); + accountBlox.roleConfigBatchRequestAndApprove(createMetaTx); // Add wallets up to limit for (uint256 i = 0; i < maxWallets; i++) { @@ -439,7 +439,7 @@ contract ComprehensiveAccessControlFuzzTest is CommonBase { ); vm.prank(broadcaster); - roleBlox.roleConfigBatchRequestAndApprove(addMetaTx); + accountBlox.roleConfigBatchRequestAndApprove(addMetaTx); } // Attempt to add one more wallet (should fail) @@ -458,9 +458,9 @@ contract ComprehensiveAccessControlFuzzTest is CommonBase { ); vm.prank(broadcaster); - uint256 _txId = roleBlox.roleConfigBatchRequestAndApprove(extraMetaTx); + uint256 _txId = accountBlox.roleConfigBatchRequestAndApprove(extraMetaTx); vm.prank(broadcaster); - EngineBlox.TxRecord memory txRecord = roleBlox.getTransaction(_txId); + EngineBlox.TxRecord memory txRecord = accountBlox.getTransaction(_txId); assertEq(uint8(txRecord.status), uint8(EngineBlox.TxStatus.FAILED)); bytes memory expectedError = abi.encodeWithSelector( @@ -491,7 +491,7 @@ contract ComprehensiveAccessControlFuzzTest is CommonBase { }); bytes memory createParams = RuntimeRBACDefinitions.roleConfigBatchExecutionParams(abi.encode(createActions)); vm.prank(broadcaster); - try roleBlox.roleConfigBatchRequestAndApprove(_createMetaTxForRoleConfig(owner, createParams, 1 hours)) { + try accountBlox.roleConfigBatchRequestAndApprove(_createMetaTxForRoleConfig(owner, createParams, 1 hours)) { // continue } catch (bytes memory reason) { if (reason.length >= 4 && bytes4(reason) == SharedValidation.NoPermission.selector) return; @@ -509,7 +509,7 @@ contract ComprehensiveAccessControlFuzzTest is CommonBase { }); bytes memory addParams = RuntimeRBACDefinitions.roleConfigBatchExecutionParams(abi.encode(addActions)); vm.prank(broadcaster); - try roleBlox.roleConfigBatchRequestAndApprove(_createMetaTxForRoleConfig(owner, addParams, 1 hours)) { + try accountBlox.roleConfigBatchRequestAndApprove(_createMetaTxForRoleConfig(owner, addParams, 1 hours)) { // continue } catch (bytes memory reason) { if (reason.length >= 4 && bytes4(reason) == SharedValidation.NoPermission.selector) return; @@ -517,9 +517,9 @@ contract ComprehensiveAccessControlFuzzTest is CommonBase { } vm.prank(owner); - assertTrue(roleBlox.hasRole(roleHash, user1)); + assertTrue(accountBlox.hasRole(roleHash, user1)); vm.prank(owner); - assertTrue(roleBlox.hasRole(roleHash, user2)); + assertTrue(accountBlox.hasRole(roleHash, user2)); IRuntimeRBAC.RoleConfigAction[] memory revokeActions = new IRuntimeRBAC.RoleConfigAction[](1); revokeActions[0] = IRuntimeRBAC.RoleConfigAction({ @@ -528,7 +528,7 @@ contract ComprehensiveAccessControlFuzzTest is CommonBase { }); bytes memory revokeParams = RuntimeRBACDefinitions.roleConfigBatchExecutionParams(abi.encode(revokeActions)); vm.prank(broadcaster); - try roleBlox.roleConfigBatchRequestAndApprove(_createMetaTxForRoleConfig(owner, revokeParams, 1 hours)) { + try accountBlox.roleConfigBatchRequestAndApprove(_createMetaTxForRoleConfig(owner, revokeParams, 1 hours)) { // continue } catch (bytes memory reason) { if (reason.length >= 4 && bytes4(reason) == SharedValidation.NoPermission.selector) return; @@ -536,11 +536,11 @@ contract ComprehensiveAccessControlFuzzTest is CommonBase { } vm.prank(owner); - assertFalse(roleBlox.hasRole(roleHash, user1)); + assertFalse(accountBlox.hasRole(roleHash, user1)); vm.prank(owner); - assertTrue(roleBlox.hasRole(roleHash, user2)); + assertTrue(accountBlox.hasRole(roleHash, user2)); vm.prank(owner); - address[] memory wallets = roleBlox.getWalletsInRole(roleHash); + address[] memory wallets = accountBlox.getWalletsInRole(roleHash); assertEq(wallets.length, 1); assertEq(wallets[0], user2); } @@ -575,7 +575,7 @@ contract ComprehensiveAccessControlFuzzTest is CommonBase { ); vm.prank(broadcaster); - roleBlox.roleConfigBatchRequestAndApprove(createMetaTx); + accountBlox.roleConfigBatchRequestAndApprove(createMetaTx); // Add wallet first time (should succeed) IRuntimeRBAC.RoleConfigAction[] memory addActions1 = new IRuntimeRBAC.RoleConfigAction[](1); @@ -592,7 +592,7 @@ contract ComprehensiveAccessControlFuzzTest is CommonBase { ); vm.prank(broadcaster); - roleBlox.roleConfigBatchRequestAndApprove(addMetaTx1); + accountBlox.roleConfigBatchRequestAndApprove(addMetaTx1); // Attempt to add same wallet again (should fail) IRuntimeRBAC.RoleConfigAction[] memory addActions2 = new IRuntimeRBAC.RoleConfigAction[](1); @@ -609,9 +609,9 @@ contract ComprehensiveAccessControlFuzzTest is CommonBase { ); vm.prank(broadcaster); - uint256 _txId = roleBlox.roleConfigBatchRequestAndApprove(addMetaTx2); + uint256 _txId = accountBlox.roleConfigBatchRequestAndApprove(addMetaTx2); vm.prank(broadcaster); - EngineBlox.TxRecord memory txRecord = roleBlox.getTransaction(_txId); + EngineBlox.TxRecord memory txRecord = accountBlox.getTransaction(_txId); assertEq(uint8(txRecord.status), uint8(EngineBlox.TxStatus.FAILED)); bytes memory expectedError = abi.encodeWithSelector( @@ -650,9 +650,9 @@ contract ComprehensiveAccessControlFuzzTest is CommonBase { ); vm.prank(broadcaster); - uint256 _txId = roleBlox.roleConfigBatchRequestAndApprove(metaTx); + uint256 _txId = accountBlox.roleConfigBatchRequestAndApprove(metaTx); vm.prank(broadcaster); - EngineBlox.TxRecord memory txRecord = roleBlox.getTransaction(_txId); + EngineBlox.TxRecord memory txRecord = accountBlox.getTransaction(_txId); // Should fail - role already exists assertEq(uint8(txRecord.status), uint8(EngineBlox.TxStatus.FAILED)); @@ -691,7 +691,7 @@ contract ComprehensiveAccessControlFuzzTest is CommonBase { ); vm.prank(broadcaster); - roleBlox.roleConfigBatchRequestAndApprove(createMetaTx); + accountBlox.roleConfigBatchRequestAndApprove(createMetaTx); // Attempt to add permission with both SIGN and EXECUTE actions (should fail) // Note: This requires a function schema to exist first @@ -729,7 +729,7 @@ contract ComprehensiveAccessControlFuzzTest is CommonBase { ); vm.prank(broadcaster); - roleBlox.roleConfigBatchRequestAndApprove(createMetaTx); + accountBlox.roleConfigBatchRequestAndApprove(createMetaTx); // Attempt to add permission with empty bitmap (bitmap = 0) // Should fail with NotSupported @@ -743,8 +743,8 @@ contract ComprehensiveAccessControlFuzzTest is CommonBase { bytes memory executionParams, uint256 deadline ) internal returns (EngineBlox.MetaTransaction memory) { - EngineBlox.MetaTxParams memory metaTxParams = roleBlox.createMetaTxParams( - address(roleBlox), + EngineBlox.MetaTxParams memory metaTxParams = accountBlox.createMetaTxParams( + address(accountBlox), ROLE_CONFIG_BATCH_META_SELECTOR, EngineBlox.TxAction.SIGN_META_REQUEST_AND_APPROVE, deadline, @@ -752,9 +752,9 @@ contract ComprehensiveAccessControlFuzzTest is CommonBase { signer ); - EngineBlox.MetaTransaction memory metaTx = roleBlox.generateUnsignedMetaTransactionForNew( + EngineBlox.MetaTransaction memory metaTx = accountBlox.generateUnsignedMetaTransactionForNew( signer, - address(roleBlox), + address(accountBlox), 0, 0, ROLE_CONFIG_BATCH_OPERATION_TYPE, diff --git a/test/foundry/fuzz/ComprehensiveCompositeFuzz.t.sol b/test/foundry/fuzz/ComprehensiveCompositeFuzz.t.sol index 7d17d981..9a697953 100644 --- a/test/foundry/fuzz/ComprehensiveCompositeFuzz.t.sol +++ b/test/foundry/fuzz/ComprehensiveCompositeFuzz.t.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: MPL-2.0 pragma solidity 0.8.34; import "../CommonBase.sol"; @@ -107,7 +107,7 @@ contract ComprehensiveCompositeFuzzTest is CommonBase { ); vm.prank(broadcaster); - roleBlox.roleConfigBatchRequestAndApprove(createMetaTx1); + accountBlox.roleConfigBatchRequestAndApprove(createMetaTx1); // Create role2 IRuntimeRBAC.RoleConfigAction[] memory createActions2 = new IRuntimeRBAC.RoleConfigAction[](1); @@ -125,7 +125,7 @@ contract ComprehensiveCompositeFuzzTest is CommonBase { ); vm.prank(broadcaster); - roleBlox.roleConfigBatchRequestAndApprove(createMetaTx2); + accountBlox.roleConfigBatchRequestAndApprove(createMetaTx2); // Add wallet to role1 IRuntimeRBAC.RoleConfigAction[] memory addActions1 = new IRuntimeRBAC.RoleConfigAction[](1); @@ -142,7 +142,7 @@ contract ComprehensiveCompositeFuzzTest is CommonBase { ); vm.prank(broadcaster); - roleBlox.roleConfigBatchRequestAndApprove(addMetaTx1); + accountBlox.roleConfigBatchRequestAndApprove(addMetaTx1); // Add wallet to role2 IRuntimeRBAC.RoleConfigAction[] memory addActions2 = new IRuntimeRBAC.RoleConfigAction[](1); @@ -159,11 +159,11 @@ contract ComprehensiveCompositeFuzzTest is CommonBase { ); vm.prank(broadcaster); - roleBlox.roleConfigBatchRequestAndApprove(addMetaTx2); + accountBlox.roleConfigBatchRequestAndApprove(addMetaTx2); // Verify wallet has both roles (permission accumulation) - assertTrue(roleBlox.hasRole(roleHash1, wallet), "Wallet should have role1"); - assertTrue(roleBlox.hasRole(roleHash2, wallet), "Wallet should have role2"); + assertTrue(accountBlox.hasRole(roleHash1, wallet), "Wallet should have role1"); + assertTrue(accountBlox.hasRole(roleHash2, wallet), "Wallet should have role2"); // This tests OR logic for permissions (intentional behavior) } @@ -230,9 +230,9 @@ contract ComprehensiveCompositeFuzzTest is CommonBase { vm.prank(broadcaster); // Use low-level call to check result without Foundry detecting revert - (bool success, bytes memory returnData) = address(roleBlox).call( + (bool success, bytes memory returnData) = address(accountBlox).call( abi.encodeWithSelector( - roleBlox.roleConfigBatchRequestAndApprove.selector, + accountBlox.roleConfigBatchRequestAndApprove.selector, metaTx ) ); @@ -245,7 +245,7 @@ contract ComprehensiveCompositeFuzzTest is CommonBase { // This tells Foundry the revert is expected, making the test pass vm.prank(broadcaster); vm.expectRevert(abi.encodeWithSelector(SharedValidation.NoPermission.selector, broadcaster)); - roleBlox.roleConfigBatchRequestAndApprove(metaTx); + accountBlox.roleConfigBatchRequestAndApprove(metaTx); return; // Test passes - security working correctly } // Re-throw other errors @@ -257,7 +257,7 @@ contract ComprehensiveCompositeFuzzTest is CommonBase { // Call succeeded - decode txId (roleConfigBatchRequestAndApprove returns uint256) uint256 txId = abi.decode(returnData, (uint256)); vm.prank(broadcaster); - EngineBlox.TxRecord memory txRecord = roleBlox.getTransaction(txId); + EngineBlox.TxRecord memory txRecord = accountBlox.getTransaction(txId); // CRITICAL: Batch should be atomic - Action 1 should NOT execute // The batch should fail because Action 2 (modifying protected role) is invalid @@ -267,7 +267,7 @@ contract ComprehensiveCompositeFuzzTest is CommonBase { // If the batch was atomic, the valid role should not have been created // Note: getSupportedRoles() requires permissions, so we use owner vm.prank(owner); - bytes32[] memory roles = roleBlox.getSupportedRoles(); + bytes32[] memory roles = accountBlox.getSupportedRoles(); bool roleExists = false; for (uint256 i = 0; i < roles.length; i++) { if (roles[i] == validRoleHash) { @@ -435,10 +435,10 @@ contract ComprehensiveCompositeFuzzTest is CommonBase { * @dev Test: Nonce prediction + signature replay prevention * Attack Vector: Nonce Prediction + Signature Replay (HIGH) */ - function testFuzz_NoncePredictionReplayPrevented() public { + function test_NoncePredictionReplayPrevented() public { // getSignerNonce requires role permissions vm.prank(owner); - uint256 currentNonce = roleBlox.getSignerNonce(owner); + uint256 currentNonce = accountBlox.getSignerNonce(owner); // Create legitimate meta-transaction (will use currentNonce) IRuntimeRBAC.RoleConfigAction[] memory actions = new IRuntimeRBAC.RoleConfigAction[](1); @@ -457,9 +457,9 @@ contract ComprehensiveCompositeFuzzTest is CommonBase { // Execute legitimate transaction first - this will increment nonce vm.prank(broadcaster); - uint256 legitTxId = roleBlox.roleConfigBatchRequestAndApprove(legitMetaTx); + uint256 legitTxId = accountBlox.roleConfigBatchRequestAndApprove(legitMetaTx); vm.prank(broadcaster); - EngineBlox.TxRecord memory legitResult = roleBlox.getTransaction(legitTxId); + EngineBlox.TxRecord memory legitResult = accountBlox.getTransaction(legitTxId); // If legitimate transaction failed, skip test if (legitResult.status != EngineBlox.TxStatus.COMPLETED) { @@ -468,15 +468,15 @@ contract ComprehensiveCompositeFuzzTest is CommonBase { // Get updated nonce after legitimate transaction vm.prank(owner); - uint256 updatedNonce = roleBlox.getSignerNonce(owner); + uint256 updatedNonce = accountBlox.getSignerNonce(owner); // Verify nonce was incremented assertEq(updatedNonce, currentNonce + 1, "Nonce should increment after transaction"); // Now create attacker transaction that tries to use the old nonce (currentNonce) // This should fail because the nonce has already been used - EngineBlox.MetaTxParams memory attackerParams = roleBlox.createMetaTxParams( - address(roleBlox), + EngineBlox.MetaTxParams memory attackerParams = accountBlox.createMetaTxParams( + address(accountBlox), ROLE_CONFIG_BATCH_META_SELECTOR, EngineBlox.TxAction.SIGN_META_REQUEST_AND_APPROVE, 1 hours, @@ -498,9 +498,9 @@ contract ComprehensiveCompositeFuzzTest is CommonBase { // Generate meta-transaction with old nonce // Note: generateUnsignedMetaTransactionForNew might override the nonce, so we need to // manually construct or use a different approach - EngineBlox.MetaTransaction memory attackerMetaTx = roleBlox.generateUnsignedMetaTransactionForNew( + EngineBlox.MetaTransaction memory attackerMetaTx = accountBlox.generateUnsignedMetaTransactionForNew( owner, - address(roleBlox), + address(accountBlox), 0, 0, ROLE_CONFIG_BATCH_OPERATION_TYPE, @@ -529,8 +529,8 @@ contract ComprehensiveCompositeFuzzTest is CommonBase { bytes memory executionParams, uint256 deadline ) internal returns (EngineBlox.MetaTransaction memory) { - EngineBlox.MetaTxParams memory metaTxParams = roleBlox.createMetaTxParams( - address(roleBlox), + EngineBlox.MetaTxParams memory metaTxParams = accountBlox.createMetaTxParams( + address(accountBlox), ROLE_CONFIG_BATCH_META_SELECTOR, EngineBlox.TxAction.SIGN_META_REQUEST_AND_APPROVE, deadline, @@ -538,9 +538,9 @@ contract ComprehensiveCompositeFuzzTest is CommonBase { signer ); - EngineBlox.MetaTransaction memory metaTx = roleBlox.generateUnsignedMetaTransactionForNew( + EngineBlox.MetaTransaction memory metaTx = accountBlox.generateUnsignedMetaTransactionForNew( signer, - address(roleBlox), + address(accountBlox), 0, 0, ROLE_CONFIG_BATCH_OPERATION_TYPE, diff --git a/test/foundry/fuzz/ComprehensiveDefinitionSecurityFuzz.t.sol b/test/foundry/fuzz/ComprehensiveDefinitionSecurityFuzz.t.sol index 3e983875..d65eca09 100644 --- a/test/foundry/fuzz/ComprehensiveDefinitionSecurityFuzz.t.sol +++ b/test/foundry/fuzz/ComprehensiveDefinitionSecurityFuzz.t.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: MPL-2.0 pragma solidity 0.8.34; import "../CommonBase.sol"; diff --git a/test/foundry/fuzz/ComprehensiveEIP712AndViewFuzz.t.sol b/test/foundry/fuzz/ComprehensiveEIP712AndViewFuzz.t.sol index 41912769..2abe8c11 100644 --- a/test/foundry/fuzz/ComprehensiveEIP712AndViewFuzz.t.sol +++ b/test/foundry/fuzz/ComprehensiveEIP712AndViewFuzz.t.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: MPL-2.0 pragma solidity 0.8.34; import "../CommonBase.sol"; @@ -39,8 +39,8 @@ contract ComprehensiveEIP712AndViewFuzzTest is CommonBase { uint256 deadline ) public { deadline = bound(deadline, 1, 30 days); - EngineBlox.MetaTxParams memory p = roleBlox.createMetaTxParams( - address(roleBlox), + EngineBlox.MetaTxParams memory p = accountBlox.createMetaTxParams( + address(accountBlox), ROLE_CONFIG_BATCH_META_SELECTOR, EngineBlox.TxAction.SIGN_META_REQUEST_AND_APPROVE, deadline, @@ -52,12 +52,12 @@ contract ComprehensiveEIP712AndViewFuzzTest is CommonBase { m.params = p; m.txRecord.txId = txId; m.txRecord.params.requester = owner; - m.txRecord.params.target = address(roleBlox); + m.txRecord.params.target = address(accountBlox); m.txRecord.params.operationType = ROLE_CONFIG_BATCH_OPERATION_TYPE; m.txRecord.params.executionSelector = ROLE_CONFIG_BATCH_EXECUTE_SELECTOR; - bytes32 h1 = metaTxSigner.generateMessageHash(m, address(roleBlox)); - bytes32 h2 = metaTxSigner.generateMessageHash(m, address(roleBlox)); + bytes32 h1 = metaTxSigner.generateMessageHash(m, address(accountBlox)); + bytes32 h2 = metaTxSigner.generateMessageHash(m, address(accountBlox)); assertEq(h1, h2, "Message hash must be deterministic for same inputs"); } @@ -84,7 +84,7 @@ contract ComprehensiveEIP712AndViewFuzzTest is CommonBase { bytes memory createParams = RuntimeRBACDefinitions.roleConfigBatchExecutionParams(abi.encode(createActions)); EngineBlox.MetaTransaction memory createMetaTx = _createMetaTxForRoleConfig(owner, createParams, 1 hours); vm.prank(broadcaster); - try roleBlox.roleConfigBatchRequestAndApprove(createMetaTx) { + try accountBlox.roleConfigBatchRequestAndApprove(createMetaTx) { // continue } catch (bytes memory reason) { if (reason.length >= 4 && bytes4(reason) == SharedValidation.InvalidSignature.selector) return; @@ -92,7 +92,7 @@ contract ComprehensiveEIP712AndViewFuzzTest is CommonBase { } vm.prank(owner); - bytes32[] memory roles = roleBlox.getSupportedRoles(); + bytes32[] memory roles = accountBlox.getSupportedRoles(); bool found; for (uint256 i = 0; i < roles.length; i++) { if (roles[i] == roleHash) { @@ -102,7 +102,7 @@ contract ComprehensiveEIP712AndViewFuzzTest is CommonBase { } assertTrue(found, "getSupportedRoles must include new role"); vm.prank(owner); - address[] memory wallets = roleBlox.getWalletsInRole(roleHash); + address[] memory wallets = accountBlox.getWalletsInRole(roleHash); assertEq(wallets.length, 0, "New role must have no wallets"); } @@ -146,17 +146,17 @@ contract ComprehensiveEIP712AndViewFuzzTest is CommonBase { bytes memory executionParams, uint256 deadline ) internal returns (EngineBlox.MetaTransaction memory) { - EngineBlox.MetaTxParams memory metaTxParams = roleBlox.createMetaTxParams( - address(roleBlox), + EngineBlox.MetaTxParams memory metaTxParams = accountBlox.createMetaTxParams( + address(accountBlox), ROLE_CONFIG_BATCH_META_SELECTOR, EngineBlox.TxAction.SIGN_META_REQUEST_AND_APPROVE, deadline, 0, signer ); - EngineBlox.MetaTransaction memory metaTx = roleBlox.generateUnsignedMetaTransactionForNew( + EngineBlox.MetaTransaction memory metaTx = accountBlox.generateUnsignedMetaTransactionForNew( signer, - address(roleBlox), + address(accountBlox), 0, 0, ROLE_CONFIG_BATCH_OPERATION_TYPE, @@ -165,7 +165,7 @@ contract ComprehensiveEIP712AndViewFuzzTest is CommonBase { metaTxParams ); uint256 signerPrivateKey = _getPrivateKeyForAddress(signer); - metaTx.signature = metaTxSigner.signMetaTransaction(metaTx, signerPrivateKey, address(roleBlox)); + metaTx.signature = metaTxSigner.signMetaTransaction(metaTx, signerPrivateKey, address(accountBlox)); return metaTx; } diff --git a/test/foundry/fuzz/ComprehensiveEventForwardingFuzz.t.sol b/test/foundry/fuzz/ComprehensiveEventForwardingFuzz.t.sol index f85047d8..5470cf91 100644 --- a/test/foundry/fuzz/ComprehensiveEventForwardingFuzz.t.sol +++ b/test/foundry/fuzz/ComprehensiveEventForwardingFuzz.t.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: MPL-2.0 pragma solidity 0.8.34; import "../CommonBase.sol"; diff --git a/test/foundry/fuzz/ComprehensiveGasExhaustionFuzz.t.sol b/test/foundry/fuzz/ComprehensiveGasExhaustionFuzz.t.sol index a4c6fb26..32f5fd00 100644 --- a/test/foundry/fuzz/ComprehensiveGasExhaustionFuzz.t.sol +++ b/test/foundry/fuzz/ComprehensiveGasExhaustionFuzz.t.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: MPL-2.0 pragma solidity 0.8.34; import "../CommonBase.sol"; @@ -47,15 +47,15 @@ contract ComprehensiveGasExhaustionFuzzTest is CommonBase { bytes4 executeSelector = bytes4(keccak256("execute()")); _whitelistTarget(address(mockTarget), executeSelector); - // Whitelist roleBlox itself for role config batch operations - // When roleBlox.generateUnsignedMetaTransactionForNew is called with roleBlox as target, - // it checks if roleBlox is whitelisted on roleBlox's own whitelist - // Since roleBlox extends BaseStateMachine, we can use EngineBlox library functions directly + // Whitelist accountBlox itself for role config batch operations + // When accountBlox.generateUnsignedMetaTransactionForNew is called with accountBlox as target, + // it checks if accountBlox is whitelisted on accountBlox's own whitelist + // Since accountBlox extends BaseStateMachine, we can use EngineBlox library functions directly // But we need to do this through a transaction since addTargetToFunctionWhitelist requires permissions - // Actually, since target == address(this) for roleBlox, internal calls should be allowed + // Actually, since target == address(this) for accountBlox, internal calls should be allowed // The issue might be that the target check happens before the address(this) check - // Let's whitelist roleBlox on itself using a direct call if possible - // For now, we'll skip this and see if using roleBlox directly fixes it + // Let's whitelist accountBlox on itself using a direct call if possible + // For now, we'll skip this and see if using accountBlox directly fixes it } /** @@ -101,15 +101,10 @@ contract ComprehensiveGasExhaustionFuzzTest is CommonBase { } /** - * @dev Helper to whitelist a target for a function selector on roleBlox (if it extends GuardController) - * Note: roleBlox extends RuntimeRBAC which doesn't extend GuardController, so this may not be needed - * But we include it for completeness in case the contract structure changes + * @dev Helper to whitelist a target for a function selector on an RBAC contract that also has GuardController. + * accountBlox has both; we whitelist on accountBlox. */ - function _whitelistTargetOnRoleBlox(address target, bytes4 selector) internal { - // Check if roleBlox has GuardController functionality - // Since RoleBlox doesn't extend GuardController, we skip whitelisting - // The whitelist check error might be coming from a different source - // For now, we'll try to whitelist on accountBlox instead + function _whitelistTargetForRBACContract(address target, bytes4 selector) internal { _whitelistTarget(target, selector); } @@ -256,9 +251,9 @@ contract ComprehensiveGasExhaustionFuzzTest is CommonBase { ); vm.prank(broadcaster); - uint256 _createTxId = roleBlox.roleConfigBatchRequestAndApprove(createMetaTx); + uint256 _createTxId = accountBlox.roleConfigBatchRequestAndApprove(createMetaTx); vm.prank(broadcaster); - EngineBlox.TxRecord memory createTxRecord = roleBlox.getTransaction(_createTxId); + EngineBlox.TxRecord memory createTxRecord = accountBlox.getTransaction(_createTxId); // If role creation failed (e.g., MaxRolesExceeded), skip adding wallet if (createTxRecord.status == EngineBlox.TxStatus.FAILED) { @@ -280,9 +275,9 @@ contract ComprehensiveGasExhaustionFuzzTest is CommonBase { ); vm.prank(broadcaster); - uint256 _addTxId = roleBlox.roleConfigBatchRequestAndApprove(addMetaTx); + uint256 _addTxId = accountBlox.roleConfigBatchRequestAndApprove(addMetaTx); vm.prank(broadcaster); - EngineBlox.TxRecord memory addTxRecord = roleBlox.getTransaction(_addTxId); + EngineBlox.TxRecord memory addTxRecord = accountBlox.getTransaction(_addTxId); // If wallet addition succeeded, count it if (addTxRecord.status == EngineBlox.TxStatus.COMPLETED) { @@ -556,9 +551,9 @@ contract ComprehensiveGasExhaustionFuzzTest is CommonBase { // Note: In Foundry tests, gasleft() measurement can be inaccurate for external calls // We'll use a simpler approach - just verify the operation completes or fails gracefully vm.prank(broadcaster); - uint256 _txId = roleBlox.roleConfigBatchRequestAndApprove(metaTx); + uint256 _txId = accountBlox.roleConfigBatchRequestAndApprove(metaTx); vm.prank(broadcaster); - EngineBlox.TxRecord memory txRecord = roleBlox.getTransaction(_txId); + EngineBlox.TxRecord memory txRecord = accountBlox.getTransaction(_txId); // Verify batch completes or fails gracefully assertTrue( @@ -622,9 +617,9 @@ contract ComprehensiveGasExhaustionFuzzTest is CommonBase { // Should fail with BatchSizeExceeded error vm.prank(broadcaster); - uint256 _txId = roleBlox.roleConfigBatchRequestAndApprove(metaTx); + uint256 _txId = accountBlox.roleConfigBatchRequestAndApprove(metaTx); vm.prank(broadcaster); - EngineBlox.TxRecord memory txRecord = roleBlox.getTransaction(_txId); + EngineBlox.TxRecord memory txRecord = accountBlox.getTransaction(_txId); assertEq(uint8(txRecord.status), uint8(EngineBlox.TxStatus.FAILED)); bytes memory expectedError = abi.encodeWithSelector( @@ -881,9 +876,9 @@ contract ComprehensiveGasExhaustionFuzzTest is CommonBase { ); vm.prank(broadcaster); - uint256 _txId = roleBlox.roleConfigBatchRequestAndApprove(metaTx); + uint256 _txId = accountBlox.roleConfigBatchRequestAndApprove(metaTx); vm.prank(broadcaster); - EngineBlox.TxRecord memory txRecord = roleBlox.getTransaction(_txId); + EngineBlox.TxRecord memory txRecord = accountBlox.getTransaction(_txId); // Count successfully created roles if (txRecord.status == EngineBlox.TxStatus.COMPLETED) { @@ -1051,9 +1046,9 @@ contract ComprehensiveGasExhaustionFuzzTest is CommonBase { ); vm.prank(broadcaster); - uint256 _txId = roleBlox.roleConfigBatchRequestAndApprove(metaTx); + uint256 _txId = accountBlox.roleConfigBatchRequestAndApprove(metaTx); vm.prank(broadcaster); - EngineBlox.TxRecord memory txRecord = roleBlox.getTransaction(_txId); + EngineBlox.TxRecord memory txRecord = accountBlox.getTransaction(_txId); assertEq(uint8(txRecord.status), uint8(EngineBlox.TxStatus.FAILED)); bytes memory expectedError = abi.encodeWithSelector( @@ -1176,9 +1171,9 @@ contract ComprehensiveGasExhaustionFuzzTest is CommonBase { // Note: Gas measurement using gasleft() can be inaccurate for external calls in Foundry // Gas consumption is measured by Foundry's gas reporting system vm.prank(broadcaster); - uint256 _txId = roleBlox.roleConfigBatchRequestAndApprove(metaTx); + uint256 _txId = accountBlox.roleConfigBatchRequestAndApprove(metaTx); vm.prank(broadcaster); - EngineBlox.TxRecord memory txRecord = roleBlox.getTransaction(_txId); + EngineBlox.TxRecord memory txRecord = accountBlox.getTransaction(_txId); // Verify operation completes or fails gracefully assertTrue( @@ -1234,9 +1229,9 @@ contract ComprehensiveGasExhaustionFuzzTest is CommonBase { ); vm.prank(broadcaster); - uint256 _txId = roleBlox.roleConfigBatchRequestAndApprove(metaTx); + uint256 _txId = accountBlox.roleConfigBatchRequestAndApprove(metaTx); vm.prank(broadcaster); - EngineBlox.TxRecord memory txRecord = roleBlox.getTransaction(_txId); + EngineBlox.TxRecord memory txRecord = accountBlox.getTransaction(_txId); success = txRecord.status == EngineBlox.TxStatus.COMPLETED; } @@ -1260,9 +1255,9 @@ contract ComprehensiveGasExhaustionFuzzTest is CommonBase { ); vm.prank(broadcaster); - uint256 _txId = roleBlox.roleConfigBatchRequestAndApprove(metaTx); + uint256 _txId = accountBlox.roleConfigBatchRequestAndApprove(metaTx); vm.prank(broadcaster); - EngineBlox.TxRecord memory txRecord = roleBlox.getTransaction(_txId); + EngineBlox.TxRecord memory txRecord = accountBlox.getTransaction(_txId); success = txRecord.status == EngineBlox.TxStatus.COMPLETED; } @@ -1298,9 +1293,9 @@ contract ComprehensiveGasExhaustionFuzzTest is CommonBase { ); vm.prank(broadcaster); - uint256 _txId = roleBlox.roleConfigBatchRequestAndApprove(metaTx); + uint256 _txId = accountBlox.roleConfigBatchRequestAndApprove(metaTx); vm.prank(broadcaster); - EngineBlox.TxRecord memory txRecord = roleBlox.getTransaction(_txId); + EngineBlox.TxRecord memory txRecord = accountBlox.getTransaction(_txId); success = txRecord.status == EngineBlox.TxStatus.COMPLETED; } @@ -1412,15 +1407,15 @@ contract ComprehensiveGasExhaustionFuzzTest is CommonBase { /** * @dev Helper to create meta-transaction for role config - * Note: Uses roleBlox (not accountBlox) since role config operations are executed on roleBlox + * Note: Uses accountBlox for role config operations. */ function _createMetaTxForRoleConfig( address signer, bytes memory executionParams, uint256 deadline ) internal view returns (EngineBlox.MetaTransaction memory) { - EngineBlox.MetaTxParams memory metaTxParams = roleBlox.createMetaTxParams( - address(roleBlox), + EngineBlox.MetaTxParams memory metaTxParams = accountBlox.createMetaTxParams( + address(accountBlox), ROLE_CONFIG_BATCH_META_SELECTOR, EngineBlox.TxAction.SIGN_META_REQUEST_AND_APPROVE, deadline, @@ -1428,9 +1423,9 @@ contract ComprehensiveGasExhaustionFuzzTest is CommonBase { signer ); - EngineBlox.MetaTransaction memory metaTx = roleBlox.generateUnsignedMetaTransactionForNew( + EngineBlox.MetaTransaction memory metaTx = accountBlox.generateUnsignedMetaTransactionForNew( signer, - address(roleBlox), + address(accountBlox), 0, 0, RuntimeRBACDefinitions.ROLE_CONFIG_BATCH, diff --git a/test/foundry/fuzz/ComprehensiveHookSystemFuzz.t.sol b/test/foundry/fuzz/ComprehensiveHookSystemFuzz.t.sol index 3fdf17e9..da04e836 100644 --- a/test/foundry/fuzz/ComprehensiveHookSystemFuzz.t.sol +++ b/test/foundry/fuzz/ComprehensiveHookSystemFuzz.t.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: MPL-2.0 pragma solidity 0.8.34; import "../CommonBase.sol"; diff --git a/test/foundry/fuzz/ComprehensiveInitializationFuzz.t.sol b/test/foundry/fuzz/ComprehensiveInitializationFuzz.t.sol index aa9f74c4..5e4369e2 100644 --- a/test/foundry/fuzz/ComprehensiveInitializationFuzz.t.sol +++ b/test/foundry/fuzz/ComprehensiveInitializationFuzz.t.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: MPL-2.0 pragma solidity 0.8.34; import "../CommonBase.sol"; diff --git a/test/foundry/fuzz/ComprehensiveInputValidationFuzz.t.sol b/test/foundry/fuzz/ComprehensiveInputValidationFuzz.t.sol index 5adba0eb..fdf40305 100644 --- a/test/foundry/fuzz/ComprehensiveInputValidationFuzz.t.sol +++ b/test/foundry/fuzz/ComprehensiveInputValidationFuzz.t.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: MPL-2.0 pragma solidity 0.8.34; import "../CommonBase.sol"; @@ -88,7 +88,7 @@ contract ComprehensiveInputValidationFuzzTest is CommonBase { ); vm.prank(broadcaster); - roleBlox.roleConfigBatchRequestAndApprove(createMetaTx); + accountBlox.roleConfigBatchRequestAndApprove(createMetaTx); // Attempt to add zero address to role IRuntimeRBAC.RoleConfigAction[] memory addActions = new IRuntimeRBAC.RoleConfigAction[](1); @@ -105,9 +105,9 @@ contract ComprehensiveInputValidationFuzzTest is CommonBase { ); vm.prank(broadcaster); - uint256 _txId = roleBlox.roleConfigBatchRequestAndApprove(addMetaTx); + uint256 _txId = accountBlox.roleConfigBatchRequestAndApprove(addMetaTx); vm.prank(broadcaster); - EngineBlox.TxRecord memory txRecord = roleBlox.getTransaction(_txId); + EngineBlox.TxRecord memory txRecord = accountBlox.getTransaction(_txId); // Should fail with InvalidAddress assertEq(uint8(txRecord.status), uint8(EngineBlox.TxStatus.FAILED)); @@ -150,9 +150,9 @@ contract ComprehensiveInputValidationFuzzTest is CommonBase { // Execute - should handle large arrays vm.prank(broadcaster); - uint256 _txId = roleBlox.roleConfigBatchRequestAndApprove(metaTx); + uint256 _txId = accountBlox.roleConfigBatchRequestAndApprove(metaTx); vm.prank(broadcaster); - EngineBlox.TxRecord memory txRecord = roleBlox.getTransaction(_txId); + EngineBlox.TxRecord memory txRecord = accountBlox.getTransaction(_txId); // Transaction should either complete or fail gracefully assertTrue( @@ -175,7 +175,7 @@ contract ComprehensiveInputValidationFuzzTest is CommonBase { ) public { // Try to get role wallets - may fail if role doesn't exist vm.prank(owner); - try roleBlox.getWalletsInRole(roleHash) returns (address[] memory wallets) { + try accountBlox.getWalletsInRole(roleHash) returns (address[] memory wallets) { uint256 walletCount = wallets.length; if (walletCount > 0) { @@ -210,9 +210,9 @@ contract ComprehensiveInputValidationFuzzTest is CommonBase { // Execute empty batch - should succeed (no-op) vm.prank(broadcaster); - uint256 _txId = roleBlox.roleConfigBatchRequestAndApprove(metaTx); + uint256 _txId = accountBlox.roleConfigBatchRequestAndApprove(metaTx); vm.prank(broadcaster); - EngineBlox.TxRecord memory txRecord = roleBlox.getTransaction(_txId); + EngineBlox.TxRecord memory txRecord = accountBlox.getTransaction(_txId); // Empty batch should complete (no operations to perform) assertEq(uint8(txRecord.status), uint8(EngineBlox.TxStatus.COMPLETED)); @@ -275,9 +275,9 @@ contract ComprehensiveInputValidationFuzzTest is CommonBase { ); vm.prank(broadcaster); - uint256 _txId = roleBlox.roleConfigBatchRequestAndApprove(metaTx); + uint256 _txId = accountBlox.roleConfigBatchRequestAndApprove(metaTx); vm.prank(broadcaster); - EngineBlox.TxRecord memory txRecord = roleBlox.getTransaction(_txId); + EngineBlox.TxRecord memory txRecord = accountBlox.getTransaction(_txId); // Should handle various name lengths assertTrue( @@ -486,9 +486,9 @@ contract ComprehensiveInputValidationFuzzTest is CommonBase { ); vm.prank(broadcaster); - uint256 _txId = roleBlox.roleConfigBatchRequestAndApprove(metaTx); + uint256 _txId = accountBlox.roleConfigBatchRequestAndApprove(metaTx); vm.prank(broadcaster); - EngineBlox.TxRecord memory txRecord = roleBlox.getTransaction(_txId); + EngineBlox.TxRecord memory txRecord = accountBlox.getTransaction(_txId); // Should fail with MaxWalletsZero assertEq(uint8(txRecord.status), uint8(EngineBlox.TxStatus.FAILED)); @@ -507,8 +507,8 @@ contract ComprehensiveInputValidationFuzzTest is CommonBase { bytes memory executionParams, uint256 deadline ) internal returns (EngineBlox.MetaTransaction memory) { - EngineBlox.MetaTxParams memory metaTxParams = roleBlox.createMetaTxParams( - address(roleBlox), + EngineBlox.MetaTxParams memory metaTxParams = accountBlox.createMetaTxParams( + address(accountBlox), ROLE_CONFIG_BATCH_META_SELECTOR, EngineBlox.TxAction.SIGN_META_REQUEST_AND_APPROVE, deadline, @@ -516,9 +516,9 @@ contract ComprehensiveInputValidationFuzzTest is CommonBase { signer ); - EngineBlox.MetaTransaction memory metaTx = roleBlox.generateUnsignedMetaTransactionForNew( + EngineBlox.MetaTransaction memory metaTx = accountBlox.generateUnsignedMetaTransactionForNew( signer, - address(roleBlox), + address(accountBlox), 0, 0, ROLE_CONFIG_BATCH_OPERATION_TYPE, diff --git a/test/foundry/fuzz/ComprehensiveMetaTransactionFuzz.t.sol b/test/foundry/fuzz/ComprehensiveMetaTransactionFuzz.t.sol index 22e16e94..cf5fa0c5 100644 --- a/test/foundry/fuzz/ComprehensiveMetaTransactionFuzz.t.sol +++ b/test/foundry/fuzz/ComprehensiveMetaTransactionFuzz.t.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: MPL-2.0 pragma solidity 0.8.34; import "../CommonBase.sol"; @@ -57,8 +57,8 @@ contract ComprehensiveMetaTransactionFuzzTest is CommonBase { bytes memory executionParams = RuntimeRBACDefinitions.roleConfigBatchExecutionParams(abi.encode(actions)); // Create meta-transaction with wrong chainId - EngineBlox.MetaTxParams memory metaTxParams = roleBlox.createMetaTxParams( - address(roleBlox), + EngineBlox.MetaTxParams memory metaTxParams = accountBlox.createMetaTxParams( + address(accountBlox), ROLE_CONFIG_BATCH_META_SELECTOR, EngineBlox.TxAction.SIGN_META_REQUEST_AND_APPROVE, 1 hours, @@ -78,9 +78,9 @@ contract ComprehensiveMetaTransactionFuzzTest is CommonBase { block.chainid ) ); - roleBlox.generateUnsignedMetaTransactionForNew( + accountBlox.generateUnsignedMetaTransactionForNew( owner, - address(roleBlox), + address(accountBlox), 0, 0, ROLE_CONFIG_BATCH_OPERATION_TYPE, @@ -98,7 +98,7 @@ contract ComprehensiveMetaTransactionFuzzTest is CommonBase { uint256 wrongNonce ) public { vm.prank(owner); - uint256 actualNonce = roleBlox.getSignerNonce(owner); + uint256 actualNonce = accountBlox.getSignerNonce(owner); vm.assume(wrongNonce != actualNonce); // Create valid action @@ -112,8 +112,8 @@ contract ComprehensiveMetaTransactionFuzzTest is CommonBase { bytes memory executionParams = RuntimeRBACDefinitions.roleConfigBatchExecutionParams(abi.encode(actions)); // Create meta-transaction (will get current nonce during generation) - EngineBlox.MetaTxParams memory metaTxParams = roleBlox.createMetaTxParams( - address(roleBlox), + EngineBlox.MetaTxParams memory metaTxParams = accountBlox.createMetaTxParams( + address(accountBlox), ROLE_CONFIG_BATCH_META_SELECTOR, EngineBlox.TxAction.SIGN_META_REQUEST_AND_APPROVE, 1 hours, @@ -122,9 +122,9 @@ contract ComprehensiveMetaTransactionFuzzTest is CommonBase { ); // Generate meta-transaction (nonce will be set to current nonce) - EngineBlox.MetaTransaction memory metaTx = roleBlox.generateUnsignedMetaTransactionForNew( + EngineBlox.MetaTransaction memory metaTx = accountBlox.generateUnsignedMetaTransactionForNew( owner, - address(roleBlox), + address(accountBlox), 0, 0, ROLE_CONFIG_BATCH_OPERATION_TYPE, @@ -137,7 +137,7 @@ contract ComprehensiveMetaTransactionFuzzTest is CommonBase { metaTx.params.nonce = wrongNonce; // Re-generate message hash with wrong nonce - metaTx.message = metaTxSigner.generateMessageHash(metaTx, address(roleBlox)); + metaTx.message = metaTxSigner.generateMessageHash(metaTx, address(accountBlox)); // Sign with wrong nonce uint256 signerPrivateKey = _getPrivateKeyForAddress(owner); @@ -155,7 +155,7 @@ contract ComprehensiveMetaTransactionFuzzTest is CommonBase { actualNonce ) ); - roleBlox.roleConfigBatchRequestAndApprove(metaTx); + accountBlox.roleConfigBatchRequestAndApprove(metaTx); // Test verifies nonce replay is prevented โœ… } @@ -169,7 +169,7 @@ contract ComprehensiveMetaTransactionFuzzTest is CommonBase { */ function testFuzz_NonceIncrementsBeforeExecution() public { vm.prank(owner); - uint256 initialNonce = roleBlox.getSignerNonce(owner); + uint256 initialNonce = accountBlox.getSignerNonce(owner); // Create and execute valid meta-transaction IRuntimeRBAC.RoleConfigAction[] memory actions = new IRuntimeRBAC.RoleConfigAction[](1); @@ -191,22 +191,22 @@ contract ComprehensiveMetaTransactionFuzzTest is CommonBase { // Execute transaction vm.prank(broadcaster); - uint256 _txId1 = roleBlox.roleConfigBatchRequestAndApprove(metaTx); + uint256 _txId1 = accountBlox.roleConfigBatchRequestAndApprove(metaTx); vm.prank(broadcaster); - EngineBlox.TxRecord memory txRecord1 = roleBlox.getTransaction(_txId1); + EngineBlox.TxRecord memory txRecord1 = accountBlox.getTransaction(_txId1); // Transaction should succeed assertEq(uint8(txRecord1.status), uint8(EngineBlox.TxStatus.COMPLETED), "Transaction should succeed"); // CRITICAL: Verify nonce incremented immediately after execution vm.prank(owner); - uint256 newNonce = roleBlox.getSignerNonce(owner); + uint256 newNonce = accountBlox.getSignerNonce(owner); assertEq(newNonce, initialNonce + 1, "Nonce should increment after execution"); // Attempt to replay with old nonce - should fail // Create new meta-transaction (will get new txId and current nonce) - EngineBlox.MetaTxParams memory replayParams = roleBlox.createMetaTxParams( - address(roleBlox), + EngineBlox.MetaTxParams memory replayParams = accountBlox.createMetaTxParams( + address(accountBlox), ROLE_CONFIG_BATCH_META_SELECTOR, EngineBlox.TxAction.SIGN_META_REQUEST_AND_APPROVE, 1 hours, @@ -214,9 +214,9 @@ contract ComprehensiveMetaTransactionFuzzTest is CommonBase { owner ); - EngineBlox.MetaTransaction memory replayMetaTx = roleBlox.generateUnsignedMetaTransactionForNew( + EngineBlox.MetaTransaction memory replayMetaTx = accountBlox.generateUnsignedMetaTransactionForNew( owner, - address(roleBlox), + address(accountBlox), 0, 0, ROLE_CONFIG_BATCH_OPERATION_TYPE, @@ -229,7 +229,7 @@ contract ComprehensiveMetaTransactionFuzzTest is CommonBase { replayMetaTx.params.nonce = initialNonce; // Use old nonce // Re-generate message hash with old nonce using the helper - replayMetaTx.message = metaTxSigner.generateMessageHash(replayMetaTx, address(roleBlox)); + replayMetaTx.message = metaTxSigner.generateMessageHash(replayMetaTx, address(accountBlox)); uint256 signerPrivateKey = _getPrivateKeyForAddress(owner); bytes32 replayEthSignedMessageHash = MessageHashUtils.toEthSignedMessageHash(replayMetaTx.message); @@ -246,7 +246,7 @@ contract ComprehensiveMetaTransactionFuzzTest is CommonBase { initialNonce + 1 // The current nonce after first execution ) ); - roleBlox.roleConfigBatchRequestAndApprove(replayMetaTx); + accountBlox.roleConfigBatchRequestAndApprove(replayMetaTx); // Test verifies nonce increment timing prevents replay โœ… } @@ -306,7 +306,7 @@ contract ComprehensiveMetaTransactionFuzzTest is CommonBase { vm.prank(broadcaster); // Accept either InvalidSValue or InvalidSignature - both indicate protection works vm.expectRevert(); // Any revert is acceptable - malleable signature is rejected - roleBlox.roleConfigBatchRequestAndApprove(metaTx); + accountBlox.roleConfigBatchRequestAndApprove(metaTx); // Test verifies signature malleability is prevented โœ… } else { @@ -325,8 +325,8 @@ contract ComprehensiveMetaTransactionFuzzTest is CommonBase { function testFuzz_MessageHashManipulationPrevented( uint256 manipulatedValue ) public { - // Use roleBlox as target (it's whitelisted for role config operations) - address manipulatedTarget = address(roleBlox); + // Use accountBlox as target (it's whitelisted for role config operations) + address manipulatedTarget = address(accountBlox); // Create valid meta-transaction IRuntimeRBAC.RoleConfigAction[] memory actions = new IRuntimeRBAC.RoleConfigAction[](1); @@ -347,13 +347,13 @@ contract ComprehensiveMetaTransactionFuzzTest is CommonBase { bytes memory originalSignature = metaTx.signature; // Manipulate transaction parameters after signing - // Since target is already roleBlox, we'll manipulate value instead + // Since target is already accountBlox, we'll manipulate value instead uint256 originalValue = metaTx.txRecord.params.value; uint256 newValue = manipulatedValue != originalValue ? manipulatedValue : originalValue + 1; // Create new meta-transaction with manipulated value EngineBlox.MetaTxParams memory manipulatedParams = metaTx.params; - EngineBlox.MetaTransaction memory manipulatedMetaTx = roleBlox.generateUnsignedMetaTransactionForNew( + EngineBlox.MetaTransaction memory manipulatedMetaTx = accountBlox.generateUnsignedMetaTransactionForNew( owner, manipulatedTarget, newValue, // Changed value @@ -378,7 +378,7 @@ contract ComprehensiveMetaTransactionFuzzTest is CommonBase { originalSignature ) ); - roleBlox.roleConfigBatchRequestAndApprove(metaTx); + accountBlox.roleConfigBatchRequestAndApprove(metaTx); // Test verifies message hash manipulation is prevented โœ… } @@ -405,8 +405,8 @@ contract ComprehensiveMetaTransactionFuzzTest is CommonBase { bytes memory executionParams = RuntimeRBACDefinitions.roleConfigBatchExecutionParams(abi.encode(actions)); // Create meta-transaction with expired deadline - EngineBlox.MetaTxParams memory metaTxParams = roleBlox.createMetaTxParams( - address(roleBlox), + EngineBlox.MetaTxParams memory metaTxParams = accountBlox.createMetaTxParams( + address(accountBlox), ROLE_CONFIG_BATCH_META_SELECTOR, EngineBlox.TxAction.SIGN_META_REQUEST_AND_APPROVE, deadline, // Expired deadline (in past) @@ -429,9 +429,9 @@ contract ComprehensiveMetaTransactionFuzzTest is CommonBase { block.timestamp ) ); - roleBlox.generateUnsignedMetaTransactionForNew( + accountBlox.generateUnsignedMetaTransactionForNew( owner, - address(roleBlox), + address(accountBlox), 0, 0, ROLE_CONFIG_BATCH_OPERATION_TYPE, @@ -467,8 +467,8 @@ contract ComprehensiveMetaTransactionFuzzTest is CommonBase { bytes memory executionParams = RuntimeRBACDefinitions.roleConfigBatchExecutionParams(abi.encode(actions)); // Create meta-transaction with very long deadline - EngineBlox.MetaTxParams memory metaTxParams = roleBlox.createMetaTxParams( - address(roleBlox), + EngineBlox.MetaTxParams memory metaTxParams = accountBlox.createMetaTxParams( + address(accountBlox), ROLE_CONFIG_BATCH_META_SELECTOR, EngineBlox.TxAction.SIGN_META_REQUEST_AND_APPROVE, deadline, @@ -476,9 +476,9 @@ contract ComprehensiveMetaTransactionFuzzTest is CommonBase { owner ); - EngineBlox.MetaTransaction memory metaTx = roleBlox.generateUnsignedMetaTransactionForNew( + EngineBlox.MetaTransaction memory metaTx = accountBlox.generateUnsignedMetaTransactionForNew( owner, - address(roleBlox), + address(accountBlox), 0, 0, ROLE_CONFIG_BATCH_OPERATION_TYPE, @@ -495,9 +495,9 @@ contract ComprehensiveMetaTransactionFuzzTest is CommonBase { // Very long deadline should be allowed (signature still requires permissions) vm.prank(broadcaster); - uint256 _txId = roleBlox.roleConfigBatchRequestAndApprove(metaTx); + uint256 _txId = accountBlox.roleConfigBatchRequestAndApprove(metaTx); vm.prank(broadcaster); - EngineBlox.TxRecord memory txRecord = roleBlox.getTransaction(_txId); + EngineBlox.TxRecord memory txRecord = accountBlox.getTransaction(_txId); // Transaction should succeed if permissions are correct // The key is that long deadline doesn't bypass permission checks @@ -534,8 +534,8 @@ contract ComprehensiveMetaTransactionFuzzTest is CommonBase { bytes memory executionParams = RuntimeRBACDefinitions.roleConfigBatchExecutionParams(abi.encode(actions)); - EngineBlox.MetaTxParams memory metaTxParams = roleBlox.createMetaTxParams( - address(roleBlox), + EngineBlox.MetaTxParams memory metaTxParams = accountBlox.createMetaTxParams( + address(accountBlox), ROLE_CONFIG_BATCH_META_SELECTOR, EngineBlox.TxAction.SIGN_META_REQUEST_AND_APPROVE, 1 hours, @@ -543,9 +543,9 @@ contract ComprehensiveMetaTransactionFuzzTest is CommonBase { owner ); - EngineBlox.MetaTransaction memory metaTx = roleBlox.generateUnsignedMetaTransactionForNew( + EngineBlox.MetaTransaction memory metaTx = accountBlox.generateUnsignedMetaTransactionForNew( owner, - address(roleBlox), + address(accountBlox), 0, 0, ROLE_CONFIG_BATCH_OPERATION_TYPE, @@ -572,7 +572,7 @@ contract ComprehensiveMetaTransactionFuzzTest is CommonBase { maxGasPrice ) ); - roleBlox.roleConfigBatchRequestAndApprove(metaTx); + accountBlox.roleConfigBatchRequestAndApprove(metaTx); // Test verifies gas price limits are enforced โœ… } @@ -586,7 +586,7 @@ contract ComprehensiveMetaTransactionFuzzTest is CommonBase { */ function testFuzz_ConcurrentNonceUsagePrevented() public { vm.prank(owner); - uint256 currentNonce = roleBlox.getSignerNonce(owner); + uint256 currentNonce = accountBlox.getSignerNonce(owner); // Create first meta-transaction IRuntimeRBAC.RoleConfigAction[] memory actions1 = new IRuntimeRBAC.RoleConfigAction[](1); @@ -615,8 +615,8 @@ contract ComprehensiveMetaTransactionFuzzTest is CommonBase { bytes memory executionParams2 = RuntimeRBACDefinitions.roleConfigBatchExecutionParams(abi.encode(actions2)); - EngineBlox.MetaTxParams memory metaTxParams2 = roleBlox.createMetaTxParams( - address(roleBlox), + EngineBlox.MetaTxParams memory metaTxParams2 = accountBlox.createMetaTxParams( + address(accountBlox), ROLE_CONFIG_BATCH_META_SELECTOR, EngineBlox.TxAction.SIGN_META_REQUEST_AND_APPROVE, 1 hours, @@ -626,9 +626,9 @@ contract ComprehensiveMetaTransactionFuzzTest is CommonBase { // Override nonce to match first transaction metaTxParams2.nonce = currentNonce; - EngineBlox.MetaTransaction memory metaTx2 = roleBlox.generateUnsignedMetaTransactionForNew( + EngineBlox.MetaTransaction memory metaTx2 = accountBlox.generateUnsignedMetaTransactionForNew( owner, - address(roleBlox), + address(accountBlox), 0, 0, ROLE_CONFIG_BATCH_OPERATION_TYPE, @@ -645,16 +645,16 @@ contract ComprehensiveMetaTransactionFuzzTest is CommonBase { // Execute first transaction vm.prank(broadcaster); - uint256 _txId1 = roleBlox.roleConfigBatchRequestAndApprove(metaTx1); + uint256 _txId1 = accountBlox.roleConfigBatchRequestAndApprove(metaTx1); vm.prank(broadcaster); - EngineBlox.TxRecord memory txRecord1 = roleBlox.getTransaction(_txId1); + EngineBlox.TxRecord memory txRecord1 = accountBlox.getTransaction(_txId1); // First transaction should succeed assertEq(uint8(txRecord1.status), uint8(EngineBlox.TxStatus.COMPLETED), "First transaction should succeed"); // Verify nonce incremented vm.prank(owner); - uint256 newNonce = roleBlox.getSignerNonce(owner); + uint256 newNonce = accountBlox.getSignerNonce(owner); assertEq(newNonce, currentNonce + 1, "Nonce should increment after first transaction"); // Attempt to execute second transaction with same nonce - should fail @@ -667,7 +667,7 @@ contract ComprehensiveMetaTransactionFuzzTest is CommonBase { currentNonce + 1 // The actual nonce after first transaction (1) ) ); - roleBlox.roleConfigBatchRequestAndApprove(metaTx2); + accountBlox.roleConfigBatchRequestAndApprove(metaTx2); // Test verifies concurrent nonce usage is prevented โœ… } @@ -704,7 +704,7 @@ contract ComprehensiveMetaTransactionFuzzTest is CommonBase { 0 ) ); - roleBlox.roleConfigBatchRequestAndApprove(metaTx); + accountBlox.roleConfigBatchRequestAndApprove(metaTx); // Test verifies invalid signature rejection works โœ… } @@ -750,7 +750,7 @@ contract ComprehensiveMetaTransactionFuzzTest is CommonBase { 65 ) ); - roleBlox.roleConfigBatchRequestAndApprove(metaTx); + accountBlox.roleConfigBatchRequestAndApprove(metaTx); // Test verifies signature length validation works โœ… } @@ -765,7 +765,7 @@ contract ComprehensiveMetaTransactionFuzzTest is CommonBase { */ function testFuzz_NonceConsumedEvenOnExecutionFailure() public { vm.prank(owner); - uint256 nonceBefore = roleBlox.getSignerNonce(owner); + uint256 nonceBefore = accountBlox.getSignerNonce(owner); // Meta-tx that will pass verification but fail during execution (ADD_WALLET to protected role) IRuntimeRBAC.RoleConfigAction[] memory actions = new IRuntimeRBAC.RoleConfigAction[](1); @@ -778,13 +778,13 @@ contract ComprehensiveMetaTransactionFuzzTest is CommonBase { // Execute: signature valid, but batch execution fails (CannotModifyProtected) vm.prank(broadcaster); - uint256 txId = roleBlox.roleConfigBatchRequestAndApprove(metaTx); + uint256 txId = accountBlox.roleConfigBatchRequestAndApprove(metaTx); vm.prank(broadcaster); - EngineBlox.TxRecord memory txRecord = roleBlox.getTransaction(txId); + EngineBlox.TxRecord memory txRecord = accountBlox.getTransaction(txId); assertEq(uint8(txRecord.status), uint8(EngineBlox.TxStatus.FAILED), "Execution should fail"); vm.prank(owner); - uint256 nonceAfter = roleBlox.getSignerNonce(owner); + uint256 nonceAfter = accountBlox.getSignerNonce(owner); assertEq(nonceAfter, nonceBefore + 1, "Nonce must be consumed even when execution fails"); // Replay same meta-tx: must revert with InvalidNonce (replay prevented) @@ -792,7 +792,7 @@ contract ComprehensiveMetaTransactionFuzzTest is CommonBase { vm.expectRevert( abi.encodeWithSelector(SharedValidation.InvalidNonce.selector, nonceBefore, nonceAfter) ); - roleBlox.roleConfigBatchRequestAndApprove(metaTx); + accountBlox.roleConfigBatchRequestAndApprove(metaTx); } /** @@ -805,8 +805,8 @@ contract ComprehensiveMetaTransactionFuzzTest is CommonBase { vm.assume(chainIdA < type(uint256).max / 2); vm.assume(chainIdB < type(uint256).max / 2); - EngineBlox.MetaTxParams memory p = roleBlox.createMetaTxParams( - address(roleBlox), + EngineBlox.MetaTxParams memory p = accountBlox.createMetaTxParams( + address(accountBlox), ROLE_CONFIG_BATCH_META_SELECTOR, EngineBlox.TxAction.SIGN_META_REQUEST_AND_APPROVE, 1 hours, @@ -818,17 +818,17 @@ contract ComprehensiveMetaTransactionFuzzTest is CommonBase { metaTxA.params = p; metaTxA.txRecord.txId = 1; metaTxA.txRecord.params.requester = owner; - metaTxA.txRecord.params.target = address(roleBlox); + metaTxA.txRecord.params.target = address(accountBlox); metaTxA.txRecord.params.value = 0; metaTxA.txRecord.params.gasLimit = 0; metaTxA.txRecord.params.operationType = ROLE_CONFIG_BATCH_OPERATION_TYPE; metaTxA.txRecord.params.executionSelector = ROLE_CONFIG_BATCH_EXECUTE_SELECTOR; metaTxA.txRecord.params.executionParams = ""; - bytes32 hashA = metaTxSigner.generateMessageHash(metaTxA, address(roleBlox)); + bytes32 hashA = metaTxSigner.generateMessageHash(metaTxA, address(accountBlox)); p.chainId = chainIdB; metaTxA.params = p; - bytes32 hashB = metaTxSigner.generateMessageHash(metaTxA, address(roleBlox)); + bytes32 hashB = metaTxSigner.generateMessageHash(metaTxA, address(accountBlox)); assertTrue(hashA != hashB, "Message hash must depend on chainId"); } @@ -843,8 +843,8 @@ contract ComprehensiveMetaTransactionFuzzTest is CommonBase { uint256 nonce2 ) public { vm.assume(txId1 != txId2 || nonce1 != nonce2); - EngineBlox.MetaTxParams memory p = roleBlox.createMetaTxParams( - address(roleBlox), + EngineBlox.MetaTxParams memory p = accountBlox.createMetaTxParams( + address(accountBlox), ROLE_CONFIG_BATCH_META_SELECTOR, EngineBlox.TxAction.SIGN_META_REQUEST_AND_APPROVE, 1 hours, @@ -856,7 +856,7 @@ contract ComprehensiveMetaTransactionFuzzTest is CommonBase { m1.params = p; m1.txRecord.txId = txId1; m1.txRecord.params.requester = owner; - m1.txRecord.params.target = address(roleBlox); + m1.txRecord.params.target = address(accountBlox); m1.txRecord.params.operationType = ROLE_CONFIG_BATCH_OPERATION_TYPE; m1.txRecord.params.executionSelector = ROLE_CONFIG_BATCH_EXECUTE_SELECTOR; @@ -865,12 +865,12 @@ contract ComprehensiveMetaTransactionFuzzTest is CommonBase { m2.params = p; m2.txRecord.txId = txId2; m2.txRecord.params.requester = owner; - m2.txRecord.params.target = address(roleBlox); + m2.txRecord.params.target = address(accountBlox); m2.txRecord.params.operationType = ROLE_CONFIG_BATCH_OPERATION_TYPE; m2.txRecord.params.executionSelector = ROLE_CONFIG_BATCH_EXECUTE_SELECTOR; - bytes32 h1 = metaTxSigner.generateMessageHash(m1, address(roleBlox)); - bytes32 h2 = metaTxSigner.generateMessageHash(m2, address(roleBlox)); + bytes32 h1 = metaTxSigner.generateMessageHash(m1, address(accountBlox)); + bytes32 h2 = metaTxSigner.generateMessageHash(m2, address(accountBlox)); // Require both txId and nonce to differ so the structs differ in multiple hashed fields if (txId1 != txId2 && nonce1 != nonce2) { assertTrue(h1 != h2, "Distinct structs must not collide"); @@ -884,8 +884,8 @@ contract ComprehensiveMetaTransactionFuzzTest is CommonBase { bytes memory executionParams, uint256 deadline ) internal returns (EngineBlox.MetaTransaction memory) { - EngineBlox.MetaTxParams memory metaTxParams = roleBlox.createMetaTxParams( - address(roleBlox), + EngineBlox.MetaTxParams memory metaTxParams = accountBlox.createMetaTxParams( + address(accountBlox), ROLE_CONFIG_BATCH_META_SELECTOR, EngineBlox.TxAction.SIGN_META_REQUEST_AND_APPROVE, deadline, @@ -893,9 +893,9 @@ contract ComprehensiveMetaTransactionFuzzTest is CommonBase { signer ); - EngineBlox.MetaTransaction memory metaTx = roleBlox.generateUnsignedMetaTransactionForNew( + EngineBlox.MetaTransaction memory metaTx = accountBlox.generateUnsignedMetaTransactionForNew( signer, - address(roleBlox), + address(accountBlox), 0, 0, ROLE_CONFIG_BATCH_OPERATION_TYPE, diff --git a/test/foundry/fuzz/ComprehensivePaymentSecurityFuzz.t.sol b/test/foundry/fuzz/ComprehensivePaymentSecurityFuzz.t.sol index 92938920..f7a83a62 100644 --- a/test/foundry/fuzz/ComprehensivePaymentSecurityFuzz.t.sol +++ b/test/foundry/fuzz/ComprehensivePaymentSecurityFuzz.t.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: MPL-2.0 pragma solidity 0.8.34; import "../CommonBase.sol"; diff --git a/test/foundry/fuzz/ComprehensiveSecurityEdgeCasesFuzz.t.sol b/test/foundry/fuzz/ComprehensiveSecurityEdgeCasesFuzz.t.sol index 926a7c92..a1343b0d 100644 --- a/test/foundry/fuzz/ComprehensiveSecurityEdgeCasesFuzz.t.sol +++ b/test/foundry/fuzz/ComprehensiveSecurityEdgeCasesFuzz.t.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: MPL-2.0 pragma solidity 0.8.34; import "../CommonBase.sol"; @@ -9,7 +9,7 @@ import "../../../contracts/core/access/RuntimeRBAC.sol"; import "../../../contracts/core/access/lib/definitions/RuntimeRBACDefinitions.sol"; import "../../../contracts/core/lib/utils/SharedValidation.sol"; import "../../../contracts/standards/hooks/IOnActionHook.sol"; -import "../../../contracts/examples/templates/MachineBlox.sol"; +import "../helpers/HookTestBlox.sol"; import "../helpers/MockContracts.sol"; import "../helpers/PaymentTestHelper.sol"; import "../helpers/TestHelpers.sol"; @@ -36,7 +36,7 @@ contract ComprehensiveSecurityEdgeCasesFuzzTest is CommonBase { using TestHelpers for *; PaymentTestHelper public paymentHelper; - MachineBlox public machineBlox; + HookTestBlox public hookTestBlox; bytes4 public constant ROLE_CONFIG_BATCH_META_SELECTOR = RuntimeRBACDefinitions.ROLE_CONFIG_BATCH_META_SELECTOR; bytes4 public constant ROLE_CONFIG_BATCH_EXECUTE_SELECTOR = RuntimeRBACDefinitions.ROLE_CONFIG_BATCH_EXECUTE_SELECTOR; @@ -57,17 +57,17 @@ contract ComprehensiveSecurityEdgeCasesFuzzTest is CommonBase { ); vm.deal(address(paymentHelper), 1000 ether); - // Deploy MachineBlox for hook testing - machineBlox = new MachineBlox(); + // Deploy HookTestBlox for hook testing + hookTestBlox = new HookTestBlox(); vm.prank(owner); - machineBlox.initialize( + hookTestBlox.initialize( owner, broadcaster, recovery, DEFAULT_TIMELOCK_PERIOD, address(0) ); - vm.deal(address(machineBlox), 1000 ether); + vm.deal(address(hookTestBlox), 1000 ether); // Hook contracts are created as needed in individual tests } @@ -191,7 +191,7 @@ contract ComprehensiveSecurityEdgeCasesFuzzTest is CommonBase { ); vm.prank(broadcaster); - try roleBlox.roleConfigBatchRequestAndApprove(metaTx) { + try accountBlox.roleConfigBatchRequestAndApprove(metaTx) { // Role created successfully } catch { // Role might already exist or other error, continue @@ -228,9 +228,9 @@ contract ComprehensiveSecurityEdgeCasesFuzzTest is CommonBase { // This should fail - empty bitmap should be rejected vm.prank(broadcaster); - uint256 _txId = roleBlox.roleConfigBatchRequestAndApprove(addMetaTx); + uint256 _txId = accountBlox.roleConfigBatchRequestAndApprove(addMetaTx); vm.prank(broadcaster); - EngineBlox.TxRecord memory result = roleBlox.getTransaction(_txId); + EngineBlox.TxRecord memory result = accountBlox.getTransaction(_txId); // Should fail with empty bitmap error assertEq(uint8(result.status), uint8(EngineBlox.TxStatus.FAILED), "Should fail with empty bitmap"); @@ -244,8 +244,8 @@ contract ComprehensiveSecurityEdgeCasesFuzzTest is CommonBase { bytes memory executionParams, uint256 deadline ) internal returns (EngineBlox.MetaTransaction memory) { - EngineBlox.MetaTxParams memory metaTxParams = roleBlox.createMetaTxParams( - address(roleBlox), + EngineBlox.MetaTxParams memory metaTxParams = accountBlox.createMetaTxParams( + address(accountBlox), ROLE_CONFIG_BATCH_META_SELECTOR, EngineBlox.TxAction.SIGN_META_REQUEST_AND_APPROVE, deadline, @@ -253,9 +253,9 @@ contract ComprehensiveSecurityEdgeCasesFuzzTest is CommonBase { signer ); - EngineBlox.MetaTransaction memory metaTx = roleBlox.generateUnsignedMetaTransactionForNew( + EngineBlox.MetaTransaction memory metaTx = accountBlox.generateUnsignedMetaTransactionForNew( signer, - address(roleBlox), + address(accountBlox), 0, 0, ROLE_CONFIG_BATCH_OPERATION_TYPE, @@ -309,19 +309,19 @@ contract ComprehensiveSecurityEdgeCasesFuzzTest is CommonBase { } // Use an existing function selector from GuardController definitions - // This selector is registered during MachineBlox initialization + // This selector is registered during HookTestBlox (Account) initialization bytes4 functionSelector = GuardControllerDefinitions.EXECUTE_WITH_TIMELOCK_SELECTOR; // Set hooks for the function selector // Hooks can be set for any function selector that exists in the schema for (uint8 i = 0; i < numberOfHooks; i++) { vm.prank(owner); - machineBlox.setHook(functionSelector, hooks[i]); + hookTestBlox.setHook(functionSelector, hooks[i]); } // Verify hooks are set in order vm.prank(owner); - address[] memory retrievedHooks = machineBlox.getHooks(functionSelector); + address[] memory retrievedHooks = hookTestBlox.getHooks(functionSelector); assertEq(retrievedHooks.length, numberOfHooks, "All hooks should be set"); // Hook execution order should be deterministic (EnumerableSet iteration order) @@ -345,11 +345,11 @@ contract ComprehensiveSecurityEdgeCasesFuzzTest is CommonBase { // This should be allowed (no compile-time check), but hook execution should fail gracefully NonCompliantHookContract nonCompliantHook = new NonCompliantHookContract(); vm.prank(owner); - machineBlox.setHook(functionSelector, address(nonCompliantHook)); + hookTestBlox.setHook(functionSelector, address(nonCompliantHook)); // Verify hook is set vm.prank(owner); - address[] memory hooks = machineBlox.getHooks(functionSelector); + address[] memory hooks = hookTestBlox.getHooks(functionSelector); assertTrue(hooks.length > 0, "Hook should be set"); // Key security property: Hook failures should not affect core state @@ -379,12 +379,12 @@ contract ComprehensiveSecurityEdgeCasesFuzzTest is CommonBase { for (uint8 i = 0; i < numberOfHooks; i++) { GasIntensiveHookContract gasHook = new GasIntensiveHookContract(); vm.prank(owner); - machineBlox.setHook(functionSelector, address(gasHook)); + hookTestBlox.setHook(functionSelector, address(gasHook)); } // Verify hooks are set vm.prank(owner); - address[] memory hooks = machineBlox.getHooks(functionSelector); + address[] memory hooks = hookTestBlox.getHooks(functionSelector); assertEq(hooks.length, numberOfHooks, "All hooks should be set"); // Key security property: Multiple hooks should not cause gas exhaustion @@ -406,13 +406,13 @@ contract ComprehensiveSecurityEdgeCasesFuzzTest is CommonBase { bytes4 functionSelector = GuardControllerDefinitions.EXECUTE_WITH_TIMELOCK_SELECTOR; // Set up reentrancy hook (hook that attempts to reenter) - ReentrancyHookContract reentrancyHook = new ReentrancyHookContract(address(machineBlox)); + ReentrancyHookContract reentrancyHook = new ReentrancyHookContract(address(hookTestBlox)); vm.prank(owner); - machineBlox.setHook(functionSelector, address(reentrancyHook)); + hookTestBlox.setHook(functionSelector, address(reentrancyHook)); // Verify hook is set vm.prank(owner); - address[] memory hooks = machineBlox.getHooks(functionSelector); + address[] memory hooks = hookTestBlox.getHooks(functionSelector); assertTrue(hooks.length > 0, "Hook should be set"); // Key security property: Hooks should not be able to reenter diff --git a/test/foundry/fuzz/ComprehensiveStateMachineFuzz.t.sol b/test/foundry/fuzz/ComprehensiveStateMachineFuzz.t.sol index af0d86e1..7a253001 100644 --- a/test/foundry/fuzz/ComprehensiveStateMachineFuzz.t.sol +++ b/test/foundry/fuzz/ComprehensiveStateMachineFuzz.t.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: MPL-2.0 pragma solidity 0.8.34; import "../CommonBase.sol"; @@ -765,8 +765,8 @@ contract ComprehensiveStateMachineFuzzTest is CommonBase { bytes memory executionParams = SecureOwnableDefinitions.updateTimeLockExecutionParams(newTimeLockPeriod); // Create meta-transaction for time-lock update - EngineBlox.MetaTxParams memory metaTxParams = secureBlox.createMetaTxParams( - address(secureBlox), + EngineBlox.MetaTxParams memory metaTxParams = accountBlox.createMetaTxParams( + address(accountBlox), SecureOwnableDefinitions.UPDATE_TIMELOCK_META_SELECTOR, EngineBlox.TxAction.SIGN_META_REQUEST_AND_APPROVE, 1 hours, @@ -774,9 +774,9 @@ contract ComprehensiveStateMachineFuzzTest is CommonBase { owner ); - EngineBlox.MetaTransaction memory metaTx = secureBlox.generateUnsignedMetaTransactionForNew( + EngineBlox.MetaTransaction memory metaTx = accountBlox.generateUnsignedMetaTransactionForNew( owner, - address(secureBlox), + address(accountBlox), 0, 0, SecureOwnableDefinitions.TIMELOCK_UPDATE, @@ -794,10 +794,10 @@ contract ComprehensiveStateMachineFuzzTest is CommonBase { // Execute meta-transaction (bypasses time-lock as designed) vm.prank(broadcaster); - secureBlox.updateTimeLockRequestAndApprove(metaTx); + accountBlox.updateTimeLockRequestAndApprove(metaTx); // Verify time-lock updated (meta-transaction executes immediately) - assertEq(secureBlox.getTimeLockPeriodSec(), newTimeLockPeriod); + assertEq(accountBlox.getTimeLockPeriodSec(), newTimeLockPeriod); // Note: Meta-transactions bypass time-lock by design // This is intentional - meta-transactions provide immediate execution diff --git a/test/foundry/fuzz/ComprehensiveWhitelistSchemaFuzz.t.sol b/test/foundry/fuzz/ComprehensiveWhitelistSchemaFuzz.t.sol index a06d931f..e2d6143a 100644 --- a/test/foundry/fuzz/ComprehensiveWhitelistSchemaFuzz.t.sol +++ b/test/foundry/fuzz/ComprehensiveWhitelistSchemaFuzz.t.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: MPL-2.0 pragma solidity 0.8.34; import "../CommonBase.sol"; diff --git a/test/foundry/fuzz/EdgeCasesFuzz.t.sol b/test/foundry/fuzz/EdgeCasesFuzz.t.sol index 58dba32d..e6e9a998 100644 --- a/test/foundry/fuzz/EdgeCasesFuzz.t.sol +++ b/test/foundry/fuzz/EdgeCasesFuzz.t.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: MPL-2.0 pragma solidity 0.8.34; import "../CommonBase.sol"; @@ -63,9 +63,9 @@ contract EdgeCasesFuzzTest is CommonBase { ); vm.prank(broadcaster); - uint256 _txId = roleBlox.roleConfigBatchRequestAndApprove(metaTx); + uint256 _txId = accountBlox.roleConfigBatchRequestAndApprove(metaTx); vm.prank(broadcaster); - EngineBlox.TxRecord memory txRecord = roleBlox.getTransaction(_txId); + EngineBlox.TxRecord memory txRecord = accountBlox.getTransaction(_txId); // Transaction should fail due to protected role modification assertEq(uint8(txRecord.status), uint8(EngineBlox.TxStatus.FAILED), "Transaction should fail"); @@ -93,9 +93,9 @@ contract EdgeCasesFuzzTest is CommonBase { // Empty batch should still execute (no-op) vm.prank(broadcaster); - uint256 _txId = roleBlox.roleConfigBatchRequestAndApprove(metaTx); + uint256 _txId = accountBlox.roleConfigBatchRequestAndApprove(metaTx); vm.prank(broadcaster); - EngineBlox.TxRecord memory txRecord = roleBlox.getTransaction(_txId); + EngineBlox.TxRecord memory txRecord = accountBlox.getTransaction(_txId); assertEq(uint8(txRecord.status), uint8(EngineBlox.TxStatus.COMPLETED)); } @@ -126,16 +126,16 @@ contract EdgeCasesFuzzTest is CommonBase { ); vm.prank(broadcaster); - uint256 _txId = roleBlox.roleConfigBatchRequestAndApprove(metaTx); + uint256 _txId = accountBlox.roleConfigBatchRequestAndApprove(metaTx); vm.prank(broadcaster); - EngineBlox.TxRecord memory txRecord = roleBlox.getTransaction(_txId); + EngineBlox.TxRecord memory txRecord = accountBlox.getTransaction(_txId); assertEq(uint8(txRecord.status), uint8(EngineBlox.TxStatus.COMPLETED)); // Verify all roles were created for (uint256 i = 0; i < size; i++) { bytes32 roleHash = keccak256(abi.encodePacked("ROLE_", i)); vm.prank(owner); - (string memory name, bytes32 hash, , , ) = roleBlox.getRole(roleHash); + (string memory name, bytes32 hash, , , ) = accountBlox.getRole(roleHash); assertEq(hash, roleHash, "Role should be created"); } } @@ -170,14 +170,14 @@ contract EdgeCasesFuzzTest is CommonBase { ); vm.prank(broadcaster); - uint256 _txId = roleBlox.roleConfigBatchRequestAndApprove(metaTx); + uint256 _txId = accountBlox.roleConfigBatchRequestAndApprove(metaTx); vm.prank(broadcaster); - EngineBlox.TxRecord memory txRecord = roleBlox.getTransaction(_txId); + EngineBlox.TxRecord memory txRecord = accountBlox.getTransaction(_txId); assertEq(uint8(txRecord.status), uint8(EngineBlox.TxStatus.COMPLETED)); // Verify role was created with correct name vm.prank(owner); - (string memory name, bytes32 hash, , , ) = roleBlox.getRole(roleHash); + (string memory name, bytes32 hash, , , ) = accountBlox.getRole(roleHash); assertEq(keccak256(bytes(name)), keccak256(bytes(roleName)), "Role name should match"); } @@ -190,8 +190,8 @@ contract EdgeCasesFuzzTest is CommonBase { uint256 deadline ) internal returns (EngineBlox.MetaTransaction memory) { // Create meta-transaction parameters - EngineBlox.MetaTxParams memory metaTxParams = roleBlox.createMetaTxParams( - address(roleBlox), + EngineBlox.MetaTxParams memory metaTxParams = accountBlox.createMetaTxParams( + address(accountBlox), ROLE_CONFIG_BATCH_META_SELECTOR, EngineBlox.TxAction.SIGN_META_REQUEST_AND_APPROVE, deadline, @@ -200,9 +200,9 @@ contract EdgeCasesFuzzTest is CommonBase { ); // Generate unsigned meta-transaction - EngineBlox.MetaTransaction memory metaTx = roleBlox.generateUnsignedMetaTransactionForNew( + EngineBlox.MetaTransaction memory metaTx = accountBlox.generateUnsignedMetaTransactionForNew( signer, - address(roleBlox), + address(accountBlox), 0, // value 0, // gasLimit ROLE_CONFIG_BATCH_OPERATION_TYPE, diff --git a/test/foundry/fuzz/GuardControllerFuzz.t.sol b/test/foundry/fuzz/GuardControllerFuzz.t.sol index 96793673..7ad1ac36 100644 --- a/test/foundry/fuzz/GuardControllerFuzz.t.sol +++ b/test/foundry/fuzz/GuardControllerFuzz.t.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: MPL-2.0 pragma solidity 0.8.34; import "../CommonBase.sol"; diff --git a/test/foundry/fuzz/MetaTransactionSecurityFuzz.t.sol b/test/foundry/fuzz/MetaTransactionSecurityFuzz.t.sol index 903ddc1d..a6050bac 100644 --- a/test/foundry/fuzz/MetaTransactionSecurityFuzz.t.sol +++ b/test/foundry/fuzz/MetaTransactionSecurityFuzz.t.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: MPL-2.0 pragma solidity 0.8.34; import "../CommonBase.sol"; @@ -45,8 +45,8 @@ contract MetaTransactionSecurityFuzzTest is CommonBase { }); bytes memory executionParams = RuntimeRBACDefinitions.roleConfigBatchExecutionParams(abi.encode(actions)); - EngineBlox.MetaTxParams memory metaTxParams = roleBlox.createMetaTxParams( - address(roleBlox), + EngineBlox.MetaTxParams memory metaTxParams = accountBlox.createMetaTxParams( + address(accountBlox), ROLE_CONFIG_BATCH_META_SELECTOR, EngineBlox.TxAction.SIGN_META_REQUEST_AND_APPROVE, 1 hours, @@ -63,9 +63,9 @@ contract MetaTransactionSecurityFuzzTest is CommonBase { block.timestamp ) ); - roleBlox.generateUnsignedMetaTransactionForNew( + accountBlox.generateUnsignedMetaTransactionForNew( owner, - address(roleBlox), + address(accountBlox), 0, 0, ROLE_CONFIG_BATCH_OPERATION_TYPE, @@ -90,8 +90,8 @@ contract MetaTransactionSecurityFuzzTest is CommonBase { }); bytes memory executionParams = RuntimeRBACDefinitions.roleConfigBatchExecutionParams(abi.encode(actions)); - EngineBlox.MetaTxParams memory metaTxParams = roleBlox.createMetaTxParams( - address(roleBlox), + EngineBlox.MetaTxParams memory metaTxParams = accountBlox.createMetaTxParams( + address(accountBlox), ROLE_CONFIG_BATCH_META_SELECTOR, EngineBlox.TxAction.SIGN_META_REQUEST_AND_APPROVE, 1 hours, @@ -99,9 +99,9 @@ contract MetaTransactionSecurityFuzzTest is CommonBase { owner ); - EngineBlox.MetaTransaction memory metaTx = roleBlox.generateUnsignedMetaTransactionForNew( + EngineBlox.MetaTransaction memory metaTx = accountBlox.generateUnsignedMetaTransactionForNew( owner, - address(roleBlox), + address(accountBlox), 0, 0, ROLE_CONFIG_BATCH_OPERATION_TYPE, @@ -114,13 +114,13 @@ contract MetaTransactionSecurityFuzzTest is CommonBase { bytes memory signature = metaTxSigner.signMetaTransaction( metaTx, signerPrivateKey, - address(roleBlox) + address(accountBlox) ); metaTx.signature = signature; // Tamper nonce so validateNonce(provided, expected) reverts InvalidNonce (checked before signature) vm.prank(owner); - uint256 expectedNonce = roleBlox.getSignerNonce(owner); + uint256 expectedNonce = accountBlox.getSignerNonce(owner); metaTx.params.nonce = expectedNonce + 1; vm.prank(broadcaster); @@ -131,7 +131,7 @@ contract MetaTransactionSecurityFuzzTest is CommonBase { expectedNonce ) ); - roleBlox.roleConfigBatchRequestAndApprove(metaTx); + accountBlox.roleConfigBatchRequestAndApprove(metaTx); } /** @@ -152,8 +152,8 @@ contract MetaTransactionSecurityFuzzTest is CommonBase { bytes memory executionParams = RuntimeRBACDefinitions.roleConfigBatchExecutionParams(abi.encode(actions)); - EngineBlox.MetaTxParams memory metaTxParams = roleBlox.createMetaTxParams( - address(roleBlox), + EngineBlox.MetaTxParams memory metaTxParams = accountBlox.createMetaTxParams( + address(accountBlox), ROLE_CONFIG_BATCH_META_SELECTOR, EngineBlox.TxAction.SIGN_META_REQUEST_AND_APPROVE, 1 hours, @@ -170,9 +170,9 @@ contract MetaTransactionSecurityFuzzTest is CommonBase { block.chainid ) ); - roleBlox.generateUnsignedMetaTransactionForNew( + accountBlox.generateUnsignedMetaTransactionForNew( owner, - address(roleBlox), + address(accountBlox), 0, 0, ROLE_CONFIG_BATCH_OPERATION_TYPE, @@ -215,7 +215,7 @@ contract MetaTransactionSecurityFuzzTest is CommonBase { uint256(65) ) ); - roleBlox.roleConfigBatchRequestAndApprove(metaTx); + accountBlox.roleConfigBatchRequestAndApprove(metaTx); } /** @@ -237,8 +237,8 @@ contract MetaTransactionSecurityFuzzTest is CommonBase { bytes memory executionParams = RuntimeRBACDefinitions.roleConfigBatchExecutionParams(abi.encode(actions)); // Create meta-transaction signed by unauthorized address - EngineBlox.MetaTxParams memory metaTxParams = roleBlox.createMetaTxParams( - address(roleBlox), + EngineBlox.MetaTxParams memory metaTxParams = accountBlox.createMetaTxParams( + address(accountBlox), ROLE_CONFIG_BATCH_META_SELECTOR, EngineBlox.TxAction.SIGN_META_REQUEST_AND_APPROVE, 1 hours, @@ -246,9 +246,9 @@ contract MetaTransactionSecurityFuzzTest is CommonBase { unauthorizedSigner ); - EngineBlox.MetaTransaction memory metaTx = roleBlox.generateUnsignedMetaTransactionForNew( + EngineBlox.MetaTransaction memory metaTx = accountBlox.generateUnsignedMetaTransactionForNew( unauthorizedSigner, - address(roleBlox), + address(accountBlox), 0, 0, ROLE_CONFIG_BATCH_OPERATION_TYPE, @@ -271,7 +271,7 @@ contract MetaTransactionSecurityFuzzTest is CommonBase { unauthorizedSigner ) ); - roleBlox.roleConfigBatchRequestAndApprove(metaTx); + accountBlox.roleConfigBatchRequestAndApprove(metaTx); } /** @@ -296,7 +296,7 @@ contract MetaTransactionSecurityFuzzTest is CommonBase { // Execute first transaction vm.prank(broadcaster); - roleBlox.roleConfigBatchRequestAndApprove(metaTx1); + accountBlox.roleConfigBatchRequestAndApprove(metaTx1); // Replay the same meta-tx (same nonce already used) - must revert with InvalidNonce vm.prank(broadcaster); @@ -307,7 +307,7 @@ contract MetaTransactionSecurityFuzzTest is CommonBase { metaTx1.params.nonce + 1 ) ); - roleBlox.roleConfigBatchRequestAndApprove(metaTx1); + accountBlox.roleConfigBatchRequestAndApprove(metaTx1); } /** @@ -319,8 +319,8 @@ contract MetaTransactionSecurityFuzzTest is CommonBase { uint256 deadline ) internal returns (EngineBlox.MetaTransaction memory) { // Create meta-transaction parameters - EngineBlox.MetaTxParams memory metaTxParams = roleBlox.createMetaTxParams( - address(roleBlox), + EngineBlox.MetaTxParams memory metaTxParams = accountBlox.createMetaTxParams( + address(accountBlox), ROLE_CONFIG_BATCH_META_SELECTOR, EngineBlox.TxAction.SIGN_META_REQUEST_AND_APPROVE, deadline, @@ -329,9 +329,9 @@ contract MetaTransactionSecurityFuzzTest is CommonBase { ); // Generate unsigned meta-transaction - EngineBlox.MetaTransaction memory metaTx = roleBlox.generateUnsignedMetaTransactionForNew( + EngineBlox.MetaTransaction memory metaTx = accountBlox.generateUnsignedMetaTransactionForNew( signer, - address(roleBlox), + address(accountBlox), 0, // value 0, // gasLimit ROLE_CONFIG_BATCH_OPERATION_TYPE, diff --git a/test/foundry/fuzz/ProtectedResourceFuzz.t.sol b/test/foundry/fuzz/ProtectedResourceFuzz.t.sol index 46b1cbfb..7a58b02e 100644 --- a/test/foundry/fuzz/ProtectedResourceFuzz.t.sol +++ b/test/foundry/fuzz/ProtectedResourceFuzz.t.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: MPL-2.0 pragma solidity 0.8.34; import "../CommonBase.sol"; @@ -58,9 +58,9 @@ contract ProtectedResourceFuzzTest is CommonBase { ); vm.prank(broadcaster); - uint256 _txId = roleBlox.roleConfigBatchRequestAndApprove(metaTx); + uint256 _txId = accountBlox.roleConfigBatchRequestAndApprove(metaTx); vm.prank(broadcaster); - EngineBlox.TxRecord memory txRecord = roleBlox.getTransaction(_txId); + EngineBlox.TxRecord memory txRecord = accountBlox.getTransaction(_txId); // Transaction should be marked as FAILED with CannotModifyProtected error assertEq(uint8(txRecord.status), uint8(EngineBlox.TxStatus.FAILED), "Transaction should fail"); @@ -93,9 +93,9 @@ contract ProtectedResourceFuzzTest is CommonBase { ); vm.prank(broadcaster); - uint256 _txId = roleBlox.roleConfigBatchRequestAndApprove(metaTx); + uint256 _txId = accountBlox.roleConfigBatchRequestAndApprove(metaTx); vm.prank(broadcaster); - EngineBlox.TxRecord memory txRecord = roleBlox.getTransaction(_txId); + EngineBlox.TxRecord memory txRecord = accountBlox.getTransaction(_txId); // Transaction should be marked as FAILED with CannotModifyProtected error assertEq(uint8(txRecord.status), uint8(EngineBlox.TxStatus.FAILED), "Transaction should fail"); @@ -129,9 +129,9 @@ contract ProtectedResourceFuzzTest is CommonBase { ); vm.prank(broadcaster); - uint256 _txId = roleBlox.roleConfigBatchRequestAndApprove(metaTx); + uint256 _txId = accountBlox.roleConfigBatchRequestAndApprove(metaTx); vm.prank(broadcaster); - EngineBlox.TxRecord memory txRecord = roleBlox.getTransaction(_txId); + EngineBlox.TxRecord memory txRecord = accountBlox.getTransaction(_txId); // Transaction should be marked as FAILED with CannotModifyProtected error assertEq(uint8(txRecord.status), uint8(EngineBlox.TxStatus.FAILED), "Transaction should fail"); @@ -160,9 +160,9 @@ contract ProtectedResourceFuzzTest is CommonBase { vm.assume(wallet != recovery); // Store initial protected role states - address initialOwner = roleBlox.owner(); - address initialRecovery = roleBlox.getRecovery(); - address[] memory initialBroadcasters = roleBlox.getBroadcasters(); + address initialOwner = accountBlox.owner(); + address initialRecovery = accountBlox.getRecovery(); + address[] memory initialBroadcasters = accountBlox.getBroadcasters(); // Create a non-protected role and add wallet to it bytes32 newRoleHash = keccak256(bytes(roleName)); @@ -183,7 +183,7 @@ contract ProtectedResourceFuzzTest is CommonBase { ); vm.prank(broadcaster); - roleBlox.roleConfigBatchRequestAndApprove(createMetaTx); + accountBlox.roleConfigBatchRequestAndApprove(createMetaTx); // Then add wallet to the new role IRuntimeRBAC.RoleConfigAction[] memory addActions = new IRuntimeRBAC.RoleConfigAction[](1); @@ -200,12 +200,12 @@ contract ProtectedResourceFuzzTest is CommonBase { ); vm.prank(broadcaster); - roleBlox.roleConfigBatchRequestAndApprove(addMetaTx); + accountBlox.roleConfigBatchRequestAndApprove(addMetaTx); // Verify protected roles are unchanged - assertEq(roleBlox.owner(), initialOwner); - assertEq(roleBlox.getRecovery(), initialRecovery); - address[] memory finalBroadcasters = roleBlox.getBroadcasters(); + assertEq(accountBlox.owner(), initialOwner); + assertEq(accountBlox.getRecovery(), initialRecovery); + address[] memory finalBroadcasters = accountBlox.getBroadcasters(); assertEq(finalBroadcasters.length, initialBroadcasters.length); assertEq(finalBroadcasters[0], initialBroadcasters[0]); } @@ -219,8 +219,8 @@ contract ProtectedResourceFuzzTest is CommonBase { uint256 deadline ) internal returns (EngineBlox.MetaTransaction memory) { // Create meta-transaction parameters - EngineBlox.MetaTxParams memory metaTxParams = roleBlox.createMetaTxParams( - address(roleBlox), + EngineBlox.MetaTxParams memory metaTxParams = accountBlox.createMetaTxParams( + address(accountBlox), ROLE_CONFIG_BATCH_META_SELECTOR, EngineBlox.TxAction.SIGN_META_REQUEST_AND_APPROVE, deadline, @@ -229,9 +229,9 @@ contract ProtectedResourceFuzzTest is CommonBase { ); // Generate unsigned meta-transaction - EngineBlox.MetaTransaction memory metaTx = roleBlox.generateUnsignedMetaTransactionForNew( + EngineBlox.MetaTransaction memory metaTx = accountBlox.generateUnsignedMetaTransactionForNew( signer, - address(roleBlox), + address(accountBlox), 0, // value 0, // gasLimit ROLE_CONFIG_BATCH_OPERATION_TYPE, diff --git a/test/foundry/fuzz/RBACPermissionFuzz.t.sol b/test/foundry/fuzz/RBACPermissionFuzz.t.sol index 20fd3a17..d3f5ccc2 100644 --- a/test/foundry/fuzz/RBACPermissionFuzz.t.sol +++ b/test/foundry/fuzz/RBACPermissionFuzz.t.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: MPL-2.0 pragma solidity 0.8.34; import "../CommonBase.sol"; @@ -54,10 +54,10 @@ contract RBACPermissionFuzzTest is CommonBase { abi.encodeWithSelector( SharedValidation.OnlyCallableByContract.selector, unauthorizedUser, - address(roleBlox) + address(accountBlox) ) ); - roleBlox.executeRoleConfigBatch(actions); + accountBlox.executeRoleConfigBatch(actions); } /** @@ -105,7 +105,7 @@ contract RBACPermissionFuzzTest is CommonBase { ); vm.prank(broadcaster); - roleBlox.roleConfigBatchRequestAndApprove(createMetaTx); + accountBlox.roleConfigBatchRequestAndApprove(createMetaTx); // Add wallets up to the limit for (uint256 i = 0; i < maxWallets; i++) { @@ -123,7 +123,7 @@ contract RBACPermissionFuzzTest is CommonBase { ); vm.prank(broadcaster); - roleBlox.roleConfigBatchRequestAndApprove(addMetaTx); + accountBlox.roleConfigBatchRequestAndApprove(addMetaTx); } // Try to add one more - should fail @@ -141,9 +141,9 @@ contract RBACPermissionFuzzTest is CommonBase { ); vm.prank(broadcaster); - uint256 _txId = roleBlox.roleConfigBatchRequestAndApprove(overflowMetaTx); + uint256 _txId = accountBlox.roleConfigBatchRequestAndApprove(overflowMetaTx); vm.prank(broadcaster); - EngineBlox.TxRecord memory txRecord = roleBlox.getTransaction(_txId); + EngineBlox.TxRecord memory txRecord = accountBlox.getTransaction(_txId); // Transaction should fail with RoleWalletLimitReached error assertEq(uint8(txRecord.status), uint8(EngineBlox.TxStatus.FAILED), "Transaction should fail"); @@ -192,7 +192,7 @@ contract RBACPermissionFuzzTest is CommonBase { ); vm.prank(broadcaster); - roleBlox.roleConfigBatchRequestAndApprove(createMetaTx); + accountBlox.roleConfigBatchRequestAndApprove(createMetaTx); // Add wallet first time IRuntimeRBAC.RoleConfigAction[] memory addActions1 = new IRuntimeRBAC.RoleConfigAction[](1); @@ -209,7 +209,7 @@ contract RBACPermissionFuzzTest is CommonBase { ); vm.prank(broadcaster); - roleBlox.roleConfigBatchRequestAndApprove(addMetaTx1); + accountBlox.roleConfigBatchRequestAndApprove(addMetaTx1); // Try to add same wallet again - should fail IRuntimeRBAC.RoleConfigAction[] memory addActions2 = new IRuntimeRBAC.RoleConfigAction[](1); @@ -226,9 +226,9 @@ contract RBACPermissionFuzzTest is CommonBase { ); vm.prank(broadcaster); - uint256 _txId = roleBlox.roleConfigBatchRequestAndApprove(addMetaTx2); + uint256 _txId = accountBlox.roleConfigBatchRequestAndApprove(addMetaTx2); vm.prank(broadcaster); - EngineBlox.TxRecord memory txRecord = roleBlox.getTransaction(_txId); + EngineBlox.TxRecord memory txRecord = accountBlox.getTransaction(_txId); // Transaction should fail with ItemAlreadyExists error assertEq(uint8(txRecord.status), uint8(EngineBlox.TxStatus.FAILED), "Transaction should fail"); @@ -249,8 +249,8 @@ contract RBACPermissionFuzzTest is CommonBase { uint256 deadline ) internal returns (EngineBlox.MetaTransaction memory) { // Create meta-transaction parameters - EngineBlox.MetaTxParams memory metaTxParams = roleBlox.createMetaTxParams( - address(roleBlox), + EngineBlox.MetaTxParams memory metaTxParams = accountBlox.createMetaTxParams( + address(accountBlox), ROLE_CONFIG_BATCH_META_SELECTOR, EngineBlox.TxAction.SIGN_META_REQUEST_AND_APPROVE, deadline, @@ -259,9 +259,9 @@ contract RBACPermissionFuzzTest is CommonBase { ); // Generate unsigned meta-transaction - EngineBlox.MetaTransaction memory metaTx = roleBlox.generateUnsignedMetaTransactionForNew( + EngineBlox.MetaTransaction memory metaTx = accountBlox.generateUnsignedMetaTransactionForNew( signer, - address(roleBlox), + address(accountBlox), 0, // value 0, // gasLimit ROLE_CONFIG_BATCH_OPERATION_TYPE, diff --git a/test/foundry/fuzz/RuntimeRBACFuzz.t.sol b/test/foundry/fuzz/RuntimeRBACFuzz.t.sol index ae2b252b..06a4444d 100644 --- a/test/foundry/fuzz/RuntimeRBACFuzz.t.sol +++ b/test/foundry/fuzz/RuntimeRBACFuzz.t.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: MPL-2.0 pragma solidity 0.8.34; import "../CommonBase.sol"; @@ -77,16 +77,16 @@ contract RuntimeRBACFuzzTest is CommonBase { ); vm.prank(broadcaster); - uint256 _txId = roleBlox.roleConfigBatchRequestAndApprove(metaTx); + uint256 _txId = accountBlox.roleConfigBatchRequestAndApprove(metaTx); vm.prank(broadcaster); - EngineBlox.TxRecord memory txRecord = roleBlox.getTransaction(_txId); + EngineBlox.TxRecord memory txRecord = accountBlox.getTransaction(_txId); // Verify transaction completed assertEq(uint8(txRecord.status), uint8(EngineBlox.TxStatus.COMPLETED)); // Verify role was created vm.prank(owner); - (string memory name, bytes32 hash, , , ) = roleBlox.getRole(roleHash); + (string memory name, bytes32 hash, , , ) = accountBlox.getRole(roleHash); assertEq(hash, roleHash); assertEq(keccak256(bytes(name)), keccak256(bytes(roleName))); } @@ -125,7 +125,7 @@ contract RuntimeRBACFuzzTest is CommonBase { ); vm.prank(broadcaster); - roleBlox.roleConfigBatchRequestAndApprove(createMetaTx); + accountBlox.roleConfigBatchRequestAndApprove(createMetaTx); // Then add wallet to the role IRuntimeRBAC.RoleConfigAction[] memory addActions = new IRuntimeRBAC.RoleConfigAction[](1); @@ -142,16 +142,16 @@ contract RuntimeRBACFuzzTest is CommonBase { ); vm.prank(broadcaster); - uint256 _txId = roleBlox.roleConfigBatchRequestAndApprove(addMetaTx); + uint256 _txId = accountBlox.roleConfigBatchRequestAndApprove(addMetaTx); vm.prank(broadcaster); - EngineBlox.TxRecord memory txRecord = roleBlox.getTransaction(_txId); + EngineBlox.TxRecord memory txRecord = accountBlox.getTransaction(_txId); // Verify transaction completed assertEq(uint8(txRecord.status), uint8(EngineBlox.TxStatus.COMPLETED)); // Verify wallet was added vm.prank(owner); - assertTrue(roleBlox.hasRole(roleHash, wallet), "Wallet should be in role"); + assertTrue(accountBlox.hasRole(roleHash, wallet), "Wallet should be in role"); } /** @@ -163,8 +163,8 @@ contract RuntimeRBACFuzzTest is CommonBase { uint256 deadline ) internal returns (EngineBlox.MetaTransaction memory) { // Create meta-transaction parameters - EngineBlox.MetaTxParams memory metaTxParams = roleBlox.createMetaTxParams( - address(roleBlox), + EngineBlox.MetaTxParams memory metaTxParams = accountBlox.createMetaTxParams( + address(accountBlox), ROLE_CONFIG_BATCH_META_SELECTOR, EngineBlox.TxAction.SIGN_META_REQUEST_AND_APPROVE, deadline, @@ -173,9 +173,9 @@ contract RuntimeRBACFuzzTest is CommonBase { ); // Generate unsigned meta-transaction - EngineBlox.MetaTransaction memory metaTx = roleBlox.generateUnsignedMetaTransactionForNew( + EngineBlox.MetaTransaction memory metaTx = accountBlox.generateUnsignedMetaTransactionForNew( signer, - address(roleBlox), + address(accountBlox), 0, // value 0, // gasLimit ROLE_CONFIG_BATCH_OPERATION_TYPE, @@ -204,11 +204,11 @@ contract RuntimeRBACFuzzTest is CommonBase { function testFuzz_GetFunctionSchema(bytes4 selector) public { // Selector 0 can make functionSchemaExists true (default storage) while getFunctionSchema reverts with ResourceNotFound vm.assume(selector != bytes4(0)); - bool exists = roleBlox.functionSchemaExists(selector); + bool exists = accountBlox.functionSchemaExists(selector); if (exists) { vm.prank(owner); // getFunctionSchema requires caller to have any role - EngineBlox.FunctionSchema memory schema = roleBlox.getFunctionSchema(selector); + EngineBlox.FunctionSchema memory schema = accountBlox.getFunctionSchema(selector); // Basic sanity checks for existing schemas assertEq(schema.functionSelector, selector, "Returned selector must match input selector"); @@ -227,7 +227,7 @@ contract RuntimeRBACFuzzTest is CommonBase { } else { vm.prank(owner); // getFunctionSchema requires caller to have any role vm.expectRevert(abi.encodeWithSelector(SharedValidation.ResourceNotFound.selector, bytes32(selector))); - roleBlox.getFunctionSchema(selector); + accountBlox.getFunctionSchema(selector); } } diff --git a/test/foundry/fuzz/SecureOwnableFuzz.t.sol b/test/foundry/fuzz/SecureOwnableFuzz.t.sol index 117e459d..dee1f04c 100644 --- a/test/foundry/fuzz/SecureOwnableFuzz.t.sol +++ b/test/foundry/fuzz/SecureOwnableFuzz.t.sol @@ -1,7 +1,8 @@ -// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: MPL-2.0 pragma solidity 0.8.34; import "../CommonBase.sol"; +import "../../../contracts/examples/templates/AccountBlox.sol"; import "../../../contracts/core/lib/utils/SharedValidation.sol"; /** @@ -19,7 +20,7 @@ contract SecureOwnableFuzzTest is CommonBase { vm.assume(timelockPeriod < 365 days); // Create new contract with fuzzed timelock - SecureBlox newContract = new SecureBlox(); + AccountBlox newContract = new AccountBlox(); vm.prank(owner); newContract.initialize( owner, @@ -56,16 +57,16 @@ contract SecureOwnableFuzzTest is CommonBase { vm.assume(newBroadcaster != recovery); vm.prank(owner); - uint256 txId = secureBlox.updateBroadcasterRequest(newBroadcaster, 0); + uint256 txId = accountBlox.updateBroadcasterRequest(newBroadcaster, 0); vm.prank(owner); - EngineBlox.TxRecord memory requestTx = secureBlox.getTransaction(txId); + EngineBlox.TxRecord memory requestTx = accountBlox.getTransaction(txId); advanceTime(DEFAULT_TIMELOCK_PERIOD + 1); vm.prank(owner); - secureBlox.updateBroadcasterDelayedApproval(txId); + accountBlox.updateBroadcasterDelayedApproval(txId); - address[] memory broadcasters = secureBlox.getBroadcasters(); + address[] memory broadcasters = accountBlox.getBroadcasters(); assertEq(broadcasters[0], newBroadcaster); } @@ -99,11 +100,11 @@ contract SecureOwnableFuzzTest is CommonBase { vm.assume(maxGasPrice < type(uint256).max / 2); // Create meta-tx params - address handlerContract = address(secureBlox); + address handlerContract = address(accountBlox); bytes4 handlerSelector = bytes4(keccak256("testHandler()")); EngineBlox.TxAction action = EngineBlox.TxAction.EXECUTE_META_APPROVE; - EngineBlox.MetaTxParams memory params = secureBlox.createMetaTxParams( + EngineBlox.MetaTxParams memory params = accountBlox.createMetaTxParams( handlerContract, handlerSelector, action, diff --git a/test/foundry/fuzz/StateMachineWorkflowFuzz.t.sol b/test/foundry/fuzz/StateMachineWorkflowFuzz.t.sol index a63e85d8..ccbd026b 100644 --- a/test/foundry/fuzz/StateMachineWorkflowFuzz.t.sol +++ b/test/foundry/fuzz/StateMachineWorkflowFuzz.t.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: MPL-2.0 pragma solidity 0.8.34; import "../CommonBase.sol"; diff --git a/test/foundry/fuzz/SystemMacroSelectorSecurityFuzz.t.sol b/test/foundry/fuzz/SystemMacroSelectorSecurityFuzz.t.sol index 0f607b6b..24ca4aee 100644 --- a/test/foundry/fuzz/SystemMacroSelectorSecurityFuzz.t.sol +++ b/test/foundry/fuzz/SystemMacroSelectorSecurityFuzz.t.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: MPL-2.0 pragma solidity 0.8.34; import "../CommonBase.sol"; @@ -181,7 +181,6 @@ contract SystemMacroSelectorSecurityFuzzTest is CommonBase { */ function testFuzz_UpdatePaymentSelectorRequiresPermissions( address unauthorizedUser, - uint256 txId, uint256 paymentAmount ) public { vm.assume(unauthorizedUser != address(0)); @@ -250,8 +249,8 @@ contract SystemMacroSelectorSecurityFuzzTest is CommonBase { vm.assume(externalTarget != address(paymentHelper)); vm.assume(externalTarget != address(accountBlox)); - // Bound transfer amount - transferAmount = bound(transferAmount, 1, address(paymentHelper).balance); + // Bound transfer amount so multiple test phases have sufficient balance (Test 1 and Test 3 each use transferAmount) + transferAmount = bound(transferAmount, 1, address(paymentHelper).balance / 2); bytes32 operationType = keccak256("NATIVE_TRANSFER"); bytes4 systemMacroSelector = EngineBlox.NATIVE_TRANSFER_SELECTOR; diff --git a/test/foundry/helpers/DefinitionValidator.sol b/test/foundry/helpers/DefinitionValidator.sol index 3ac66f01..3aca549f 100644 --- a/test/foundry/helpers/DefinitionValidator.sol +++ b/test/foundry/helpers/DefinitionValidator.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: MPL-2.0 pragma solidity 0.8.34; import "../../../contracts/core/lib/EngineBlox.sol"; diff --git a/test/foundry/helpers/HookTestBlox.sol b/test/foundry/helpers/HookTestBlox.sol new file mode 100644 index 00000000..a7ec381b --- /dev/null +++ b/test/foundry/helpers/HookTestBlox.sol @@ -0,0 +1,46 @@ +// SPDX-License-Identifier: MPL-2.0 +pragma solidity 0.8.34; + +import "../../../contracts/core/pattern/Account.sol"; +import "../../../contracts/core/base/BaseStateMachine.sol"; +import "../../../contracts/experimental/hook/HookManager.sol"; +import "../../../contracts/core/lib/utils/SharedValidation.sol"; + +/** + * @title HookTestBlox + * @dev Test-only contract: Account + HookManager for hook fuzz tests. + * Replaces MachineBlox in tests so templates can stay minimal (AccountBlox only). + */ +contract HookTestBlox is Account, HookManager { + function initialize( + address initialOwner, + address broadcaster, + address recovery, + uint256 timeLockPeriodSec, + address eventForwarder + ) public virtual override(Account) initializer { + Account.initialize(initialOwner, broadcaster, recovery, timeLockPeriodSec, eventForwarder); + } + + function supportsInterface(bytes4 interfaceId) public view virtual override(Account, BaseStateMachine) returns (bool) { + return Account.supportsInterface(interfaceId) || BaseStateMachine.supportsInterface(interfaceId); + } + + function _postActionHook( + EngineBlox.TxRecord memory txRecord + ) internal virtual override(BaseStateMachine, HookManager) { + HookManager._postActionHook(txRecord); + } + + function deposit() external payable { + emit EthReceived(msg.sender, msg.value); + } + + receive() external payable override { + revert SharedValidation.NotSupported(); + } + + fallback() external payable override { + revert SharedValidation.NotSupported(); + } +} diff --git a/test/foundry/helpers/MaliciousDefinitions.sol b/test/foundry/helpers/MaliciousDefinitions.sol index e99e5054..e418bdc4 100644 --- a/test/foundry/helpers/MaliciousDefinitions.sol +++ b/test/foundry/helpers/MaliciousDefinitions.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: MPL-2.0 pragma solidity 0.8.34; import "../../../contracts/core/lib/EngineBlox.sol"; diff --git a/test/foundry/helpers/MockContracts.sol b/test/foundry/helpers/MockContracts.sol index f5d8571b..5fc688a4 100644 --- a/test/foundry/helpers/MockContracts.sol +++ b/test/foundry/helpers/MockContracts.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: MPL-2.0 pragma solidity 0.8.34; import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; diff --git a/test/foundry/helpers/PaymentTestHelper.sol b/test/foundry/helpers/PaymentTestHelper.sol index 46ba0950..e67a2df7 100644 --- a/test/foundry/helpers/PaymentTestHelper.sol +++ b/test/foundry/helpers/PaymentTestHelper.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: MPL-2.0 pragma solidity 0.8.34; import "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; diff --git a/test/foundry/helpers/TestDefinitionContracts.sol b/test/foundry/helpers/TestDefinitionContracts.sol index d3706de2..71b0b533 100644 --- a/test/foundry/helpers/TestDefinitionContracts.sol +++ b/test/foundry/helpers/TestDefinitionContracts.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: MPL-2.0 pragma solidity 0.8.34; import "../../../contracts/core/lib/EngineBlox.sol"; diff --git a/test/foundry/helpers/TestHelpers.sol b/test/foundry/helpers/TestHelpers.sol index 84e57dbc..42e7ba2b 100644 --- a/test/foundry/helpers/TestHelpers.sol +++ b/test/foundry/helpers/TestHelpers.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: MPL-2.0 pragma solidity 0.8.34; import {MessageHashUtils} from "@openzeppelin/contracts/utils/cryptography/MessageHashUtils.sol"; diff --git a/test/foundry/helpers/TestStateMachine.sol b/test/foundry/helpers/TestStateMachine.sol index a3c5bc81..d6d0ce68 100644 --- a/test/foundry/helpers/TestStateMachine.sol +++ b/test/foundry/helpers/TestStateMachine.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: MPL-2.0 pragma solidity 0.8.34; import "../../../contracts/core/base/BaseStateMachine.sol"; diff --git a/test/foundry/integration/MetaTransaction.t.sol b/test/foundry/integration/MetaTransaction.t.sol index cb52bec3..7d0c1f6b 100644 --- a/test/foundry/integration/MetaTransaction.t.sol +++ b/test/foundry/integration/MetaTransaction.t.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: MPL-2.0 pragma solidity 0.8.34; import "../CommonBase.sol"; @@ -26,13 +26,13 @@ contract MetaTransactionTest is CommonBase { address newOwner = user1; // Step 1: Create meta-transaction parameters - address handlerContract = address(secureBlox); + address handlerContract = address(accountBlox); bytes4 handlerSelector = bytes4(keccak256("transferOwnershipDelayedApproval(uint256)")); EngineBlox.TxAction action = EngineBlox.TxAction.EXECUTE_META_APPROVE; uint256 deadlineDuration = 3600; // Duration in seconds (not absolute timestamp) uint256 maxGasPrice = 100 gwei; - EngineBlox.MetaTxParams memory metaTxParams = secureBlox.createMetaTxParams( + EngineBlox.MetaTxParams memory metaTxParams = accountBlox.createMetaTxParams( handlerContract, handlerSelector, action, @@ -43,14 +43,14 @@ contract MetaTransactionTest is CommonBase { // Step 2: Create the transaction request first vm.prank(recovery); - uint256 txId = secureBlox.transferOwnershipRequest(); + uint256 txId = accountBlox.transferOwnershipRequest(); vm.prank(recovery); - EngineBlox.TxRecord memory requestTx = secureBlox.getTransaction(txId); + EngineBlox.TxRecord memory requestTx = accountBlox.getTransaction(txId); // Step 3: Generate unsigned meta-transaction for existing transaction // Note: We use generateUnsignedMetaTransactionForExisting since we already created the request vm.prank(recovery); - EngineBlox.MetaTransaction memory unsignedMetaTx = secureBlox.generateUnsignedMetaTransactionForExisting( + EngineBlox.MetaTransaction memory unsignedMetaTx = accountBlox.generateUnsignedMetaTransactionForExisting( txId, metaTxParams ); @@ -64,7 +64,7 @@ contract MetaTransactionTest is CommonBase { bytes memory signature = metaTxSigner.signMetaTransaction( unsignedMetaTx, RECOVERY_PRIVATE_KEY, - address(secureBlox) + address(accountBlox) ); // Verify signature length @@ -86,7 +86,7 @@ contract MetaTransactionTest is CommonBase { // The message hash in the meta-transaction should match our calculation bytes32 expectedMessageHash = metaTxSigner.generateMessageHash( signedMetaTx, - address(secureBlox) + address(accountBlox) ); // Note: The message hash in the meta-transaction is set by EngineBlox // We verify our signer generates the same hash @@ -97,13 +97,13 @@ contract MetaTransactionTest is CommonBase { * @dev Test meta-transaction parameter creation */ function test_MetaTransaction_CreateParams() public { - address handlerContract = address(secureBlox); + address handlerContract = address(accountBlox); bytes4 handlerSelector = bytes4(keccak256("testHandler()")); EngineBlox.TxAction action = EngineBlox.TxAction.EXECUTE_META_APPROVE; uint256 deadlineDuration = 3600; // Duration in seconds uint256 maxGasPrice = 100 gwei; - EngineBlox.MetaTxParams memory params = secureBlox.createMetaTxParams( + EngineBlox.MetaTxParams memory params = accountBlox.createMetaTxParams( handlerContract, handlerSelector, action, @@ -131,16 +131,16 @@ contract MetaTransactionTest is CommonBase { function test_MetaTransaction_MessageHashConsistency() public { // Create a transaction first to get a valid txId vm.prank(recovery); - uint256 txId = secureBlox.transferOwnershipRequest(); + uint256 txId = accountBlox.transferOwnershipRequest(); vm.prank(recovery); - EngineBlox.TxRecord memory requestTx = secureBlox.getTransaction(txId); + EngineBlox.TxRecord memory requestTx = accountBlox.getTransaction(txId); // Create meta-tx params - need to get nonce first vm.prank(owner); - uint256 currentNonce = secureBlox.getSignerNonce(owner); + uint256 currentNonce = accountBlox.getSignerNonce(owner); - EngineBlox.MetaTxParams memory params = secureBlox.createMetaTxParams( - address(secureBlox), + EngineBlox.MetaTxParams memory params = accountBlox.createMetaTxParams( + address(accountBlox), bytes4(keccak256("testHandler()")), EngineBlox.TxAction.EXECUTE_META_APPROVE, 3600, // Duration in seconds @@ -150,13 +150,13 @@ contract MetaTransactionTest is CommonBase { // Generate meta-transactions for existing transaction vm.prank(owner); - EngineBlox.MetaTransaction memory metaTx1 = secureBlox.generateUnsignedMetaTransactionForExisting( + EngineBlox.MetaTransaction memory metaTx1 = accountBlox.generateUnsignedMetaTransactionForExisting( txId, params ); vm.prank(owner); - EngineBlox.MetaTransaction memory metaTx2 = secureBlox.generateUnsignedMetaTransactionForExisting( + EngineBlox.MetaTransaction memory metaTx2 = accountBlox.generateUnsignedMetaTransactionForExisting( txId, params ); diff --git a/test/foundry/integration/WhitelistWorkflow.t.sol b/test/foundry/integration/WhitelistWorkflow.t.sol index 9e66a68d..09cbb79c 100644 --- a/test/foundry/integration/WhitelistWorkflow.t.sol +++ b/test/foundry/integration/WhitelistWorkflow.t.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: MPL-2.0 pragma solidity 0.8.34; import "../CommonBase.sol"; diff --git a/test/foundry/invariant/RoleInvariants.t.sol b/test/foundry/invariant/RoleInvariants.t.sol index 1d7453c7..ff2382ab 100644 --- a/test/foundry/invariant/RoleInvariants.t.sol +++ b/test/foundry/invariant/RoleInvariants.t.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: MPL-2.0 pragma solidity 0.8.34; import "../CommonBase.sol"; @@ -21,17 +21,17 @@ contract RoleInvariantsTest is CommonBase { secureOwnableExecutionSelectors[2] = UPDATE_RECOVERY_SELECTOR; secureOwnableExecutionSelectors[3] = UPDATE_TIMELOCK_SELECTOR; excludeSelector( - StdInvariant.FuzzSelector({ addr: address(roleBlox), selectors: secureOwnableExecutionSelectors }) + StdInvariant.FuzzSelector({ addr: address(accountBlox), selectors: secureOwnableExecutionSelectors }) ); } function invariant_RoleWalletLimits() public { vm.prank(owner); - bytes32[] memory roles = secureBlox.getSupportedRoles(); + bytes32[] memory roles = accountBlox.getSupportedRoles(); for (uint256 i = 0; i < roles.length; i++) { vm.prank(owner); - (, , uint256 maxWallets, uint256 walletCount, ) = secureBlox.getRole(roles[i]); + (, , uint256 maxWallets, uint256 walletCount, ) = accountBlox.getRole(roles[i]); assertLe(walletCount, maxWallets); } } @@ -39,19 +39,19 @@ contract RoleInvariantsTest is CommonBase { function invariant_ProtectedRolesImmutable() public { // Protected roles should always exist vm.prank(owner); - assertTrue(secureBlox.hasRole(OWNER_ROLE, owner)); + assertTrue(accountBlox.hasRole(OWNER_ROLE, owner)); vm.prank(owner); - assertTrue(secureBlox.hasRole(BROADCASTER_ROLE, broadcaster)); + assertTrue(accountBlox.hasRole(BROADCASTER_ROLE, broadcaster)); vm.prank(owner); - assertTrue(secureBlox.hasRole(RECOVERY_ROLE, recovery)); + assertTrue(accountBlox.hasRole(RECOVERY_ROLE, recovery)); // Protected roles should have isProtected = true vm.prank(owner); - (, , , , bool ownerProtected) = secureBlox.getRole(OWNER_ROLE); + (, , , , bool ownerProtected) = accountBlox.getRole(OWNER_ROLE); vm.prank(owner); - (, , , , bool broadcasterProtected) = secureBlox.getRole(BROADCASTER_ROLE); + (, , , , bool broadcasterProtected) = accountBlox.getRole(BROADCASTER_ROLE); vm.prank(owner); - (, , , , bool recoveryProtected) = secureBlox.getRole(RECOVERY_ROLE); + (, , , , bool recoveryProtected) = accountBlox.getRole(RECOVERY_ROLE); assertTrue(ownerProtected); assertTrue(broadcasterProtected); @@ -64,9 +64,9 @@ contract RoleInvariantsTest is CommonBase { */ function invariant_ProtectedRolesNeverModifiedViaRuntimeRBAC() public { // Verify protected roles unchanged - address currentOwner = roleBlox.owner(); - address currentRecovery = roleBlox.getRecovery(); - address[] memory currentBroadcasters = roleBlox.getBroadcasters(); + address currentOwner = accountBlox.owner(); + address currentRecovery = accountBlox.getRecovery(); + address[] memory currentBroadcasters = accountBlox.getBroadcasters(); assertEq(currentOwner, owner, "Owner should never change via RuntimeRBAC"); assertEq(currentRecovery, recovery, "Recovery should never change via RuntimeRBAC"); @@ -75,11 +75,11 @@ contract RoleInvariantsTest is CommonBase { // Verify protection flags remain true vm.prank(owner); - (, , , , bool ownerProtected) = roleBlox.getRole(OWNER_ROLE); + (, , , , bool ownerProtected) = accountBlox.getRole(OWNER_ROLE); vm.prank(owner); - (, , , , bool broadcasterProtected) = roleBlox.getRole(BROADCASTER_ROLE); + (, , , , bool broadcasterProtected) = accountBlox.getRole(BROADCASTER_ROLE); vm.prank(owner); - (, , , , bool recoveryProtected) = roleBlox.getRole(RECOVERY_ROLE); + (, , , , bool recoveryProtected) = accountBlox.getRole(RECOVERY_ROLE); assertTrue(ownerProtected, "OWNER_ROLE should remain protected"); assertTrue(broadcasterProtected, "BROADCASTER_ROLE should remain protected"); @@ -88,22 +88,22 @@ contract RoleInvariantsTest is CommonBase { function invariant_RoleHashConsistency() public { vm.prank(owner); - bytes32[] memory roles = secureBlox.getSupportedRoles(); + bytes32[] memory roles = accountBlox.getSupportedRoles(); for (uint256 i = 0; i < roles.length; i++) { vm.prank(owner); - (, bytes32 roleHash, , , ) = secureBlox.getRole(roles[i]); + (, bytes32 roleHash, , , ) = accountBlox.getRole(roles[i]); assertEq(roleHash, roles[i]); } } function invariant_FunctionPermissionConsistency() public { vm.prank(owner); - bytes32[] memory roles = secureBlox.getSupportedRoles(); + bytes32[] memory roles = accountBlox.getSupportedRoles(); for (uint256 i = 0; i < roles.length; i++) { vm.prank(owner); - EngineBlox.FunctionPermission[] memory permissions = secureBlox.getActiveRolePermissions(roles[i]); + EngineBlox.FunctionPermission[] memory permissions = accountBlox.getActiveRolePermissions(roles[i]); // Verify permissions are valid for (uint256 j = 0; j < permissions.length; j++) { diff --git a/test/foundry/invariant/StateMachineInvariants.t.sol b/test/foundry/invariant/StateMachineInvariants.t.sol index 5c03cc39..0b441bc9 100644 --- a/test/foundry/invariant/StateMachineInvariants.t.sol +++ b/test/foundry/invariant/StateMachineInvariants.t.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: MPL-2.0 pragma solidity 0.8.34; import "../CommonBase.sol"; @@ -14,15 +14,15 @@ contract StateMachineInvariantsTest is CommonBase { function invariant_OwnerRoleSingleWallet() public { vm.prank(owner); - (, , uint256 maxWallets, uint256 walletCount, ) = secureBlox.getRole(OWNER_ROLE); + (, , uint256 maxWallets, uint256 walletCount, ) = accountBlox.getRole(OWNER_ROLE); assertEq(walletCount, 1); assertEq(maxWallets, 1); } function invariant_NoZeroAddressInProtectedRoles() public { - address ownerAddr = secureBlox.owner(); - address recoveryAddr = secureBlox.getRecovery(); - address[] memory broadcasters = secureBlox.getBroadcasters(); + address ownerAddr = accountBlox.owner(); + address recoveryAddr = accountBlox.getRecovery(); + address[] memory broadcasters = accountBlox.getBroadcasters(); assertNotEq(ownerAddr, address(0)); assertNotEq(recoveryAddr, address(0)); @@ -33,29 +33,29 @@ contract StateMachineInvariantsTest is CommonBase { function invariant_ValidStatusTransitions() public { // Get all pending transactions vm.prank(owner); - uint256[] memory pending = secureBlox.getPendingTransactions(); + uint256[] memory pending = accountBlox.getPendingTransactions(); for (uint256 i = 0; i < pending.length; i++) { vm.prank(owner); - EngineBlox.TxRecord memory txRecord = secureBlox.getTransaction(pending[i]); + EngineBlox.TxRecord memory txRecord = accountBlox.getTransaction(pending[i]); // Pending transactions should have PENDING status assertEq(uint8(txRecord.status), uint8(EngineBlox.TxStatus.PENDING)); } } function invariant_TimelockPeriodPositive() public { - uint256 period = secureBlox.getTimeLockPeriodSec(); + uint256 period = accountBlox.getTimeLockPeriodSec(); assertGt(period, 0); } function invariant_PendingTransactionsConsistency() public { vm.prank(owner); - uint256[] memory pending = secureBlox.getPendingTransactions(); + uint256[] memory pending = accountBlox.getPendingTransactions(); // Verify all pending transactions are actually pending for (uint256 i = 0; i < pending.length; i++) { vm.prank(owner); - EngineBlox.TxRecord memory txRecord = secureBlox.getTransaction(pending[i]); + EngineBlox.TxRecord memory txRecord = accountBlox.getTransaction(pending[i]); assertEq(uint8(txRecord.status), uint8(EngineBlox.TxStatus.PENDING)); } } @@ -63,15 +63,15 @@ contract StateMachineInvariantsTest is CommonBase { function invariant_TransactionCounterMonotonic() public { // Create a transaction to increment counter vm.prank(recovery); - uint256 txId1 = secureBlox.transferOwnershipRequest(); + uint256 txId1 = accountBlox.transferOwnershipRequest(); // Cancel it vm.prank(recovery); - secureBlox.transferOwnershipCancellation(txId1); + accountBlox.transferOwnershipCancellation(txId1); // Create another transaction vm.prank(recovery); - uint256 txId2 = secureBlox.transferOwnershipRequest(); + uint256 txId2 = accountBlox.transferOwnershipRequest(); // Counter should be monotonic assertGt(txId2, txId1); diff --git a/test/foundry/invariant/TransactionInvariants.t.sol b/test/foundry/invariant/TransactionInvariants.t.sol index 58e4aacb..35dea2a0 100644 --- a/test/foundry/invariant/TransactionInvariants.t.sol +++ b/test/foundry/invariant/TransactionInvariants.t.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: MPL-2.0 pragma solidity 0.8.34; import "../CommonBase.sol"; @@ -15,36 +15,38 @@ contract TransactionInvariantsTest is CommonBase { function invariant_TransactionStatusConsistency() public { // getTransactionHistory requires fromTxId < toTxId; need at least 2 tx ids for a valid range vm.prank(owner); - uint256[] memory pending = secureBlox.getPendingTransactions(); + uint256[] memory pending = accountBlox.getPendingTransactions(); if (pending.length >= 2) { uint256 toTxId = pending[pending.length - 1]; - vm.prank(owner); - EngineBlox.TxRecord[] memory history = secureBlox.getTransactionHistory(1, toTxId); - - for (uint256 i = 0; i < history.length; i++) { - EngineBlox.TxStatus status = history[i].status; + if (toTxId > 1) { + vm.prank(owner); + EngineBlox.TxRecord[] memory history = accountBlox.getTransactionHistory(1, toTxId); + + for (uint256 i = 0; i < history.length; i++) { + EngineBlox.TxStatus status = history[i].status; // Status should be a valid enum value - assertTrue( - status == EngineBlox.TxStatus.PENDING || - status == EngineBlox.TxStatus.EXECUTING || - status == EngineBlox.TxStatus.COMPLETED || - status == EngineBlox.TxStatus.CANCELLED || - status == EngineBlox.TxStatus.FAILED || - status == EngineBlox.TxStatus.REJECTED - ); + assertTrue( + status == EngineBlox.TxStatus.PENDING || + status == EngineBlox.TxStatus.EXECUTING || + status == EngineBlox.TxStatus.COMPLETED || + status == EngineBlox.TxStatus.CANCELLED || + status == EngineBlox.TxStatus.FAILED || + status == EngineBlox.TxStatus.REJECTED + ); + } } } } function invariant_ReleaseTimeValidation() public { vm.prank(owner); - uint256[] memory pending = secureBlox.getPendingTransactions(); + uint256[] memory pending = accountBlox.getPendingTransactions(); for (uint256 i = 0; i < pending.length; i++) { vm.prank(owner); - EngineBlox.TxRecord memory txRecord = secureBlox.getTransaction(pending[i]); + EngineBlox.TxRecord memory txRecord = accountBlox.getTransaction(pending[i]); // Release time should be validly set (greater than zero) // Note: Pending transactions can have releaseTime <= block.timestamp when timelock has elapsed // but transaction hasn't been approved/cancelled yet @@ -57,7 +59,7 @@ contract TransactionInvariantsTest is CommonBase { function invariant_MetaTransactionNonceMonotonic() public { vm.prank(owner); - uint256 currentNonce = secureBlox.getSignerNonce(owner); + uint256 currentNonce = accountBlox.getSignerNonce(owner); // Nonce should be non-decreasing across all state transitions // This invariant is checked across multiple calls via the ghost variable @@ -70,23 +72,25 @@ contract TransactionInvariantsTest is CommonBase { function invariant_PaymentValidation() public { // getTransactionHistory requires fromTxId < toTxId; need at least 2 tx ids for a valid range vm.prank(owner); - uint256[] memory pending = secureBlox.getPendingTransactions(); + uint256[] memory pending = accountBlox.getPendingTransactions(); if (pending.length >= 2) { uint256 toTxId = pending[pending.length - 1]; - vm.prank(owner); - EngineBlox.TxRecord[] memory history = secureBlox.getTransactionHistory(1, toTxId); - - for (uint256 i = 0; i < history.length; i++) { - EngineBlox.PaymentDetails memory payment = history[i].payment; + if (toTxId > 1) { + vm.prank(owner); + EngineBlox.TxRecord[] memory history = accountBlox.getTransactionHistory(1, toTxId); - // If payment recipient is set, verify at least one amount is non-zero - if (payment.recipient != address(0)) { - assertNotEq(payment.recipient, address(0)); - // Payment should have either native token amount or ERC20 amount - bool hasNativePayment = payment.nativeTokenAmount > 0; - bool hasERC20Payment = payment.erc20TokenAddress != address(0) && payment.erc20TokenAmount > 0; - assertTrue(hasNativePayment || hasERC20Payment, "Payment recipient set but no amount"); + for (uint256 i = 0; i < history.length; i++) { + EngineBlox.PaymentDetails memory payment = history[i].payment; + + // If payment recipient is set, verify at least one amount is non-zero + if (payment.recipient != address(0)) { + assertNotEq(payment.recipient, address(0)); + // Payment should have either native token amount or ERC20 amount + bool hasNativePayment = payment.nativeTokenAmount > 0; + bool hasERC20Payment = payment.erc20TokenAddress != address(0) && payment.erc20TokenAmount > 0; + assertTrue(hasNativePayment || hasERC20Payment, "Payment recipient set but no amount"); + } } } } diff --git a/test/foundry/security/AccessControl.t.sol b/test/foundry/security/AccessControl.t.sol index 765c6716..ec2cafa6 100644 --- a/test/foundry/security/AccessControl.t.sol +++ b/test/foundry/security/AccessControl.t.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: MPL-2.0 pragma solidity 0.8.34; import "../CommonBase.sol"; @@ -20,7 +20,7 @@ contract AccessControlTest is CommonBase { function test_Revert_UnauthorizedOwnershipTransfer() public { vm.prank(attacker); vm.expectRevert(abi.encodeWithSelector(SharedValidation.RestrictedRecovery.selector, attacker, recovery)); - secureBlox.transferOwnershipRequest(); + accountBlox.transferOwnershipRequest(); } function test_Revert_UnauthorizedRoleCreation() public { @@ -35,8 +35,8 @@ contract AccessControlTest is CommonBase { // Attempt direct execution (should fail - internal only) vm.prank(attacker); - vm.expectRevert(abi.encodeWithSelector(SharedValidation.OnlyCallableByContract.selector, attacker, address(roleBlox))); - roleBlox.executeRoleConfigBatch(actions); + vm.expectRevert(abi.encodeWithSelector(SharedValidation.OnlyCallableByContract.selector, attacker, address(accountBlox))); + accountBlox.executeRoleConfigBatch(actions); } // NOTE: Function registration has been moved to GuardController @@ -67,21 +67,14 @@ contract AccessControlTest is CommonBase { // This is enforced in EngineBlox library // We verify the roles remain protected vm.prank(owner); - (, , , , bool ownerProtected) = secureBlox.getRole(OWNER_ROLE); + (, , , , bool ownerProtected) = accountBlox.getRole(OWNER_ROLE); assertTrue(ownerProtected); } function test_PermissionBoundary_OwnerOnly() public { // Owner-only functions should reject non-owners vm.prank(attacker); - vm.expectRevert(); - secureBlox.updateBroadcasterRequest(user1, 0); - } - - function test_PermissionBoundary_RecoveryOnly() public { - // Recovery-only functions should reject non-recovery - vm.prank(attacker); - vm.expectRevert(abi.encodeWithSelector(SharedValidation.RestrictedRecovery.selector, attacker, recovery)); - secureBlox.transferOwnershipRequest(); + vm.expectRevert(abi.encodeWithSelector(SharedValidation.RestrictedOwner.selector, attacker, owner)); + accountBlox.updateBroadcasterRequest(user1, 0); } } diff --git a/test/foundry/security/EdgeCases.t.sol b/test/foundry/security/EdgeCases.t.sol index 5eba4073..8871978d 100644 --- a/test/foundry/security/EdgeCases.t.sol +++ b/test/foundry/security/EdgeCases.t.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: MPL-2.0 pragma solidity 0.8.34; import "../CommonBase.sol"; @@ -24,18 +24,16 @@ contract EdgeCasesTest is CommonBase { function test_InvalidStateTransitions() public { // Create and complete a transaction vm.prank(recovery); - uint256 txId = secureBlox.transferOwnershipRequest(); - vm.prank(recovery); - EngineBlox.TxRecord memory requestTx = secureBlox.getTransaction(txId); + uint256 txId = accountBlox.transferOwnershipRequest(); advanceTime(DEFAULT_TIMELOCK_PERIOD + 1); vm.prank(recovery); - secureBlox.transferOwnershipDelayedApproval(txId); + accountBlox.transferOwnershipDelayedApproval(txId); // Try to cancel a completed transaction (should fail) vm.prank(recovery); vm.expectRevert(); - secureBlox.transferOwnershipCancellation(txId); + accountBlox.transferOwnershipCancellation(txId); } function test_CreateMetaTxParams_ShortDeadline() public { @@ -43,13 +41,13 @@ contract EdgeCasesTest is CommonBase { // Note: createMetaTxParams expects duration, so we use a small duration uint256 shortDuration = 1; // 1 second duration - address handlerContract = address(secureBlox); + address handlerContract = address(accountBlox); bytes4 handlerSelector = bytes4(keccak256("testHandler()")); EngineBlox.TxAction action = EngineBlox.TxAction.EXECUTE_META_APPROVE; uint256 maxGasPrice = 100 gwei; // Creating params with short duration should be allowed (validation happens on execution) - EngineBlox.MetaTxParams memory params = secureBlox.createMetaTxParams( + EngineBlox.MetaTxParams memory params = accountBlox.createMetaTxParams( handlerContract, handlerSelector, action, @@ -70,12 +68,12 @@ contract EdgeCasesTest is CommonBase { function test_DuplicateRequests() public { // Create first request vm.prank(recovery); - secureBlox.transferOwnershipRequest(); + accountBlox.transferOwnershipRequest(); // Try to create duplicate (should fail) vm.prank(recovery); vm.expectRevert(SharedValidation.PendingSecureRequest.selector); - secureBlox.transferOwnershipRequest(); + accountBlox.transferOwnershipRequest(); } function test_EmptyArrays() public { @@ -113,16 +111,16 @@ contract EdgeCasesTest is CommonBase { function test_ConcurrentOperations() public { // Only one secure request (ownership or broadcaster) may be pending at a time vm.prank(recovery); - secureBlox.transferOwnershipRequest(); + accountBlox.transferOwnershipRequest(); // Second request while ownership is pending should revert vm.prank(owner); vm.expectRevert(SharedValidation.PendingSecureRequest.selector); - secureBlox.updateBroadcasterRequest(user1, 0); + accountBlox.updateBroadcasterRequest(user1, 0); // Exactly one should be pending vm.prank(owner); - uint256[] memory pending = secureBlox.getPendingTransactions(); + uint256[] memory pending = accountBlox.getPendingTransactions(); assertEq(pending.length, 1); } @@ -130,19 +128,19 @@ contract EdgeCasesTest is CommonBase { // Try to approve non-existent transaction vm.prank(recovery); vm.expectRevert(); - secureBlox.transferOwnershipDelayedApproval(99999); + accountBlox.transferOwnershipDelayedApproval(99999); } function test_BeforeReleaseTime() public { // Create request vm.prank(recovery); - uint256 txId = secureBlox.transferOwnershipRequest(); + uint256 txId = accountBlox.transferOwnershipRequest(); vm.prank(recovery); - EngineBlox.TxRecord memory requestTx = secureBlox.getTransaction(txId); + EngineBlox.TxRecord memory requestTx = accountBlox.getTransaction(txId); // Try to approve before release time vm.prank(recovery); vm.expectRevert(abi.encodeWithSelector(SharedValidation.BeforeReleaseTime.selector, requestTx.releaseTime, block.timestamp)); - secureBlox.transferOwnershipDelayedApproval(txId); + accountBlox.transferOwnershipDelayedApproval(txId); } } diff --git a/test/foundry/security/Reentrancy.t.sol b/test/foundry/security/Reentrancy.t.sol index 78acd2f0..425a39bc 100644 --- a/test/foundry/security/Reentrancy.t.sol +++ b/test/foundry/security/Reentrancy.t.sol @@ -1,8 +1,9 @@ -// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: MPL-2.0 pragma solidity 0.8.34; import "../CommonBase.sol"; import "../helpers/MockContracts.sol"; +import "../../../contracts/core/lib/utils/SharedValidation.sol"; /** * @title ReentrancyTest @@ -19,27 +20,31 @@ contract ReentrancyTest is CommonBase { function test_ReentrancyProtection_OwnershipTransfer() public { // Create ownership transfer request vm.prank(recovery); - uint256 txId = secureBlox.transferOwnershipRequest(); + uint256 txId = accountBlox.transferOwnershipRequest(); vm.prank(recovery); - EngineBlox.TxRecord memory requestTx = secureBlox.getTransaction(txId); + EngineBlox.TxRecord memory requestTx = accountBlox.getTransaction(txId); advanceTime(DEFAULT_TIMELOCK_PERIOD + 1); // First approval should succeed vm.prank(recovery); - secureBlox.transferOwnershipDelayedApproval(txId); + accountBlox.transferOwnershipDelayedApproval(txId); vm.prank(recovery); - EngineBlox.TxRecord memory approvalTx = secureBlox.getTransaction(txId); + EngineBlox.TxRecord memory approvalTx = accountBlox.getTransaction(txId); // Verify single execution completed assertEq(uint8(approvalTx.status), uint8(EngineBlox.TxStatus.COMPLETED)); - assertEq(secureBlox.owner(), recovery); + assertEq(accountBlox.owner(), recovery); // Attempt to call again - state machine should prevent reentrancy - // The transaction status is now COMPLETED, not PENDING, so it should revert + // The transaction status is now COMPLETED, not PENDING, so it should revert with TransactionStatusMismatch vm.prank(recovery); - vm.expectRevert(); - secureBlox.transferOwnershipDelayedApproval(txId); + vm.expectRevert(abi.encodeWithSelector( + SharedValidation.TransactionStatusMismatch.selector, + uint8(EngineBlox.TxStatus.PENDING), + uint8(EngineBlox.TxStatus.COMPLETED) + )); + accountBlox.transferOwnershipDelayedApproval(txId); } function test_ReentrancyProtection_StateMachinePrevents() public { @@ -48,19 +53,23 @@ contract ReentrancyTest is CommonBase { // Reentry attempts would find status as EXECUTING, not PENDING, and fail vm.prank(recovery); - uint256 txId = secureBlox.transferOwnershipRequest(); + uint256 txId = accountBlox.transferOwnershipRequest(); vm.prank(recovery); - EngineBlox.TxRecord memory requestTx = secureBlox.getTransaction(txId); + EngineBlox.TxRecord memory requestTx = accountBlox.getTransaction(txId); advanceTime(DEFAULT_TIMELOCK_PERIOD + 1); // First approval should succeed vm.prank(recovery); - secureBlox.transferOwnershipDelayedApproval(txId); + accountBlox.transferOwnershipDelayedApproval(txId); // Attempt to approve again (would be reentrancy if not protected) vm.prank(recovery); - vm.expectRevert(); - secureBlox.transferOwnershipDelayedApproval(txId); + vm.expectRevert(abi.encodeWithSelector( + SharedValidation.TransactionStatusMismatch.selector, + uint8(EngineBlox.TxStatus.PENDING), + uint8(EngineBlox.TxStatus.COMPLETED) + )); + accountBlox.transferOwnershipDelayedApproval(txId); } } diff --git a/test/foundry/unit/BaseStateMachine.t.sol b/test/foundry/unit/BaseStateMachine.t.sol index 3e0bee03..24d5fc54 100644 --- a/test/foundry/unit/BaseStateMachine.t.sol +++ b/test/foundry/unit/BaseStateMachine.t.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: MPL-2.0 pragma solidity 0.8.34; import "../CommonBase.sol"; @@ -17,14 +17,14 @@ contract BaseStateMachineTest is CommonBase { // ============ META-TRANSACTION UTILITIES TESTS ============ function test_CreateMetaTxParams_ValidParams() public { - address handlerContract = address(secureBlox); + address handlerContract = address(accountBlox); bytes4 handlerSelector = bytes4(keccak256("testHandler()")); EngineBlox.TxAction action = EngineBlox.TxAction.EXECUTE_META_APPROVE; uint256 deadlineDuration = 3600; // Duration in seconds uint256 maxGasPrice = 100 gwei; address signer = owner; - EngineBlox.MetaTxParams memory params = secureBlox.createMetaTxParams( + EngineBlox.MetaTxParams memory params = accountBlox.createMetaTxParams( handlerContract, handlerSelector, action, @@ -50,12 +50,12 @@ contract BaseStateMachineTest is CommonBase { function test_GetTransaction_ReturnsCorrectTransaction() public { // Create a transaction first vm.prank(recovery); - uint256 txId = secureBlox.transferOwnershipRequest(); + uint256 txId = accountBlox.transferOwnershipRequest(); vm.prank(owner); - EngineBlox.TxRecord memory requestTx = secureBlox.getTransaction(txId); + EngineBlox.TxRecord memory requestTx = accountBlox.getTransaction(txId); vm.prank(owner); - EngineBlox.TxRecord memory retrievedTx = secureBlox.getTransaction(txId); + EngineBlox.TxRecord memory retrievedTx = accountBlox.getTransaction(txId); assertEq(retrievedTx.txId, txId); assertEq(uint8(retrievedTx.status), uint8(EngineBlox.TxStatus.PENDING)); } @@ -63,91 +63,91 @@ contract BaseStateMachineTest is CommonBase { function test_GetTransactionHistory_ReturnsRange() public { // Create first transaction (ownership request) vm.prank(recovery); - uint256 txId1 = secureBlox.transferOwnershipRequest(); + uint256 txId1 = accountBlox.transferOwnershipRequest(); vm.prank(recovery); - EngineBlox.TxRecord memory tx1 = secureBlox.getTransaction(txId1); + EngineBlox.TxRecord memory tx1 = accountBlox.getTransaction(txId1); // Complete it so we can create a second request (only one secure request allowed at a time) advanceTime(DEFAULT_TIMELOCK_PERIOD + 1); vm.prank(recovery); - secureBlox.transferOwnershipDelayedApproval(txId1); + accountBlox.transferOwnershipDelayedApproval(txId1); // After approval, recovery is now the owner // Create second transaction (broadcaster request) as new owner vm.prank(recovery); - uint256 txId2 = secureBlox.updateBroadcasterRequest(user1, 0); + uint256 txId2 = accountBlox.updateBroadcasterRequest(user1, 0); vm.prank(recovery); - EngineBlox.TxRecord memory tx2 = secureBlox.getTransaction(txId2); + EngineBlox.TxRecord memory tx2 = accountBlox.getTransaction(txId2); // getTransactionHistory requires fromTxId < toTxId (strictly less than) vm.prank(recovery); - EngineBlox.TxRecord[] memory history = secureBlox.getTransactionHistory(txId1, txId2); + EngineBlox.TxRecord[] memory history = accountBlox.getTransactionHistory(txId1, txId2); assertGe(history.length, 2); } function test_GetPendingTransactions_ReturnsPendingOnly() public { vm.prank(recovery); - secureBlox.transferOwnershipRequest(); + accountBlox.transferOwnershipRequest(); vm.prank(owner); - uint256[] memory pending = secureBlox.getPendingTransactions(); + uint256[] memory pending = accountBlox.getPendingTransactions(); assertGt(pending.length, 0); } function test_GetSupportedOperationTypes_ReturnsAllTypes() public { vm.prank(owner); - bytes32[] memory types = secureBlox.getSupportedOperationTypes(); + bytes32[] memory types = accountBlox.getSupportedOperationTypes(); assertGt(types.length, 0); } function test_GetSupportedRoles_ReturnsAllRoles() public { vm.prank(owner); - bytes32[] memory roles = secureBlox.getSupportedRoles(); + bytes32[] memory roles = accountBlox.getSupportedRoles(); assertGe(roles.length, 3); // At least OWNER, BROADCASTER, RECOVERY } function test_GetSupportedFunctions_ReturnsAllFunctions() public { vm.prank(owner); - bytes4[] memory functions = secureBlox.getSupportedFunctions(); + bytes4[] memory functions = accountBlox.getSupportedFunctions(); assertGt(functions.length, 0); } function test_GetTimeLockPeriodSec_ReturnsCorrectPeriod() public { - assertEq(secureBlox.getTimeLockPeriodSec(), DEFAULT_TIMELOCK_PERIOD); + assertEq(accountBlox.getTimeLockPeriodSec(), DEFAULT_TIMELOCK_PERIOD); } function test_Initialized_ReturnsTrue() public { - assertTrue(secureBlox.initialized()); + assertTrue(accountBlox.initialized()); } // ============ ROLE QUERIES TESTS ============ function test_Owner_ReturnsOwnerAddress() public { - assertEq(secureBlox.owner(), owner); + assertEq(accountBlox.owner(), owner); } function test_GetBroadcasters_ReturnsBroadcasterAddresses() public { - address[] memory broadcasters = secureBlox.getBroadcasters(); + address[] memory broadcasters = accountBlox.getBroadcasters(); assertEq(broadcasters.length, 1); assertEq(broadcasters[0], broadcaster); } function test_GetRecovery_ReturnsRecoveryAddress() public { - assertEq(secureBlox.getRecovery(), recovery); + assertEq(accountBlox.getRecovery(), recovery); } function test_HasRole_ReturnsCorrectPermissions() public { vm.prank(owner); - assertTrue(secureBlox.hasRole(OWNER_ROLE, owner)); + assertTrue(accountBlox.hasRole(OWNER_ROLE, owner)); vm.prank(owner); - assertTrue(secureBlox.hasRole(BROADCASTER_ROLE, broadcaster)); + assertTrue(accountBlox.hasRole(BROADCASTER_ROLE, broadcaster)); vm.prank(owner); - assertTrue(secureBlox.hasRole(RECOVERY_ROLE, recovery)); + assertTrue(accountBlox.hasRole(RECOVERY_ROLE, recovery)); vm.prank(owner); - assertFalse(secureBlox.hasRole(OWNER_ROLE, attacker)); + assertFalse(accountBlox.hasRole(OWNER_ROLE, attacker)); } function test_IsActionSupportedByFunction_ValidatesActions() public { @@ -156,7 +156,7 @@ contract BaseStateMachineTest is CommonBase { // This may or may not be supported depending on function registration // We test the function exists and returns a boolean value - try secureBlox.isActionSupportedByFunction(selector, action) returns (bool supported) { + try accountBlox.isActionSupportedByFunction(selector, action) returns (bool supported) { // Function handled the check and returned a boolean value // Both true and false are valid responses depending on function registration // We verify the function executes successfully and returns a value @@ -169,7 +169,7 @@ contract BaseStateMachineTest is CommonBase { function test_GetActiveRolePermissions_ReturnsPermissions() public { vm.prank(owner); - EngineBlox.FunctionPermission[] memory permissions = secureBlox.getActiveRolePermissions(OWNER_ROLE); + EngineBlox.FunctionPermission[] memory permissions = accountBlox.getActiveRolePermissions(OWNER_ROLE); // Permissions may be empty or populated depending on initialization // We verify the function executes successfully and returns a valid array @@ -186,12 +186,12 @@ contract BaseStateMachineTest is CommonBase { address freshAddress = address(0x9999); vm.prank(owner); - uint256 freshNonce = secureBlox.getSignerNonce(freshAddress); + uint256 freshNonce = accountBlox.getSignerNonce(freshAddress); assertEq(freshNonce, 0, "Nonce should start at 0 for addresses that haven't signed meta-transactions"); // Test that nonce for owner is accessible (may be 0 or higher depending on prior meta-transactions) vm.prank(owner); - uint256 ownerNonce = secureBlox.getSignerNonce(owner); + uint256 ownerNonce = accountBlox.getSignerNonce(owner); // Owner nonce should be >= 0 (always true for uint256, but documents expected behavior) // The actual value depends on whether any meta-transactions have been executed assertGe(ownerNonce, 0, "Owner nonce should be accessible"); @@ -201,10 +201,10 @@ contract BaseStateMachineTest is CommonBase { function test_SupportsInterface_IBaseStateMachine() public { bytes4 interfaceId = type(IBaseStateMachine).interfaceId; - assertTrue(secureBlox.supportsInterface(interfaceId)); + assertTrue(accountBlox.supportsInterface(interfaceId)); } function test_SupportsInterface_ERC165() public { - assertTrue(secureBlox.supportsInterface(0x01ffc9a7)); + assertTrue(accountBlox.supportsInterface(0x01ffc9a7)); } } diff --git a/test/foundry/unit/GuardController.t.sol b/test/foundry/unit/GuardController.t.sol index 6bfe92b3..f66ea8c6 100644 --- a/test/foundry/unit/GuardController.t.sol +++ b/test/foundry/unit/GuardController.t.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: MPL-2.0 pragma solidity 0.8.34; import "../CommonBase.sol"; diff --git a/test/foundry/unit/RuntimeRBAC.t.sol b/test/foundry/unit/RuntimeRBAC.t.sol index 8e36ec71..18ed374b 100644 --- a/test/foundry/unit/RuntimeRBAC.t.sol +++ b/test/foundry/unit/RuntimeRBAC.t.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: MPL-2.0 pragma solidity 0.8.34; import "../CommonBase.sol"; @@ -45,7 +45,7 @@ contract RuntimeRBACTest is CommonBase { // Verify role doesn't exist yet vm.expectRevert(); - roleBlox.getWalletsInRole(roleHash); + accountBlox.getWalletsInRole(roleHash); } function test_GetFunctionSchema_RegisteredFunction() public { @@ -54,7 +54,7 @@ contract RuntimeRBACTest is CommonBase { // This may or may not be registered depending on initialization // We test the function exists and handles both cases - try roleBlox.getFunctionSchema(selector) returns (EngineBlox.FunctionSchema memory schema) { + try accountBlox.getFunctionSchema(selector) returns (EngineBlox.FunctionSchema memory schema) { // Function schema exists - verify it's valid assertGt(bytes(schema.functionSignature).length, 0); assertEq(schema.functionSelector, selector); @@ -69,7 +69,7 @@ contract RuntimeRBACTest is CommonBase { bytes4 invalidSelector = bytes4(0x12345678); vm.prank(owner); // getFunctionSchema requires caller to have any role vm.expectRevert(abi.encodeWithSelector(SharedValidation.ResourceNotFound.selector, bytes32(invalidSelector))); - roleBlox.getFunctionSchema(invalidSelector); + accountBlox.getFunctionSchema(invalidSelector); } function test_GetWalletsInRole_RequiresRole() public { @@ -77,7 +77,7 @@ contract RuntimeRBACTest is CommonBase { // Should work if caller has a role vm.prank(owner); - address[] memory wallets = roleBlox.getWalletsInRole(roleHash); + address[] memory wallets = accountBlox.getWalletsInRole(roleHash); assertGt(wallets.length, 0); } @@ -86,7 +86,7 @@ contract RuntimeRBACTest is CommonBase { vm.prank(attacker); vm.expectRevert(abi.encodeWithSelector(SharedValidation.NoPermission.selector, attacker)); - roleBlox.getWalletsInRole(roleHash); + accountBlox.getWalletsInRole(roleHash); } function test_GetWalletsInRole_Revert_RoleNotFound() public { @@ -94,18 +94,18 @@ contract RuntimeRBACTest is CommonBase { vm.prank(owner); vm.expectRevert(abi.encodeWithSelector(SharedValidation.ResourceNotFound.selector, nonExistentRole)); - roleBlox.getWalletsInRole(nonExistentRole); + accountBlox.getWalletsInRole(nonExistentRole); } // ============ INTERFACE SUPPORT TESTS ============ function test_SupportsInterface_IRuntimeRBAC() public { bytes4 interfaceId = type(IRuntimeRBAC).interfaceId; - assertTrue(roleBlox.supportsInterface(interfaceId)); + assertTrue(accountBlox.supportsInterface(interfaceId)); } function test_SupportsInterface_ERC165() public { - assertTrue(roleBlox.supportsInterface(0x01ffc9a7)); + assertTrue(accountBlox.supportsInterface(0x01ffc9a7)); } // ============ PROTECTED ROLES TESTS ============ @@ -115,12 +115,12 @@ contract RuntimeRBACTest is CommonBase { // This is tested through the state machine's role management // The actual protection is in EngineBlox library vm.prank(owner); - assertTrue(roleBlox.hasRole(OWNER_ROLE, owner)); + assertTrue(accountBlox.hasRole(OWNER_ROLE, owner)); vm.prank(owner); - assertTrue(roleBlox.hasRole(BROADCASTER_ROLE, broadcaster)); + assertTrue(accountBlox.hasRole(BROADCASTER_ROLE, broadcaster)); vm.prank(owner); - assertTrue(roleBlox.hasRole(RECOVERY_ROLE, recovery)); + assertTrue(accountBlox.hasRole(RECOVERY_ROLE, recovery)); } } diff --git a/test/foundry/unit/SecureOwnable.t.sol b/test/foundry/unit/SecureOwnable.t.sol index c5c7b159..45082f9a 100644 --- a/test/foundry/unit/SecureOwnable.t.sol +++ b/test/foundry/unit/SecureOwnable.t.sol @@ -1,7 +1,8 @@ -// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: MPL-2.0 pragma solidity 0.8.34; import "../CommonBase.sol"; +import "../../../contracts/examples/templates/AccountBlox.sol"; import "../../../contracts/core/security/SecureOwnable.sol"; import "../../../contracts/core/security/interface/ISecureOwnable.sol"; import "../../../contracts/core/security/lib/definitions/SecureOwnableDefinitions.sol"; @@ -31,7 +32,7 @@ contract SecureOwnableTest is CommonBase { // ============ INITIALIZATION TESTS ============ function test_Initialize_WithValidParameters() public { - SecureBlox newContract = new SecureBlox(); + AccountBlox newContract = new AccountBlox(); vm.prank(owner); newContract.initialize( owner, @@ -48,7 +49,7 @@ contract SecureOwnableTest is CommonBase { } function test_Initialize_Revert_ZeroOwner() public { - SecureBlox newContract = new SecureBlox(); + AccountBlox newContract = new AccountBlox(); vm.prank(owner); vm.expectRevert(abi.encodeWithSelector(SharedValidation.InvalidAddress.selector, address(0))); newContract.initialize( @@ -61,7 +62,7 @@ contract SecureOwnableTest is CommonBase { } function test_Initialize_Revert_ZeroRecovery() public { - SecureBlox newContract = new SecureBlox(); + AccountBlox newContract = new AccountBlox(); vm.prank(owner); vm.expectRevert(abi.encodeWithSelector(SharedValidation.InvalidAddress.selector, address(0))); newContract.initialize( @@ -74,7 +75,7 @@ contract SecureOwnableTest is CommonBase { } function test_Initialize_Revert_ZeroTimelock() public { - SecureBlox newContract = new SecureBlox(); + AccountBlox newContract = new AccountBlox(); vm.prank(owner); vm.expectRevert(abi.encodeWithSelector(SharedValidation.TimeLockPeriodZero.selector, 0)); newContract.initialize( @@ -87,7 +88,7 @@ contract SecureOwnableTest is CommonBase { } function test_Initialize_Revert_DoubleInitialization() public { - SecureBlox newContract = new SecureBlox(); + AccountBlox newContract = new AccountBlox(); vm.prank(owner); newContract.initialize( owner, @@ -112,9 +113,9 @@ contract SecureOwnableTest is CommonBase { function test_TransferOwnershipRequest_RecoveryCanRequest() public { vm.prank(recovery); - uint256 txId = secureBlox.transferOwnershipRequest(); + uint256 txId = accountBlox.transferOwnershipRequest(); vm.prank(recovery); - EngineBlox.TxRecord memory txRecord = secureBlox.getTransaction(txId); + EngineBlox.TxRecord memory txRecord = accountBlox.getTransaction(txId); assertGt(txRecord.txId, 0); assertEq(uint8(txRecord.status), uint8(EngineBlox.TxStatus.PENDING)); @@ -124,82 +125,82 @@ contract SecureOwnableTest is CommonBase { function test_TransferOwnershipRequest_Revert_Unauthorized() public { vm.prank(attacker); vm.expectRevert(abi.encodeWithSelector(SharedValidation.RestrictedRecovery.selector, attacker, recovery)); - secureBlox.transferOwnershipRequest(); + accountBlox.transferOwnershipRequest(); } function test_TransferOwnershipRequest_Revert_DuplicateRequest() public { vm.prank(recovery); - secureBlox.transferOwnershipRequest(); + accountBlox.transferOwnershipRequest(); vm.prank(recovery); vm.expectRevert(SharedValidation.PendingSecureRequest.selector); - secureBlox.transferOwnershipRequest(); + accountBlox.transferOwnershipRequest(); } function test_TransferOwnershipDelayedApproval_AfterTimelock() public { vm.prank(recovery); - uint256 requestTxId = secureBlox.transferOwnershipRequest(); + uint256 requestTxId = accountBlox.transferOwnershipRequest(); vm.prank(recovery); - EngineBlox.TxRecord memory requestTx = secureBlox.getTransaction(requestTxId); + EngineBlox.TxRecord memory requestTx = accountBlox.getTransaction(requestTxId); uint256 txId = requestTx.txId; // Advance time past timelock advanceTime(DEFAULT_TIMELOCK_PERIOD + 1); vm.prank(recovery); - secureBlox.transferOwnershipDelayedApproval(txId); + accountBlox.transferOwnershipDelayedApproval(txId); vm.prank(recovery); - EngineBlox.TxRecord memory approvalTx = secureBlox.getTransaction(txId); + EngineBlox.TxRecord memory approvalTx = accountBlox.getTransaction(txId); assertEq(uint8(approvalTx.status), uint8(EngineBlox.TxStatus.COMPLETED)); - assertEq(secureBlox.owner(), recovery); + assertEq(accountBlox.owner(), recovery); } function test_TransferOwnershipDelayedApproval_Revert_BeforeTimelock() public { vm.prank(recovery); - uint256 requestTxId = secureBlox.transferOwnershipRequest(); + uint256 requestTxId = accountBlox.transferOwnershipRequest(); vm.prank(recovery); - EngineBlox.TxRecord memory requestTx = secureBlox.getTransaction(requestTxId); + EngineBlox.TxRecord memory requestTx = accountBlox.getTransaction(requestTxId); uint256 txId = requestTx.txId; // Don't advance time vm.prank(recovery); vm.expectRevert(abi.encodeWithSelector(SharedValidation.BeforeReleaseTime.selector, requestTx.releaseTime, block.timestamp)); - secureBlox.transferOwnershipDelayedApproval(txId); + accountBlox.transferOwnershipDelayedApproval(txId); } function test_TransferOwnershipDelayedApproval_OwnerCanApprove() public { vm.prank(recovery); - uint256 requestTxId = secureBlox.transferOwnershipRequest(); + uint256 requestTxId = accountBlox.transferOwnershipRequest(); vm.prank(recovery); - EngineBlox.TxRecord memory requestTx = secureBlox.getTransaction(requestTxId); + EngineBlox.TxRecord memory requestTx = accountBlox.getTransaction(requestTxId); uint256 txId = requestTx.txId; advanceTime(DEFAULT_TIMELOCK_PERIOD + 1); vm.prank(owner); - secureBlox.transferOwnershipDelayedApproval(txId); + accountBlox.transferOwnershipDelayedApproval(txId); // After approval, recovery is the new owner; use recovery to query vm.prank(recovery); - EngineBlox.TxRecord memory approvalTx = secureBlox.getTransaction(txId); + EngineBlox.TxRecord memory approvalTx = accountBlox.getTransaction(txId); assertEq(uint8(approvalTx.status), uint8(EngineBlox.TxStatus.COMPLETED)); } function test_TransferOwnershipCancellation_RecoveryCanCancel() public { vm.prank(recovery); - uint256 requestTxId = secureBlox.transferOwnershipRequest(); + uint256 requestTxId = accountBlox.transferOwnershipRequest(); vm.prank(recovery); - EngineBlox.TxRecord memory requestTx = secureBlox.getTransaction(requestTxId); + EngineBlox.TxRecord memory requestTx = accountBlox.getTransaction(requestTxId); uint256 txId = requestTx.txId; vm.prank(recovery); - secureBlox.transferOwnershipCancellation(txId); + accountBlox.transferOwnershipCancellation(txId); vm.prank(recovery); - EngineBlox.TxRecord memory cancelTx = secureBlox.getTransaction(txId); + EngineBlox.TxRecord memory cancelTx = accountBlox.getTransaction(txId); assertEq(uint8(cancelTx.status), uint8(EngineBlox.TxStatus.CANCELLED)); - assertEq(secureBlox.owner(), owner); // Owner unchanged + assertEq(accountBlox.owner(), owner); // Owner unchanged } // ============ BROADCASTER UPDATE TESTS ============ @@ -207,9 +208,9 @@ contract SecureOwnableTest is CommonBase { function test_UpdateBroadcasterRequest_OwnerCanRequest() public { address newBroadcaster = user1; vm.prank(owner); - uint256 txId = secureBlox.updateBroadcasterRequest(newBroadcaster, 0); + uint256 txId = accountBlox.updateBroadcasterRequest(newBroadcaster, 0); vm.prank(owner); - EngineBlox.TxRecord memory txRecord = secureBlox.getTransaction(txId); + EngineBlox.TxRecord memory txRecord = accountBlox.getTransaction(txId); assertGt(txRecord.txId, 0); assertEq(uint8(txRecord.status), uint8(EngineBlox.TxStatus.PENDING)); @@ -219,41 +220,41 @@ contract SecureOwnableTest is CommonBase { function test_UpdateBroadcasterRequest_Revert_Unauthorized() public { vm.prank(attacker); vm.expectRevert(); - secureBlox.updateBroadcasterRequest(user1, 0); + accountBlox.updateBroadcasterRequest(user1, 0); } function test_UpdateBroadcasterDelayedApproval_AfterTimelock() public { address newBroadcaster = user1; vm.prank(owner); - uint256 requestTxId = secureBlox.updateBroadcasterRequest(newBroadcaster, 0); + uint256 requestTxId = accountBlox.updateBroadcasterRequest(newBroadcaster, 0); vm.prank(owner); - EngineBlox.TxRecord memory requestTx = secureBlox.getTransaction(requestTxId); + EngineBlox.TxRecord memory requestTx = accountBlox.getTransaction(requestTxId); uint256 txId = requestTx.txId; advanceTime(DEFAULT_TIMELOCK_PERIOD + 1); vm.prank(owner); - secureBlox.updateBroadcasterDelayedApproval(txId); + accountBlox.updateBroadcasterDelayedApproval(txId); vm.prank(owner); - EngineBlox.TxRecord memory approvalTx = secureBlox.getTransaction(txId); + EngineBlox.TxRecord memory approvalTx = accountBlox.getTransaction(txId); assertEq(uint8(approvalTx.status), uint8(EngineBlox.TxStatus.COMPLETED)); - address[] memory broadcasters = secureBlox.getBroadcasters(); + address[] memory broadcasters = accountBlox.getBroadcasters(); assertEq(broadcasters[0], newBroadcaster); } function test_UpdateBroadcasterCancellation_OwnerCanCancel() public { address newBroadcaster = user1; vm.prank(owner); - uint256 requestTxId = secureBlox.updateBroadcasterRequest(newBroadcaster, 0); + uint256 requestTxId = accountBlox.updateBroadcasterRequest(newBroadcaster, 0); vm.prank(owner); - EngineBlox.TxRecord memory requestTx = secureBlox.getTransaction(requestTxId); + EngineBlox.TxRecord memory requestTx = accountBlox.getTransaction(requestTxId); uint256 txId = requestTx.txId; vm.prank(owner); - secureBlox.updateBroadcasterCancellation(txId); + accountBlox.updateBroadcasterCancellation(txId); vm.prank(owner); - EngineBlox.TxRecord memory cancelTx = secureBlox.getTransaction(txId); + EngineBlox.TxRecord memory cancelTx = accountBlox.getTransaction(txId); assertEq(uint8(cancelTx.status), uint8(EngineBlox.TxStatus.CANCELLED)); } @@ -261,32 +262,32 @@ contract SecureOwnableTest is CommonBase { function test_UpdateBroadcasterRequest_RevokeAtLocation_ZeroAddress() public { // Add a second broadcaster at location 1 first (BROADCASTER_ROLE is protected: cannot revoke the last wallet) vm.prank(owner); - uint256 addTxId = secureBlox.updateBroadcasterRequest(user2, 1); + uint256 addTxId = accountBlox.updateBroadcasterRequest(user2, 1); vm.prank(owner); - EngineBlox.TxRecord memory addTx = secureBlox.getTransaction(addTxId); + EngineBlox.TxRecord memory addTx = accountBlox.getTransaction(addTxId); advanceTime(DEFAULT_TIMELOCK_PERIOD + 1); vm.prank(owner); - secureBlox.updateBroadcasterDelayedApproval(addTxId); - address[] memory before = secureBlox.getBroadcasters(); + accountBlox.updateBroadcasterDelayedApproval(addTxId); + address[] memory before = accountBlox.getBroadcasters(); assertEq(before.length, 2); assertEq(before[1], user2); // Request revoke at location 1 (zero address = revoke) vm.prank(owner); - uint256 requestTxId = secureBlox.updateBroadcasterRequest(address(0), 1); + uint256 requestTxId = accountBlox.updateBroadcasterRequest(address(0), 1); vm.prank(owner); - EngineBlox.TxRecord memory requestTx = secureBlox.getTransaction(requestTxId); + EngineBlox.TxRecord memory requestTx = accountBlox.getTransaction(requestTxId); uint256 txId = requestTx.txId; advanceTime(DEFAULT_TIMELOCK_PERIOD + 1); vm.prank(owner); - secureBlox.updateBroadcasterDelayedApproval(txId); + accountBlox.updateBroadcasterDelayedApproval(txId); vm.prank(owner); - EngineBlox.TxRecord memory approvalTx = secureBlox.getTransaction(txId); + EngineBlox.TxRecord memory approvalTx = accountBlox.getTransaction(txId); assertEq(uint8(approvalTx.status), uint8(EngineBlox.TxStatus.COMPLETED)); - address[] memory broadcasters = secureBlox.getBroadcasters(); + address[] memory broadcasters = accountBlox.getBroadcasters(); assertEq(broadcasters.length, 1); assertEq(broadcasters[0], broadcaster); } @@ -295,19 +296,19 @@ contract SecureOwnableTest is CommonBase { * @dev Fuzz test for revoke-at-location path: seeds broadcaster list to >= 2, * clamps location, submits revoke with address(0), approves, then asserts * length decreased by one, removal-at-index behavior, no duplicates. - * References: secureBlox.updateBroadcasterRequest, updateBroadcasterDelayedApproval, + * References: accountBlox.updateBroadcasterRequest, updateBroadcasterDelayedApproval, * getBroadcasters, test_UpdateBroadcasterRequest_RevokeAtLocation_ZeroAddress. */ function testFuzz_UpdateBroadcasterRequest_RevokeAtLocation(uint256 location) public { // Seed broadcaster list to at least two entries (same as test_UpdateBroadcasterRequest_RevokeAtLocation_ZeroAddress) vm.prank(owner); - uint256 addTxId = secureBlox.updateBroadcasterRequest(user2, 1); + uint256 addTxId = accountBlox.updateBroadcasterRequest(user2, 1); vm.prank(owner); - EngineBlox.TxRecord memory addTx = secureBlox.getTransaction(addTxId); + EngineBlox.TxRecord memory addTx = accountBlox.getTransaction(addTxId); advanceTime(DEFAULT_TIMELOCK_PERIOD + 1); vm.prank(owner); - secureBlox.updateBroadcasterDelayedApproval(addTxId); - address[] memory before = secureBlox.getBroadcasters(); + accountBlox.updateBroadcasterDelayedApproval(addTxId); + address[] memory before = accountBlox.getBroadcasters(); assertEq(before.length, 2); assertEq(before[1], user2); @@ -316,20 +317,20 @@ contract SecureOwnableTest is CommonBase { // Submit revoke-at-location request (address(0) = revoke) vm.prank(owner); - uint256 requestTxId = secureBlox.updateBroadcasterRequest(address(0), loc); + uint256 requestTxId = accountBlox.updateBroadcasterRequest(address(0), loc); vm.prank(owner); - EngineBlox.TxRecord memory requestTx = secureBlox.getTransaction(requestTxId); + EngineBlox.TxRecord memory requestTx = accountBlox.getTransaction(requestTxId); uint256 txId = requestTx.txId; advanceTime(DEFAULT_TIMELOCK_PERIOD + 1); vm.prank(owner); - secureBlox.updateBroadcasterDelayedApproval(txId); + accountBlox.updateBroadcasterDelayedApproval(txId); vm.prank(owner); - EngineBlox.TxRecord memory approvalTx = secureBlox.getTransaction(txId); + EngineBlox.TxRecord memory approvalTx = accountBlox.getTransaction(txId); assertEq(uint8(approvalTx.status), uint8(EngineBlox.TxStatus.COMPLETED)); - address[] memory after_ = secureBlox.getBroadcasters(); + address[] memory after_ = accountBlox.getBroadcasters(); // Post-conditions: length decreased by one assertEq(after_.length, before.length - 1, "length should decrease by one"); @@ -356,23 +357,23 @@ contract SecureOwnableTest is CommonBase { * delayed approval catches the internal revert and returns status FAILED, list unchanged. */ function test_UpdateBroadcasterRequest_RevokeAtLocation_LastBroadcaster_Reverts() public { - address[] memory b = secureBlox.getBroadcasters(); + address[] memory b = accountBlox.getBroadcasters(); assertEq(b.length, 1, "exactly one broadcaster initially"); vm.prank(owner); - uint256 requestTxId = secureBlox.updateBroadcasterRequest(address(0), 0); + uint256 requestTxId = accountBlox.updateBroadcasterRequest(address(0), 0); vm.prank(owner); - EngineBlox.TxRecord memory requestTx = secureBlox.getTransaction(requestTxId); + EngineBlox.TxRecord memory requestTx = accountBlox.getTransaction(requestTxId); uint256 txId = requestTx.txId; advanceTime(DEFAULT_TIMELOCK_PERIOD + 1); vm.prank(owner); - secureBlox.updateBroadcasterDelayedApproval(txId); + accountBlox.updateBroadcasterDelayedApproval(txId); vm.prank(owner); - EngineBlox.TxRecord memory approvalTx = secureBlox.getTransaction(txId); + EngineBlox.TxRecord memory approvalTx = accountBlox.getTransaction(txId); assertEq(uint8(approvalTx.status), uint8(EngineBlox.TxStatus.FAILED), "owner protection: revoke last must fail"); - address[] memory after_ = secureBlox.getBroadcasters(); + address[] memory after_ = accountBlox.getBroadcasters(); assertEq(after_.length, 1, "broadcaster list unchanged"); assertEq(after_[0], broadcaster, "single broadcaster preserved"); } @@ -386,12 +387,12 @@ contract SecureOwnableTest is CommonBase { * test_UpdateBroadcasterRequest_RevokeAtLocation_ZeroAddress. */ function invariant_BroadcasterListSafety() public { - address[] memory broadcasters = secureBlox.getBroadcasters(); + address[] memory broadcasters = accountBlox.getBroadcasters(); assertGe(broadcasters.length, 1, "at least one broadcaster"); vm.prank(owner); - (, , uint256 maxWallets, , ) = secureBlox.getRole(BROADCASTER_ROLE); + (, , uint256 maxWallets, , ) = accountBlox.getRole(BROADCASTER_ROLE); assertLe(broadcasters.length, maxWallets, "broadcasters within role limit"); for (uint256 i = 0; i < broadcasters.length; i++) { @@ -454,39 +455,39 @@ contract SecureOwnableTest is CommonBase { // Create a transaction that will call executeTransferOwnership vm.prank(recovery); - uint256 requestTxId = secureBlox.transferOwnershipRequest(); + uint256 requestTxId = accountBlox.transferOwnershipRequest(); vm.prank(recovery); - EngineBlox.TxRecord memory requestTx = secureBlox.getTransaction(requestTxId); + EngineBlox.TxRecord memory requestTx = accountBlox.getTransaction(requestTxId); uint256 txId = requestTx.txId; advanceTime(DEFAULT_TIMELOCK_PERIOD + 1); // The approval will internally call executeTransferOwnership vm.prank(recovery); - secureBlox.transferOwnershipDelayedApproval(txId); + accountBlox.transferOwnershipDelayedApproval(txId); - assertEq(secureBlox.owner(), recovery); + assertEq(accountBlox.owner(), recovery); } function test_ExecuteTransferOwnership_Revert_ExternalCall() public { - vm.expectRevert(abi.encodeWithSelector(SharedValidation.OnlyCallableByContract.selector, attacker, address(secureBlox))); + vm.expectRevert(abi.encodeWithSelector(SharedValidation.OnlyCallableByContract.selector, attacker, address(accountBlox))); vm.prank(attacker); - secureBlox.executeTransferOwnership(user1); + accountBlox.executeTransferOwnership(user1); } // ============ INTERFACE SUPPORT TESTS ============ function test_SupportsInterface_ISecureOwnable() public { bytes4 interfaceId = type(ISecureOwnable).interfaceId; - assertTrue(secureBlox.supportsInterface(interfaceId)); + assertTrue(accountBlox.supportsInterface(interfaceId)); } function test_SupportsInterface_ERC165() public { - assertTrue(secureBlox.supportsInterface(0x01ffc9a7)); + assertTrue(accountBlox.supportsInterface(0x01ffc9a7)); } function test_SupportsInterface_InvalidInterface() public { - assertFalse(secureBlox.supportsInterface(0x12345678)); + assertFalse(accountBlox.supportsInterface(0x12345678)); } // ============ META-TRANSACTION TESTS ============ @@ -497,19 +498,19 @@ contract SecureOwnableTest is CommonBase { // Step 1: Create ownership transfer request vm.prank(recovery); - uint256 requestTxId = secureBlox.transferOwnershipRequest(); + uint256 requestTxId = accountBlox.transferOwnershipRequest(); vm.prank(recovery); - EngineBlox.TxRecord memory requestTx = secureBlox.getTransaction(requestTxId); + EngineBlox.TxRecord memory requestTx = accountBlox.getTransaction(requestTxId); uint256 txId = requestTx.txId; // Step 2: Create meta-transaction parameters - address handlerContract = address(secureBlox); + address handlerContract = address(accountBlox); bytes4 handlerSelector = bytes4(keccak256("transferOwnershipDelayedApproval(uint256)")); EngineBlox.TxAction action = EngineBlox.TxAction.EXECUTE_META_APPROVE; uint256 deadlineDuration = 3600; // Duration in seconds uint256 maxGasPrice = 100 gwei; - EngineBlox.MetaTxParams memory metaTxParams = secureBlox.createMetaTxParams( + EngineBlox.MetaTxParams memory metaTxParams = accountBlox.createMetaTxParams( handlerContract, handlerSelector, action, @@ -520,7 +521,7 @@ contract SecureOwnableTest is CommonBase { // Step 3: Generate unsigned meta-transaction vm.prank(recovery); - EngineBlox.MetaTransaction memory unsignedMetaTx = secureBlox.generateUnsignedMetaTransactionForExisting( + EngineBlox.MetaTransaction memory unsignedMetaTx = accountBlox.generateUnsignedMetaTransactionForExisting( txId, metaTxParams ); @@ -529,7 +530,7 @@ contract SecureOwnableTest is CommonBase { bytes memory signature = metaTxSigner.signMetaTransaction( unsignedMetaTx, privateKey, - address(secureBlox) + address(accountBlox) ); // Step 5: Verify signature structure @@ -539,7 +540,7 @@ contract SecureOwnableTest is CommonBase { // Step 6: Verify message hash consistency bytes32 expectedHash = metaTxSigner.generateMessageHash( unsignedMetaTx, - address(secureBlox) + address(accountBlox) ); assertEq(unsignedMetaTx.message, expectedHash); @@ -551,12 +552,12 @@ contract SecureOwnableTest is CommonBase { function test_MultiplePendingRequests_OnlyOneOwnership() public { vm.prank(recovery); - secureBlox.transferOwnershipRequest(); + accountBlox.transferOwnershipRequest(); // Try to create another ownership request vm.prank(recovery); vm.expectRevert(SharedValidation.PendingSecureRequest.selector); - secureBlox.transferOwnershipRequest(); + accountBlox.transferOwnershipRequest(); } function test_OwnershipTransfer_CompleteWorkflow() public { @@ -564,14 +565,14 @@ contract SecureOwnableTest is CommonBase { // Step 1: Request vm.prank(recovery); - uint256 requestTxId = secureBlox.transferOwnershipRequest(); + uint256 requestTxId = accountBlox.transferOwnershipRequest(); vm.prank(recovery); - EngineBlox.TxRecord memory requestTx = secureBlox.getTransaction(requestTxId); + EngineBlox.TxRecord memory requestTx = accountBlox.getTransaction(requestTxId); uint256 txId = requestTx.txId; // Verify pending vm.prank(owner); - EngineBlox.TxRecord memory pendingTx = secureBlox.getTransaction(txId); + EngineBlox.TxRecord memory pendingTx = accountBlox.getTransaction(txId); assertEq(uint8(pendingTx.status), uint8(EngineBlox.TxStatus.PENDING)); // Step 2: Advance time @@ -579,12 +580,12 @@ contract SecureOwnableTest is CommonBase { // Step 3: Approve vm.prank(recovery); - secureBlox.transferOwnershipDelayedApproval(txId); + accountBlox.transferOwnershipDelayedApproval(txId); vm.prank(recovery); - EngineBlox.TxRecord memory approvalTx = secureBlox.getTransaction(txId); + EngineBlox.TxRecord memory approvalTx = accountBlox.getTransaction(txId); // Step 4: Verify completion assertEq(uint8(approvalTx.status), uint8(EngineBlox.TxStatus.COMPLETED)); - assertEq(secureBlox.owner(), recovery); + assertEq(accountBlox.owner(), recovery); } } diff --git a/test/foundry/unit/StateAbstraction.t.sol b/test/foundry/unit/StateAbstraction.t.sol index dfefb176..dcb62da6 100644 --- a/test/foundry/unit/StateAbstraction.t.sol +++ b/test/foundry/unit/StateAbstraction.t.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: MPL-2.0 pragma solidity 0.8.34; import "../CommonBase.sol"; @@ -44,34 +44,34 @@ contract EngineBloxTest is CommonBase { function test_TransactionStatus_Transitions() public { // Create a transaction vm.prank(recovery); - uint256 txId = secureBlox.transferOwnershipRequest(); + uint256 txId = accountBlox.transferOwnershipRequest(); // Verify PENDING status vm.prank(owner); - EngineBlox.TxRecord memory pendingTx = secureBlox.getTransaction(txId); + EngineBlox.TxRecord memory pendingTx = accountBlox.getTransaction(txId); assertEq(uint8(pendingTx.status), uint8(EngineBlox.TxStatus.PENDING)); // Advance time and approve advanceTime(DEFAULT_TIMELOCK_PERIOD + 1); vm.prank(recovery); - secureBlox.transferOwnershipDelayedApproval(txId); + accountBlox.transferOwnershipDelayedApproval(txId); // Verify COMPLETED status // Note: After ownership transfer, the owner changes from owner to recovery // So we need to use recovery (the new owner) to view the transaction vm.prank(recovery); - EngineBlox.TxRecord memory completedTx = secureBlox.getTransaction(txId); + EngineBlox.TxRecord memory completedTx = accountBlox.getTransaction(txId); assertEq(uint8(completedTx.status), uint8(EngineBlox.TxStatus.COMPLETED)); } function test_TransactionStatus_InvalidTransition() public { // Create and immediately try to approve (should fail) vm.prank(recovery); - uint256 txId = secureBlox.transferOwnershipRequest(); + uint256 txId = accountBlox.transferOwnershipRequest(); // Try to approve before timelock (should revert) vm.prank(recovery); vm.expectRevert(); - secureBlox.transferOwnershipDelayedApproval(txId); + accountBlox.transferOwnershipDelayedApproval(txId); } } diff --git a/truffle-config.cjs b/truffle-config.cjs index 3642b270..014d8222 100644 --- a/truffle-config.cjs +++ b/truffle-config.cjs @@ -39,7 +39,7 @@ */ // Load environment variables from .env file -require('dotenv').config(); +require('dotenv').config({ quiet: true }); // Helper function to create provider URL function getProviderUrl() {