diff --git a/control-panel.compose.yml b/control-panel.compose.yml index 25e8d93c..2fff3e81 100644 --- a/control-panel.compose.yml +++ b/control-panel.compose.yml @@ -9,42 +9,3 @@ services: command: -config.file=/etc/loki/local-config.yaml networks: - loki - - promtail: - image: grafana/promtail:latest - volumes: - - /var/log:/var/log - command: -config.file=/etc/promtail/config.yml - networks: - - loki - - grafana: - environment: - - GF_PATHS_PROVISIONING=/etc/grafana/provisioning - - GF_AUTH_ANONYMOUS_ENABLED=true - - GF_AUTH_ANONYMOUS_ORG_ROLE=Admin - - GF_FEATURE_TOGGLES_ENABLE=alertingSimplifiedRouting,alertingQueryAndExpressionsStepMode - entrypoint: - - sh - - -euc - - | - mkdir -p /etc/grafana/provisioning/datasources - cat < /etc/grafana/provisioning/datasources/ds.yaml - apiVersion: 1 - datasources: - - name: Loki - type: loki - access: proxy - orgId: 1 - url: http://loki:3100 - basicAuth: false - isDefault: true - version: 1 - editable: false - EOF - /run.sh - image: grafana/grafana:latest - ports: - - "3000:3000" - networks: - - loki diff --git a/infrastructure/blindvote/README.md b/infrastructure/blindvote/README.md new file mode 100644 index 00000000..94a7cfe5 --- /dev/null +++ b/infrastructure/blindvote/README.md @@ -0,0 +1,256 @@ +# BlindVote - Decentralized Privacy-Preserving Voting System + +A cryptographically secure voting system that uses Pedersen commitments to ensure voter privacy while maintaining public verifiability of election results. + +## Key Features + +- **Totally Decentralized**: No trusted servers or dealers needed +- **Flexible Voting Options**: Support for any number of vote options (not just binary yes/no) +- **Privacy Preserving**: Individual votes are never revealed +- **Publicly Verifiable**: Anyone can verify the final election results +- **Cryptographically Sound**: Uses ed25519 elliptic curve and proper Pedersen commitments +- **Simple & Clean**: No complex ZK proofs - just the essential crypto operations + +## Architecture + +The system follows a simple 5-phase process: + +1. **Registration**: Voters create public randomness anchors +2. **Voting**: Voters submit encrypted ballots using Pedersen commitments +3. **Aggregation**: All commitments are homomorphically combined +4. **Tally**: Final results are computed from the aggregate commitment +5. **Verification**: Anyone can verify the results are consistent + +## Cryptographic Foundation + +### Pedersen Commitments + +- **Commitment**: `C(m, r) = g^m * h^r` + - `g` = generator point + - `h` = second generator (unknown discrete log relationship) + - `m` = vote value + - `r` = random blinding factor + +### Homomorphic Properties + +- **Addition**: `C(m1, r1) * C(m2, r2) = C(m1 + m2, r1 + r2)` +- **Aggregation**: `C_agg = ∏ C_i = g^(∑m_i) * h^(∑r_i)` +- **Cancellation**: `X = C_agg * H_S^(-1) = g^(∑m_i)` + +## Project Structure + +``` +src/ +├── core/ +│ ├── types.ts # Type definitions +│ └── voting-system.ts # Main voting system implementation +├── crypto/ +│ └── pedersen.ts # Pedersen commitment implementation +└── examples/ + └── example.ts # Presidential election example +``` + +## Quick Start + +### Installation + +```bash +# Clone the repository +git clone +cd blindvote + +# Install dependencies +pnpm install + +# Build the project +pnpm build +``` + +### Basic Usage + +```typescript +import { DecentralizedVotingSystem, ElectionConfig } from "blindvote"; + +// Create an election configuration +const electionConfig: ElectionConfig = { + id: "demo-election", + title: "Demo Election", + description: "A simple demonstration", + options: [ + { id: "option-a", label: "Option A", value: 1 }, + { id: "option-b", label: "Option B", value: 2 }, + { id: "option-c", label: "Option C", value: 3 }, + ], +}; + +// Initialize the voting system +const votingSystem = new DecentralizedVotingSystem(electionConfig); + +// Register voters +await votingSystem.registerVoter("alice"); +await votingSystem.registerVoter("bob"); + +// Cast votes +await votingSystem.castBallot("alice", "option-a"); +await votingSystem.castBallot("bob", "option-b"); + +// Aggregate and tally +const result = await votingSystem.tally(); +console.log("Election result:", result); +``` + +### Running Examples + +```bash +# Presidential election example +node dist/examples/example.js +``` + +## API Reference + +### ElectionConfig + +```typescript +interface ElectionConfig { + id: string; // Unique election identifier + title: string; // Human-readable title + description?: string; // Optional description + options: VoteOption[]; // Available vote options + maxVotes?: number; // Maximum votes per voter (default: 1) + allowAbstain?: boolean; // Allow abstaining (default: false) +} +``` + +### VoteOption + +```typescript +interface VoteOption { + id: string; // Unique option identifier + label: string; // Human-readable label + value: number; // Numeric value for the option +} +``` + +### DecentralizedVotingSystem + +#### Core Methods + +- `registerVoter(voterId: string): Promise` - Register a new voter +- `castBallot(voterId: string, optionId: string): Promise` - Cast a vote +- `aggregate(): Promise` - Aggregate all ballots +- `tally(): Promise` - Compute final results +- `verifyTally(results, expected): Promise` - Verify results + +#### Utility Methods + +- `getRegisteredVoters(): Anchor[]` - Get all registered voters +- `getSubmittedBallots(): Ballot[]` - Get all submitted ballots +- `isVoterRegistered(voterId): boolean` - Check voter registration +- `hasVoterVoted(voterId): boolean` - Check if voter has voted + +## Use Cases + +### Multi-Candidate Elections + +- Presidential elections +- Board member elections +- Award voting + +### Preference Voting + +- Ranked choice voting +- Approval voting +- Score voting + +### Surveys and Polls + +- Customer satisfaction surveys +- Product preference polls +- Team decision making + +## Security Properties + +1. **Vote Privacy**: Individual votes are never revealed +2. **Vote Integrity**: Votes cannot be modified after submission +3. **Voter Anonymity**: Voter identity is not linked to their vote +4. **Public Verifiability**: Anyone can verify the final results +5. **No Double Voting**: Each voter can only vote once +6. **Decentralized**: No single point of failure or control + +## Limitations & Considerations + +### Current Implementation + +- **Demo Tallying**: The current tally implementation simulates vote counting for demonstration +- **No ZK Proofs**: Simplified version without zero-knowledge proofs +- **Basic Validation**: Simple validation without advanced cryptographic proofs + +### Production Considerations + +- **Discrete Log Problem**: For large vote counts, discrete log computation becomes expensive +- **Multi-Option Tallying**: Current scheme works best for binary or small-range voting +- **Voter Authentication**: This implementation doesn't handle real-world voter authentication +- **Network Layer**: No built-in networking or bulletin board implementation + +## Future Enhancements + +1. **Efficient Multi-Option Tallying**: Implement proper schemes for multi-option voting +2. **Voter Authentication**: Add real-world voter identity verification +3. **Network Layer**: Implement decentralized bulletin board +4. **Advanced Privacy**: Add mix networks or other privacy enhancements +5. **Scalability**: Optimize for large-scale elections + +## Testing + +```bash +# Build the project +pnpm build + +# Run examples +node dist/examples/example.js + +# Run tests (if available) +pnpm test +``` + +## Technical Details + +### Curve Choice: ed25519 + +- **Performance**: Faster than secp256k1 for most operations +- **Security**: 128-bit security level +- **Standardization**: Well-established and audited +- **Implementation**: Uses @noble/curves library + +### Commitment Scheme + +- **Binding**: Computationally infeasible to find different messages with same commitment +- **Hiding**: Commitment reveals no information about the message +- **Homomorphic**: Commitments can be combined algebraically + +## Contributing + +1. Fork the repository +2. Create a feature branch +3. Make your changes +4. Add tests if applicable +5. Submit a pull request + +## License + +This project is licensed under the MIT License - see the LICENSE file for details. + +## Disclaimer + +This is a research and educational implementation. For production use, additional security audits, testing, and hardening would be required. + +## References + +- [Pedersen Commitments](https://en.wikipedia.org/wiki/Commitment_scheme#Pedersen_commitment) +- [ed25519 Curve](https://ed25519.cr.yp.to/) +- [Homomorphic Encryption](https://en.wikipedia.org/wiki/Homomorphic_encryption) +- [Decentralized Voting](https://en.wikipedia.org/wiki/Electronic_voting#Decentralized_voting) + +--- + +Built with love for transparent, secure, and democratic voting systems. diff --git a/infrastructure/blindvote/package.json b/infrastructure/blindvote/package.json new file mode 100644 index 00000000..e6ad88d0 --- /dev/null +++ b/infrastructure/blindvote/package.json @@ -0,0 +1,36 @@ +{ + "name": "blindvote", + "version": "1.0.0", + "description": "Privacy-preserving voting system using Pedersen commitments and zero-knowledge proofs", + "main": "dist/index.js", + "types": "dist/index.d.ts", + "scripts": { + "build": "tsc", + "dev": "ts-node src/index.ts", + "test": "jest", + "example": "ts-node src/examples/example.ts", + "postinstall": "npm run build" + }, + "keywords": [ + "voting", + "privacy", + "zero-knowledge", + "pedersen", + "commitments" + ], + "author": "", + "license": "ISC", + "devDependencies": { + "@types/jest": "^29.0.0", + "@types/node": "^20.0.0", + "jest": "^29.0.0", + "ts-jest": "^29.0.0", + "ts-node": "^10.9.0", + "typescript": "^5.0.0" + }, + "dependencies": { + "@noble/curves": "^1.9.7", + "@noble/hashes": "^1.8.0", + "tiny-invariant": "^1.3.3" + } +} diff --git a/infrastructure/blindvote/pnpm-lock.yaml b/infrastructure/blindvote/pnpm-lock.yaml new file mode 100644 index 00000000..3f18c783 --- /dev/null +++ b/infrastructure/blindvote/pnpm-lock.yaml @@ -0,0 +1,3563 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: + dependencies: + '@noble/curves': + specifier: ^1.9.7 + version: 1.9.7 + big-integer: + specifier: ^1.6.51 + version: 1.6.52 + circomlibjs: + specifier: ^0.1.7 + version: 0.1.7 + ffjavascript: + specifier: ^0.2.55 + version: 0.2.63 + noble-bls12-381: + specifier: ^0.7.0 + version: 0.7.2 + noble-hashes: + specifier: ^0.3.1 + version: 0.3.1 + noble-secp256k1: + specifier: ^1.2.14 + version: 1.2.14 + snarkjs: + specifier: ^0.7.0 + version: 0.7.5 + devDependencies: + '@types/jest': + specifier: ^29.0.0 + version: 29.5.14 + '@types/node': + specifier: ^20.0.0 + version: 20.19.9 + jest: + specifier: ^29.0.0 + version: 29.7.0(@types/node@20.19.9)(ts-node@10.9.2(@types/node@20.19.9)(typescript@5.8.3)) + ts-jest: + specifier: ^29.0.0 + version: 29.4.0(@babel/core@7.28.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.28.0))(jest-util@29.7.0)(jest@29.7.0(@types/node@20.19.9)(ts-node@10.9.2(@types/node@20.19.9)(typescript@5.8.3)))(typescript@5.8.3) + ts-node: + specifier: ^10.9.0 + version: 10.9.2(@types/node@20.19.9)(typescript@5.8.3) + typescript: + specifier: ^5.0.0 + version: 5.8.3 + +packages: + + '@ampproject/remapping@2.3.0': + resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==} + engines: {node: '>=6.0.0'} + + '@babel/code-frame@7.27.1': + resolution: {integrity: sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==} + engines: {node: '>=6.9.0'} + + '@babel/compat-data@7.28.0': + resolution: {integrity: sha512-60X7qkglvrap8mn1lh2ebxXdZYtUcpd7gsmy9kLaBJ4i/WdY8PqTSdxyA8qraikqKQK5C1KRBKXqznrVapyNaw==} + engines: {node: '>=6.9.0'} + + '@babel/core@7.28.0': + resolution: {integrity: sha512-UlLAnTPrFdNGoFtbSXwcGFQBtQZJCNjaN6hQNP3UPvuNXT1i82N26KL3dZeIpNalWywr9IuQuncaAfUaS1g6sQ==} + engines: {node: '>=6.9.0'} + + '@babel/generator@7.28.0': + resolution: {integrity: sha512-lJjzvrbEeWrhB4P3QBsH7tey117PjLZnDbLiQEKjQ/fNJTjuq4HSqgFA+UNSwZT8D7dxxbnuSBMsa1lrWzKlQg==} + engines: {node: '>=6.9.0'} + + '@babel/helper-compilation-targets@7.27.2': + resolution: {integrity: sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==} + engines: {node: '>=6.9.0'} + + '@babel/helper-globals@7.28.0': + resolution: {integrity: sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-module-imports@7.27.1': + resolution: {integrity: sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==} + engines: {node: '>=6.9.0'} + + '@babel/helper-module-transforms@7.27.3': + resolution: {integrity: sha512-dSOvYwvyLsWBeIRyOeHXp5vPj5l1I011r52FM1+r1jCERv+aFXYk4whgQccYEGYxK2H3ZAIA8nuPkQ0HaUo3qg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/helper-plugin-utils@7.27.1': + resolution: {integrity: sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-string-parser@7.27.1': + resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-identifier@7.27.1': + resolution: {integrity: sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-option@7.27.1': + resolution: {integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==} + engines: {node: '>=6.9.0'} + + '@babel/helpers@7.28.2': + resolution: {integrity: sha512-/V9771t+EgXz62aCcyofnQhGM8DQACbRhvzKFsXKC9QM+5MadF8ZmIm0crDMaz3+o0h0zXfJnd4EhbYbxsrcFw==} + engines: {node: '>=6.9.0'} + + '@babel/parser@7.28.0': + resolution: {integrity: sha512-jVZGvOxOuNSsuQuLRTh13nU0AogFlw32w/MT+LV6D3sP5WdbW61E77RnkbaO2dUvmPAYrBDJXGn5gGS6tH4j8g==} + engines: {node: '>=6.0.0'} + hasBin: true + + '@babel/plugin-syntax-async-generators@7.8.4': + resolution: {integrity: sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-bigint@7.8.3': + resolution: {integrity: sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-class-properties@7.12.13': + resolution: {integrity: sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-class-static-block@7.14.5': + resolution: {integrity: sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-import-attributes@7.27.1': + resolution: {integrity: sha512-oFT0FrKHgF53f4vOsZGi2Hh3I35PfSmVs4IBFLFj4dnafP+hIWDLg3VyKmUHfLoLHlyxY4C7DGtmHuJgn+IGww==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-import-meta@7.10.4': + resolution: {integrity: sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-json-strings@7.8.3': + resolution: {integrity: sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-jsx@7.27.1': + resolution: {integrity: sha512-y8YTNIeKoyhGd9O0Jiyzyyqk8gdjnumGTQPsz0xOZOQ2RmkVJeZ1vmmfIvFEKqucBG6axJGBZDE/7iI5suUI/w==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-logical-assignment-operators@7.10.4': + resolution: {integrity: sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3': + resolution: {integrity: sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-numeric-separator@7.10.4': + resolution: {integrity: sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-object-rest-spread@7.8.3': + resolution: {integrity: sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-optional-catch-binding@7.8.3': + resolution: {integrity: sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-optional-chaining@7.8.3': + resolution: {integrity: sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-private-property-in-object@7.14.5': + resolution: {integrity: sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-top-level-await@7.14.5': + resolution: {integrity: sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-typescript@7.27.1': + resolution: {integrity: sha512-xfYCBMxveHrRMnAWl1ZlPXOZjzkN82THFvLhQhFXFt81Z5HnN+EtUkZhv/zcKpmT3fzmWZB0ywiBrbC3vogbwQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/template@7.27.2': + resolution: {integrity: sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==} + engines: {node: '>=6.9.0'} + + '@babel/traverse@7.28.0': + resolution: {integrity: sha512-mGe7UK5wWyh0bKRfupsUchrQGqvDbZDbKJw+kcRGSmdHVYrv+ltd0pnpDTVpiTqnaBru9iEvA8pz8W46v0Amwg==} + engines: {node: '>=6.9.0'} + + '@babel/types@7.28.2': + resolution: {integrity: sha512-ruv7Ae4J5dUYULmeXw1gmb7rYRz57OWCPM57pHojnLq/3Z1CK2lNSLTCVjxVk1F/TZHwOZZrOWi0ur95BbLxNQ==} + engines: {node: '>=6.9.0'} + + '@bcoe/v8-coverage@0.2.3': + resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==} + + '@cspotcode/source-map-support@0.8.1': + resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==} + engines: {node: '>=12'} + + '@ethersproject/abi@5.8.0': + resolution: {integrity: sha512-b9YS/43ObplgyV6SlyQsG53/vkSal0MNA1fskSC4mbnCMi8R+NkcH8K9FPYNESf6jUefBUniE4SOKms0E/KK1Q==} + + '@ethersproject/abstract-provider@5.8.0': + resolution: {integrity: sha512-wC9SFcmh4UK0oKuLJQItoQdzS/qZ51EJegK6EmAWlh+OptpQ/npECOR3QqECd8iGHC0RJb4WKbVdSfif4ammrg==} + + '@ethersproject/abstract-signer@5.8.0': + resolution: {integrity: sha512-N0XhZTswXcmIZQdYtUnd79VJzvEwXQw6PK0dTl9VoYrEBxxCPXqS0Eod7q5TNKRxe1/5WUMuR0u0nqTF/avdCA==} + + '@ethersproject/address@5.8.0': + resolution: {integrity: sha512-GhH/abcC46LJwshoN+uBNoKVFPxUuZm6dA257z0vZkKmU1+t8xTn8oK7B9qrj8W2rFRMch4gbJl6PmVxjxBEBA==} + + '@ethersproject/base64@5.8.0': + resolution: {integrity: sha512-lN0oIwfkYj9LbPx4xEkie6rAMJtySbpOAFXSDVQaBnAzYfB4X2Qr+FXJGxMoc3Bxp2Sm8OwvzMrywxyw0gLjIQ==} + + '@ethersproject/basex@5.8.0': + resolution: {integrity: sha512-PIgTszMlDRmNwW9nhS6iqtVfdTAKosA7llYXNmGPw4YAI1PUyMv28988wAb41/gHF/WqGdoLv0erHaRcHRKW2Q==} + + '@ethersproject/bignumber@5.8.0': + resolution: {integrity: sha512-ZyaT24bHaSeJon2tGPKIiHszWjD/54Sz8t57Toch475lCLljC6MgPmxk7Gtzz+ddNN5LuHea9qhAe0x3D+uYPA==} + + '@ethersproject/bytes@5.8.0': + resolution: {integrity: sha512-vTkeohgJVCPVHu5c25XWaWQOZ4v+DkGoC42/TS2ond+PARCxTJvgTFUNDZovyQ/uAQ4EcpqqowKydcdmRKjg7A==} + + '@ethersproject/constants@5.8.0': + resolution: {integrity: sha512-wigX4lrf5Vu+axVTIvNsuL6YrV4O5AXl5ubcURKMEME5TnWBouUh0CDTWxZ2GpnRn1kcCgE7l8O5+VbV9QTTcg==} + + '@ethersproject/contracts@5.8.0': + resolution: {integrity: sha512-0eFjGz9GtuAi6MZwhb4uvUM216F38xiuR0yYCjKJpNfSEy4HUM8hvqqBj9Jmm0IUz8l0xKEhWwLIhPgxNY0yvQ==} + + '@ethersproject/hash@5.8.0': + resolution: {integrity: sha512-ac/lBcTbEWW/VGJij0CNSw/wPcw9bSRgCB0AIBz8CvED/jfvDoV9hsIIiWfvWmFEi8RcXtlNwp2jv6ozWOsooA==} + + '@ethersproject/hdnode@5.8.0': + resolution: {integrity: sha512-4bK1VF6E83/3/Im0ERnnUeWOY3P1BZml4ZD3wcH8Ys0/d1h1xaFt6Zc+Dh9zXf9TapGro0T4wvO71UTCp3/uoA==} + + '@ethersproject/json-wallets@5.8.0': + resolution: {integrity: sha512-HxblNck8FVUtNxS3VTEYJAcwiKYsBIF77W15HufqlBF9gGfhmYOJtYZp8fSDZtn9y5EaXTE87zDwzxRoTFk11w==} + + '@ethersproject/keccak256@5.8.0': + resolution: {integrity: sha512-A1pkKLZSz8pDaQ1ftutZoaN46I6+jvuqugx5KYNeQOPqq+JZ0Txm7dlWesCHB5cndJSu5vP2VKptKf7cksERng==} + + '@ethersproject/logger@5.8.0': + resolution: {integrity: sha512-Qe6knGmY+zPPWTC+wQrpitodgBfH7XoceCGL5bJVejmH+yCS3R8jJm8iiWuvWbG76RUmyEG53oqv6GMVWqunjA==} + + '@ethersproject/networks@5.8.0': + resolution: {integrity: sha512-egPJh3aPVAzbHwq8DD7Po53J4OUSsA1MjQp8Vf/OZPav5rlmWUaFLiq8cvQiGK0Z5K6LYzm29+VA/p4RL1FzNg==} + + '@ethersproject/pbkdf2@5.8.0': + resolution: {integrity: sha512-wuHiv97BrzCmfEaPbUFpMjlVg/IDkZThp9Ri88BpjRleg4iePJaj2SW8AIyE8cXn5V1tuAaMj6lzvsGJkGWskg==} + + '@ethersproject/properties@5.8.0': + resolution: {integrity: sha512-PYuiEoQ+FMaZZNGrStmN7+lWjlsoufGIHdww7454FIaGdbe/p5rnaCXTr5MtBYl3NkeoVhHZuyzChPeGeKIpQw==} + + '@ethersproject/providers@5.8.0': + resolution: {integrity: sha512-3Il3oTzEx3o6kzcg9ZzbE+oCZYyY+3Zh83sKkn4s1DZfTUjIegHnN2Cm0kbn9YFy45FDVcuCLLONhU7ny0SsCw==} + + '@ethersproject/random@5.8.0': + resolution: {integrity: sha512-E4I5TDl7SVqyg4/kkA/qTfuLWAQGXmSOgYyO01So8hLfwgKvYK5snIlzxJMk72IFdG/7oh8yuSqY2KX7MMwg+A==} + + '@ethersproject/rlp@5.8.0': + resolution: {integrity: sha512-LqZgAznqDbiEunaUvykH2JAoXTT9NV0Atqk8rQN9nx9SEgThA/WMx5DnW8a9FOufo//6FZOCHZ+XiClzgbqV9Q==} + + '@ethersproject/sha2@5.8.0': + resolution: {integrity: sha512-dDOUrXr9wF/YFltgTBYS0tKslPEKr6AekjqDW2dbn1L1xmjGR+9GiKu4ajxovnrDbwxAKdHjW8jNcwfz8PAz4A==} + + '@ethersproject/signing-key@5.8.0': + resolution: {integrity: sha512-LrPW2ZxoigFi6U6aVkFN/fa9Yx/+4AtIUe4/HACTvKJdhm0eeb107EVCIQcrLZkxaSIgc/eCrX8Q1GtbH+9n3w==} + + '@ethersproject/solidity@5.8.0': + resolution: {integrity: sha512-4CxFeCgmIWamOHwYN9d+QWGxye9qQLilpgTU0XhYs1OahkclF+ewO+3V1U0mvpiuQxm5EHHmv8f7ClVII8EHsA==} + + '@ethersproject/strings@5.8.0': + resolution: {integrity: sha512-qWEAk0MAvl0LszjdfnZ2uC8xbR2wdv4cDabyHiBh3Cldq/T8dPH3V4BbBsAYJUeonwD+8afVXld274Ls+Y1xXg==} + + '@ethersproject/transactions@5.8.0': + resolution: {integrity: sha512-UglxSDjByHG0TuU17bDfCemZ3AnKO2vYrL5/2n2oXvKzvb7Cz+W9gOWXKARjp2URVwcWlQlPOEQyAviKwT4AHg==} + + '@ethersproject/units@5.8.0': + resolution: {integrity: sha512-lxq0CAnc5kMGIiWW4Mr041VT8IhNM+Pn5T3haO74XZWFulk7wH1Gv64HqE96hT4a7iiNMdOCFEBgaxWuk8ETKQ==} + + '@ethersproject/wallet@5.8.0': + resolution: {integrity: sha512-G+jnzmgg6UxurVKRKvw27h0kvG75YKXZKdlLYmAHeF32TGUzHkOFd7Zn6QHOTYRFWnfjtSSFjBowKo7vfrXzPA==} + + '@ethersproject/web@5.8.0': + resolution: {integrity: sha512-j7+Ksi/9KfGviws6Qtf9Q7KCqRhpwrYKQPs+JBA/rKVFF/yaWLHJEH3zfVP2plVu+eys0d2DlFmhoQJayFewcw==} + + '@ethersproject/wordlists@5.8.0': + resolution: {integrity: sha512-2df9bbXicZws2Sb5S6ET493uJ0Z84Fjr3pC4tu/qlnZERibZCeUVuqdtt+7Tv9xxhUxHoIekIA7avrKUWHrezg==} + + '@iden3/bigarray@0.0.2': + resolution: {integrity: sha512-Xzdyxqm1bOFF6pdIsiHLLl3HkSLjbhqJHVyqaTxXt3RqXBEnmsUmEW47H7VOi/ak7TdkRpNkxjyK5Zbkm+y52g==} + + '@iden3/binfileutils@0.0.12': + resolution: {integrity: sha512-naAmzuDufRIcoNfQ1d99d7hGHufLA3wZSibtr4dMe6ZeiOPV1KwOZWTJ1YVz4HbaWlpDuzVU72dS4ATQS4PXBQ==} + + '@istanbuljs/load-nyc-config@1.1.0': + resolution: {integrity: sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==} + engines: {node: '>=8'} + + '@istanbuljs/schema@0.1.3': + resolution: {integrity: sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==} + engines: {node: '>=8'} + + '@jest/console@29.7.0': + resolution: {integrity: sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jest/core@29.7.0': + resolution: {integrity: sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + peerDependencies: + node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 + peerDependenciesMeta: + node-notifier: + optional: true + + '@jest/environment@29.7.0': + resolution: {integrity: sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jest/expect-utils@29.7.0': + resolution: {integrity: sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jest/expect@29.7.0': + resolution: {integrity: sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jest/fake-timers@29.7.0': + resolution: {integrity: sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jest/globals@29.7.0': + resolution: {integrity: sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jest/reporters@29.7.0': + resolution: {integrity: sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + peerDependencies: + node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 + peerDependenciesMeta: + node-notifier: + optional: true + + '@jest/schemas@29.6.3': + resolution: {integrity: sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jest/source-map@29.6.3': + resolution: {integrity: sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jest/test-result@29.7.0': + resolution: {integrity: sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jest/test-sequencer@29.7.0': + resolution: {integrity: sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jest/transform@29.7.0': + resolution: {integrity: sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jest/types@29.6.3': + resolution: {integrity: sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jridgewell/gen-mapping@0.3.12': + resolution: {integrity: sha512-OuLGC46TjB5BbN1dH8JULVVZY4WTdkF7tV9Ys6wLL1rubZnCMstOhNHueU5bLCrnRuDhKPDM4g6sw4Bel5Gzqg==} + + '@jridgewell/resolve-uri@3.1.2': + resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} + engines: {node: '>=6.0.0'} + + '@jridgewell/sourcemap-codec@1.5.4': + resolution: {integrity: sha512-VT2+G1VQs/9oz078bLrYbecdZKs912zQlkelYpuf+SXF+QvZDYJlbx/LSx+meSAwdDFnF8FVXW92AVjjkVmgFw==} + + '@jridgewell/trace-mapping@0.3.29': + resolution: {integrity: sha512-uw6guiW/gcAGPDhLmd77/6lW8QLeiV5RUTsAX46Db6oLhGaVj4lhnPwb184s1bkc8kdVg/+h988dro8GRDpmYQ==} + + '@jridgewell/trace-mapping@0.3.9': + resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==} + + '@noble/curves@1.9.7': + resolution: {integrity: sha512-gbKGcRUYIjA3/zCCNaWDciTMFI0dCkvou3TL8Zmy5Nc7sJ47a0jtOeZoTaMxkuqRo9cRhjOdZJXegxYE5FN/xw==} + engines: {node: ^14.21.3 || >=16} + + '@noble/hashes@1.8.0': + resolution: {integrity: sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==} + engines: {node: ^14.21.3 || >=16} + + '@sinclair/typebox@0.27.8': + resolution: {integrity: sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==} + + '@sinonjs/commons@3.0.1': + resolution: {integrity: sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==} + + '@sinonjs/fake-timers@10.3.0': + resolution: {integrity: sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==} + + '@tsconfig/node10@1.0.11': + resolution: {integrity: sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==} + + '@tsconfig/node12@1.0.11': + resolution: {integrity: sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==} + + '@tsconfig/node14@1.0.3': + resolution: {integrity: sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==} + + '@tsconfig/node16@1.0.4': + resolution: {integrity: sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==} + + '@types/babel__core@7.20.5': + resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==} + + '@types/babel__generator@7.27.0': + resolution: {integrity: sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==} + + '@types/babel__template@7.4.4': + resolution: {integrity: sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==} + + '@types/babel__traverse@7.20.7': + resolution: {integrity: sha512-dkO5fhS7+/oos4ciWxyEyjWe48zmG6wbCheo/G2ZnHx4fs3EU6YC6UM8rk56gAjNJ9P3MTH2jo5jb92/K6wbng==} + + '@types/graceful-fs@4.1.9': + resolution: {integrity: sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==} + + '@types/istanbul-lib-coverage@2.0.6': + resolution: {integrity: sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==} + + '@types/istanbul-lib-report@3.0.3': + resolution: {integrity: sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==} + + '@types/istanbul-reports@3.0.4': + resolution: {integrity: sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==} + + '@types/jest@29.5.14': + resolution: {integrity: sha512-ZN+4sdnLUbo8EVvVc2ao0GFW6oVrQRPn4K2lglySj7APvSrgzxHiNNK99us4WDMi57xxA2yggblIAMNhXOotLQ==} + + '@types/node@20.19.9': + resolution: {integrity: sha512-cuVNgarYWZqxRJDQHEB58GEONhOK79QVR/qYx4S7kcUObQvUwvFnYxJuuHUKm2aieN9X3yZB4LZsuYNU1Qphsw==} + + '@types/stack-utils@2.0.3': + resolution: {integrity: sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==} + + '@types/yargs-parser@21.0.3': + resolution: {integrity: sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==} + + '@types/yargs@17.0.33': + resolution: {integrity: sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA==} + + acorn-walk@8.3.4: + resolution: {integrity: sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==} + engines: {node: '>=0.4.0'} + + acorn@8.15.0: + resolution: {integrity: sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==} + engines: {node: '>=0.4.0'} + hasBin: true + + aes-js@3.0.0: + resolution: {integrity: sha512-H7wUZRn8WpTq9jocdxQ2c8x2sKo9ZVmzfRE13GiNJXfp7NcKYEdvl3vspKjXox6RIG2VtaRe4JFvxG4rqp2Zuw==} + + ansi-escapes@4.3.2: + resolution: {integrity: sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==} + engines: {node: '>=8'} + + ansi-regex@5.0.1: + resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} + engines: {node: '>=8'} + + ansi-styles@4.3.0: + resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} + engines: {node: '>=8'} + + ansi-styles@5.2.0: + resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==} + engines: {node: '>=10'} + + anymatch@3.1.3: + resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} + engines: {node: '>= 8'} + + arg@4.1.3: + resolution: {integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==} + + argparse@1.0.10: + resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==} + + async@3.2.6: + resolution: {integrity: sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==} + + b4a@1.6.7: + resolution: {integrity: sha512-OnAYlL5b7LEkALw87fUVafQw5rVR9RjwGd4KUwNQ6DrrNmaVaUCgLipfVlzrPQ4tWOR9P0IXGNOx50jYCCdSJg==} + + babel-jest@29.7.0: + resolution: {integrity: sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + peerDependencies: + '@babel/core': ^7.8.0 + + babel-plugin-istanbul@6.1.1: + resolution: {integrity: sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==} + engines: {node: '>=8'} + + babel-plugin-jest-hoist@29.6.3: + resolution: {integrity: sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + babel-preset-current-node-syntax@1.1.1: + resolution: {integrity: sha512-23fWKohMTvS5s0wwJKycOe0dBdCwQ6+iiLaNR9zy8P13mtFRFM9qLLX6HJX5DL2pi/FNDf3fCQHM4FIMoHH/7w==} + peerDependencies: + '@babel/core': ^7.0.0 || ^8.0.0-0 + + babel-preset-jest@29.6.3: + resolution: {integrity: sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + peerDependencies: + '@babel/core': ^7.0.0 + + balanced-match@1.0.2: + resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + + bech32@1.1.4: + resolution: {integrity: sha512-s0IrSOzLlbvX7yp4WBfPITzpAU8sqQcpsmwXDiKwrG4r491vwCO/XpejasRNl0piBMe/DvP4Tz0mIS/X1DPJBQ==} + + bfj@7.1.0: + resolution: {integrity: sha512-I6MMLkn+anzNdCUp9hMRyui1HaNEUCco50lxbvNS4+EyXg8lN3nJ48PjPWtbH8UVS9CuMoaKE9U2V3l29DaRQw==} + engines: {node: '>= 8.0.0'} + + big-integer@1.6.52: + resolution: {integrity: sha512-QxD8cf2eVqJOOz63z6JIN9BzvVs/dlySa5HGSBH5xtR8dPteIRQnBxxKqkNTiT6jbDTF6jAfrd4oMcND9RGbQg==} + engines: {node: '>=0.6'} + + blake-hash@2.0.0: + resolution: {integrity: sha512-Igj8YowDu1PRkRsxZA7NVkdFNxH5rKv5cpLxQ0CVXSIA77pVYwCPRQJ2sMew/oneUpfuYRyjG6r8SmmmnbZb1w==} + engines: {node: '>= 10'} + + blake2b-wasm@2.4.0: + resolution: {integrity: sha512-S1kwmW2ZhZFFFOghcx73+ZajEfKBqhP82JMssxtLVMxlaPea1p9uoLiUZ5WYyHn0KddwbLc+0vh4wR0KBNoT5w==} + + blake2b@2.1.4: + resolution: {integrity: sha512-AyBuuJNI64gIvwx13qiICz6H6hpmjvYS5DGkG6jbXMOT8Z3WUJ3V1X0FlhIoT1b/5JtHE3ki+xjtMvu1nn+t9A==} + + bluebird@3.7.2: + resolution: {integrity: sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==} + + bn.js@4.12.2: + resolution: {integrity: sha512-n4DSx829VRTRByMRGdjQ9iqsN0Bh4OolPsFnaZBLcbi8iXcB+kJ9s7EnRt4wILZNV3kPLHkRVfOc/HvhC3ovDw==} + + bn.js@5.2.2: + resolution: {integrity: sha512-v2YAxEmKaBLahNwE1mjp4WON6huMNeuDvagFZW+ASCuA/ku0bXR9hSMw0XpiqMoA3+rmnyck/tPRSFQkoC9Cuw==} + + brace-expansion@1.1.12: + resolution: {integrity: sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==} + + brace-expansion@2.0.2: + resolution: {integrity: sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==} + + braces@3.0.3: + resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} + engines: {node: '>=8'} + + brorand@1.1.0: + resolution: {integrity: sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==} + + browserslist@4.25.1: + resolution: {integrity: sha512-KGj0KoOMXLpSNkkEI6Z6mShmQy0bc1I+T7K9N81k4WWMrfz+6fQ6es80B/YLAeRoKvjYE1YSHHOW1qe9xIVzHw==} + engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} + hasBin: true + + bs-logger@0.2.6: + resolution: {integrity: sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==} + engines: {node: '>= 6'} + + bser@2.1.1: + resolution: {integrity: sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==} + + buffer-from@1.1.2: + resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} + + callsites@3.1.0: + resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} + engines: {node: '>=6'} + + camelcase@5.3.1: + resolution: {integrity: sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==} + engines: {node: '>=6'} + + camelcase@6.3.0: + resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==} + engines: {node: '>=10'} + + caniuse-lite@1.0.30001727: + resolution: {integrity: sha512-pB68nIHmbN6L/4C6MH1DokyR3bYqFwjaSs/sWDHGj4CTcFtQUQMuJftVwWkXq7mNWOybD3KhUv3oWHoGxgP14Q==} + + chalk@4.1.2: + resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} + engines: {node: '>=10'} + + char-regex@1.0.2: + resolution: {integrity: sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==} + engines: {node: '>=10'} + + check-types@11.2.3: + resolution: {integrity: sha512-+67P1GkJRaxQD6PKK0Et9DhwQB+vGg3PM5+aavopCpZT1lj9jeqfvpgTLAWErNj8qApkkmXlu/Ug74kmhagkXg==} + + ci-info@3.9.0: + resolution: {integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==} + engines: {node: '>=8'} + + circom_runtime@0.1.28: + resolution: {integrity: sha512-ACagpQ7zBRLKDl5xRZ4KpmYIcZDUjOiNRuxvXLqhnnlLSVY1Dbvh73TI853nqoR0oEbihtWmMSjgc5f+pXf/jQ==} + hasBin: true + + circomlibjs@0.1.7: + resolution: {integrity: sha512-GRAUoAlKAsiiTa+PA725G9RmEmJJRc8tRFxw/zKktUxlQISGznT4hH4ESvW8FNTsrGg/nNd06sGP/Wlx0LUHVg==} + + cjs-module-lexer@1.4.3: + resolution: {integrity: sha512-9z8TZaGM1pfswYeXrUpzPrkx8UnWYdhJclsiYMm6x/w5+nN+8Tf/LnAgfLGQCm59qAOxU8WwHEq2vNwF6i4j+Q==} + + cliui@8.0.1: + resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} + engines: {node: '>=12'} + + co@4.6.0: + resolution: {integrity: sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==} + engines: {iojs: '>= 1.0.0', node: '>= 0.12.0'} + + collect-v8-coverage@1.0.2: + resolution: {integrity: sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q==} + + color-convert@2.0.1: + resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} + engines: {node: '>=7.0.0'} + + color-name@1.1.4: + resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + + concat-map@0.0.1: + resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + + convert-source-map@2.0.0: + resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} + + create-jest@29.7.0: + resolution: {integrity: sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + hasBin: true + + create-require@1.1.1: + resolution: {integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==} + + cross-spawn@7.0.6: + resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} + engines: {node: '>= 8'} + + debug@4.4.1: + resolution: {integrity: sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + dedent@1.6.0: + resolution: {integrity: sha512-F1Z+5UCFpmQUzJa11agbyPVMbpgT/qA3/SKyJ1jyBgm7dUcUEa8v9JwDkerSQXfakBwFljIxhOJqGkjUwZ9FSA==} + peerDependencies: + babel-plugin-macros: ^3.1.0 + peerDependenciesMeta: + babel-plugin-macros: + optional: true + + deep-is@0.1.4: + resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} + + deepmerge@4.3.1: + resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==} + engines: {node: '>=0.10.0'} + + detect-newline@3.1.0: + resolution: {integrity: sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==} + engines: {node: '>=8'} + + diff-sequences@29.6.3: + resolution: {integrity: sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + diff@4.0.2: + resolution: {integrity: sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==} + engines: {node: '>=0.3.1'} + + ejs@3.1.10: + resolution: {integrity: sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==} + engines: {node: '>=0.10.0'} + hasBin: true + + electron-to-chromium@1.5.192: + resolution: {integrity: sha512-rP8Ez0w7UNw/9j5eSXCe10o1g/8B1P5SM90PCCMVkIRQn2R0LEHWz4Eh9RnxkniuDe1W0cTSOB3MLlkTGDcuCg==} + + elliptic@6.6.1: + resolution: {integrity: sha512-RaddvvMatK2LJHqFJ+YA4WysVN5Ita9E35botqIYspQ4TkRAlCicdzKOjlyv/1Za5RyTNn7di//eEV0uTAfe3g==} + + emittery@0.13.1: + resolution: {integrity: sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==} + engines: {node: '>=12'} + + emoji-regex@8.0.0: + resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} + + error-ex@1.3.2: + resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==} + + escalade@3.2.0: + resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} + engines: {node: '>=6'} + + escape-string-regexp@2.0.0: + resolution: {integrity: sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==} + engines: {node: '>=8'} + + escodegen@1.14.3: + resolution: {integrity: sha512-qFcX0XJkdg+PB3xjZZG/wKSuT1PnQWx57+TVSjIMmILd2yC/6ByYElPwJnslDsuWuSAp4AwJGumarAAmJch5Kw==} + engines: {node: '>=4.0'} + hasBin: true + + esprima@1.2.2: + resolution: {integrity: sha512-+JpPZam9w5DuJ3Q67SqsMGtiHKENSMRVoxvArfJZK01/BfLEObtZ6orJa/MtoGNR/rfMgp5837T41PAmTwAv/A==} + engines: {node: '>=0.4.0'} + hasBin: true + + esprima@4.0.1: + resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} + engines: {node: '>=4'} + hasBin: true + + estraverse@4.3.0: + resolution: {integrity: sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==} + engines: {node: '>=4.0'} + + esutils@2.0.3: + resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} + engines: {node: '>=0.10.0'} + + ethers@5.8.0: + resolution: {integrity: sha512-DUq+7fHrCg1aPDFCHx6UIPb3nmt2XMpM7Y/g2gLhsl3lIBqeAfOJIl1qEvRf2uq3BiKxmh6Fh5pfp2ieyek7Kg==} + + execa@5.1.1: + resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==} + engines: {node: '>=10'} + + exit@0.1.2: + resolution: {integrity: sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==} + engines: {node: '>= 0.8.0'} + + expect@29.7.0: + resolution: {integrity: sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + fast-json-stable-stringify@2.1.0: + resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} + + fast-levenshtein@2.0.6: + resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} + + fastfile@0.0.20: + resolution: {integrity: sha512-r5ZDbgImvVWCP0lA/cGNgQcZqR+aYdFx3u+CtJqUE510pBUVGMn4ulL/iRTI4tACTYsNJ736uzFxEBXesPAktA==} + + fb-watchman@2.0.2: + resolution: {integrity: sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==} + + ffjavascript@0.2.63: + resolution: {integrity: sha512-dBgdsfGks58b66JnUZeZpGxdMIDQ4QsD3VYlRJyFVrKQHb2kJy4R2gufx5oetrTxXPT+aEjg0dOvOLg1N0on4A==} + + ffjavascript@0.3.0: + resolution: {integrity: sha512-l7sR5kmU3gRwDy8g0Z2tYBXy5ttmafRPFOqY7S6af5cq51JqJWt5eQ/lSR/rs2wQNbDYaYlQr5O+OSUf/oMLoQ==} + + ffjavascript@0.3.1: + resolution: {integrity: sha512-4PbK1WYodQtuF47D4pRI5KUg3Q392vuP5WjE1THSnceHdXwU3ijaoS0OqxTzLknCtz4Z2TtABzkBdBdMn3B/Aw==} + + filelist@1.0.4: + resolution: {integrity: sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==} + + fill-range@7.1.1: + resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} + engines: {node: '>=8'} + + find-up@4.1.0: + resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==} + engines: {node: '>=8'} + + fs.realpath@1.0.0: + resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} + + fsevents@2.3.3: + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + + function-bind@1.1.2: + resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + + gensync@1.0.0-beta.2: + resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} + engines: {node: '>=6.9.0'} + + get-caller-file@2.0.5: + resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} + engines: {node: 6.* || 8.* || >= 10.*} + + get-package-type@0.1.0: + resolution: {integrity: sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==} + engines: {node: '>=8.0.0'} + + get-stream@6.0.1: + resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==} + engines: {node: '>=10'} + + glob@7.2.3: + resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} + deprecated: Glob versions prior to v9 are no longer supported + + graceful-fs@4.2.11: + resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + + has-flag@4.0.0: + resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} + engines: {node: '>=8'} + + hash.js@1.1.7: + resolution: {integrity: sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==} + + hasown@2.0.2: + resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} + engines: {node: '>= 0.4'} + + hmac-drbg@1.0.1: + resolution: {integrity: sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==} + + hoopy@0.1.4: + resolution: {integrity: sha512-HRcs+2mr52W0K+x8RzcLzuPPmVIKMSv97RGHy0Ea9y/mpcaK+xTrjICA04KAHi4GRzxliNqNJEFYWHghy3rSfQ==} + engines: {node: '>= 6.0.0'} + + html-escaper@2.0.2: + resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==} + + human-signals@2.1.0: + resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==} + engines: {node: '>=10.17.0'} + + import-local@3.2.0: + resolution: {integrity: sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA==} + engines: {node: '>=8'} + hasBin: true + + imurmurhash@0.1.4: + resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} + engines: {node: '>=0.8.19'} + + inflight@1.0.6: + resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} + deprecated: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful. + + inherits@2.0.4: + resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + + is-arrayish@0.2.1: + resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} + + is-core-module@2.16.1: + resolution: {integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==} + engines: {node: '>= 0.4'} + + is-fullwidth-code-point@3.0.0: + resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} + engines: {node: '>=8'} + + is-generator-fn@2.1.0: + resolution: {integrity: sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==} + engines: {node: '>=6'} + + is-number@7.0.0: + resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} + engines: {node: '>=0.12.0'} + + is-stream@2.0.1: + resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} + engines: {node: '>=8'} + + isexe@2.0.0: + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + + istanbul-lib-coverage@3.2.2: + resolution: {integrity: sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==} + engines: {node: '>=8'} + + istanbul-lib-instrument@5.2.1: + resolution: {integrity: sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==} + engines: {node: '>=8'} + + istanbul-lib-instrument@6.0.3: + resolution: {integrity: sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q==} + engines: {node: '>=10'} + + istanbul-lib-report@3.0.1: + resolution: {integrity: sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==} + engines: {node: '>=10'} + + istanbul-lib-source-maps@4.0.1: + resolution: {integrity: sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==} + engines: {node: '>=10'} + + istanbul-reports@3.1.7: + resolution: {integrity: sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g==} + engines: {node: '>=8'} + + jake@10.9.2: + resolution: {integrity: sha512-2P4SQ0HrLQ+fw6llpLnOaGAvN2Zu6778SJMrCUwns4fOoG9ayrTiZk3VV8sCPkVZF8ab0zksVpS8FDY5pRCNBA==} + engines: {node: '>=10'} + hasBin: true + + jest-changed-files@29.7.0: + resolution: {integrity: sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-circus@29.7.0: + resolution: {integrity: sha512-3E1nCMgipcTkCocFwM90XXQab9bS+GMsjdpmPrlelaxwD93Ad8iVEjX/vvHPdLPnFf+L40u+5+iutRdA1N9myw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-cli@29.7.0: + resolution: {integrity: sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + hasBin: true + peerDependencies: + node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 + peerDependenciesMeta: + node-notifier: + optional: true + + jest-config@29.7.0: + resolution: {integrity: sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + peerDependencies: + '@types/node': '*' + ts-node: '>=9.0.0' + peerDependenciesMeta: + '@types/node': + optional: true + ts-node: + optional: true + + jest-diff@29.7.0: + resolution: {integrity: sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-docblock@29.7.0: + resolution: {integrity: sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-each@29.7.0: + resolution: {integrity: sha512-gns+Er14+ZrEoC5fhOfYCY1LOHHr0TI+rQUHZS8Ttw2l7gl+80eHc/gFf2Ktkw0+SIACDTeWvpFcv3B04VembQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-environment-node@29.7.0: + resolution: {integrity: sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-get-type@29.6.3: + resolution: {integrity: sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-haste-map@29.7.0: + resolution: {integrity: sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-leak-detector@29.7.0: + resolution: {integrity: sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-matcher-utils@29.7.0: + resolution: {integrity: sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-message-util@29.7.0: + resolution: {integrity: sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-mock@29.7.0: + resolution: {integrity: sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-pnp-resolver@1.2.3: + resolution: {integrity: sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==} + engines: {node: '>=6'} + peerDependencies: + jest-resolve: '*' + peerDependenciesMeta: + jest-resolve: + optional: true + + jest-regex-util@29.6.3: + resolution: {integrity: sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-resolve-dependencies@29.7.0: + resolution: {integrity: sha512-un0zD/6qxJ+S0et7WxeI3H5XSe9lTBBR7bOHCHXkKR6luG5mwDDlIzVQ0V5cZCuoTgEdcdwzTghYkTWfubi+nA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-resolve@29.7.0: + resolution: {integrity: sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-runner@29.7.0: + resolution: {integrity: sha512-fsc4N6cPCAahybGBfTRcq5wFR6fpLznMg47sY5aDpsoejOcVYFb07AHuSnR0liMcPTgBsA3ZJL6kFOjPdoNipQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-runtime@29.7.0: + resolution: {integrity: sha512-gUnLjgwdGqW7B4LvOIkbKs9WGbn+QLqRQQ9juC6HndeDiezIwhDP+mhMwHWCEcfQ5RUXa6OPnFF8BJh5xegwwQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-snapshot@29.7.0: + resolution: {integrity: sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-util@29.7.0: + resolution: {integrity: sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-validate@29.7.0: + resolution: {integrity: sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-watcher@29.7.0: + resolution: {integrity: sha512-49Fg7WXkU3Vl2h6LbLtMQ/HyB6rXSIX7SqvBLQmssRBGN9I0PNvPmAmCWSOY6SOvrjhI/F7/bGAv9RtnsPA03g==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-worker@29.7.0: + resolution: {integrity: sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest@29.7.0: + resolution: {integrity: sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + hasBin: true + peerDependencies: + node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 + peerDependenciesMeta: + node-notifier: + optional: true + + js-sha3@0.8.0: + resolution: {integrity: sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==} + + js-tokens@4.0.0: + resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + + js-yaml@3.14.1: + resolution: {integrity: sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==} + hasBin: true + + jsesc@3.1.0: + resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==} + engines: {node: '>=6'} + hasBin: true + + json-parse-even-better-errors@2.3.1: + resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} + + json5@2.2.3: + resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} + engines: {node: '>=6'} + hasBin: true + + jsonpath@1.1.1: + resolution: {integrity: sha512-l6Cg7jRpixfbgoWgkrl77dgEj8RPvND0wMH6TwQmi9Qs4TFfS9u5cUFnbeKTwj5ga5Y3BTGGNI28k117LJ009w==} + + kleur@3.0.3: + resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==} + engines: {node: '>=6'} + + leven@3.1.0: + resolution: {integrity: sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==} + engines: {node: '>=6'} + + levn@0.3.0: + resolution: {integrity: sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==} + engines: {node: '>= 0.8.0'} + + lines-and-columns@1.2.4: + resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} + + locate-path@5.0.0: + resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==} + engines: {node: '>=8'} + + lodash.memoize@4.1.2: + resolution: {integrity: sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==} + + logplease@1.2.15: + resolution: {integrity: sha512-jLlHnlsPSJjpwUfcNyUxXCl33AYg2cHhIf9QhGL2T4iPT0XPB+xP1LRKFPgIg1M/sg9kAJvy94w9CzBNrfnstA==} + + lru-cache@5.1.1: + resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} + + make-dir@4.0.0: + resolution: {integrity: sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==} + engines: {node: '>=10'} + + make-error@1.3.6: + resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==} + + makeerror@1.0.12: + resolution: {integrity: sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==} + + merge-stream@2.0.0: + resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} + + micromatch@4.0.8: + resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} + engines: {node: '>=8.6'} + + mimic-fn@2.1.0: + resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} + engines: {node: '>=6'} + + minimalistic-assert@1.0.1: + resolution: {integrity: sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==} + + minimalistic-crypto-utils@1.0.1: + resolution: {integrity: sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==} + + minimatch@3.1.2: + resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} + + minimatch@5.1.6: + resolution: {integrity: sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==} + engines: {node: '>=10'} + + ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + + nanoassert@2.0.0: + resolution: {integrity: sha512-7vO7n28+aYO4J+8w96AzhmU8G+Y/xpPDJz/se19ICsqj/momRbb9mh9ZUtkoJ5X3nTnPdhEJyc0qnM6yAsHBaA==} + + natural-compare@1.4.0: + resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} + + noble-bls12-381@0.7.2: + resolution: {integrity: sha512-Z5isbU6opuWPL3dxsGqO5BdOE8WP1XUM7HFIn/xeE5pATTnml/PEIy4MFQQrktHiitkuJdsCDtzEOnS9eIpC3Q==} + deprecated: Switch to @noble/curves for security updates + + noble-hashes@0.3.1: + resolution: {integrity: sha512-TpYvlZvM8nGB582H9qQdTCLTNPS4TX9r5gkB4iiCWlO/URrdFJKAKwzwwEcNYPhLrcmCvBF1Nfm25GMbFWEplw==} + deprecated: Switch to namespaced @noble/hashes for security and feature updates + + noble-secp256k1@1.2.14: + resolution: {integrity: sha512-GSCXyoZBUaaPwVWdYncMEmzlSUjF9J/YeEHpklYJCyg8wPuJP3NzDx0BkiwArzINkdX2HJHvUJhL6vVWPOQQcg==} + deprecated: Switch to namespaced @noble/secp256k1 for security and feature updates + + node-addon-api@3.2.1: + resolution: {integrity: sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A==} + + node-gyp-build@4.8.4: + resolution: {integrity: sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==} + hasBin: true + + node-int64@0.4.0: + resolution: {integrity: sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==} + + node-releases@2.0.19: + resolution: {integrity: sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==} + + normalize-path@3.0.0: + resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} + engines: {node: '>=0.10.0'} + + npm-run-path@4.0.1: + resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==} + engines: {node: '>=8'} + + once@1.4.0: + resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + + onetime@5.1.2: + resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==} + engines: {node: '>=6'} + + optionator@0.8.3: + resolution: {integrity: sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==} + engines: {node: '>= 0.8.0'} + + p-limit@2.3.0: + resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==} + engines: {node: '>=6'} + + p-limit@3.1.0: + resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} + engines: {node: '>=10'} + + p-locate@4.1.0: + resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==} + engines: {node: '>=8'} + + p-try@2.2.0: + resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} + engines: {node: '>=6'} + + parse-json@5.2.0: + resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} + engines: {node: '>=8'} + + path-exists@4.0.0: + resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} + engines: {node: '>=8'} + + path-is-absolute@1.0.1: + resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} + engines: {node: '>=0.10.0'} + + path-key@3.1.1: + resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} + engines: {node: '>=8'} + + path-parse@1.0.7: + resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} + + picocolors@1.1.1: + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + + picomatch@2.3.1: + resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} + engines: {node: '>=8.6'} + + pirates@4.0.7: + resolution: {integrity: sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==} + engines: {node: '>= 6'} + + pkg-dir@4.2.0: + resolution: {integrity: sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==} + engines: {node: '>=8'} + + prelude-ls@1.1.2: + resolution: {integrity: sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==} + engines: {node: '>= 0.8.0'} + + pretty-format@29.7.0: + resolution: {integrity: sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + prompts@2.4.2: + resolution: {integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==} + engines: {node: '>= 6'} + + pure-rand@6.1.0: + resolution: {integrity: sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==} + + r1csfile@0.0.48: + resolution: {integrity: sha512-kHRkKUJNaor31l05f2+RFzvcH5XSa7OfEfd/l4hzjte6NL6fjRkSMfZ4BjySW9wmfdwPOtq3mXurzPvPGEf5Tw==} + + react-is@18.3.1: + resolution: {integrity: sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==} + + readable-stream@3.6.2: + resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} + engines: {node: '>= 6'} + + require-directory@2.1.1: + resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} + engines: {node: '>=0.10.0'} + + resolve-cwd@3.0.0: + resolution: {integrity: sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==} + engines: {node: '>=8'} + + resolve-from@5.0.0: + resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} + engines: {node: '>=8'} + + resolve.exports@2.0.3: + resolution: {integrity: sha512-OcXjMsGdhL4XnbShKpAcSqPMzQoYkYyhbEaeSko47MjRP9NfEQMhZkXL1DoFlt9LWQn4YttrdnV6X2OiyzBi+A==} + engines: {node: '>=10'} + + resolve@1.22.10: + resolution: {integrity: sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==} + engines: {node: '>= 0.4'} + hasBin: true + + safe-buffer@5.2.1: + resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} + + scrypt-js@3.0.1: + resolution: {integrity: sha512-cdwTTnqPu0Hyvf5in5asVdZocVDTNRmR7XEcJuIzMjJeSHybHl7vpB66AzwTaIg6CLSbtjcxc8fqcySfnTkccA==} + + semver@6.3.1: + resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} + hasBin: true + + semver@7.7.2: + resolution: {integrity: sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==} + engines: {node: '>=10'} + hasBin: true + + shebang-command@2.0.0: + resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} + engines: {node: '>=8'} + + shebang-regex@3.0.0: + resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} + engines: {node: '>=8'} + + signal-exit@3.0.7: + resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} + + sisteransi@1.0.5: + resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==} + + slash@3.0.0: + resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} + engines: {node: '>=8'} + + snarkjs@0.7.5: + resolution: {integrity: sha512-h+3c4rXZKLhLuHk4LHydZCk/h5GcNvk5GjVKRRkHmfb6Ntf8gHOA9zea3g656iclRuhqQ3iKDWFgiD9ypLrKiA==} + hasBin: true + + source-map-support@0.5.13: + resolution: {integrity: sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==} + + source-map@0.6.1: + resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} + engines: {node: '>=0.10.0'} + + sprintf-js@1.0.3: + resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} + + stack-utils@2.0.6: + resolution: {integrity: sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==} + engines: {node: '>=10'} + + static-eval@2.0.2: + resolution: {integrity: sha512-N/D219Hcr2bPjLxPiV+TQE++Tsmrady7TqAJugLy7Xk1EumfDWS/f5dtBbkRCGE7wKKXuYockQoj8Rm2/pVKyg==} + + string-length@4.0.2: + resolution: {integrity: sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==} + engines: {node: '>=10'} + + string-width@4.2.3: + resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} + engines: {node: '>=8'} + + string_decoder@1.3.0: + resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} + + strip-ansi@6.0.1: + resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} + engines: {node: '>=8'} + + strip-bom@4.0.0: + resolution: {integrity: sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==} + engines: {node: '>=8'} + + strip-final-newline@2.0.0: + resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==} + engines: {node: '>=6'} + + strip-json-comments@3.1.1: + resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} + engines: {node: '>=8'} + + supports-color@7.2.0: + resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} + engines: {node: '>=8'} + + supports-color@8.1.1: + resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} + engines: {node: '>=10'} + + supports-preserve-symlinks-flag@1.0.0: + resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} + engines: {node: '>= 0.4'} + + test-exclude@6.0.0: + resolution: {integrity: sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==} + engines: {node: '>=8'} + + tmpl@1.0.5: + resolution: {integrity: sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==} + + to-regex-range@5.0.1: + resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} + engines: {node: '>=8.0'} + + tryer@1.0.1: + resolution: {integrity: sha512-c3zayb8/kWWpycWYg87P71E1S1ZL6b6IJxfb5fvsUgsf0S2MVGaDhDXXjDMpdCpfWXqptc+4mXwmiy1ypXqRAA==} + + ts-jest@29.4.0: + resolution: {integrity: sha512-d423TJMnJGu80/eSgfQ5w/R+0zFJvdtTxwtF9KzFFunOpSeD+79lHJQIiAhluJoyGRbvj9NZJsl9WjCUo0ND7Q==} + engines: {node: ^14.15.0 || ^16.10.0 || ^18.0.0 || >=20.0.0} + hasBin: true + peerDependencies: + '@babel/core': '>=7.0.0-beta.0 <8' + '@jest/transform': ^29.0.0 || ^30.0.0 + '@jest/types': ^29.0.0 || ^30.0.0 + babel-jest: ^29.0.0 || ^30.0.0 + esbuild: '*' + jest: ^29.0.0 || ^30.0.0 + jest-util: ^29.0.0 || ^30.0.0 + typescript: '>=4.3 <6' + peerDependenciesMeta: + '@babel/core': + optional: true + '@jest/transform': + optional: true + '@jest/types': + optional: true + babel-jest: + optional: true + esbuild: + optional: true + jest-util: + optional: true + + ts-node@10.9.2: + resolution: {integrity: sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==} + hasBin: true + peerDependencies: + '@swc/core': '>=1.2.50' + '@swc/wasm': '>=1.2.50' + '@types/node': '*' + typescript: '>=2.7' + peerDependenciesMeta: + '@swc/core': + optional: true + '@swc/wasm': + optional: true + + type-check@0.3.2: + resolution: {integrity: sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==} + engines: {node: '>= 0.8.0'} + + type-detect@4.0.8: + resolution: {integrity: sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==} + engines: {node: '>=4'} + + type-fest@0.21.3: + resolution: {integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==} + engines: {node: '>=10'} + + type-fest@4.41.0: + resolution: {integrity: sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==} + engines: {node: '>=16'} + + typescript@5.8.3: + resolution: {integrity: sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==} + engines: {node: '>=14.17'} + hasBin: true + + underscore@1.12.1: + resolution: {integrity: sha512-hEQt0+ZLDVUMhebKxL4x1BTtDY7bavVofhZ9KZ4aI26X9SRaE+Y3m83XUL1UP2jn8ynjndwCCpEHdUG+9pP1Tw==} + + undici-types@6.21.0: + resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} + + update-browserslist-db@1.1.3: + resolution: {integrity: sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==} + hasBin: true + peerDependencies: + browserslist: '>= 4.21.0' + + util-deprecate@1.0.2: + resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + + v8-compile-cache-lib@3.0.1: + resolution: {integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==} + + v8-to-istanbul@9.3.0: + resolution: {integrity: sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==} + engines: {node: '>=10.12.0'} + + walker@1.0.8: + resolution: {integrity: sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==} + + wasmbuilder@0.0.16: + resolution: {integrity: sha512-Qx3lEFqaVvp1cEYW7Bfi+ebRJrOiwz2Ieu7ZG2l7YyeSJIok/reEQCQCuicj/Y32ITIJuGIM9xZQppGx5LrQdA==} + + wasmcurves@0.2.2: + resolution: {integrity: sha512-JRY908NkmKjFl4ytnTu5ED6AwPD+8VJ9oc94kdq7h5bIwbj0L4TDJ69mG+2aLs2SoCmGfqIesMWTEJjtYsoQXQ==} + + web-worker@1.2.0: + resolution: {integrity: sha512-PgF341avzqyx60neE9DD+XS26MMNMoUQRz9NOZwW32nPQrF6p77f1htcnjBSEV8BGMKZ16choqUG4hyI0Hx7mA==} + + which@2.0.2: + resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} + engines: {node: '>= 8'} + hasBin: true + + word-wrap@1.2.5: + resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} + engines: {node: '>=0.10.0'} + + wrap-ansi@7.0.0: + resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} + engines: {node: '>=10'} + + wrappy@1.0.2: + resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + + write-file-atomic@4.0.2: + resolution: {integrity: sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==} + engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + + ws@8.18.0: + resolution: {integrity: sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==} + 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 + + y18n@5.0.8: + resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} + engines: {node: '>=10'} + + yallist@3.1.1: + resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} + + yargs-parser@21.1.1: + resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} + engines: {node: '>=12'} + + yargs@17.7.2: + resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} + engines: {node: '>=12'} + + yn@3.1.1: + resolution: {integrity: sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==} + engines: {node: '>=6'} + + yocto-queue@0.1.0: + resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} + engines: {node: '>=10'} + +snapshots: + + '@ampproject/remapping@2.3.0': + dependencies: + '@jridgewell/gen-mapping': 0.3.12 + '@jridgewell/trace-mapping': 0.3.29 + + '@babel/code-frame@7.27.1': + dependencies: + '@babel/helper-validator-identifier': 7.27.1 + js-tokens: 4.0.0 + picocolors: 1.1.1 + + '@babel/compat-data@7.28.0': {} + + '@babel/core@7.28.0': + dependencies: + '@ampproject/remapping': 2.3.0 + '@babel/code-frame': 7.27.1 + '@babel/generator': 7.28.0 + '@babel/helper-compilation-targets': 7.27.2 + '@babel/helper-module-transforms': 7.27.3(@babel/core@7.28.0) + '@babel/helpers': 7.28.2 + '@babel/parser': 7.28.0 + '@babel/template': 7.27.2 + '@babel/traverse': 7.28.0 + '@babel/types': 7.28.2 + convert-source-map: 2.0.0 + debug: 4.4.1 + gensync: 1.0.0-beta.2 + json5: 2.2.3 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + + '@babel/generator@7.28.0': + dependencies: + '@babel/parser': 7.28.0 + '@babel/types': 7.28.2 + '@jridgewell/gen-mapping': 0.3.12 + '@jridgewell/trace-mapping': 0.3.29 + jsesc: 3.1.0 + + '@babel/helper-compilation-targets@7.27.2': + dependencies: + '@babel/compat-data': 7.28.0 + '@babel/helper-validator-option': 7.27.1 + browserslist: 4.25.1 + lru-cache: 5.1.1 + semver: 6.3.1 + + '@babel/helper-globals@7.28.0': {} + + '@babel/helper-module-imports@7.27.1': + dependencies: + '@babel/traverse': 7.28.0 + '@babel/types': 7.28.2 + transitivePeerDependencies: + - supports-color + + '@babel/helper-module-transforms@7.27.3(@babel/core@7.28.0)': + dependencies: + '@babel/core': 7.28.0 + '@babel/helper-module-imports': 7.27.1 + '@babel/helper-validator-identifier': 7.27.1 + '@babel/traverse': 7.28.0 + transitivePeerDependencies: + - supports-color + + '@babel/helper-plugin-utils@7.27.1': {} + + '@babel/helper-string-parser@7.27.1': {} + + '@babel/helper-validator-identifier@7.27.1': {} + + '@babel/helper-validator-option@7.27.1': {} + + '@babel/helpers@7.28.2': + dependencies: + '@babel/template': 7.27.2 + '@babel/types': 7.28.2 + + '@babel/parser@7.28.0': + dependencies: + '@babel/types': 7.28.2 + + '@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.28.0)': + dependencies: + '@babel/core': 7.28.0 + '@babel/helper-plugin-utils': 7.27.1 + + '@babel/plugin-syntax-bigint@7.8.3(@babel/core@7.28.0)': + dependencies: + '@babel/core': 7.28.0 + '@babel/helper-plugin-utils': 7.27.1 + + '@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.28.0)': + dependencies: + '@babel/core': 7.28.0 + '@babel/helper-plugin-utils': 7.27.1 + + '@babel/plugin-syntax-class-static-block@7.14.5(@babel/core@7.28.0)': + dependencies: + '@babel/core': 7.28.0 + '@babel/helper-plugin-utils': 7.27.1 + + '@babel/plugin-syntax-import-attributes@7.27.1(@babel/core@7.28.0)': + dependencies: + '@babel/core': 7.28.0 + '@babel/helper-plugin-utils': 7.27.1 + + '@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.28.0)': + dependencies: + '@babel/core': 7.28.0 + '@babel/helper-plugin-utils': 7.27.1 + + '@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.28.0)': + dependencies: + '@babel/core': 7.28.0 + '@babel/helper-plugin-utils': 7.27.1 + + '@babel/plugin-syntax-jsx@7.27.1(@babel/core@7.28.0)': + dependencies: + '@babel/core': 7.28.0 + '@babel/helper-plugin-utils': 7.27.1 + + '@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.28.0)': + dependencies: + '@babel/core': 7.28.0 + '@babel/helper-plugin-utils': 7.27.1 + + '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.28.0)': + dependencies: + '@babel/core': 7.28.0 + '@babel/helper-plugin-utils': 7.27.1 + + '@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.28.0)': + dependencies: + '@babel/core': 7.28.0 + '@babel/helper-plugin-utils': 7.27.1 + + '@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.28.0)': + dependencies: + '@babel/core': 7.28.0 + '@babel/helper-plugin-utils': 7.27.1 + + '@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.28.0)': + dependencies: + '@babel/core': 7.28.0 + '@babel/helper-plugin-utils': 7.27.1 + + '@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.28.0)': + dependencies: + '@babel/core': 7.28.0 + '@babel/helper-plugin-utils': 7.27.1 + + '@babel/plugin-syntax-private-property-in-object@7.14.5(@babel/core@7.28.0)': + dependencies: + '@babel/core': 7.28.0 + '@babel/helper-plugin-utils': 7.27.1 + + '@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.28.0)': + dependencies: + '@babel/core': 7.28.0 + '@babel/helper-plugin-utils': 7.27.1 + + '@babel/plugin-syntax-typescript@7.27.1(@babel/core@7.28.0)': + dependencies: + '@babel/core': 7.28.0 + '@babel/helper-plugin-utils': 7.27.1 + + '@babel/template@7.27.2': + dependencies: + '@babel/code-frame': 7.27.1 + '@babel/parser': 7.28.0 + '@babel/types': 7.28.2 + + '@babel/traverse@7.28.0': + dependencies: + '@babel/code-frame': 7.27.1 + '@babel/generator': 7.28.0 + '@babel/helper-globals': 7.28.0 + '@babel/parser': 7.28.0 + '@babel/template': 7.27.2 + '@babel/types': 7.28.2 + debug: 4.4.1 + transitivePeerDependencies: + - supports-color + + '@babel/types@7.28.2': + dependencies: + '@babel/helper-string-parser': 7.27.1 + '@babel/helper-validator-identifier': 7.27.1 + + '@bcoe/v8-coverage@0.2.3': {} + + '@cspotcode/source-map-support@0.8.1': + dependencies: + '@jridgewell/trace-mapping': 0.3.9 + + '@ethersproject/abi@5.8.0': + dependencies: + '@ethersproject/address': 5.8.0 + '@ethersproject/bignumber': 5.8.0 + '@ethersproject/bytes': 5.8.0 + '@ethersproject/constants': 5.8.0 + '@ethersproject/hash': 5.8.0 + '@ethersproject/keccak256': 5.8.0 + '@ethersproject/logger': 5.8.0 + '@ethersproject/properties': 5.8.0 + '@ethersproject/strings': 5.8.0 + + '@ethersproject/abstract-provider@5.8.0': + dependencies: + '@ethersproject/bignumber': 5.8.0 + '@ethersproject/bytes': 5.8.0 + '@ethersproject/logger': 5.8.0 + '@ethersproject/networks': 5.8.0 + '@ethersproject/properties': 5.8.0 + '@ethersproject/transactions': 5.8.0 + '@ethersproject/web': 5.8.0 + + '@ethersproject/abstract-signer@5.8.0': + dependencies: + '@ethersproject/abstract-provider': 5.8.0 + '@ethersproject/bignumber': 5.8.0 + '@ethersproject/bytes': 5.8.0 + '@ethersproject/logger': 5.8.0 + '@ethersproject/properties': 5.8.0 + + '@ethersproject/address@5.8.0': + dependencies: + '@ethersproject/bignumber': 5.8.0 + '@ethersproject/bytes': 5.8.0 + '@ethersproject/keccak256': 5.8.0 + '@ethersproject/logger': 5.8.0 + '@ethersproject/rlp': 5.8.0 + + '@ethersproject/base64@5.8.0': + dependencies: + '@ethersproject/bytes': 5.8.0 + + '@ethersproject/basex@5.8.0': + dependencies: + '@ethersproject/bytes': 5.8.0 + '@ethersproject/properties': 5.8.0 + + '@ethersproject/bignumber@5.8.0': + dependencies: + '@ethersproject/bytes': 5.8.0 + '@ethersproject/logger': 5.8.0 + bn.js: 5.2.2 + + '@ethersproject/bytes@5.8.0': + dependencies: + '@ethersproject/logger': 5.8.0 + + '@ethersproject/constants@5.8.0': + dependencies: + '@ethersproject/bignumber': 5.8.0 + + '@ethersproject/contracts@5.8.0': + dependencies: + '@ethersproject/abi': 5.8.0 + '@ethersproject/abstract-provider': 5.8.0 + '@ethersproject/abstract-signer': 5.8.0 + '@ethersproject/address': 5.8.0 + '@ethersproject/bignumber': 5.8.0 + '@ethersproject/bytes': 5.8.0 + '@ethersproject/constants': 5.8.0 + '@ethersproject/logger': 5.8.0 + '@ethersproject/properties': 5.8.0 + '@ethersproject/transactions': 5.8.0 + + '@ethersproject/hash@5.8.0': + dependencies: + '@ethersproject/abstract-signer': 5.8.0 + '@ethersproject/address': 5.8.0 + '@ethersproject/base64': 5.8.0 + '@ethersproject/bignumber': 5.8.0 + '@ethersproject/bytes': 5.8.0 + '@ethersproject/keccak256': 5.8.0 + '@ethersproject/logger': 5.8.0 + '@ethersproject/properties': 5.8.0 + '@ethersproject/strings': 5.8.0 + + '@ethersproject/hdnode@5.8.0': + dependencies: + '@ethersproject/abstract-signer': 5.8.0 + '@ethersproject/basex': 5.8.0 + '@ethersproject/bignumber': 5.8.0 + '@ethersproject/bytes': 5.8.0 + '@ethersproject/logger': 5.8.0 + '@ethersproject/pbkdf2': 5.8.0 + '@ethersproject/properties': 5.8.0 + '@ethersproject/sha2': 5.8.0 + '@ethersproject/signing-key': 5.8.0 + '@ethersproject/strings': 5.8.0 + '@ethersproject/transactions': 5.8.0 + '@ethersproject/wordlists': 5.8.0 + + '@ethersproject/json-wallets@5.8.0': + dependencies: + '@ethersproject/abstract-signer': 5.8.0 + '@ethersproject/address': 5.8.0 + '@ethersproject/bytes': 5.8.0 + '@ethersproject/hdnode': 5.8.0 + '@ethersproject/keccak256': 5.8.0 + '@ethersproject/logger': 5.8.0 + '@ethersproject/pbkdf2': 5.8.0 + '@ethersproject/properties': 5.8.0 + '@ethersproject/random': 5.8.0 + '@ethersproject/strings': 5.8.0 + '@ethersproject/transactions': 5.8.0 + aes-js: 3.0.0 + scrypt-js: 3.0.1 + + '@ethersproject/keccak256@5.8.0': + dependencies: + '@ethersproject/bytes': 5.8.0 + js-sha3: 0.8.0 + + '@ethersproject/logger@5.8.0': {} + + '@ethersproject/networks@5.8.0': + dependencies: + '@ethersproject/logger': 5.8.0 + + '@ethersproject/pbkdf2@5.8.0': + dependencies: + '@ethersproject/bytes': 5.8.0 + '@ethersproject/sha2': 5.8.0 + + '@ethersproject/properties@5.8.0': + dependencies: + '@ethersproject/logger': 5.8.0 + + '@ethersproject/providers@5.8.0': + dependencies: + '@ethersproject/abstract-provider': 5.8.0 + '@ethersproject/abstract-signer': 5.8.0 + '@ethersproject/address': 5.8.0 + '@ethersproject/base64': 5.8.0 + '@ethersproject/basex': 5.8.0 + '@ethersproject/bignumber': 5.8.0 + '@ethersproject/bytes': 5.8.0 + '@ethersproject/constants': 5.8.0 + '@ethersproject/hash': 5.8.0 + '@ethersproject/logger': 5.8.0 + '@ethersproject/networks': 5.8.0 + '@ethersproject/properties': 5.8.0 + '@ethersproject/random': 5.8.0 + '@ethersproject/rlp': 5.8.0 + '@ethersproject/sha2': 5.8.0 + '@ethersproject/strings': 5.8.0 + '@ethersproject/transactions': 5.8.0 + '@ethersproject/web': 5.8.0 + bech32: 1.1.4 + ws: 8.18.0 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + + '@ethersproject/random@5.8.0': + dependencies: + '@ethersproject/bytes': 5.8.0 + '@ethersproject/logger': 5.8.0 + + '@ethersproject/rlp@5.8.0': + dependencies: + '@ethersproject/bytes': 5.8.0 + '@ethersproject/logger': 5.8.0 + + '@ethersproject/sha2@5.8.0': + dependencies: + '@ethersproject/bytes': 5.8.0 + '@ethersproject/logger': 5.8.0 + hash.js: 1.1.7 + + '@ethersproject/signing-key@5.8.0': + dependencies: + '@ethersproject/bytes': 5.8.0 + '@ethersproject/logger': 5.8.0 + '@ethersproject/properties': 5.8.0 + bn.js: 5.2.2 + elliptic: 6.6.1 + hash.js: 1.1.7 + + '@ethersproject/solidity@5.8.0': + dependencies: + '@ethersproject/bignumber': 5.8.0 + '@ethersproject/bytes': 5.8.0 + '@ethersproject/keccak256': 5.8.0 + '@ethersproject/logger': 5.8.0 + '@ethersproject/sha2': 5.8.0 + '@ethersproject/strings': 5.8.0 + + '@ethersproject/strings@5.8.0': + dependencies: + '@ethersproject/bytes': 5.8.0 + '@ethersproject/constants': 5.8.0 + '@ethersproject/logger': 5.8.0 + + '@ethersproject/transactions@5.8.0': + dependencies: + '@ethersproject/address': 5.8.0 + '@ethersproject/bignumber': 5.8.0 + '@ethersproject/bytes': 5.8.0 + '@ethersproject/constants': 5.8.0 + '@ethersproject/keccak256': 5.8.0 + '@ethersproject/logger': 5.8.0 + '@ethersproject/properties': 5.8.0 + '@ethersproject/rlp': 5.8.0 + '@ethersproject/signing-key': 5.8.0 + + '@ethersproject/units@5.8.0': + dependencies: + '@ethersproject/bignumber': 5.8.0 + '@ethersproject/constants': 5.8.0 + '@ethersproject/logger': 5.8.0 + + '@ethersproject/wallet@5.8.0': + dependencies: + '@ethersproject/abstract-provider': 5.8.0 + '@ethersproject/abstract-signer': 5.8.0 + '@ethersproject/address': 5.8.0 + '@ethersproject/bignumber': 5.8.0 + '@ethersproject/bytes': 5.8.0 + '@ethersproject/hash': 5.8.0 + '@ethersproject/hdnode': 5.8.0 + '@ethersproject/json-wallets': 5.8.0 + '@ethersproject/keccak256': 5.8.0 + '@ethersproject/logger': 5.8.0 + '@ethersproject/properties': 5.8.0 + '@ethersproject/random': 5.8.0 + '@ethersproject/signing-key': 5.8.0 + '@ethersproject/transactions': 5.8.0 + '@ethersproject/wordlists': 5.8.0 + + '@ethersproject/web@5.8.0': + dependencies: + '@ethersproject/base64': 5.8.0 + '@ethersproject/bytes': 5.8.0 + '@ethersproject/logger': 5.8.0 + '@ethersproject/properties': 5.8.0 + '@ethersproject/strings': 5.8.0 + + '@ethersproject/wordlists@5.8.0': + dependencies: + '@ethersproject/bytes': 5.8.0 + '@ethersproject/hash': 5.8.0 + '@ethersproject/logger': 5.8.0 + '@ethersproject/properties': 5.8.0 + '@ethersproject/strings': 5.8.0 + + '@iden3/bigarray@0.0.2': {} + + '@iden3/binfileutils@0.0.12': + dependencies: + fastfile: 0.0.20 + ffjavascript: 0.3.1 + + '@istanbuljs/load-nyc-config@1.1.0': + dependencies: + camelcase: 5.3.1 + find-up: 4.1.0 + get-package-type: 0.1.0 + js-yaml: 3.14.1 + resolve-from: 5.0.0 + + '@istanbuljs/schema@0.1.3': {} + + '@jest/console@29.7.0': + dependencies: + '@jest/types': 29.6.3 + '@types/node': 20.19.9 + chalk: 4.1.2 + jest-message-util: 29.7.0 + jest-util: 29.7.0 + slash: 3.0.0 + + '@jest/core@29.7.0(ts-node@10.9.2(@types/node@20.19.9)(typescript@5.8.3))': + dependencies: + '@jest/console': 29.7.0 + '@jest/reporters': 29.7.0 + '@jest/test-result': 29.7.0 + '@jest/transform': 29.7.0 + '@jest/types': 29.6.3 + '@types/node': 20.19.9 + ansi-escapes: 4.3.2 + chalk: 4.1.2 + ci-info: 3.9.0 + exit: 0.1.2 + graceful-fs: 4.2.11 + jest-changed-files: 29.7.0 + jest-config: 29.7.0(@types/node@20.19.9)(ts-node@10.9.2(@types/node@20.19.9)(typescript@5.8.3)) + jest-haste-map: 29.7.0 + jest-message-util: 29.7.0 + jest-regex-util: 29.6.3 + jest-resolve: 29.7.0 + jest-resolve-dependencies: 29.7.0 + jest-runner: 29.7.0 + jest-runtime: 29.7.0 + jest-snapshot: 29.7.0 + jest-util: 29.7.0 + jest-validate: 29.7.0 + jest-watcher: 29.7.0 + micromatch: 4.0.8 + pretty-format: 29.7.0 + slash: 3.0.0 + strip-ansi: 6.0.1 + transitivePeerDependencies: + - babel-plugin-macros + - supports-color + - ts-node + + '@jest/environment@29.7.0': + dependencies: + '@jest/fake-timers': 29.7.0 + '@jest/types': 29.6.3 + '@types/node': 20.19.9 + jest-mock: 29.7.0 + + '@jest/expect-utils@29.7.0': + dependencies: + jest-get-type: 29.6.3 + + '@jest/expect@29.7.0': + dependencies: + expect: 29.7.0 + jest-snapshot: 29.7.0 + transitivePeerDependencies: + - supports-color + + '@jest/fake-timers@29.7.0': + dependencies: + '@jest/types': 29.6.3 + '@sinonjs/fake-timers': 10.3.0 + '@types/node': 20.19.9 + jest-message-util: 29.7.0 + jest-mock: 29.7.0 + jest-util: 29.7.0 + + '@jest/globals@29.7.0': + dependencies: + '@jest/environment': 29.7.0 + '@jest/expect': 29.7.0 + '@jest/types': 29.6.3 + jest-mock: 29.7.0 + transitivePeerDependencies: + - supports-color + + '@jest/reporters@29.7.0': + dependencies: + '@bcoe/v8-coverage': 0.2.3 + '@jest/console': 29.7.0 + '@jest/test-result': 29.7.0 + '@jest/transform': 29.7.0 + '@jest/types': 29.6.3 + '@jridgewell/trace-mapping': 0.3.29 + '@types/node': 20.19.9 + chalk: 4.1.2 + collect-v8-coverage: 1.0.2 + exit: 0.1.2 + glob: 7.2.3 + graceful-fs: 4.2.11 + istanbul-lib-coverage: 3.2.2 + istanbul-lib-instrument: 6.0.3 + istanbul-lib-report: 3.0.1 + istanbul-lib-source-maps: 4.0.1 + istanbul-reports: 3.1.7 + jest-message-util: 29.7.0 + jest-util: 29.7.0 + jest-worker: 29.7.0 + slash: 3.0.0 + string-length: 4.0.2 + strip-ansi: 6.0.1 + v8-to-istanbul: 9.3.0 + transitivePeerDependencies: + - supports-color + + '@jest/schemas@29.6.3': + dependencies: + '@sinclair/typebox': 0.27.8 + + '@jest/source-map@29.6.3': + dependencies: + '@jridgewell/trace-mapping': 0.3.29 + callsites: 3.1.0 + graceful-fs: 4.2.11 + + '@jest/test-result@29.7.0': + dependencies: + '@jest/console': 29.7.0 + '@jest/types': 29.6.3 + '@types/istanbul-lib-coverage': 2.0.6 + collect-v8-coverage: 1.0.2 + + '@jest/test-sequencer@29.7.0': + dependencies: + '@jest/test-result': 29.7.0 + graceful-fs: 4.2.11 + jest-haste-map: 29.7.0 + slash: 3.0.0 + + '@jest/transform@29.7.0': + dependencies: + '@babel/core': 7.28.0 + '@jest/types': 29.6.3 + '@jridgewell/trace-mapping': 0.3.29 + babel-plugin-istanbul: 6.1.1 + chalk: 4.1.2 + convert-source-map: 2.0.0 + fast-json-stable-stringify: 2.1.0 + graceful-fs: 4.2.11 + jest-haste-map: 29.7.0 + jest-regex-util: 29.6.3 + jest-util: 29.7.0 + micromatch: 4.0.8 + pirates: 4.0.7 + slash: 3.0.0 + write-file-atomic: 4.0.2 + transitivePeerDependencies: + - supports-color + + '@jest/types@29.6.3': + dependencies: + '@jest/schemas': 29.6.3 + '@types/istanbul-lib-coverage': 2.0.6 + '@types/istanbul-reports': 3.0.4 + '@types/node': 20.19.9 + '@types/yargs': 17.0.33 + chalk: 4.1.2 + + '@jridgewell/gen-mapping@0.3.12': + dependencies: + '@jridgewell/sourcemap-codec': 1.5.4 + '@jridgewell/trace-mapping': 0.3.29 + + '@jridgewell/resolve-uri@3.1.2': {} + + '@jridgewell/sourcemap-codec@1.5.4': {} + + '@jridgewell/trace-mapping@0.3.29': + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.5.4 + + '@jridgewell/trace-mapping@0.3.9': + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.5.4 + + '@noble/curves@1.9.7': + dependencies: + '@noble/hashes': 1.8.0 + + '@noble/hashes@1.8.0': {} + + '@sinclair/typebox@0.27.8': {} + + '@sinonjs/commons@3.0.1': + dependencies: + type-detect: 4.0.8 + + '@sinonjs/fake-timers@10.3.0': + dependencies: + '@sinonjs/commons': 3.0.1 + + '@tsconfig/node10@1.0.11': {} + + '@tsconfig/node12@1.0.11': {} + + '@tsconfig/node14@1.0.3': {} + + '@tsconfig/node16@1.0.4': {} + + '@types/babel__core@7.20.5': + dependencies: + '@babel/parser': 7.28.0 + '@babel/types': 7.28.2 + '@types/babel__generator': 7.27.0 + '@types/babel__template': 7.4.4 + '@types/babel__traverse': 7.20.7 + + '@types/babel__generator@7.27.0': + dependencies: + '@babel/types': 7.28.2 + + '@types/babel__template@7.4.4': + dependencies: + '@babel/parser': 7.28.0 + '@babel/types': 7.28.2 + + '@types/babel__traverse@7.20.7': + dependencies: + '@babel/types': 7.28.2 + + '@types/graceful-fs@4.1.9': + dependencies: + '@types/node': 20.19.9 + + '@types/istanbul-lib-coverage@2.0.6': {} + + '@types/istanbul-lib-report@3.0.3': + dependencies: + '@types/istanbul-lib-coverage': 2.0.6 + + '@types/istanbul-reports@3.0.4': + dependencies: + '@types/istanbul-lib-report': 3.0.3 + + '@types/jest@29.5.14': + dependencies: + expect: 29.7.0 + pretty-format: 29.7.0 + + '@types/node@20.19.9': + dependencies: + undici-types: 6.21.0 + + '@types/stack-utils@2.0.3': {} + + '@types/yargs-parser@21.0.3': {} + + '@types/yargs@17.0.33': + dependencies: + '@types/yargs-parser': 21.0.3 + + acorn-walk@8.3.4: + dependencies: + acorn: 8.15.0 + + acorn@8.15.0: {} + + aes-js@3.0.0: {} + + ansi-escapes@4.3.2: + dependencies: + type-fest: 0.21.3 + + ansi-regex@5.0.1: {} + + ansi-styles@4.3.0: + dependencies: + color-convert: 2.0.1 + + ansi-styles@5.2.0: {} + + anymatch@3.1.3: + dependencies: + normalize-path: 3.0.0 + picomatch: 2.3.1 + + arg@4.1.3: {} + + argparse@1.0.10: + dependencies: + sprintf-js: 1.0.3 + + async@3.2.6: {} + + b4a@1.6.7: {} + + babel-jest@29.7.0(@babel/core@7.28.0): + dependencies: + '@babel/core': 7.28.0 + '@jest/transform': 29.7.0 + '@types/babel__core': 7.20.5 + babel-plugin-istanbul: 6.1.1 + babel-preset-jest: 29.6.3(@babel/core@7.28.0) + chalk: 4.1.2 + graceful-fs: 4.2.11 + slash: 3.0.0 + transitivePeerDependencies: + - supports-color + + babel-plugin-istanbul@6.1.1: + dependencies: + '@babel/helper-plugin-utils': 7.27.1 + '@istanbuljs/load-nyc-config': 1.1.0 + '@istanbuljs/schema': 0.1.3 + istanbul-lib-instrument: 5.2.1 + test-exclude: 6.0.0 + transitivePeerDependencies: + - supports-color + + babel-plugin-jest-hoist@29.6.3: + dependencies: + '@babel/template': 7.27.2 + '@babel/types': 7.28.2 + '@types/babel__core': 7.20.5 + '@types/babel__traverse': 7.20.7 + + babel-preset-current-node-syntax@1.1.1(@babel/core@7.28.0): + dependencies: + '@babel/core': 7.28.0 + '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.28.0) + '@babel/plugin-syntax-bigint': 7.8.3(@babel/core@7.28.0) + '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.28.0) + '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.28.0) + '@babel/plugin-syntax-import-attributes': 7.27.1(@babel/core@7.28.0) + '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.28.0) + '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.28.0) + '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.28.0) + '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.28.0) + '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.28.0) + '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.28.0) + '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.28.0) + '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.28.0) + '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.28.0) + '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.28.0) + + babel-preset-jest@29.6.3(@babel/core@7.28.0): + dependencies: + '@babel/core': 7.28.0 + babel-plugin-jest-hoist: 29.6.3 + babel-preset-current-node-syntax: 1.1.1(@babel/core@7.28.0) + + balanced-match@1.0.2: {} + + bech32@1.1.4: {} + + bfj@7.1.0: + dependencies: + bluebird: 3.7.2 + check-types: 11.2.3 + hoopy: 0.1.4 + jsonpath: 1.1.1 + tryer: 1.0.1 + + big-integer@1.6.52: {} + + blake-hash@2.0.0: + dependencies: + node-addon-api: 3.2.1 + node-gyp-build: 4.8.4 + readable-stream: 3.6.2 + + blake2b-wasm@2.4.0: + dependencies: + b4a: 1.6.7 + nanoassert: 2.0.0 + + blake2b@2.1.4: + dependencies: + blake2b-wasm: 2.4.0 + nanoassert: 2.0.0 + + bluebird@3.7.2: {} + + bn.js@4.12.2: {} + + bn.js@5.2.2: {} + + brace-expansion@1.1.12: + dependencies: + balanced-match: 1.0.2 + concat-map: 0.0.1 + + brace-expansion@2.0.2: + dependencies: + balanced-match: 1.0.2 + + braces@3.0.3: + dependencies: + fill-range: 7.1.1 + + brorand@1.1.0: {} + + browserslist@4.25.1: + dependencies: + caniuse-lite: 1.0.30001727 + electron-to-chromium: 1.5.192 + node-releases: 2.0.19 + update-browserslist-db: 1.1.3(browserslist@4.25.1) + + bs-logger@0.2.6: + dependencies: + fast-json-stable-stringify: 2.1.0 + + bser@2.1.1: + dependencies: + node-int64: 0.4.0 + + buffer-from@1.1.2: {} + + callsites@3.1.0: {} + + camelcase@5.3.1: {} + + camelcase@6.3.0: {} + + caniuse-lite@1.0.30001727: {} + + chalk@4.1.2: + dependencies: + ansi-styles: 4.3.0 + supports-color: 7.2.0 + + char-regex@1.0.2: {} + + check-types@11.2.3: {} + + ci-info@3.9.0: {} + + circom_runtime@0.1.28: + dependencies: + ffjavascript: 0.3.1 + + circomlibjs@0.1.7: + dependencies: + blake-hash: 2.0.0 + blake2b: 2.1.4 + ethers: 5.8.0 + ffjavascript: 0.2.63 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + + cjs-module-lexer@1.4.3: {} + + cliui@8.0.1: + dependencies: + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi: 7.0.0 + + co@4.6.0: {} + + collect-v8-coverage@1.0.2: {} + + color-convert@2.0.1: + dependencies: + color-name: 1.1.4 + + color-name@1.1.4: {} + + concat-map@0.0.1: {} + + convert-source-map@2.0.0: {} + + create-jest@29.7.0(@types/node@20.19.9)(ts-node@10.9.2(@types/node@20.19.9)(typescript@5.8.3)): + dependencies: + '@jest/types': 29.6.3 + chalk: 4.1.2 + exit: 0.1.2 + graceful-fs: 4.2.11 + jest-config: 29.7.0(@types/node@20.19.9)(ts-node@10.9.2(@types/node@20.19.9)(typescript@5.8.3)) + jest-util: 29.7.0 + prompts: 2.4.2 + transitivePeerDependencies: + - '@types/node' + - babel-plugin-macros + - supports-color + - ts-node + + create-require@1.1.1: {} + + cross-spawn@7.0.6: + dependencies: + path-key: 3.1.1 + shebang-command: 2.0.0 + which: 2.0.2 + + debug@4.4.1: + dependencies: + ms: 2.1.3 + + dedent@1.6.0: {} + + deep-is@0.1.4: {} + + deepmerge@4.3.1: {} + + detect-newline@3.1.0: {} + + diff-sequences@29.6.3: {} + + diff@4.0.2: {} + + ejs@3.1.10: + dependencies: + jake: 10.9.2 + + electron-to-chromium@1.5.192: {} + + elliptic@6.6.1: + dependencies: + bn.js: 4.12.2 + brorand: 1.1.0 + hash.js: 1.1.7 + hmac-drbg: 1.0.1 + inherits: 2.0.4 + minimalistic-assert: 1.0.1 + minimalistic-crypto-utils: 1.0.1 + + emittery@0.13.1: {} + + emoji-regex@8.0.0: {} + + error-ex@1.3.2: + dependencies: + is-arrayish: 0.2.1 + + escalade@3.2.0: {} + + escape-string-regexp@2.0.0: {} + + escodegen@1.14.3: + dependencies: + esprima: 4.0.1 + estraverse: 4.3.0 + esutils: 2.0.3 + optionator: 0.8.3 + optionalDependencies: + source-map: 0.6.1 + + esprima@1.2.2: {} + + esprima@4.0.1: {} + + estraverse@4.3.0: {} + + esutils@2.0.3: {} + + ethers@5.8.0: + dependencies: + '@ethersproject/abi': 5.8.0 + '@ethersproject/abstract-provider': 5.8.0 + '@ethersproject/abstract-signer': 5.8.0 + '@ethersproject/address': 5.8.0 + '@ethersproject/base64': 5.8.0 + '@ethersproject/basex': 5.8.0 + '@ethersproject/bignumber': 5.8.0 + '@ethersproject/bytes': 5.8.0 + '@ethersproject/constants': 5.8.0 + '@ethersproject/contracts': 5.8.0 + '@ethersproject/hash': 5.8.0 + '@ethersproject/hdnode': 5.8.0 + '@ethersproject/json-wallets': 5.8.0 + '@ethersproject/keccak256': 5.8.0 + '@ethersproject/logger': 5.8.0 + '@ethersproject/networks': 5.8.0 + '@ethersproject/pbkdf2': 5.8.0 + '@ethersproject/properties': 5.8.0 + '@ethersproject/providers': 5.8.0 + '@ethersproject/random': 5.8.0 + '@ethersproject/rlp': 5.8.0 + '@ethersproject/sha2': 5.8.0 + '@ethersproject/signing-key': 5.8.0 + '@ethersproject/solidity': 5.8.0 + '@ethersproject/strings': 5.8.0 + '@ethersproject/transactions': 5.8.0 + '@ethersproject/units': 5.8.0 + '@ethersproject/wallet': 5.8.0 + '@ethersproject/web': 5.8.0 + '@ethersproject/wordlists': 5.8.0 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + + execa@5.1.1: + dependencies: + cross-spawn: 7.0.6 + get-stream: 6.0.1 + human-signals: 2.1.0 + is-stream: 2.0.1 + merge-stream: 2.0.0 + npm-run-path: 4.0.1 + onetime: 5.1.2 + signal-exit: 3.0.7 + strip-final-newline: 2.0.0 + + exit@0.1.2: {} + + expect@29.7.0: + dependencies: + '@jest/expect-utils': 29.7.0 + jest-get-type: 29.6.3 + jest-matcher-utils: 29.7.0 + jest-message-util: 29.7.0 + jest-util: 29.7.0 + + fast-json-stable-stringify@2.1.0: {} + + fast-levenshtein@2.0.6: {} + + fastfile@0.0.20: {} + + fb-watchman@2.0.2: + dependencies: + bser: 2.1.1 + + ffjavascript@0.2.63: + dependencies: + wasmbuilder: 0.0.16 + wasmcurves: 0.2.2 + web-worker: 1.2.0 + + ffjavascript@0.3.0: + dependencies: + wasmbuilder: 0.0.16 + wasmcurves: 0.2.2 + web-worker: 1.2.0 + + ffjavascript@0.3.1: + dependencies: + wasmbuilder: 0.0.16 + wasmcurves: 0.2.2 + web-worker: 1.2.0 + + filelist@1.0.4: + dependencies: + minimatch: 5.1.6 + + fill-range@7.1.1: + dependencies: + to-regex-range: 5.0.1 + + find-up@4.1.0: + dependencies: + locate-path: 5.0.0 + path-exists: 4.0.0 + + fs.realpath@1.0.0: {} + + fsevents@2.3.3: + optional: true + + function-bind@1.1.2: {} + + gensync@1.0.0-beta.2: {} + + get-caller-file@2.0.5: {} + + get-package-type@0.1.0: {} + + get-stream@6.0.1: {} + + glob@7.2.3: + dependencies: + fs.realpath: 1.0.0 + inflight: 1.0.6 + inherits: 2.0.4 + minimatch: 3.1.2 + once: 1.4.0 + path-is-absolute: 1.0.1 + + graceful-fs@4.2.11: {} + + has-flag@4.0.0: {} + + hash.js@1.1.7: + dependencies: + inherits: 2.0.4 + minimalistic-assert: 1.0.1 + + hasown@2.0.2: + dependencies: + function-bind: 1.1.2 + + hmac-drbg@1.0.1: + dependencies: + hash.js: 1.1.7 + minimalistic-assert: 1.0.1 + minimalistic-crypto-utils: 1.0.1 + + hoopy@0.1.4: {} + + html-escaper@2.0.2: {} + + human-signals@2.1.0: {} + + import-local@3.2.0: + dependencies: + pkg-dir: 4.2.0 + resolve-cwd: 3.0.0 + + imurmurhash@0.1.4: {} + + inflight@1.0.6: + dependencies: + once: 1.4.0 + wrappy: 1.0.2 + + inherits@2.0.4: {} + + is-arrayish@0.2.1: {} + + is-core-module@2.16.1: + dependencies: + hasown: 2.0.2 + + is-fullwidth-code-point@3.0.0: {} + + is-generator-fn@2.1.0: {} + + is-number@7.0.0: {} + + is-stream@2.0.1: {} + + isexe@2.0.0: {} + + istanbul-lib-coverage@3.2.2: {} + + istanbul-lib-instrument@5.2.1: + dependencies: + '@babel/core': 7.28.0 + '@babel/parser': 7.28.0 + '@istanbuljs/schema': 0.1.3 + istanbul-lib-coverage: 3.2.2 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + + istanbul-lib-instrument@6.0.3: + dependencies: + '@babel/core': 7.28.0 + '@babel/parser': 7.28.0 + '@istanbuljs/schema': 0.1.3 + istanbul-lib-coverage: 3.2.2 + semver: 7.7.2 + transitivePeerDependencies: + - supports-color + + istanbul-lib-report@3.0.1: + dependencies: + istanbul-lib-coverage: 3.2.2 + make-dir: 4.0.0 + supports-color: 7.2.0 + + istanbul-lib-source-maps@4.0.1: + dependencies: + debug: 4.4.1 + istanbul-lib-coverage: 3.2.2 + source-map: 0.6.1 + transitivePeerDependencies: + - supports-color + + istanbul-reports@3.1.7: + dependencies: + html-escaper: 2.0.2 + istanbul-lib-report: 3.0.1 + + jake@10.9.2: + dependencies: + async: 3.2.6 + chalk: 4.1.2 + filelist: 1.0.4 + minimatch: 3.1.2 + + jest-changed-files@29.7.0: + dependencies: + execa: 5.1.1 + jest-util: 29.7.0 + p-limit: 3.1.0 + + jest-circus@29.7.0: + dependencies: + '@jest/environment': 29.7.0 + '@jest/expect': 29.7.0 + '@jest/test-result': 29.7.0 + '@jest/types': 29.6.3 + '@types/node': 20.19.9 + chalk: 4.1.2 + co: 4.6.0 + dedent: 1.6.0 + is-generator-fn: 2.1.0 + jest-each: 29.7.0 + jest-matcher-utils: 29.7.0 + jest-message-util: 29.7.0 + jest-runtime: 29.7.0 + jest-snapshot: 29.7.0 + jest-util: 29.7.0 + p-limit: 3.1.0 + pretty-format: 29.7.0 + pure-rand: 6.1.0 + slash: 3.0.0 + stack-utils: 2.0.6 + transitivePeerDependencies: + - babel-plugin-macros + - supports-color + + jest-cli@29.7.0(@types/node@20.19.9)(ts-node@10.9.2(@types/node@20.19.9)(typescript@5.8.3)): + dependencies: + '@jest/core': 29.7.0(ts-node@10.9.2(@types/node@20.19.9)(typescript@5.8.3)) + '@jest/test-result': 29.7.0 + '@jest/types': 29.6.3 + chalk: 4.1.2 + create-jest: 29.7.0(@types/node@20.19.9)(ts-node@10.9.2(@types/node@20.19.9)(typescript@5.8.3)) + exit: 0.1.2 + import-local: 3.2.0 + jest-config: 29.7.0(@types/node@20.19.9)(ts-node@10.9.2(@types/node@20.19.9)(typescript@5.8.3)) + jest-util: 29.7.0 + jest-validate: 29.7.0 + yargs: 17.7.2 + transitivePeerDependencies: + - '@types/node' + - babel-plugin-macros + - supports-color + - ts-node + + jest-config@29.7.0(@types/node@20.19.9)(ts-node@10.9.2(@types/node@20.19.9)(typescript@5.8.3)): + dependencies: + '@babel/core': 7.28.0 + '@jest/test-sequencer': 29.7.0 + '@jest/types': 29.6.3 + babel-jest: 29.7.0(@babel/core@7.28.0) + chalk: 4.1.2 + ci-info: 3.9.0 + deepmerge: 4.3.1 + glob: 7.2.3 + graceful-fs: 4.2.11 + jest-circus: 29.7.0 + jest-environment-node: 29.7.0 + jest-get-type: 29.6.3 + jest-regex-util: 29.6.3 + jest-resolve: 29.7.0 + jest-runner: 29.7.0 + jest-util: 29.7.0 + jest-validate: 29.7.0 + micromatch: 4.0.8 + parse-json: 5.2.0 + pretty-format: 29.7.0 + slash: 3.0.0 + strip-json-comments: 3.1.1 + optionalDependencies: + '@types/node': 20.19.9 + ts-node: 10.9.2(@types/node@20.19.9)(typescript@5.8.3) + transitivePeerDependencies: + - babel-plugin-macros + - supports-color + + jest-diff@29.7.0: + dependencies: + chalk: 4.1.2 + diff-sequences: 29.6.3 + jest-get-type: 29.6.3 + pretty-format: 29.7.0 + + jest-docblock@29.7.0: + dependencies: + detect-newline: 3.1.0 + + jest-each@29.7.0: + dependencies: + '@jest/types': 29.6.3 + chalk: 4.1.2 + jest-get-type: 29.6.3 + jest-util: 29.7.0 + pretty-format: 29.7.0 + + jest-environment-node@29.7.0: + dependencies: + '@jest/environment': 29.7.0 + '@jest/fake-timers': 29.7.0 + '@jest/types': 29.6.3 + '@types/node': 20.19.9 + jest-mock: 29.7.0 + jest-util: 29.7.0 + + jest-get-type@29.6.3: {} + + jest-haste-map@29.7.0: + dependencies: + '@jest/types': 29.6.3 + '@types/graceful-fs': 4.1.9 + '@types/node': 20.19.9 + anymatch: 3.1.3 + fb-watchman: 2.0.2 + graceful-fs: 4.2.11 + jest-regex-util: 29.6.3 + jest-util: 29.7.0 + jest-worker: 29.7.0 + micromatch: 4.0.8 + walker: 1.0.8 + optionalDependencies: + fsevents: 2.3.3 + + jest-leak-detector@29.7.0: + dependencies: + jest-get-type: 29.6.3 + pretty-format: 29.7.0 + + jest-matcher-utils@29.7.0: + dependencies: + chalk: 4.1.2 + jest-diff: 29.7.0 + jest-get-type: 29.6.3 + pretty-format: 29.7.0 + + jest-message-util@29.7.0: + dependencies: + '@babel/code-frame': 7.27.1 + '@jest/types': 29.6.3 + '@types/stack-utils': 2.0.3 + chalk: 4.1.2 + graceful-fs: 4.2.11 + micromatch: 4.0.8 + pretty-format: 29.7.0 + slash: 3.0.0 + stack-utils: 2.0.6 + + jest-mock@29.7.0: + dependencies: + '@jest/types': 29.6.3 + '@types/node': 20.19.9 + jest-util: 29.7.0 + + jest-pnp-resolver@1.2.3(jest-resolve@29.7.0): + optionalDependencies: + jest-resolve: 29.7.0 + + jest-regex-util@29.6.3: {} + + jest-resolve-dependencies@29.7.0: + dependencies: + jest-regex-util: 29.6.3 + jest-snapshot: 29.7.0 + transitivePeerDependencies: + - supports-color + + jest-resolve@29.7.0: + dependencies: + chalk: 4.1.2 + graceful-fs: 4.2.11 + jest-haste-map: 29.7.0 + jest-pnp-resolver: 1.2.3(jest-resolve@29.7.0) + jest-util: 29.7.0 + jest-validate: 29.7.0 + resolve: 1.22.10 + resolve.exports: 2.0.3 + slash: 3.0.0 + + jest-runner@29.7.0: + dependencies: + '@jest/console': 29.7.0 + '@jest/environment': 29.7.0 + '@jest/test-result': 29.7.0 + '@jest/transform': 29.7.0 + '@jest/types': 29.6.3 + '@types/node': 20.19.9 + chalk: 4.1.2 + emittery: 0.13.1 + graceful-fs: 4.2.11 + jest-docblock: 29.7.0 + jest-environment-node: 29.7.0 + jest-haste-map: 29.7.0 + jest-leak-detector: 29.7.0 + jest-message-util: 29.7.0 + jest-resolve: 29.7.0 + jest-runtime: 29.7.0 + jest-util: 29.7.0 + jest-watcher: 29.7.0 + jest-worker: 29.7.0 + p-limit: 3.1.0 + source-map-support: 0.5.13 + transitivePeerDependencies: + - supports-color + + jest-runtime@29.7.0: + dependencies: + '@jest/environment': 29.7.0 + '@jest/fake-timers': 29.7.0 + '@jest/globals': 29.7.0 + '@jest/source-map': 29.6.3 + '@jest/test-result': 29.7.0 + '@jest/transform': 29.7.0 + '@jest/types': 29.6.3 + '@types/node': 20.19.9 + chalk: 4.1.2 + cjs-module-lexer: 1.4.3 + collect-v8-coverage: 1.0.2 + glob: 7.2.3 + graceful-fs: 4.2.11 + jest-haste-map: 29.7.0 + jest-message-util: 29.7.0 + jest-mock: 29.7.0 + jest-regex-util: 29.6.3 + jest-resolve: 29.7.0 + jest-snapshot: 29.7.0 + jest-util: 29.7.0 + slash: 3.0.0 + strip-bom: 4.0.0 + transitivePeerDependencies: + - supports-color + + jest-snapshot@29.7.0: + dependencies: + '@babel/core': 7.28.0 + '@babel/generator': 7.28.0 + '@babel/plugin-syntax-jsx': 7.27.1(@babel/core@7.28.0) + '@babel/plugin-syntax-typescript': 7.27.1(@babel/core@7.28.0) + '@babel/types': 7.28.2 + '@jest/expect-utils': 29.7.0 + '@jest/transform': 29.7.0 + '@jest/types': 29.6.3 + babel-preset-current-node-syntax: 1.1.1(@babel/core@7.28.0) + chalk: 4.1.2 + expect: 29.7.0 + graceful-fs: 4.2.11 + jest-diff: 29.7.0 + jest-get-type: 29.6.3 + jest-matcher-utils: 29.7.0 + jest-message-util: 29.7.0 + jest-util: 29.7.0 + natural-compare: 1.4.0 + pretty-format: 29.7.0 + semver: 7.7.2 + transitivePeerDependencies: + - supports-color + + jest-util@29.7.0: + dependencies: + '@jest/types': 29.6.3 + '@types/node': 20.19.9 + chalk: 4.1.2 + ci-info: 3.9.0 + graceful-fs: 4.2.11 + picomatch: 2.3.1 + + jest-validate@29.7.0: + dependencies: + '@jest/types': 29.6.3 + camelcase: 6.3.0 + chalk: 4.1.2 + jest-get-type: 29.6.3 + leven: 3.1.0 + pretty-format: 29.7.0 + + jest-watcher@29.7.0: + dependencies: + '@jest/test-result': 29.7.0 + '@jest/types': 29.6.3 + '@types/node': 20.19.9 + ansi-escapes: 4.3.2 + chalk: 4.1.2 + emittery: 0.13.1 + jest-util: 29.7.0 + string-length: 4.0.2 + + jest-worker@29.7.0: + dependencies: + '@types/node': 20.19.9 + jest-util: 29.7.0 + merge-stream: 2.0.0 + supports-color: 8.1.1 + + jest@29.7.0(@types/node@20.19.9)(ts-node@10.9.2(@types/node@20.19.9)(typescript@5.8.3)): + dependencies: + '@jest/core': 29.7.0(ts-node@10.9.2(@types/node@20.19.9)(typescript@5.8.3)) + '@jest/types': 29.6.3 + import-local: 3.2.0 + jest-cli: 29.7.0(@types/node@20.19.9)(ts-node@10.9.2(@types/node@20.19.9)(typescript@5.8.3)) + transitivePeerDependencies: + - '@types/node' + - babel-plugin-macros + - supports-color + - ts-node + + js-sha3@0.8.0: {} + + js-tokens@4.0.0: {} + + js-yaml@3.14.1: + dependencies: + argparse: 1.0.10 + esprima: 4.0.1 + + jsesc@3.1.0: {} + + json-parse-even-better-errors@2.3.1: {} + + json5@2.2.3: {} + + jsonpath@1.1.1: + dependencies: + esprima: 1.2.2 + static-eval: 2.0.2 + underscore: 1.12.1 + + kleur@3.0.3: {} + + leven@3.1.0: {} + + levn@0.3.0: + dependencies: + prelude-ls: 1.1.2 + type-check: 0.3.2 + + lines-and-columns@1.2.4: {} + + locate-path@5.0.0: + dependencies: + p-locate: 4.1.0 + + lodash.memoize@4.1.2: {} + + logplease@1.2.15: {} + + lru-cache@5.1.1: + dependencies: + yallist: 3.1.1 + + make-dir@4.0.0: + dependencies: + semver: 7.7.2 + + make-error@1.3.6: {} + + makeerror@1.0.12: + dependencies: + tmpl: 1.0.5 + + merge-stream@2.0.0: {} + + micromatch@4.0.8: + dependencies: + braces: 3.0.3 + picomatch: 2.3.1 + + mimic-fn@2.1.0: {} + + minimalistic-assert@1.0.1: {} + + minimalistic-crypto-utils@1.0.1: {} + + minimatch@3.1.2: + dependencies: + brace-expansion: 1.1.12 + + minimatch@5.1.6: + dependencies: + brace-expansion: 2.0.2 + + ms@2.1.3: {} + + nanoassert@2.0.0: {} + + natural-compare@1.4.0: {} + + noble-bls12-381@0.7.2: {} + + noble-hashes@0.3.1: {} + + noble-secp256k1@1.2.14: {} + + node-addon-api@3.2.1: {} + + node-gyp-build@4.8.4: {} + + node-int64@0.4.0: {} + + node-releases@2.0.19: {} + + normalize-path@3.0.0: {} + + npm-run-path@4.0.1: + dependencies: + path-key: 3.1.1 + + once@1.4.0: + dependencies: + wrappy: 1.0.2 + + onetime@5.1.2: + dependencies: + mimic-fn: 2.1.0 + + optionator@0.8.3: + dependencies: + deep-is: 0.1.4 + fast-levenshtein: 2.0.6 + levn: 0.3.0 + prelude-ls: 1.1.2 + type-check: 0.3.2 + word-wrap: 1.2.5 + + p-limit@2.3.0: + dependencies: + p-try: 2.2.0 + + p-limit@3.1.0: + dependencies: + yocto-queue: 0.1.0 + + p-locate@4.1.0: + dependencies: + p-limit: 2.3.0 + + p-try@2.2.0: {} + + parse-json@5.2.0: + dependencies: + '@babel/code-frame': 7.27.1 + error-ex: 1.3.2 + json-parse-even-better-errors: 2.3.1 + lines-and-columns: 1.2.4 + + path-exists@4.0.0: {} + + path-is-absolute@1.0.1: {} + + path-key@3.1.1: {} + + path-parse@1.0.7: {} + + picocolors@1.1.1: {} + + picomatch@2.3.1: {} + + pirates@4.0.7: {} + + pkg-dir@4.2.0: + dependencies: + find-up: 4.1.0 + + prelude-ls@1.1.2: {} + + pretty-format@29.7.0: + dependencies: + '@jest/schemas': 29.6.3 + ansi-styles: 5.2.0 + react-is: 18.3.1 + + prompts@2.4.2: + dependencies: + kleur: 3.0.3 + sisteransi: 1.0.5 + + pure-rand@6.1.0: {} + + r1csfile@0.0.48: + dependencies: + '@iden3/bigarray': 0.0.2 + '@iden3/binfileutils': 0.0.12 + fastfile: 0.0.20 + ffjavascript: 0.3.0 + + react-is@18.3.1: {} + + readable-stream@3.6.2: + dependencies: + inherits: 2.0.4 + string_decoder: 1.3.0 + util-deprecate: 1.0.2 + + require-directory@2.1.1: {} + + resolve-cwd@3.0.0: + dependencies: + resolve-from: 5.0.0 + + resolve-from@5.0.0: {} + + resolve.exports@2.0.3: {} + + resolve@1.22.10: + dependencies: + is-core-module: 2.16.1 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + + safe-buffer@5.2.1: {} + + scrypt-js@3.0.1: {} + + semver@6.3.1: {} + + semver@7.7.2: {} + + shebang-command@2.0.0: + dependencies: + shebang-regex: 3.0.0 + + shebang-regex@3.0.0: {} + + signal-exit@3.0.7: {} + + sisteransi@1.0.5: {} + + slash@3.0.0: {} + + snarkjs@0.7.5: + dependencies: + '@iden3/binfileutils': 0.0.12 + bfj: 7.1.0 + blake2b-wasm: 2.4.0 + circom_runtime: 0.1.28 + ejs: 3.1.10 + fastfile: 0.0.20 + ffjavascript: 0.3.1 + js-sha3: 0.8.0 + logplease: 1.2.15 + r1csfile: 0.0.48 + + source-map-support@0.5.13: + dependencies: + buffer-from: 1.1.2 + source-map: 0.6.1 + + source-map@0.6.1: {} + + sprintf-js@1.0.3: {} + + stack-utils@2.0.6: + dependencies: + escape-string-regexp: 2.0.0 + + static-eval@2.0.2: + dependencies: + escodegen: 1.14.3 + + string-length@4.0.2: + dependencies: + char-regex: 1.0.2 + strip-ansi: 6.0.1 + + string-width@4.2.3: + dependencies: + emoji-regex: 8.0.0 + is-fullwidth-code-point: 3.0.0 + strip-ansi: 6.0.1 + + string_decoder@1.3.0: + dependencies: + safe-buffer: 5.2.1 + + strip-ansi@6.0.1: + dependencies: + ansi-regex: 5.0.1 + + strip-bom@4.0.0: {} + + strip-final-newline@2.0.0: {} + + strip-json-comments@3.1.1: {} + + supports-color@7.2.0: + dependencies: + has-flag: 4.0.0 + + supports-color@8.1.1: + dependencies: + has-flag: 4.0.0 + + supports-preserve-symlinks-flag@1.0.0: {} + + test-exclude@6.0.0: + dependencies: + '@istanbuljs/schema': 0.1.3 + glob: 7.2.3 + minimatch: 3.1.2 + + tmpl@1.0.5: {} + + to-regex-range@5.0.1: + dependencies: + is-number: 7.0.0 + + tryer@1.0.1: {} + + ts-jest@29.4.0(@babel/core@7.28.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.28.0))(jest-util@29.7.0)(jest@29.7.0(@types/node@20.19.9)(ts-node@10.9.2(@types/node@20.19.9)(typescript@5.8.3)))(typescript@5.8.3): + dependencies: + bs-logger: 0.2.6 + ejs: 3.1.10 + fast-json-stable-stringify: 2.1.0 + jest: 29.7.0(@types/node@20.19.9)(ts-node@10.9.2(@types/node@20.19.9)(typescript@5.8.3)) + json5: 2.2.3 + lodash.memoize: 4.1.2 + make-error: 1.3.6 + semver: 7.7.2 + type-fest: 4.41.0 + typescript: 5.8.3 + yargs-parser: 21.1.1 + optionalDependencies: + '@babel/core': 7.28.0 + '@jest/transform': 29.7.0 + '@jest/types': 29.6.3 + babel-jest: 29.7.0(@babel/core@7.28.0) + jest-util: 29.7.0 + + ts-node@10.9.2(@types/node@20.19.9)(typescript@5.8.3): + dependencies: + '@cspotcode/source-map-support': 0.8.1 + '@tsconfig/node10': 1.0.11 + '@tsconfig/node12': 1.0.11 + '@tsconfig/node14': 1.0.3 + '@tsconfig/node16': 1.0.4 + '@types/node': 20.19.9 + acorn: 8.15.0 + acorn-walk: 8.3.4 + arg: 4.1.3 + create-require: 1.1.1 + diff: 4.0.2 + make-error: 1.3.6 + typescript: 5.8.3 + v8-compile-cache-lib: 3.0.1 + yn: 3.1.1 + + type-check@0.3.2: + dependencies: + prelude-ls: 1.1.2 + + type-detect@4.0.8: {} + + type-fest@0.21.3: {} + + type-fest@4.41.0: {} + + typescript@5.8.3: {} + + underscore@1.12.1: {} + + undici-types@6.21.0: {} + + update-browserslist-db@1.1.3(browserslist@4.25.1): + dependencies: + browserslist: 4.25.1 + escalade: 3.2.0 + picocolors: 1.1.1 + + util-deprecate@1.0.2: {} + + v8-compile-cache-lib@3.0.1: {} + + v8-to-istanbul@9.3.0: + dependencies: + '@jridgewell/trace-mapping': 0.3.29 + '@types/istanbul-lib-coverage': 2.0.6 + convert-source-map: 2.0.0 + + walker@1.0.8: + dependencies: + makeerror: 1.0.12 + + wasmbuilder@0.0.16: {} + + wasmcurves@0.2.2: + dependencies: + wasmbuilder: 0.0.16 + + web-worker@1.2.0: {} + + which@2.0.2: + dependencies: + isexe: 2.0.0 + + word-wrap@1.2.5: {} + + wrap-ansi@7.0.0: + dependencies: + ansi-styles: 4.3.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + + wrappy@1.0.2: {} + + write-file-atomic@4.0.2: + dependencies: + imurmurhash: 0.1.4 + signal-exit: 3.0.7 + + ws@8.18.0: {} + + y18n@5.0.8: {} + + yallist@3.1.1: {} + + yargs-parser@21.1.1: {} + + yargs@17.7.2: + dependencies: + cliui: 8.0.1 + escalade: 3.2.0 + get-caller-file: 2.0.5 + require-directory: 2.1.1 + string-width: 4.2.3 + y18n: 5.0.8 + yargs-parser: 21.1.1 + + yn@3.1.1: {} + + yocto-queue@0.1.0: {} diff --git a/infrastructure/blindvote/src/core/types.ts b/infrastructure/blindvote/src/core/types.ts new file mode 100644 index 00000000..20da8b18 --- /dev/null +++ b/infrastructure/blindvote/src/core/types.ts @@ -0,0 +1,96 @@ +/** + * Type definitions for the decentralized privacy-preserving voting system + * Updated to use proper Ristretto255 types and ZK proof structures + */ + +import { RistrettoPoint } from '@noble/curves/ed25519.js'; + +// Group element type for elliptic curve operations +export type GroupElement = InstanceType; + +// Vote option interface for flexible voting +export interface VoteOption { + id: string; + label: string; + value: number; // Numeric value for the option +} + +// Election configuration +export interface ElectionConfig { + electionId: string; + contestId: string; + options: string[]; // Array of option IDs + maxVotes: number; + allowAbstain: boolean; +} + +// Context for domain separation +export type Ctx = { + electionId: string; + contestId: string; + optionId?: string; +}; + +// Voter registration anchor with ZK proof +export interface Anchor { + voterId: string; + electionId: string; + contestId: string; + optionId: string; + H: Uint8Array; // enc(RistrettoPoint) + proofAnchor: { T: Uint8Array; s: Uint8Array }; +} + +// Option ballot with commitment and proofs +export interface OptionBallot { + optionId: string; + C: Uint8Array; + proofConsistency: any; + proofBit01: any; +} + +// Vote ballot with commitments for all options +export interface Ballot { + voterId: string; + electionId: string; + contestId: string; + options: OptionBallot[]; // one per option, same order each time + proofOneHot: any; +} + +// Aggregated results +export interface AggregatedResults { + C_agg: Uint8Array; // Aggregate commitment + H_S: Uint8Array; // Aggregate anchor + X: Uint8Array; // Final result: g^M +} + +export interface Voter { + voterId: string; + electionId: string; + contestId: string; + randomness: bigint; + registeredAt: Date; +} + +export interface VoteData { + voterId: string; + contestId: string; + chosenOptionId: string; // Which option the voter actually chose + commitments: Record; // optionId -> commitment bytes + anchors: Record; // optionId -> anchor bytes + submittedAt: Date; +} + +// Election result - updated to match VotingSystem expectations +export interface ElectionResult { + electionId: string; + contestId: string; + totalVoters: number; + totalVotes: number; + optionResults: Record; // optionId -> vote count + C_agg: Record; // optionId -> aggregated commitment + H_S: Record; // optionId -> aggregated anchor + X: Record; // optionId -> randomness cancelled result + verified: boolean; +} diff --git a/infrastructure/blindvote/src/core/voting-system.ts b/infrastructure/blindvote/src/core/voting-system.ts new file mode 100644 index 00000000..9e7997aa --- /dev/null +++ b/infrastructure/blindvote/src/core/voting-system.ts @@ -0,0 +1,310 @@ +/** + * VotingSystem - High-level abstraction for managing elections and votes + * + * This class provides a human-friendly interface for: + * - Creating and managing elections + * - Registering voters with anchors + * - Submitting votes with commitments + * - Tallying elections and verifying results + * + * The system supports both internally generated and externally provided + * cryptographic components (commitments, anchors, etc.) + */ + +import { + PedersenCommitment, + randScalar, + bigIntToBytes, + hashToScalar, + enc, + dec, + tallyOption +} from "../crypto/pedersen"; +import { + Voter, + VoteData, + ElectionConfig, + ElectionResult +} from "./types"; + +export class VotingSystem { + private pedersen: PedersenCommitment; + private voters: Map; + private votes: Map; + private elections: Map; + + constructor() { + this.pedersen = new PedersenCommitment(); + this.voters = new Map(); + this.votes = new Map(); + this.elections = new Map(); + } + + /** + * Create a new election with multiple options + */ + createElection(electionId: string, contestId: string, options: string[]): ElectionConfig { + const config: ElectionConfig = { + electionId, + contestId, + options, + maxVotes: 1, // One-hot voting + allowAbstain: false + }; + + this.elections.set(electionId, config); + return config; + } + + /** + * Register a voter for an election + */ + registerVoter(voterId: string, electionId: string, contestId: string): Voter { + const key = `${voterId}:${electionId}:${contestId}`; + + if (this.voters.has(key)) { + throw new Error(`Voter ${voterId} already registered for election ${electionId}`); + } + + const voter: Voter = { + voterId, + electionId, + contestId, + randomness: randScalar(), + registeredAt: new Date() + }; + + this.voters.set(key, voter); + return voter; + } + + /** + * Submit a vote with per-option commitments and anchors + */ + submitVote( + voterId: string, + electionId: string, + contestId: string, + chosenOptionId: string, + voteData: Omit + ): void { + const key = `${voterId}:${electionId}:${contestId}`; + + // Verify voter is registered + if (!this.voters.has(key)) { + throw new Error(`Voter ${voterId} not registered for election ${electionId}`); + } + + // Verify chosen option exists + const election = this.elections.get(electionId); + if (!election || !election.options.includes(chosenOptionId)) { + throw new Error(`Invalid option ${chosenOptionId} for election ${electionId}`); + } + + // Verify all options have commitments and anchors + for (const optionId of election.options) { + if (!voteData.commitments[optionId] || !voteData.anchors[optionId]) { + throw new Error(`Missing commitment or anchor for option ${optionId}`); + } + } + + // Store the vote + const vote: VoteData = { + ...voteData, + submittedAt: new Date() + }; + + this.votes.set(key, vote); + } + + /** + * Add vote data directly (for tallying from stored data) + * This bypasses validation since we're reconstructing from stored blind votes + */ + addVoteForTallying( + voterId: string, + electionId: string, + contestId: string, + voteData: VoteData + ): void { + const key = `${voterId}:${electionId}:${contestId}`; + this.votes.set(key, voteData); + } + + /** + * Generate per-option commitments and anchors for a voter + */ + generateVoteData( + voterId: string, + electionId: string, + contestId: string, + chosenOptionId: string + ): VoteData { + const key = `${voterId}:${electionId}:${contestId}`; + const voter = this.voters.get(key); + + if (!voter) { + throw new Error(`Voter ${voterId} not registered for election ${electionId}`); + } + + const election = this.elections.get(electionId); + if (!election || !election.options.includes(chosenOptionId)) { + throw new Error(`Invalid option ${chosenOptionId} for election ${electionId}`); + } + + const commitments: Record = {}; + const anchors: Record = {}; + + // Generate per-option randomness and commitments + for (const optionId of election.options) { + // Derive per-option randomness from base secret + const domain = `${electionId}:${contestId}:${optionId}`; + const r = hashToScalar(domain, bigIntToBytes(voter.randomness)); + + // Create anchor: H[i,c] = h · r[i,c] + const anchor = this.pedersen.createAnchor(r); + anchors[optionId] = enc(anchor); + + // Create commitment: C[i,c] = g · m[i,c] + h · r[i,c] + const m = (chosenOptionId === optionId) ? 1n : 0n; + const commitment = this.pedersen.commit(m, r); + commitments[optionId] = enc(commitment); + } + + return { + voterId, + contestId, + chosenOptionId, + commitments, + anchors, + submittedAt: new Date() + }; + } + + /** + * Tally an election and return per-option results + */ + async tallyElection(electionId: string): Promise { + const election = this.elections.get(electionId); + if (!election) { + throw new Error(`Election ${electionId} not found`); + } + + const contestId = election.contestId; + const optionResults: Record = {}; + const C_agg: Record = {}; + const H_S: Record = {}; + const X: Record = {}; + + // Tally each option separately + for (const optionId of election.options) { + const { M, C_agg_bytes, H_S_bytes, X_bytes } = await this.tallyOption(contestId, optionId); + + optionResults[optionId] = M; + C_agg[optionId] = C_agg_bytes; + H_S[optionId] = H_S_bytes; + X[optionId] = X_bytes; + } + + const totalVoters = this.voters.size; + const totalVotes = Object.values(optionResults).reduce((sum, count) => sum + count, 0); + + return { + electionId, + contestId, + totalVoters, + totalVotes, + optionResults, + C_agg, + H_S, + X, + verified: true + }; + } + + /** + * Tally votes for a specific option + */ + private async tallyOption(contestId: string, optionId: string): Promise<{ M: number; C_agg_bytes: Uint8Array; H_S_bytes: Uint8Array; X_bytes: Uint8Array }> { + const ballots: { voterId: string; C: Uint8Array }[] = []; + const anchors: { voterId: string; H: Uint8Array }[] = []; + + // Collect ballots and anchors for this specific option + for (const [key, vote] of this.votes.entries()) { + if (vote.contestId === contestId) { + const C = vote.commitments[optionId]; + const H = vote.anchors[optionId]; + + if (C && H) { + ballots.push({ voterId: vote.voterId, C }); + anchors.push({ voterId: vote.voterId, H }); + } + } + } + + if (ballots.length === 0) { + return { M: 0, C_agg_bytes: new Uint8Array(32), H_S_bytes: new Uint8Array(32), X_bytes: new Uint8Array(32) }; + } + + // Use the tallyOption function from pedersen.ts + const M = tallyOption(ballots, anchors); + + // Get the aggregated values for verification + const { C_agg_bytes, H_S_bytes, X_bytes } = await this.getAggregatedValues(ballots, anchors); + + return { M, C_agg_bytes, H_S_bytes, X_bytes }; + } + + /** + * Get aggregated values for verification + */ + private async getAggregatedValues( + ballots: { voterId: string; C: Uint8Array }[], + anchors: { voterId: string; H: Uint8Array }[] + ): Promise<{ C_agg_bytes: Uint8Array; H_S_bytes: Uint8Array; X_bytes: Uint8Array }> { + const { RistrettoPoint } = await import("@noble/curves/ed25519.js"); + + const g = RistrettoPoint.BASE; + const ZERO = RistrettoPoint.ZERO; + + // Aggregate commitments and anchors + const Cs = ballots.map(b => dec(b.C)); + const Hs = anchors.map(a => dec(a.H)); + + const addPoints = (arr: any[]) => arr.reduce((acc, p) => acc.add(p), ZERO); + const C_agg = addPoints(Cs); + const H_S = addPoints(Hs); + const X = C_agg.add(H_S.negate()); + + return { + C_agg_bytes: enc(C_agg), + H_S_bytes: enc(H_S), + X_bytes: enc(X) + }; + } + + /** + * Get a voter by ID + */ + getVoter(voterId: string, electionId: string, contestId: string): Voter | undefined { + const key = `${voterId}:${electionId}:${contestId}`; + return this.voters.get(key); + } + + /** + * Get a vote by voter ID + */ + getVote(voterId: string, electionId: string, contestId: string): VoteData | undefined { + const key = `${voterId}:${electionId}:${contestId}`; + return this.votes.get(key); + } + + /** + * Clear all data (for testing) + */ + clear(): void { + this.voters.clear(); + this.votes.clear(); + this.elections.clear(); + } +} diff --git a/infrastructure/blindvote/src/crypto/pedersen.ts b/infrastructure/blindvote/src/crypto/pedersen.ts new file mode 100644 index 00000000..8404f7f2 --- /dev/null +++ b/infrastructure/blindvote/src/crypto/pedersen.ts @@ -0,0 +1,300 @@ +/** + * Pedersen commitment implementation using @noble/curves/ed25519 (Ristretto255) + * Proper cryptographic implementation for the decentralized voting system + * Based on the AI Expert specification + */ + +import { RistrettoPoint } from '@noble/curves/ed25519.js'; +import { hmac } from '@noble/hashes/hmac'; +import { sha512 } from '@noble/hashes/sha2.js'; + +// Browser-compatible random bytes +function getRandomBytes(length: number): Uint8Array { + const array = new Uint8Array(length); + crypto.getRandomValues(array); + return array; +} + +// Type definitions +export type GroupElement = InstanceType; +export type ScalarType = bigint; + +// Context for domain separation +export type Ctx = { + electionId: string; + contestId: string; + optionId?: string; +}; + +// Helpers +export function randScalar(): bigint { + // Use the actual curve order from RistrettoPoint + const q = RistrettoPoint.Fn.ORDER; + let x: bigint; + do { + x = bytesToBigInt(getRandomBytes(64)) % q; + } while (x === 0n || x >= q); + return x; +} + +function bytesToBigInt(b: Uint8Array): bigint { + let v = 0n; + for (const x of b) v = (v << 8n) + BigInt(x); + return v; +} + +export function bigIntToBytes(x: bigint): Uint8Array { + const bytes = new Uint8Array(32); + for (let i = 31; i >= 0; i--) { + bytes[i] = Number(x & 0xffn); + x = x >> 8n; + } + return bytes; +} + +// Domain-separated hash to scalar +export function hashToScalar(domain: string, ...parts: Uint8Array[]): bigint { + const mac = hmac.create(sha512, new TextEncoder().encode(domain)); + for (const p of parts) mac.update(p); + const digest = mac.digest(); + const q = RistrettoPoint.Fn.ORDER; + return bytesToBigInt(digest) % q; +} + +// Generators g and h +const g = RistrettoPoint.BASE; +const domainBytes = new TextEncoder().encode('auvo/vote/h-generator/v1'); +const paddedDomain = new Uint8Array(64); +paddedDomain.set(domainBytes.slice(0, 64)); +const h = RistrettoPoint.hashToCurve(paddedDomain); + +// Encoding helpers +export const enc = (P: InstanceType): Uint8Array => P.toRawBytes(); +export const dec = (b: Uint8Array): InstanceType => RistrettoPoint.fromBytes(b); + +export class PedersenCommitment { + /** + * Create a Pedersen commitment: C(m, r) = g^m * h^r + */ + commit(m: bigint, r: bigint): InstanceType { + // Ensure m is a valid scalar (0 or 1 for voting) + if (m !== 0n && m !== 1n) { + throw new Error('Vote value must be 0 or 1'); + } + + // Ensure r is within valid range + const rValid = r % RistrettoPoint.Fn.ORDER; + if (rValid === 0n) { + throw new Error('Randomness cannot be 0'); + } + + if (m === 0n) { + // For m=0: C = h^r (no g component) + return h.multiply(rValid); + } else { + // For m=1: C = g + h^r + return g.add(h.multiply(rValid)); + } + } + + /** + * Create an anchor: H(r) = h^r + */ + createAnchor(r: bigint): InstanceType { + // Ensure r is within valid range + const rValid = r % RistrettoPoint.Fn.ORDER; + if (rValid === 0n) { + throw new Error('Randomness cannot be 0'); + } + return h.multiply(rValid); + } + + /** + * Homomorphically add commitments + */ + addCommitments(c1: InstanceType, c2: InstanceType): InstanceType { + return c1.add(c2); + } + + /** + * Homomorphically add anchors + */ + addAnchors(a1: InstanceType, a2: InstanceType): InstanceType { + return a1.add(a2); + } + + /** + * Cancel randomness: X = C_agg * H_S^(-1) = g^M + */ + cancelRandomness(C_agg: InstanceType, H_S: InstanceType): InstanceType { + return C_agg.add(H_S.negate()); + } + + /** + * Verify a commitment + */ + verify(commitment: InstanceType, m: bigint, r: bigint): boolean { + const computedCommitment = this.commit(m, r); + return commitment.equals(computedCommitment); + } + + /** + * Get the curve order + */ + getCurveOrder(): bigint { + return RistrettoPoint.Fn.ORDER; + } + + /** + * Get the generator g + */ + getGenerator(): InstanceType { + return g; + } + + /** + * Get the second generator h + */ + getH(): InstanceType { + return h; + } + + /** + * Generate cryptographically secure random values + */ + generateRandomness(count: number): bigint[] { + const randomness: bigint[] = []; + for (let i = 0; i < count; i++) { + randomness.push(randScalar()); + } + return randomness; + } + + /** + * Generate a single random value + */ + generateRandomValue(): bigint { + return randScalar(); + } +} + +// Schnorr proof for anchor H = h^r +export function proveAnchor(H: InstanceType, r: bigint, ctx: Ctx) { + const k = randScalar(); + const T = h.multiply(k); + const e = hashToScalar(`anchor/v1|${ctx.electionId}|${ctx.contestId}|${ctx.optionId}`, + h.toRawBytes(), H.toRawBytes(), T.toRawBytes()); + const s = (k + e * r) % RistrettoPoint.Fn.ORDER; + return { T: enc(T), s: bigIntToBytes(s) }; +} + +export function verifyAnchor(Hb: Uint8Array, proof: { T: Uint8Array; s: Uint8Array; }, ctx: Ctx): boolean { + try { + const H = dec(Hb), T = dec(proof.T); + const s = bytesToBigInt(proof.s); + const e = hashToScalar(`anchor/v1|${ctx.electionId}|${ctx.contestId}|${ctx.optionId}`, + h.toRawBytes(), H.toRawBytes(), T.toRawBytes()); + + // check: h^s ?= T * H^e + const lhs = h.multiply(s); + const rhs = T.add(H.multiply(e)); + return enc(lhs).toString() === enc(rhs).toString(); + } catch { + return false; + } +} + +// Baby-step/Giant-step for small-range discrete log +export function bsgsSmallRange(Xb: Uint8Array, nMax: number): number { + const X = dec(Xb); + const m = Math.ceil(Math.sqrt(nMax + 1)); + + // Check for M=0 case first + if (X.equals(RistrettoPoint.ZERO)) { + return 0; + } + + // baby steps: table[g^j] = j + const table = new Map(); + let P = g; // Start with g^1, not g^0 + for (let j = 1; j <= m; j++) { + table.set(enc(P).toString(), j); + P = P.add(g); + } + + // precompute g^-m (use positive scalar) + const GmInv = g.multiply(BigInt(m)).negate(); + let Y = X; + + for (let i = 0; i <= m; i++) { + const key = enc(Y).toString(); + const j = table.get(key); + if (j !== undefined) { + const M = i * m + j; + if (M <= nMax) return M; + } + Y = Y.add(GmInv); + } + + throw new Error('small-range DL not found (bad inputs)'); +} + +/** + * Tally votes for a single option using Crypto Daddy's algorithm + */ +export function tallyOption( + ballots: { voterId: string; C: Uint8Array }[], + anchors: { voterId: string; H: Uint8Array }[] +): number { + // only anchors for voters who actually cast + const present = new Set(ballots.map(b => b.voterId)); + const Cs = ballots.map(b => dec(b.C)); + const Hs = anchors.filter(a => present.has(a.voterId)).map(a => dec(a.H)); + + if (Cs.length !== Hs.length) { + throw new Error('anchor/ballot mismatch for this option'); + } + + const C_agg = addPoints(Cs); + const H_S = addPoints(Hs); + const X = C_agg.add(H_S.negate()); // X = g · M + + const nMax = Cs.length; // votes in this contest + const M = bsgsSmallRange(enc(X), nMax); // Encode X before passing to bsgsSmallRange + + // must pass - handle M=0 case specially + let expectedC_agg; + if (M === 0) { + expectedC_agg = H_S; // For M=0: C_agg = H_S (no g component) + } else { + expectedC_agg = g.multiply(BigInt(M)).add(H_S); // For M>0: C_agg = g^M + H_S + } + + const ok = encEq(C_agg, expectedC_agg); + if (!ok) throw new Error('final check failed'); + return M; +} + +/** + * Helper function to add points + */ +function addPoints(arr: any[]) { + return arr.reduce((acc, p) => acc.add(p), RistrettoPoint.ZERO); +} + +/** + * Helper function to compare encodings + */ +function encEq(A: any, B: any) { + return Buffer.from(A.toRawBytes()).equals(Buffer.from(B.toRawBytes())); +} + +export function verifyFinal(C_aggb: Uint8Array, H_Sb: Uint8Array, M: number): boolean { + try { + const C_agg = dec(C_aggb), H_S = dec(H_Sb); + const gM = g.multiply(BigInt(M)); + return enc(C_agg).toString() === enc(gM.add(H_S)).toString(); + } catch { + return false; + } +} diff --git a/infrastructure/blindvote/src/examples/example.ts b/infrastructure/blindvote/src/examples/example.ts new file mode 100644 index 00000000..72009065 --- /dev/null +++ b/infrastructure/blindvote/src/examples/example.ts @@ -0,0 +1,67 @@ +/** + * Example usage of the VotingSystem for privacy-preserving voting + */ + +import { VotingSystem } from "../core/voting-system"; + +async function main() { + console.log("🚀 Starting Blind Voting System Demo...\n"); + + const votingSystem = new VotingSystem(); + + // Create an election with multiple options + const electionId = "election-2024"; + const contestId = "president"; + const options = ["candidate-a", "candidate-b", "candidate-c"]; + + const election = votingSystem.createElection(electionId, contestId, options); + console.log(`✅ Election created: ${electionId} with ${options.length} options`); + + // Register voters + const voter1 = votingSystem.registerVoter("voter-1", electionId, contestId); + const voter2 = votingSystem.registerVoter("voter-2", electionId, contestId); + const voter3 = votingSystem.registerVoter("voter-3", electionId, contestId); + + console.log(`✅ Registered ${3} voters`); + + // Generate vote data for each voter + console.log("\n🗳️ Generating votes..."); + + // Voter 1 votes for candidate-a + const voteData1 = votingSystem.generateVoteData("voter-1", electionId, contestId, "candidate-a"); + votingSystem.submitVote("voter-1", electionId, contestId, "candidate-a", voteData1); + console.log(`✅ Voter 1 voted for candidate-a`); + + // Voter 2 votes for candidate-b + const voteData2 = votingSystem.generateVoteData("voter-2", electionId, contestId, "candidate-b"); + votingSystem.submitVote("voter-2", electionId, contestId, "candidate-b", voteData2); + console.log(`✅ Voter 2 voted for candidate-b`); + + // Voter 3 votes for candidate-a + const voteData3 = votingSystem.generateVoteData("voter-3", electionId, contestId, "candidate-a"); + votingSystem.submitVote("voter-3", electionId, contestId, "candidate-a", voteData3); + console.log(`✅ Voter 3 voted for candidate-a`); + + // Tally the election + console.log("\n🔍 Tallying election..."); + const result = await votingSystem.tallyElection(electionId); + + console.log("\n📊 Election Results:"); + console.log(`- Total Voters: ${result.totalVoters}`); + console.log(`- Total Votes: ${result.totalVotes}`); + console.log(`- Verified: ${result.verified}`); + + console.log("\n📈 Per-Option Results:"); + for (const [optionId, voteCount] of Object.entries(result.optionResults)) { + console.log(` ${optionId}: ${voteCount} votes`); + } + + console.log("\n🔐 Cryptographic Values:"); + for (const [optionId, C_agg] of Object.entries(result.C_agg)) { + console.log(` ${optionId} C_agg: ${Array.from(C_agg).map(b => b.toString(16).padStart(2, '0')).join('').substring(0, 32)}...`); + } + + console.log("\n✅ Demo completed successfully!"); +} + +main().catch(console.error); diff --git a/infrastructure/blindvote/src/index.ts b/infrastructure/blindvote/src/index.ts new file mode 100644 index 00000000..2a0a0cad --- /dev/null +++ b/infrastructure/blindvote/src/index.ts @@ -0,0 +1,39 @@ +/** + * BlindVote - Decentralized Privacy-Preserving Voting System + * + * A cryptographically secure voting system that uses Pedersen commitments + * to ensure voter privacy while maintaining public verifiability of election results. + * + * Key Features: + * - Totally decentralized (no trusted servers) + * - Supports arbitrary vote options (not just binary yes/no) + * - Uses Ristretto255 elliptic curve for better performance + * - Pedersen commitments for secret ballots + * - Public bulletin board architecture + */ + +// Export the core voting system +export { VotingSystem } from "./core/voting-system"; + +// Export types +export type { + Voter, + VoteData, + ElectionConfig, + ElectionResult +} from "./core/types"; + +// Export crypto utilities +export { + PedersenCommitment, + randScalar, + bigIntToBytes, + hashToScalar, + enc, + dec, + tallyOption, + bsgsSmallRange +} from "./crypto/pedersen"; + +// Export RistrettoPoint for identity element access +export { RistrettoPoint } from "@noble/curves/ed25519.js"; diff --git a/infrastructure/blindvote/test-crypto-expert.ts b/infrastructure/blindvote/test-crypto-expert.ts new file mode 100644 index 00000000..0603cca7 --- /dev/null +++ b/infrastructure/blindvote/test-crypto-expert.ts @@ -0,0 +1,161 @@ +/** + * Test the crypto expert's multi-option tally method + * Simple isolated test to verify the math works + */ + +import { PedersenCommitment, enc, dec } from './src/crypto/pedersen'; +import type { GroupElement } from './src/core/types'; + +// ===== Generators (use the same everywhere) ===== +const pedersen = new PedersenCommitment(); +const g = pedersen.getGenerator(); +const h = pedersen.getH(); + +// ===== Helpers ===== +// Use the identity element instead of g.multiply(0n) +const zero = () => { + // For Ristretto255, we need to find the identity element + // Let's use a different approach - start with the first ballot + throw new Error('Need to implement proper identity element'); +}; +const eq = (A: GroupElement, B: GroupElement) => { + const aBytes = enc(A); + const bBytes = enc(B); + return aBytes.length === bBytes.length && + aBytes.every((byte, i) => byte === bBytes[i]); +}; + +// ===== Baby-Step/Giant-Step in small range [0..nMax] ===== +function bsgsSmallRange(X: GroupElement, nMax: number): number { + if (nMax < 0) throw new Error('nMax must be non-negative'); + const m = Math.ceil(Math.sqrt(nMax + 1)); + + // baby steps table: j*g -> j + const table = new Map(); + // For Ristretto255, we need to find the identity element + // Let's use a different approach - start with g and build the table + let P = g; // Start with g^1 + + for (let j = 0; j < m; j++) { + table.set(Array.from(enc(P)).map(b => b.toString(16).padStart(2, '0')).join(''), j + 1); + P = P.add(g); // P = (j+2)*g + } + + // giant step factor: -(m*g) + const minusGm = g.multiply(BigInt(m)).negate(); + + let Y = X; + for (let i = 0; i <= m; i++) { + const key = Array.from(enc(Y)).map(b => b.toString(16).padStart(2, '0')).join(''); + const j = table.get(key); + if (j !== undefined) { + const M = i * m + j; + if (M <= nMax && M > 0) return M; // M must be > 0 since we start from 1 + } + Y = Y.add(minusGm); // Y = Y - m*g + } + throw new Error('DL not found: X is not g·M in [0..nMax]'); +} + +// ===== Tally a single option ===== +function tallyOption( + ballots: { voterId: string; C: Uint8Array }[], + anchors: { voterId: string; H: Uint8Array }[], + nMax: number +): { M: number; C_agg: Uint8Array; H_S: Uint8Array; X: Uint8Array } { + // Build sets & sums only over voters who actually cast ballots + const present = new Set(ballots.map(b => b.voterId)); + + // Start with first ballot, then add the rest + let C_aggP = dec(ballots[0].C); + for (let i = 1; i < ballots.length; i++) { + C_aggP = C_aggP.add(dec(ballots[i].C)); + } + + // Start with first anchor, then add the rest + let H_S_P = dec(anchors[0].H); + for (let i = 1; i < anchors.length; i++) { + H_S_P = H_S_P.add(dec(anchors[i].H)); + } + + const Xp = C_aggP.add(H_S_P.negate()); // X = C_agg - H_S + + // Recover M in [0..nMax] with BSGS + const M = bsgsSmallRange(Xp, nMax); + + // Final check: C_agg == g·M + H_S + const expectedC_agg = g.multiply(BigInt(M)).add(H_S_P); + const ok = eq(C_aggP, expectedC_agg); + if (!ok) throw new Error('final check failed for option'); + + return { M, C_agg: enc(C_aggP), H_S: enc(H_S_P), X: enc(Xp) }; +} + +// ===== Test the method ===== +async function testCryptoExpertMethod() { + console.log("🚀 Testing crypto expert's multi-option tally method..."); + + try { + // Create a simple test case: 2 voters, 2 options + const pedersen = new PedersenCommitment(); + + // Voter 1: votes for option 1 (value = 1) + const r1 = pedersen.generateRandomValue(); + const H1 = pedersen.createAnchor(r1); + const C1 = pedersen.commit(1n, r1); + + // Voter 2: votes for option 0 (value = 0) + const r2 = pedersen.generateRandomValue(); + const H2 = pedersen.createAnchor(r2); + const C2 = pedersen.commit(0n, r2); + + console.log("✅ Created test commitments:"); + console.log("- Voter 1: H1 =", Array.from(enc(H1)).map(b => b.toString(16).padStart(2, '0')).join('').substring(0, 32) + '...'); + console.log("- Voter 1: C1 =", Array.from(enc(C1)).map(b => b.toString(16).padStart(2, '0')).join('').substring(0, 32) + '...'); + console.log("- Voter 2: H2 =", Array.from(enc(H2)).map(b => b.toString(16).padStart(2, '0')).join('').substring(0, 32) + '...'); + console.log("- Voter 2: C2 =", Array.from(enc(C2)).map(b => b.toString(16).padStart(2, '0')).join('').substring(0, 32) + '...'); + + // Test tallying option 1 (should get 1 vote) + console.log("\n🔍 Testing tally for option 1..."); + const option1Result = tallyOption( + [ + { voterId: "voter1", C: enc(C1) }, + { voterId: "voter2", C: enc(C2) } + ], + [ + { voterId: "voter1", H: enc(H1) }, + { voterId: "voter2", H: enc(H2) } + ], + 2 // max votes + ); + + console.log("✅ Option 1 result:", option1Result.M, "votes"); + console.log("Expected: 1 vote (voter1 voted 1, voter2 voted 0)"); + + // Test tallying option 0 (should get 1 vote) + console.log("\n🔍 Testing tally for option 0..."); + const option0Result = tallyOption( + [ + { voterId: "voter1", C: enc(C1) }, + { voterId: "voter2", C: enc(C2) } + ], + [ + { voterId: "voter1", H: enc(H1) }, + { voterId: "voter2", H: enc(H2) } + ], + 2 // max votes + ); + + console.log("✅ Option 0 result:", option0Result.M, "votes"); + console.log("Expected: 1 vote (voter1 voted 1, voter2 voted 0)"); + + console.log("\n🎉 Crypto expert's method test completed successfully!"); + + } catch (error) { + console.error("❌ Test failed:", error); + throw error; + } +} + +// Run the test +testCryptoExpertMethod().catch(console.error); \ No newline at end of file diff --git a/infrastructure/blindvote/test-tally.ts b/infrastructure/blindvote/test-tally.ts new file mode 100644 index 00000000..dde2f80d --- /dev/null +++ b/infrastructure/blindvote/test-tally.ts @@ -0,0 +1,112 @@ +/** + * End-to-End Tally Test using VotingSystem abstraction + * Test file for Pedersen commitment voting system with predetermined vote distribution + */ + +import { VotingSystem } from './src/core/voting-system'; + +// End-to-End Tally Test using VotingSystem +async function endToEndTallyTest() { + console.log('🚀 End-to-End Tally Test using VotingSystem'); + console.log('============================================'); + + // Initialize the voting system + const votingSystem = new VotingSystem(); + + // Setup + const n = 200; + const onesCount = 83; + const zerosCount = 117; + + console.log(`Setup: n = ${n} voters`); + console.log(`Predetermined votes: ${onesCount} ones, ${zerosCount} zeros`); + + // Create election + votingSystem.createElection({ + id: 'test-election-2024', + title: 'Test Election 2024', + description: 'End-to-end test of the voting system', + contestId: 'president', + optionId: 'yes-no' + }); + + console.log('\n📋 Election created'); + + // Register voters and submit votes + console.log('\n👥 Registering voters and submitting votes...'); + + for (let i = 0; i < n; i++) { + const voterId = `voter-${i.toString().padStart(3, '0')}`; + const voteValue = i < onesCount ? 1n : 0n; + + // Register voter with generated anchor + const { anchor, randomness } = votingSystem.registerVoterWithGeneratedAnchor( + voterId, + 'test-election-2024', + 'president', + 'yes-no' + ); + + // Submit vote with generated commitment + const commitment = votingSystem.submitVoteWithGeneratedCommitment( + voterId, + 'test-election-2024', + 'president', + 'yes-no', + voteValue, + randomness + ); + + if (i % 50 === 0) { + console.log(` Processed ${i} voters...`); + } + } + + console.log(`✅ All ${n} voters registered and votes submitted`); + + // Check election status + const stats = votingSystem.getElectionStats('test-election-2024', 'president', 'yes-no'); + console.log('\n📊 Election Status:', stats); + + // Tally the election + console.log('\n🔍 Tallying election...'); + const result = votingSystem.tallyElection('test-election-2024', 'president', 'yes-no'); + + // Print results + console.log('\n📈 Election Results:'); + console.log(`Total Voters: ${result.totalVoters}`); + console.log(`Total Votes: ${result.totalVotes}`); + console.log(`Verified: ${result.verified}`); + + // Verify the mathematical relationship + console.log('\n🔬 Mathematical Verification:'); + console.log(`Expected total votes: ${onesCount}`); + console.log(`X == g^${onesCount}: ${result.verified ? '✅ true' : '❌ false'}`); + console.log(`C_agg == g^${onesCount} + H_S: ${result.verified ? '✅ true' : '❌ false'}`); + + // Print encodings + console.log('\n🔐 Encodings:'); + console.log(`C_agg: ${Array.from(result.C_agg).map(b => b.toString(16).padStart(2, '0')).join('')}`); + console.log(`H_S: ${Array.from(result.H_S).map(b => b.toString(16).padStart(2, '0')).join('')}`); + console.log(`X: ${Array.from(result.X).map(b => b.toString(16).padStart(2, '0')).join('')}`); + + const finalCheck = result.verified && result.totalVotes === onesCount; + console.log(`\n🎯 final_check: ${finalCheck}`); + + // Clean up + votingSystem.clear(); + + return { + finalCheck, + result, + stats + }; +} + +// Run the test +if (typeof window === 'undefined') { + // Node.js environment + endToEndTallyTest().catch(console.error); +} + +export { endToEndTallyTest }; \ No newline at end of file diff --git a/infrastructure/blindvote/tsconfig.json b/infrastructure/blindvote/tsconfig.json new file mode 100644 index 00000000..29aa8ac5 --- /dev/null +++ b/infrastructure/blindvote/tsconfig.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020", "DOM"], + "outDir": "./dist", + "rootDir": "./src", + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true, + "declaration": true, + "declarationMap": true, + "sourceMap": true, + "resolveJsonModule": true, + "moduleResolution": "node", + "allowSyntheticDefaultImports": true + }, + "include": [ + "src/**/*" + ], + "exclude": [ + "node_modules", + "dist" + ] +} \ No newline at end of file diff --git a/infrastructure/control-panel/.env.example b/infrastructure/control-panel/.env.example new file mode 100644 index 00000000..2e5a24e1 --- /dev/null +++ b/infrastructure/control-panel/.env.example @@ -0,0 +1,7 @@ +# Loki Configuration +LOKI_URL=http://localhost:3100 +LOKI_USERNAME=admin +LOKI_PASSWORD=admin + +# Registry Configuration +PUBLIC_REGISTRY_URL=https://registry.staging.metastate.foundation diff --git a/infrastructure/control-panel/src/lib/fragments/Nodes/VaultNode.svelte b/infrastructure/control-panel/src/lib/fragments/Nodes/VaultNode.svelte index 2257fc53..4d6a035a 100644 --- a/infrastructure/control-panel/src/lib/fragments/Nodes/VaultNode.svelte +++ b/infrastructure/control-panel/src/lib/fragments/Nodes/VaultNode.svelte @@ -1,33 +1,62 @@ -
+
-
- -
-
{data.label}
-
{data.subLabel}
-
+
+ {#if data.type === 'platform'} + +
+
+ +
+
Web3 Adapter
+
+
+
+ +
+
{data.label}
+
{data.subLabel}
+
+
+
+ {:else} + + +
+
{data.label}
+
{data.subLabel}
+
+ {/if}
{#if data.type === 'platform'} - - - + + + + {:else} - - - + + + {/if}
@@ -48,6 +77,15 @@ transition: all 0.3s ease; } + /* Make platform cards wider for split layout */ + .vault-node-wrapper.platform-node { + min-width: 280px; + background-color: transparent; + box-shadow: none; + border: none; + padding: 0; + } + .vault-node-wrapper.highlight { box-shadow: 0 0 20px rgba(76, 175, 80, 0.6); border: 2px solid #4caf50; @@ -61,6 +99,52 @@ gap: 8px; } + .vault-node-content.platform-split { + flex-direction: row; + align-items: center; + justify-content: space-between; + gap: 0; + width: 100%; + } + + .platform-cards-container { + display: flex; + flex-direction: row; + align-items: stretch; + width: 100%; + position: relative; + background: transparent; + border: 2px dotted #e5e5e5; + border-radius: 12px; + padding: 4px; + } + + .platform-card { + flex: 1; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + padding: 12px 16px; + background: white; + border-radius: 8px; + margin: 2px; + box-shadow: 0 2px 6px rgba(0, 0, 0, 0.08); + border: 1px solid rgba(0, 0, 0, 0.05); + } + + .web3-adapter-card { + border-right: 1px solid #e5e5e5; + border-top-right-radius: 0; + border-bottom-right-radius: 0; + } + + .platform-info-card { + border-left: 1px solid #e5e5e5; + border-top-left-radius: 0; + border-bottom-left-radius: 0; + } + .vault-labels { text-align: center; } @@ -71,6 +155,12 @@ margin-bottom: 2px; } + /* Web3 Adapter text should match platform name size */ + .web3-adapter-card .vault-label { + font-size: 0.9em; + font-weight: 600; + } + .vault-sub-label { font-size: 0.85em; color: #666; @@ -87,36 +177,41 @@ } :global(.evault-handle) { - top: auto; - bottom: -5px; - left: 50%; - transform: translateX(-50%); - } - - :global(.evault-handle[data-position='top']) { - top: -5px; + top: 50%; bottom: auto; + right: -5px; + left: auto; + transform: translateY(-50%); } :global(.platform-handle) { - top: -5px; + top: 50%; bottom: auto; - left: 50%; - transform: translateX(-50%); + left: -5px; + right: auto; + transform: translateY(-50%); + } + + /* Platform node handles should be on the border of the transparent container */ + .platform-node :global(.platform-handle) { + left: -5px; + right: auto; } /* Fix handle positioning for Svelte Flow */ - :global(.vault-handle[data-handlepos='top']) { - top: -5px !important; + :global(.vault-handle[data-handlepos='right']) { + top: 50% !important; bottom: auto !important; - left: 50% !important; - transform: translateX(-50%) !important; + right: -5px !important; + left: auto !important; + transform: translateY(-50%) !important; } - :global(.vault-handle[data-handlepos='bottom']) { - bottom: -5px !important; - top: auto !important; - left: 50% !important; - transform: translateX(-50%) !important; + :global(.vault-handle[data-handlepos='left']) { + top: 50% !important; + bottom: auto !important; + left: -5px !important; + right: auto !important; + transform: translateY(-50%) !important; } diff --git a/infrastructure/control-panel/src/lib/services/loki.ts b/infrastructure/control-panel/src/lib/services/loki.ts new file mode 100644 index 00000000..ffa1ed96 --- /dev/null +++ b/infrastructure/control-panel/src/lib/services/loki.ts @@ -0,0 +1,168 @@ +import { env } from '$env/dynamic/private'; + +export interface LogEntry { + timestamp: string; + line: string; + labels: Record; +} + +export interface LokiQueryResponse { + status: string; + data: { + resultType: string; + result: Array<{ + stream: Record; + values: Array<[string, string]>; + }>; + }; +} + +export interface FlowEvent { + type: 'evault_sync' | 'platform_sync' | 'metaenvelope_created' | 'awareness_notification'; + timestamp: string; + w3id: string; + platform: string; + id: string; + tableName: string; + message: string; +} + +export class LokiService { + private baseUrl: string; + private username: string; + private password: string; + private processedLogIds = new Set(); // Track processed logs to prevent duplicates + + constructor() { + this.baseUrl = env.LOKI_URL || 'http://localhost:3100'; + this.username = env.LOKI_USERNAME || 'admin'; + this.password = env.LOKI_PASSWORD || 'admin'; + } + + private getAuthHeaders() { + return { + 'Authorization': `Basic ${Buffer.from(`${this.username}:${this.password}`).toString('base64')}`, + 'Content-Type': 'application/json' + }; + } + + async queryLogs(query: string, start?: string, end?: string): Promise { + try { + const params = new URLSearchParams({ + query, + limit: '1000' + }); + + if (start) params.append('start', start); + if (end) params.append('end', end); + + const response = await fetch( + `${this.baseUrl}/loki/api/v1/query_range?${params.toString()}`, + { + headers: this.getAuthHeaders() + } + ); + + if (!response.ok) { + throw new Error(`HTTP error! status: ${response.status}`); + } + + const data: LokiQueryResponse = await response.json(); + const entries: LogEntry[] = []; + + for (const result of data.data.result) { + for (const [timestamp, line] of result.values) { + entries.push({ + timestamp: new Date(parseInt(timestamp) / 1000000).toISOString(), + line, + labels: result.stream + }); + } + } + + return entries.sort((a, b) => new Date(a.timestamp).getTime() - new Date(b.timestamp).getTime()); + } catch (error) { + console.error('Error querying Loki:', error); + return []; + } + } + + async getWeb3AdapterLogs(start?: string, end?: string): Promise { + const query = '{app="web3-adapter"}'; + const logs = await this.queryLogs(query, start, end); + + return logs + .map(log => this.parseLogEntry(log)) + .filter((event): event is FlowEvent => event !== null); + } + + parseLogEntry(log: LogEntry): FlowEvent | null { + try { + // Parse the JSON log line + const logData = JSON.parse(log.line); + + // Check if this is a logger.info call with the structure we expect + if (logData.tableName && logData.w3id && logData.platform && logData.id) { + return { + type: 'evault_sync', + timestamp: log.timestamp, + w3id: logData.w3id, + platform: logData.platform, + id: logData.id, + tableName: logData.tableName, + message: `Synced ${logData.tableName} with ID ${logData.id} to eVault ${logData.w3id} from platform ${logData.platform}` + }; + } + } catch (error) { + // Skip logs that can't be parsed + } + + return null; + } + + async streamLogs(query: string, onLog: (log: LogEntry) => void): Promise<() => void> { + let isStreaming = true; + + const streamLogs = async () => { + while (isStreaming) { + try { + const end = new Date().toISOString(); + const start = new Date(Date.now() - 30000).toISOString(); // Last 30 seconds + + const logs = await this.queryLogs(query, start, end); + + for (const log of logs) { + if (isStreaming) { + // Create a unique ID for this log to prevent duplicates + const logId = `${log.timestamp}-${log.line}`; + if (!this.processedLogIds.has(logId)) { + this.processedLogIds.add(logId); + onLog(log); + + // Clean up old IDs to prevent memory leaks (keep last 1000) + if (this.processedLogIds.size > 1000) { + const idsArray = Array.from(this.processedLogIds); + this.processedLogIds = new Set(idsArray.slice(-500)); + } + } + } + } + + // Wait 2 seconds before next query + await new Promise(resolve => setTimeout(resolve, 2000)); + } catch (error) { + console.error('Error in log stream:', error); + await new Promise(resolve => setTimeout(resolve, 5000)); + } + } + }; + + streamLogs(); + + return () => { + isStreaming = false; + }; + } +} + +export const lokiService = new LokiService(); \ No newline at end of file diff --git a/infrastructure/control-panel/src/lib/services/registry.ts b/infrastructure/control-panel/src/lib/services/registry.ts new file mode 100644 index 00000000..3778feaa --- /dev/null +++ b/infrastructure/control-panel/src/lib/services/registry.ts @@ -0,0 +1,94 @@ +import { env } from '$env/dynamic/public'; + +export interface Platform { + name: string; + url: string; + status: 'Active' | 'Inactive'; + uptime: string; +} + +export class RegistryService { + private baseUrl: string; + + constructor() { + this.baseUrl = env.PUBLIC_REGISTRY_URL || 'https://registry.staging.metastate.foundation'; + } + + async getPlatforms(): Promise { + try { + const response = await fetch(`${this.baseUrl}/platforms`); + + if (!response.ok) { + throw new Error(`HTTP error! status: ${response.status}`); + } + + const platformUrls: string[] = await response.json(); + + // Convert URLs to platform objects with friendly names + const platforms = platformUrls.map(url => { + // Ensure URL has protocol + const urlWithProtocol = url.startsWith('http://') || url.startsWith('https://') ? url : `http://${url}`; + const urlObj = new URL(urlWithProtocol); + const hostname = urlObj.hostname; + const port = urlObj.port; + const protocol = urlObj.protocol; + + // Extract platform name from hostname + let name = hostname.split('.')[0]; + + // Capitalize and format the name + if (name === 'pictique') name = 'Pictique'; + else if (name === 'blabsy') name = 'Blabsy'; + else if (name === 'charter') name = 'Group Charter'; + else if (name === 'cerberus') name = 'Cerberus'; + else if (name === 'evoting') name = 'eVoting'; + else name = name.charAt(0).toUpperCase() + name.slice(1); + + // Build the full URL with protocol and port + const fullUrl = port ? `${hostname}:${port}` : hostname; + const displayUrl = `${protocol}//${fullUrl}`; + + return { + name, + url: displayUrl, + status: 'Active' as const, + uptime: '24h' + }; + }); + + return platforms; + } catch (error) { + console.error('Error fetching platforms from registry:', error); + + // Return fallback platforms if registry is unavailable + return [ + { + name: 'Blabsy', + url: 'http://192.168.0.225:4444', + status: 'Active', + uptime: '24h' + }, + { + name: 'Pictique', + url: 'http://192.168.0.225:1111', + status: 'Active', + uptime: '24h' + }, + { + name: 'Group Charter', + url: 'http://192.168.0.225:5555', + status: 'Active', + uptime: '24h' + }, + { + name: 'Cerberus', + url: 'http://192.168.0.225:6666', + status: 'Active', + uptime: '24h' + } + ]; + } + } +} + +export const registryService = new RegistryService(); \ No newline at end of file diff --git a/infrastructure/control-panel/src/routes/+page.svelte b/infrastructure/control-panel/src/routes/+page.svelte index d3126d8a..059a7932 100644 --- a/infrastructure/control-panel/src/routes/+page.svelte +++ b/infrastructure/control-panel/src/routes/+page.svelte @@ -2,7 +2,9 @@ import { TableCard, TableCardHeader } from '$lib/fragments'; import { Table } from '$lib/ui'; import { EVaultService } from '$lib/services/evaultService'; + import { registryService } from '$lib/services/registry'; import type { EVault } from './api/evaults/+server'; + import type { Platform } from '$lib/services/registry'; import { onMount } from 'svelte'; import { RefreshCw } from 'lucide-svelte'; import { goto } from '$app/navigation'; @@ -10,62 +12,39 @@ let evaultsSearchValue = $state(''); let platformsSearchQuery = $state(''); let evaults = $state([]); + let platforms = $state([]); let isLoading = $state(true); + let platformsLoading = $state(true); let error = $state(null); + let platformsError = $state(null); let mappedData = $state([]); // Track selected items let selectedEVaults = $state([]); let selectedPlatforms = $state([]); - // Platform data - const platforms = [ - { - name: 'Blabsy', - url: 'blabsy.staging.metastate.foundation', - status: 'Active', - uptime: '24h' - }, - { - name: 'Pictique', - url: 'pictique.staging.metastate.foundation', - status: 'Active', - uptime: '24h' - }, - { - name: 'Group Charter', - url: 'charter.staging.metastate.foundation', - status: 'Active', - uptime: '24h' - }, - { - name: 'Cerberus', - url: 'cerberus.staging.metastate.foundation', - status: 'Active', - uptime: '24h' - } - ]; - - const mappedPlatformsData = platforms.map((platform) => ({ - Name: { - type: 'text', - value: platform.name - }, - Status: { - type: 'text', - value: platform.status - }, - Uptime: { - type: 'text', - value: platform.uptime - }, - URL: { - type: 'link', - value: platform.url, - link: `https://${platform.url}`, - external: true - } - })); + const mappedPlatformsData = $derived( + platforms.map((platform) => ({ + Name: { + type: 'text', + value: platform.name + }, + Status: { + type: 'text', + value: platform.status + }, + Uptime: { + type: 'text', + value: platform.uptime + }, + URL: { + type: 'link', + value: platform.url, + link: platform.url, + external: true + } + })) + ); const handlePreviousPage = async () => { alert('Previous btn clicked. Make a call to your server to fetch data.'); @@ -163,6 +142,20 @@ } }; + const fetchPlatforms = async () => { + try { + platformsLoading = true; + platformsError = null; + const data = await registryService.getPlatforms(); + platforms = data; + } catch (err) { + platformsError = 'Failed to fetch platforms'; + console.error('Error fetching platforms:', err); + } finally { + platformsLoading = false; + } + }; + let currentSelectedEVaultIndex = $state(-1); function handleEVaultRowClick(index: number) { @@ -174,6 +167,7 @@ onMount(() => { fetchEVaults(); + fetchPlatforms(); }); @@ -224,14 +218,34 @@ bind:searchValue={platformsSearchQuery} rightTitle="No platform selected. Select a platform to monitor logs" /> - + {#if platformsLoading} +
+
+
+ {:else if platformsError} +
+ {platformsError} + +
+ {:else if platforms.length === 0} +
+ No platforms found. Make sure the registry service is running. +
+ {:else} +
+ {/if} diff --git a/infrastructure/control-panel/src/routes/api/events/+server.ts b/infrastructure/control-panel/src/routes/api/events/+server.ts index 4e54395b..bba2c954 100644 --- a/infrastructure/control-panel/src/routes/api/events/+server.ts +++ b/infrastructure/control-panel/src/routes/api/events/+server.ts @@ -1,11 +1,12 @@ import { json } from '@sveltejs/kit'; import type { RequestHandler } from './$types'; +import { lokiService } from '$lib/services/loki'; export const GET: RequestHandler = async () => { const stream = new ReadableStream({ start(controller) { let isConnected = true; - const timeouts: NodeJS.Timeout[] = []; + let stopStreaming: (() => void) | null = null; // Send initial connection message if (isConnected) { @@ -20,58 +21,107 @@ export const GET: RequestHandler = async () => { } catch (error) { console.log('Client disconnected, stopping stream'); isConnected = false; + if (stopStreaming) stopStreaming(); } } }; - // Simulate the data flow sequence - const timeout1 = setTimeout(() => { + // Start streaming real logs from Loki + const startRealTimeLogs = async () => { + try { + stopStreaming = await lokiService.streamLogs( + '{app="web3-adapter"}', + (log) => { + // Parse the log entry to extract flow information + const flowEvent = lokiService.parseLogEntry(log); + + if (flowEvent) { + // Map the flow event to the expected format + const eventData = { + type: 'evault_sync_event', + timestamp: flowEvent.timestamp, + w3id: flowEvent.w3id, + platform: flowEvent.platform, + id: flowEvent.id, + tableName: flowEvent.tableName, + message: flowEvent.message, + // Extract platform and eVault indices for visualization + platformIndex: 0, // We'll need to map this based on actual platform names + evaultIndex: 0 // We'll need to map this based on actual eVault w3ids + }; + + safeEnqueue(eventData); + } + } + ); + } catch (error) { + console.error('Error starting Loki stream:', error); + // Fallback to mock data if Loki is not available + startMockData(); + } + }; + + // Fallback mock data function + const startMockData = () => { + console.log('Using mock data as fallback'); + // Step 1: Platform 1 creates a message - safeEnqueue({ - type: 'platform_message_created', - platformIndex: 1, - platformName: 'Pictique', - message: 'Creating new message in blob storage', - timestamp: new Date().toISOString() - }); - }, 3000); - timeouts.push(timeout1); + const timeout1 = setTimeout(() => { + safeEnqueue({ + type: 'platform_message_created', + platformIndex: 1, + platformName: 'Pictique', + message: 'Creating new message in blob storage', + timestamp: new Date().toISOString() + }); + }, 3000); - const timeout2 = setTimeout(() => { // Step 2: Request sent to eVault 0 - safeEnqueue({ - type: 'request_sent_to_evault', - platformIndex: 1, - evaultIndex: 0, - message: 'Request sent to eVault', - timestamp: new Date().toISOString() - }); - }, 8000); - timeouts.push(timeout2); + const timeout2 = setTimeout(() => { + safeEnqueue({ + type: 'request_sent_to_evault', + platformIndex: 1, + evaultIndex: 0, + message: 'Request sent to eVault', + timestamp: new Date().toISOString() + }); + }, 8000); - const timeout3 = setTimeout(() => { // Step 3: eVault 0 creates metaenvelope - const uuid = crypto.randomUUID(); - safeEnqueue({ - type: 'evault_metaenvelope_created', - evaultIndex: 0, - uuid: uuid, - message: `Created metaenvelope with ID: ${uuid}`, - timestamp: new Date().toISOString() - }); - }, 13000); - timeouts.push(timeout3); + const timeout3 = setTimeout(() => { + const uuid = crypto.randomUUID(); + safeEnqueue({ + type: 'evault_metaenvelope_created', + evaultIndex: 0, + uuid: uuid, + message: `Created metaenvelope with ID: ${uuid}`, + timestamp: new Date().toISOString() + }); + }, 13000); - const timeout4 = setTimeout(() => { // Step 4: Notify all platforms through awareness protocol - safeEnqueue({ - type: 'notify_platforms_awareness', - evaultIndex: 0, - message: 'Notifying platforms through awareness protocol', - timestamp: new Date().toISOString() - }); - }, 18000); - timeouts.push(timeout4); + const timeout4 = setTimeout(() => { + safeEnqueue({ + type: 'notify_platforms_awareness', + evaultIndex: 0, + message: 'Notifying platforms through awareness protocol', + timestamp: new Date().toISOString() + }); + }, 18000); + + // Cleanup function for mock timeouts + return () => { + clearTimeout(timeout1); + clearTimeout(timeout2); + clearTimeout(timeout3); + clearTimeout(timeout4); + }; + }; + + // Try to start real-time logs, fallback to mock if needed + startRealTimeLogs().catch(() => { + startMockData(); + }); // Keep connection alive with periodic heartbeats const heartbeat = setInterval(() => { @@ -82,6 +132,7 @@ export const GET: RequestHandler = async () => { console.log('Client disconnected during heartbeat, stopping stream'); isConnected = false; clearInterval(heartbeat); + if (stopStreaming) stopStreaming(); } } }, 30000); @@ -89,7 +140,7 @@ export const GET: RequestHandler = async () => { // Cleanup function const cleanup = () => { isConnected = false; - timeouts.forEach(timeout => clearTimeout(timeout)); + if (stopStreaming) stopStreaming(); clearInterval(heartbeat); }; diff --git a/infrastructure/control-panel/src/routes/monitoring/+page.svelte b/infrastructure/control-panel/src/routes/monitoring/+page.svelte index 1589659f..ba3b4c60 100644 --- a/infrastructure/control-panel/src/routes/monitoring/+page.svelte +++ b/infrastructure/control-panel/src/routes/monitoring/+page.svelte @@ -46,11 +46,11 @@ const newNodes: Node[] = []; let nodeId = 1; - // Add eVaults in one row at the top (y: 100) + // Add eVaults in a column on the left (x: 200, y: starting from 150) selectedEVaults.forEach((evault, index) => { newNodes.push({ id: `evault-${index + 1}`, - position: { x: 100 + index * 400, y: 100 }, + position: { x: 200, y: 150 + index * 180 }, data: { label: evault.evaultId || evault.name || 'eVault', subLabel: evault.serviceUrl || evault.ip || 'Unknown', @@ -61,11 +61,11 @@ }); }); - // Add platforms in one row at the bottom (y: 400) + // Add platforms in a column on the right (x: 800, y: starting from 150) selectedPlatforms.forEach((platform, index) => { newNodes.push({ id: `platform-${index + 1}`, - position: { x: 100 + index * 400, y: 400 }, + position: { x: 800, y: 150 + index * 180 }, data: { label: platform.name, subLabel: platform.url, @@ -125,6 +125,9 @@ function handleFlowEvent(data: any) { switch (data.type) { + case 'evault_sync_event': + handleEvaultSyncEvent(data); + break; case 'platform_message_created': handlePlatformMessageCreated(data); break; @@ -140,6 +143,105 @@ } } + function handleEvaultSyncEvent(data: any) { + // Map the real data to visualization indices + const platformIndex = getPlatformIndex(data.platform); + const evaultIndex = getEvaultIndex(data.w3id); + + // Step 1: Platform creates entry locally + currentFlowStep = 1; + flowMessages = [ + ...flowMessages, + `[${new Date(data.timestamp).toLocaleTimeString()}] ${data.platform}: Created ${data.tableName} entry locally` + ]; + + // Highlight the platform + highlightNode(`platform-${platformIndex + 1}`); + + // Step 2: After 1 second, show syncing to eVault + setTimeout(() => { + currentFlowStep = 2; + flowMessages = [ + ...flowMessages, + `[${new Date().toLocaleTimeString()}] ${data.message}` + ]; + + // Clear old edges first + edges = []; + + // Create arrow from platform to eVault + const platformId = `platform-${platformIndex + 1}`; + const evaultId = `evault-${evaultIndex + 1}`; + + console.log('Creating edge from:', platformId, 'to:', evaultId); + + const newEdge: Edge = { + id: `flow-${Date.now()}`, + source: platformId, + target: evaultId, + type: 'bezier', + animated: true, + style: 'stroke: #007BFF; stroke-width: 3; marker-end: url(#arrowhead-blue);', + label: `Syncing ${data.tableName}` + }; + + edges = [newEdge]; + + // Highlight the platform and eVault + highlightNode(platformId); + setTimeout(() => highlightNode(evaultId), 1000); + + // Remove this edge after 3 seconds and then show awareness protocol + setTimeout(() => { + edges = edges.filter((edge) => edge.id !== newEdge.id); + + // After sync completes, show the awareness protocol + setTimeout(() => { + handleAwarenessProtocol(evaultIndex, data); + }, 500); + }, 3000); + }, 1000); + } + + function handleAwarenessProtocol(evaultIndex: number, data: any) { + currentFlowStep = 4; + flowMessages = [ + ...flowMessages, + `[${new Date().toLocaleTimeString()}] eVault ${evaultIndex + 1}: Notifying platforms through awareness protocol` + ]; + + // Clear old edges first + edges = []; + + // Create edges from eVault to all platforms + const evaultId = `evault-${evaultIndex + 1}`; + const newEdges: Edge[] = selectedPlatforms.map((platform, index) => ({ + id: `awareness-${Date.now()}-${index}`, + source: evaultId, + target: `platform-${index + 1}`, + type: 'bezier', + animated: true, + style: 'stroke: #28a745; stroke-width: 3; marker-end: url(#arrowhead-green);', + label: 'Awareness Protocol' + })); + + edges = newEdges; + + // Remove all awareness edges after 5 seconds and show completion + setTimeout(() => { + edges = edges.filter((edge) => !edge.id.startsWith('awareness-')); + + // Step 5: Show completion message + setTimeout(() => { + currentFlowStep = 5; + flowMessages = [ + ...flowMessages, + `[${new Date().toLocaleTimeString()}] All platforms notified successfully` + ]; + }, 500); + }, 5000); + } + function handlePlatformMessageCreated(data: any) { currentFlowStep = 1; flowMessages = [ @@ -298,6 +400,37 @@ eventSource = null; } } + + // Helper functions to map real data to visualization indices + function getPlatformIndex(platformName: string): number { + // Try exact match first + let index = selectedPlatforms.findIndex((p) => p.name === platformName); + + // If no exact match, try partial matching + if (index === -1) { + index = selectedPlatforms.findIndex( + (p) => + p.name.toLowerCase().includes(platformName.toLowerCase()) || + platformName.toLowerCase().includes(p.name.toLowerCase()) + ); + } + + // If still no match, try matching by URL + if (index === -1) { + index = selectedPlatforms.findIndex( + (p) => + p.url.toLowerCase().includes(platformName.toLowerCase()) || + platformName.toLowerCase().includes(p.url.toLowerCase()) + ); + } + + return index >= 0 ? index : 0; + } + + function getEvaultIndex(w3id: string): number { + const index = selectedEVaults.findIndex((e) => e.evaultId === w3id || e.w3id === w3id); + return index >= 0 ? index : 0; + }
@@ -317,14 +450,16 @@
{currentFlowStep === 1 - ? 'Platform creating message' + ? 'Platform creating entry locally' : currentFlowStep === 2 - ? 'Request sent to eVault' + ? 'Syncing to eVault' : currentFlowStep === 3 ? 'eVault created metaenvelope' : currentFlowStep === 4 - ? 'Notifying platforms' - : 'Complete'} + ? 'Awareness Protocol' + : currentFlowStep === 5 + ? 'All platforms notified' + : 'Complete'} {/if} @@ -408,7 +543,7 @@
= 4 ? startSequence : undefined} class:cursor-pointer={!sequenceStarted || currentFlowStep >= 4} class:cursor-default={sequenceStarted && currentFlowStep < 4} @@ -420,19 +555,21 @@ Current Step: {currentFlowStep === 0 ? 'Waiting...' : currentFlowStep === 1 - ? 'Platform creating message' + ? 'Platform creating entry locally' : currentFlowStep === 2 - ? 'Request sent to eVault' + ? 'Syncing to eVault' : currentFlowStep === 3 ? 'eVault created metaenvelope' : currentFlowStep === 4 - ? 'Notifying platforms' - : 'Complete'} + ? 'Awareness Protocol' + : currentFlowStep === 5 + ? 'All platforms notified' + : 'Complete'}
{/if} -
+
{#each flowMessages as message, i}
{message} diff --git a/infrastructure/eid-wallet/package.json b/infrastructure/eid-wallet/package.json index f68df63f..5f32b9b0 100644 --- a/infrastructure/eid-wallet/package.json +++ b/infrastructure/eid-wallet/package.json @@ -22,6 +22,7 @@ "@auvo/tauri-plugin-crypto-hw-api": "^0.1.0", "@hugeicons/core-free-icons": "^1.0.13", "@hugeicons/svelte": "^1.0.2", + "@iconify/svelte": "^5.0.1", "@ngneat/falso": "^7.3.0", "@tailwindcss/container-queries": "^0.1.1", "@tauri-apps/api": "^2", @@ -33,10 +34,12 @@ "@veriff/incontext-sdk": "^2.4.0", "@veriff/js-sdk": "^1.5.1", "axios": "^1.6.7", + "blindvote": "workspace:*", "clsx": "^2.1.1", "dotenv": "^16.5.0", "flag-icons": "^7.3.2", "graphql-request": "^6.1.0", + "html5-qrcode": "^2.3.8", "import": "^0.0.6", "svelte-loading-spinners": "^0.3.6", "svelte-qrcode": "^1.0.1", @@ -75,6 +78,7 @@ "tailwindcss": "^4.0.14", "typescript": "~5.6.2", "vite": "^6.0.3", + "vite-plugin-node-polyfills": "^0.24.0", "vitest": "^3.0.9" } } diff --git a/infrastructure/eid-wallet/src-tauri/gen/android/app/arm64/release/eid-w3ds-v0.2.0.1.apk b/infrastructure/eid-wallet/src-tauri/gen/android/app/arm64/release/eid-w3ds-v0.2.0.1.apk new file mode 100644 index 00000000..8eb37f3b Binary files /dev/null and b/infrastructure/eid-wallet/src-tauri/gen/android/app/arm64/release/eid-w3ds-v0.2.0.1.apk differ diff --git a/infrastructure/eid-wallet/src-tauri/gen/apple/eid-wallet.xcodeproj/project.pbxproj b/infrastructure/eid-wallet/src-tauri/gen/apple/eid-wallet.xcodeproj/project.pbxproj index 8ce11f53..1306488f 100644 --- a/infrastructure/eid-wallet/src-tauri/gen/apple/eid-wallet.xcodeproj/project.pbxproj +++ b/infrastructure/eid-wallet/src-tauri/gen/apple/eid-wallet.xcodeproj/project.pbxproj @@ -388,8 +388,8 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = "eid-wallet_iOS/eid-wallet_iOS.entitlements"; CODE_SIGN_IDENTITY = "iPhone Developer"; - CURRENT_PROJECT_VERSION = 0.1.8; - DEVELOPMENT_TEAM = 3FS4B734X5; + CURRENT_PROJECT_VERSION = 0.2.0.1; + DEVELOPMENT_TEAM = M49C8XS835; ENABLE_BITCODE = NO; "EXCLUDED_ARCHS[sdk=iphoneos*]" = x86_64; FRAMEWORK_SEARCH_PATHS = ( @@ -415,7 +415,7 @@ "$(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME)", "$(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME)", ); - MARKETING_VERSION = 0.1.7; + MARKETING_VERSION = 0.2.0; PRODUCT_BUNDLE_IDENTIFIER = foundation.metastate.eid-wallet; PRODUCT_NAME = "eID for W3DS"; SDKROOT = iphoneos; @@ -436,8 +436,8 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = "eid-wallet_iOS/eid-wallet_iOS.entitlements"; CODE_SIGN_IDENTITY = "iPhone Developer"; - CURRENT_PROJECT_VERSION = 0.1.8; - DEVELOPMENT_TEAM = 3FS4B734X5; + CURRENT_PROJECT_VERSION = 0.2.0.1; + DEVELOPMENT_TEAM = M49C8XS835; ENABLE_BITCODE = NO; "EXCLUDED_ARCHS[sdk=iphoneos*]" = x86_64; FRAMEWORK_SEARCH_PATHS = ( @@ -463,7 +463,7 @@ "$(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME)", "$(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME)", ); - MARKETING_VERSION = 0.1.7; + MARKETING_VERSION = 0.2.0; PRODUCT_BUNDLE_IDENTIFIER = foundation.metastate.eid-wallet; PRODUCT_NAME = "eID for W3DS"; SDKROOT = iphoneos; diff --git a/infrastructure/eid-wallet/src-tauri/gen/apple/eid-wallet_iOS/Info.plist b/infrastructure/eid-wallet/src-tauri/gen/apple/eid-wallet_iOS/Info.plist index fb7f2cfa..42b39d2d 100644 --- a/infrastructure/eid-wallet/src-tauri/gen/apple/eid-wallet_iOS/Info.plist +++ b/infrastructure/eid-wallet/src-tauri/gen/apple/eid-wallet_iOS/Info.plist @@ -15,9 +15,20 @@ CFBundlePackageType APPL CFBundleShortVersionString - 0.1.8 + 0.2.0 + CFBundleURLTypes + + + CFBundleURLName + foundation.metastate.eid-wallet + CFBundleURLSchemes + + w3ds + + + CFBundleVersion - 0.1.8 + 0.2.0.1 LSRequiresIPhoneOS NSAppTransportSecurity @@ -49,16 +60,5 @@ UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight - CFBundleURLTypes - - - CFBundleURLName - foundation.metastate.eid-wallet - CFBundleURLSchemes - - w3ds - - - \ No newline at end of file diff --git a/infrastructure/eid-wallet/src/routes/(app)/scan-qr/+page.svelte b/infrastructure/eid-wallet/src/routes/(app)/scan-qr/+page.svelte index 818420cb..ea8aef92 100644 --- a/infrastructure/eid-wallet/src/routes/(app)/scan-qr/+page.svelte +++ b/infrastructure/eid-wallet/src/routes/(app)/scan-qr/+page.svelte @@ -46,6 +46,21 @@ let isSigningRequest = $state(false); let signingSuccess = $state(false); + // Blind voting specific state + let isBlindVotingRequest = $state(false); + let selectedBlindVoteOption = $state(null); + let blindVoteError = $state(null); // Add error state + let isSubmittingBlindVote = $state(false); // Add loading state + let blindVoteSuccess = $state(false); // Add success state + + // Debug logging for selectedBlindVoteOption changes + $effect(() => { + console.log( + "🔍 DEBUG: selectedBlindVoteOption changed to:", + selectedBlindVoteOption, + ); + }); + async function startScan() { let permissions = await checkPermissions() .then((permissions) => { @@ -73,6 +88,51 @@ // Check if this is a signing request if (res.content.startsWith("w3ds://sign")) { handleSigningRequest(res.content); + } else if (res.content.includes("/blind-vote")) { + // This is a blind voting request via HTTP URL + // Parse the URL and extract the data + try { + const url = new URL(res.content); + const sessionId = url.searchParams.get("session"); + const base64Data = url.searchParams.get("data"); + const redirectUri = + url.searchParams.get("redirect_uri"); + const platformUrl = + url.searchParams.get("platform_url"); + + if ( + sessionId && + base64Data && + redirectUri && + platformUrl + ) { + // Decode the base64 data + const decodedString = atob( + decodeURIComponent(base64Data), + ); + const decodedData = JSON.parse(decodedString); + + if (decodedData.type === "blind-vote") { + console.log( + "🔍 Detected blind voting request from HTTP URL", + ); + // Call the existing function with the right parameters + handleBlindVotingRequest( + decodedData, + platformUrl, + redirectUri, + ); + return; + } + } + } catch (error) { + console.error( + "Error parsing blind voting HTTP URL:", + error, + ); + } + // If parsing fails, fall back to auth request + handleAuthRequest(res.content); } else { handleAuthRequest(res.content); } @@ -229,14 +289,39 @@ function handleSigningRequest(content: string) { try { // Parse w3ds://sign URI scheme - // Format: w3ds://sign?session=&data=&redirect_uri= - const url = new URL(content); + // Format: w3ds://sign?session=&data=&redirect_uri=&platform_url= + + // Handle w3ds:// scheme by converting to a parseable format + let parseableContent = content; + if (content.startsWith("w3ds://")) { + parseableContent = content.replace( + "w3ds://", + "https://dummy.com/", + ); + } + + const url = new URL(parseableContent); signingSessionId = url.searchParams.get("session"); const base64Data = url.searchParams.get("data"); const redirectUri = url.searchParams.get("redirect_uri"); + const platformUrl = url.searchParams.get("platform_url"); + + console.log("🔍 Parsed w3ds://sign URI:", { + session: signingSessionId, + data: base64Data, + redirect_uri: redirectUri, + platform_url: platformUrl, + }); + + console.log("🔍 Raw redirect_uri from QR:", redirectUri); + console.log("🔍 Raw platform_url from QR:", platformUrl); if (!signingSessionId || !base64Data || !redirectUri) { - console.error("Invalid signing request parameters"); + console.error("Invalid signing request parameters:", { + signingSessionId, + base64Data, + redirectUri, + }); return; } @@ -246,7 +331,21 @@ // Decode the base64 data try { const decodedString = atob(base64Data); - signingData = JSON.parse(decodedString); + const decodedData = JSON.parse(decodedString); + + // Check if this is a blind voting request + if (decodedData.type === "blind-vote") { + console.log("🔍 Detected blind voting request"); + handleBlindVotingRequest( + decodedData, + platformUrl, + redirectUri, + ); + return; + } + + // Regular signing request + signingData = decodedData; // Debug logging console.log("🔍 DEBUG: Decoded signing data:", signingData); @@ -363,15 +462,361 @@ setTimeout(() => { signingSuccess = false; startScan(); - }, 2000); + }, 1500); } catch (error) { console.error("Error signing vote:", error); - // You could show an error message here } finally { loading = false; } } + async function handleBlindVotingRequest( + blindVoteData: any, + platformUrl: string | null, + redirectUri: string | null, + ) { + try { + console.log("🔍 Handling blind voting request:", blindVoteData); + console.log("🔗 Platform URL:", platformUrl); + + // Extract poll details from the blind vote data + const pollId = blindVoteData.pollId; + if (!pollId) { + throw new Error("No poll ID provided in blind vote data"); + } + + // Fetch poll details from the platform + const pollResponse = await fetch( + `${platformUrl}/api/polls/${pollId}`, + ); + if (!pollResponse.ok) { + throw new Error("Failed to fetch poll details"); + } + + const pollDetails = await pollResponse.json(); + console.log("📊 Poll details:", pollDetails); + + // Store the data for the blind voting interface + signingData = { + pollId: pollId, + pollDetails: pollDetails, + redirect: redirectUri, + sessionId: blindVoteData.sessionId, + platform_url: platformUrl, // Add the platform URL for API calls + }; + + console.log("🔍 DEBUG: Stored signing data:", { + pollId, + redirect: redirectUri, + platform_url: platformUrl, + }); + + // Set up blind voting state + isBlindVotingRequest = true; + selectedBlindVoteOption = null; + signingDrawerOpen = true; + blindVoteError = null; // Clear any previous errors + + console.log("✅ Blind voting request set up successfully"); + } catch (error) { + console.error("❌ Error handling blind voting request:", error); + } + } + + async function handleBlindVote() { + console.log("🔍 DEBUG: handleBlindVote called"); + console.log( + "🔍 DEBUG: selectedBlindVoteOption:", + selectedBlindVoteOption, + ); + console.log("🔍 DEBUG: signingData:", signingData); + console.log("🔍 DEBUG: isBlindVotingRequest:", isBlindVotingRequest); + + // Clear any previous errors and start loading + blindVoteError = null; + isSubmittingBlindVote = true; + + if (selectedBlindVoteOption === null || !signingData) { + const errorMsg = "No vote option selected or poll details missing"; + console.error("❌ Validation failed:", errorMsg); + console.error( + "❌ selectedBlindVoteOption:", + selectedBlindVoteOption, + ); + console.error( + "❌ selectedBlindVoteOption === null:", + selectedBlindVoteOption === null, + ); + console.error("❌ signingData:", signingData); + blindVoteError = errorMsg; + isSubmittingBlindVote = false; + return; + } + + try { + // Get the vault for user identification + const vault = await globalState.vaultController.vault; + if (!vault) { + throw new Error("No vault available for blind voting"); + } + + // Dynamically import the blindvote library + const { VotingSystem } = await import("blindvote"); + + // Use the user's W3ID as the voter ID (strip @ prefix if present) + const voterId = vault.ename?.startsWith("@") + ? vault.ename.slice(1) + : vault.ename; + console.log("🔍 DEBUG: Using voter ID:", voterId); + + // Get platform URL for API calls + const platformUrl = signingData.platform_url; + if (!platformUrl) { + throw new Error("Platform URL not provided in signing data"); + } + + // Check if user has already voted before attempting registration + console.log("🔍 DEBUG: Checking if user has already voted..."); + const voteStatusResponse = await axios.get( + `${platformUrl}/api/polls/${signingData.pollId}/vote?userId=${voterId}`, + ); + + console.log( + "🔍 DEBUG: Vote status response:", + voteStatusResponse.data, + ); + + // The API returns null if user hasn't voted, or a Vote object if they have + if (voteStatusResponse.data !== null) { + throw new Error( + "You have already submitted a vote for this poll", + ); + } + + console.log( + "🔍 DEBUG: User has not voted yet, proceeding with registration", + ); + + // Register the voter on the backend first + console.log("🔍 DEBUG: Registering voter on backend:", voterId); + const registerResponse = await axios.post( + `${platformUrl}/api/votes/${signingData.pollId}/register`, + { + voterId: voterId, + }, + ); + + if ( + registerResponse.status < 200 || + registerResponse.status >= 300 + ) { + throw new Error("Failed to register voter on backend"); + } + console.log("🔍 DEBUG: Voter registered on backend successfully"); + + // Generate vote data locally using the blindvote library (PRIVACY PRESERVING) + console.log("🔍 DEBUG: Generating vote data locally..."); + + // Create ElectionConfig from poll details + const electionConfig = { + id: signingData.pollId, + title: signingData.pollDetails.title, + description: "", + options: signingData.pollDetails.options.map( + (option: string, index: number) => `option_${index}`, + ), + maxVotes: 1, + allowAbstain: false, + }; + + console.log("🔍 DEBUG: Created electionConfig:", electionConfig); + + // Create voting system and register voter locally + const votingSystem = new VotingSystem(); + votingSystem.createElection( + signingData.pollId, + signingData.pollId, + electionConfig.options, + ); + + // Register the voter locally (this creates the voter's key pair and anchor) + console.log("🔍 DEBUG: Registering voter locally:", voterId); + votingSystem.registerVoter( + voterId, + signingData.pollId, + signingData.pollId, + ); + + // Generate vote data with the selected option (PRIVACY PRESERVING - only known locally) + const optionId = `option_${selectedBlindVoteOption}`; + console.log("🔍 DEBUG: Generating vote data for option:", optionId); + + const voteData = votingSystem.generateVoteData( + voterId, + signingData.pollId, + signingData.pollId, + optionId, + ); + + // Extract commitments and anchors from the generated data + const commitments = voteData.commitments; + const anchors = voteData.anchors; + + // Convert Uint8Array to hex strings for API transmission + const hexCommitments: Record = {}; + const hexAnchors: Record = {}; + + for (const [optionId, commitment] of Object.entries(commitments)) { + hexCommitments[optionId] = Array.from(commitment) + .map((b) => b.toString(16).padStart(2, "0")) + .join(""); + } + + for (const [optionId, anchor] of Object.entries(anchors)) { + hexAnchors[optionId] = Array.from(anchor) + .map((b) => b.toString(16).padStart(2, "0")) + .join(""); + } + + // Store vote data locally for later revelation + // Convert BigInt values to strings for JSON serialization + const localVoteData = { + pollId: signingData.pollId, + optionId: `option_${selectedBlindVoteOption}`, // Use the correct option ID format + commitments: commitments, + anchors: anchors, + timestamp: new Date().toISOString(), + }; + + // Custom JSON serializer to handle BigInt values + const jsonString = JSON.stringify(localVoteData, (key, value) => { + if (typeof value === "bigint") { + return value.toString(); + } + return value; + }); + + localStorage.setItem(`blindVote_${signingData.pollId}`, jsonString); + + // Submit to the API (PRIVACY PRESERVING - no chosenOptionId revealed) + const payload = { + pollId: signingData.pollId, + voterId: voterId, + // chosenOptionId is NOT sent - this preserves privacy! + commitments: hexCommitments, + anchors: hexAnchors, + sessionId: signingData.sessionId, + userW3id: vault?.ename || "", + }; + + console.log("🔍 DEBUG: Original commitments:", commitments); + console.log("🔍 DEBUG: Original anchors:", anchors); + console.log("🔍 DEBUG: Hex commitments:", hexCommitments); + console.log("🔍 DEBUG: Hex anchors:", hexAnchors); + console.log( + "🔗 Submitting blind vote to API:", + signingData.redirect, + ); + console.log("📦 Payload:", payload); + + // Convert BigInt values to strings for API submission + const apiPayload = JSON.stringify(payload, (key, value) => { + if (typeof value === "bigint") { + return value.toString(); + } + return value; + }); + + // Ensure we have a full URL for the redirect + // The redirect from frontend is a relative path like /api/votes/{pollId}/blind + // We need to combine it with the platform URL + console.log("🔍 DEBUG: Constructing redirect URL:"); + console.log( + "🔍 DEBUG: signingData.redirect:", + signingData.redirect, + ); + console.log( + "🔍 DEBUG: signingData.platform_url:", + signingData.platform_url, + ); + + const redirectUrl = signingData.redirect.startsWith("http") + ? signingData.redirect + : `${signingData.platform_url}${signingData.redirect}`; + + console.log("🔍 DEBUG: Final redirect URL:", redirectUrl); + console.log("🔍 Submitting blind vote to:", redirectUrl); + + const response = await axios.post(redirectUrl, apiPayload, { + headers: { + "Content-Type": "application/json", + }, + }); + + if (response.status >= 200 && response.status < 300) { + console.log("✅ Blind vote submitted successfully"); + + // Set success state for proper UI feedback + blindVoteSuccess = true; + + // Reset states gradually to avoid white screen + blindVoteError = null; + isSubmittingBlindVote = false; + blindVoteSuccess = true; // Set success state + + // Close the signing drawer + signingDrawerOpen = false; + + // Reset blind voting specific states + isBlindVotingRequest = false; + selectedBlindVoteOption = null; + signingData = null; + + // Ensure we're back to scanning mode + setTimeout(() => { + // Reset all drawer states to ensure camera view is shown + codeScannedDrawerOpen = false; + loggedInDrawerOpen = false; + signingDrawerOpen = false; + signingSuccess = false; + blindVoteSuccess = false; // Reset success state + + // Start scanning again + startScan(); + }, 100); // Small delay to ensure state transitions complete + } else { + console.error("❌ Failed to submit blind vote"); + blindVoteError = + "Failed to submit blind vote. Please try again."; + } + } catch (error) { + console.error("❌ Error submitting blind vote:", error); + blindVoteError = + error instanceof Error + ? error.message + : "Unknown error occurred during blind voting"; + + // Make sure we're not stuck in loading state + isSubmittingBlindVote = false; + + // Don't reset other states on error - let user see the error and retry + } finally { + // Always ensure loading state is reset + isSubmittingBlindVote = false; + } + } + + function closeDrawer() { + codeScannedDrawerOpen = false; + loggedInDrawerOpen = false; + signingDrawerOpen = false; + signingSuccess = false; + isBlindVotingRequest = false; + selectedBlindVoteOption = null; + signingData = null; + signingSessionId = null; + } + onMount(async () => { console.log("Scan QR page mounted, checking authentication..."); @@ -450,6 +895,16 @@ console.log("Signing modal should now be open"); } } + // Handle blind voting requests + if (data.type === "blind-vote") { + console.log("🔍 Blind voting request detected"); + isBlindVotingRequest = true; + selectedBlindVoteOption = null; + signingData = data; + signingDrawerOpen = true; + blindVoteError = null; // Clear any previous errors + return; + } } // Check if we have deep link data from sessionStorage @@ -667,7 +1122,11 @@ @@ -690,12 +1149,18 @@

- {signingData?.pollId ? "Sign Vote Request" : "Sign Message Request"} + {isBlindVotingRequest + ? "Blind Vote Request" + : signingData?.pollId + ? "Sign Vote Request" + : "Sign Message Request"}

- {signingData?.pollId - ? "You're being asked to sign a vote for the following poll" - : "You're being asked to sign the following message"} + {isBlindVotingRequest + ? "You're being asked to submit a blind vote for the following poll" + : signingData?.pollId + ? "You're being asked to sign a vote for the following poll" + : "You're being asked to sign the following message"}

{#if signingData?.pollId && signingData?.voteData} @@ -786,6 +1251,119 @@ {/if}
+ {:else if isBlindVotingRequest && signingData?.pollDetails} + +
+

Blind Voting

+ + + {#if blindVoteError} +
+
+
+ + + +
+
+

+ Error +

+
+ {blindVoteError} +
+
+
+
+ {/if} + + +
+

+ Poll: {signingData.pollDetails?.title || "Unknown"} +

+

+ Creator: {signingData.pollDetails?.creatorName || "Unknown"} +

+
+ + +
+ + {#each signingData.pollDetails?.options || [] as option, index} + + {/each} +
+ + + +
{:else}
@@ -804,23 +1382,31 @@ {/if}
- { - signingDrawerOpen = false; - startScan(); - }} - > - Decline - - - {loading - ? "Signing..." - : signingData?.pollId - ? "Sign Vote" - : "Sign Message"} - + {#if !isBlindVotingRequest} + { + signingDrawerOpen = false; + startScan(); + }} + > + Decline + + {/if} + {#if !isBlindVotingRequest} + + {loading + ? "Signing..." + : signingData?.pollId + ? "Sign Vote" + : "Sign Message"} + + {/if}
@@ -846,14 +1432,18 @@ />

- {signingData?.pollId - ? "Vote Signed Successfully!" - : "Message Signed Successfully!"} + {isBlindVotingRequest + ? "Blind Vote Submitted Successfully!" + : signingData?.pollId + ? "Vote Signed Successfully!" + : "Message Signed Successfully!"}

- {signingData?.pollId - ? "Your vote has been signed and submitted to the voting system." - : "Your message has been signed and submitted successfully."} + {isBlindVotingRequest + ? "Your blind vote has been submitted and is now hidden from the platform." + : signingData?.pollId + ? "Your vote has been signed and submitted to the voting system." + : "Your message has been signed and submitted successfully."}

{#if redirect} @@ -879,3 +1469,39 @@
{/if} + + +{#if blindVoteSuccess} +
+
+
+ +
+

+ Blind Vote Submitted Successfully! +

+

+ Your blind vote has been submitted and is now hidden from the + platform. +

+ { + blindVoteSuccess = false; + }} + class="w-full" + > + Continue + +
+
+{/if} diff --git a/infrastructure/eid-wallet/src/routes/(app)/sign/+page.svelte b/infrastructure/eid-wallet/src/routes/(app)/sign/+page.svelte deleted file mode 100644 index f3fc761b..00000000 --- a/infrastructure/eid-wallet/src/routes/(app)/sign/+page.svelte +++ /dev/null @@ -1,405 +0,0 @@ - - - - -
-
- {#if signingStatus === "pending" && signingData && decodedData} - -
-
- 📝 -
- -
-

- {decodedData.pollId ? "Sign Your Vote" : "Sign Message"} -

-

- {decodedData.pollId - ? "You're about to sign a vote for the following poll:" - : "You're about to sign the following message:"} -

-
- - {#if decodedData.pollId && decodedData.voteData} - -
-

- Poll Details -

-
-
- Poll ID: - {decodedData.pollId?.slice(0, 8)}... -
-
- Voting Mode: - {decodedData.voteData?.optionId - ? "Single Choice" - : "Ranked Choice"} -
- {#if decodedData.voteData?.optionId} -
- Selected Option: - Option {decodedData.voteData.optionId + 1} -
- {:else if decodedData.voteData?.ranks} -
- Rankings: -
- {#each Object.entries(decodedData.voteData.ranks) as [rank, optionIndex]} -
- {rank === "1" - ? "1st" - : rank === "2" - ? "2nd" - : "3rd"}: Option {(optionIndex as number) + - 1} -
- {/each} -
-
- {/if} -
-
- {:else} - -
-

- Message Details -

-
-
- Message: -

- {decodedData.message} -

-
-
- Session ID: -

- {decodedData.sessionId?.slice(0, 8)}... -

-
-
-
- {/if} - - -
-
- 🛡️ -
-

Security Notice

-

- {decodedData.pollId - ? "By signing this message, you're confirming your vote. This action cannot be undone." - : "By signing this message, you're confirming your agreement to the content. This action cannot be undone."} -

-
-
-
- - -
- - Cancel - - - {decodedData.pollId ? "Sign Vote" : "Sign Message"} - -
-
- {:else if signingStatus === "signing"} - -
-
- -
- -
-

- {decodedData?.pollId - ? "Signing Your Vote" - : "Signing Your Message"} -

-

- Please wait while we process your signature... -

-
- -
-
-
- Processing signature... -
-
-
- {:else if signingStatus === "success"} - -
-
- -
- -
-

- {decodedData?.pollId - ? "Vote Signed Successfully!" - : "Message Signed Successfully!"} -

-

- {decodedData?.pollId - ? "Your vote has been signed and submitted to the voting system." - : "Your message has been signed and submitted successfully."} -

-
- -
-
- - Signature verified and vote submitted -
-
- -

Redirecting to main app...

-
- {:else if signingStatus === "error"} - -
-
- -
- -
-

- Signing Failed -

-

{errorMessage}

-
- -
-
- ⚠️ - Unable to complete signing process -
-
- - -
- - Go Back - - - Try Again - -
-
- {/if} -
-
diff --git a/infrastructure/eid-wallet/svelte.config.js b/infrastructure/eid-wallet/svelte.config.js index 9e995d0f..d7e7183b 100644 --- a/infrastructure/eid-wallet/svelte.config.js +++ b/infrastructure/eid-wallet/svelte.config.js @@ -12,6 +12,9 @@ const config = { env: { dir: "../../", }, + alias: { + blindvote: "../../infrastructure/blindvote/src" + } }, }; diff --git a/infrastructure/eid-wallet/vite.config.js b/infrastructure/eid-wallet/vite.config.js index a3ebac39..1acb7b36 100644 --- a/infrastructure/eid-wallet/vite.config.js +++ b/infrastructure/eid-wallet/vite.config.js @@ -1,12 +1,49 @@ import { defineConfig } from "vite"; import { sveltekit } from "@sveltejs/kit/vite"; import tailwindcss from "@tailwindcss/vite"; +import { nodePolyfills } from "vite-plugin-node-polyfills"; const host = process.env.TAURI_DEV_HOST; // https://vitejs.dev/config/ export default defineConfig(async () => ({ - plugins: [tailwindcss(), sveltekit()], + plugins: [ + tailwindcss(), + sveltekit(), + nodePolyfills({ + // Polyfill all Node.js core modules + include: ['buffer', 'crypto', 'stream', 'util'], + // Polyfill globals + globals: { + Buffer: true, + global: true, + process: true, + }, + // Override specific polyfills + overrides: { + // Use proper Buffer polyfill + buffer: 'buffer', + }, + }), + ], + + // Environment variables + define: { + 'process.env.NEXT_PUBLIC_EVOTING_BASE_URL': JSON.stringify(process.env.NEXT_PUBLIC_EVOTING_BASE_URL || 'http://localhost:3001'), + 'process.env.NEXT_PUBLIC_EID_WALLET_URL': JSON.stringify(process.env.NEXT_PUBLIC_EID_WALLET_URL || 'w3ds://'), + }, + + // Handle workspace dependencies + optimizeDeps: { + include: ['blindvote'] + }, + + // Handle Node.js modules in browser environment + resolve: { + alias: { + 'noble-secp256k1': 'noble-secp256k1' + } + }, // Vite options tailored for Tauri development and only applied in `tauri dev` or `tauri build` // diff --git a/infrastructure/web3-adapter/src/db/index.d.ts b/infrastructure/web3-adapter/src/db/index.d.ts deleted file mode 100644 index 2b35a798..00000000 --- a/infrastructure/web3-adapter/src/db/index.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from "./mapping.db"; -//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/infrastructure/web3-adapter/src/db/index.d.ts.map b/infrastructure/web3-adapter/src/db/index.d.ts.map deleted file mode 100644 index 30c34a3a..00000000 --- a/infrastructure/web3-adapter/src/db/index.d.ts.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAC"} \ No newline at end of file diff --git a/infrastructure/web3-adapter/src/db/index.js b/infrastructure/web3-adapter/src/db/index.js deleted file mode 100644 index c8fda5d5..00000000 --- a/infrastructure/web3-adapter/src/db/index.js +++ /dev/null @@ -1,18 +0,0 @@ -"use strict"; -var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - var desc = Object.getOwnPropertyDescriptor(m, k); - if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { - desc = { enumerable: true, get: function() { return m[k]; } }; - } - Object.defineProperty(o, k2, desc); -}) : (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - o[k2] = m[k]; -})); -var __exportStar = (this && this.__exportStar) || function(m, exports) { - for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p); -}; -Object.defineProperty(exports, "__esModule", { value: true }); -__exportStar(require("./mapping.db"), exports); -//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/infrastructure/web3-adapter/src/db/index.js.map b/infrastructure/web3-adapter/src/db/index.js.map deleted file mode 100644 index 9cedaaba..00000000 --- a/infrastructure/web3-adapter/src/db/index.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,+CAA6B"} \ No newline at end of file diff --git a/infrastructure/web3-adapter/src/db/mapping.db.d.ts b/infrastructure/web3-adapter/src/db/mapping.db.d.ts deleted file mode 100644 index 2e9d5073..00000000 --- a/infrastructure/web3-adapter/src/db/mapping.db.d.ts +++ /dev/null @@ -1,39 +0,0 @@ -export declare class MappingDatabase { - private db; - private runAsync; - private getAsync; - private allAsync; - constructor(dbPath: string); - private initialize; - /** - * Store a mapping between local and global IDs - */ - storeMapping(params: { - localId: string; - globalId: string; - }): Promise; - /** - * Get the global ID for a local ID - */ - getGlobalId(localId: string): Promise; - /** - * Get the local ID for a global ID - */ - getLocalId(globalId: string): Promise; - /** - * Delete a mapping - */ - deleteMapping(localId: string): Promise; - /** - * Get all mappings - */ - getAllMappings(): Promise>; - /** - * Close the database connection - */ - close(): void; -} -//# sourceMappingURL=mapping.db.d.ts.map \ No newline at end of file diff --git a/infrastructure/web3-adapter/src/db/mapping.db.d.ts.map b/infrastructure/web3-adapter/src/db/mapping.db.d.ts.map deleted file mode 100644 index 5d3658f8..00000000 --- a/infrastructure/web3-adapter/src/db/mapping.db.d.ts.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"mapping.db.d.ts","sourceRoot":"","sources":["mapping.db.ts"],"names":[],"mappings":"AAIA,qBAAa,eAAe;IACxB,OAAO,CAAC,EAAE,CAAmB;IAC7B,OAAO,CAAC,QAAQ,CAAoD;IACpE,OAAO,CAAC,QAAQ,CAI2B;IAC3C,OAAO,CAAC,QAAQ,CAI6B;gBAEjC,MAAM,EAAE,MAAM;YAcZ,UAAU;IAexB;;OAEG;IACU,YAAY,CAAC,MAAM,EAAE;QAC9B,OAAO,EAAE,MAAM,CAAC;QAChB,QAAQ,EAAE,MAAM,CAAC;KACpB,GAAG,OAAO,CAAC,IAAI,CAAC;IAgCjB;;OAEG;IACU,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAmBjE;;OAEG;IACU,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAkBjE;;OAEG;IACU,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAY1D;;OAEG;IACU,cAAc,IAAI,OAAO,CAClC,KAAK,CAAC;QACF,OAAO,EAAE,MAAM,CAAC;QAChB,QAAQ,EAAE,MAAM,CAAC;KACpB,CAAC,CACL;IAgBD;;OAEG;IACI,KAAK,IAAI,IAAI;CAOvB"} \ No newline at end of file diff --git a/infrastructure/web3-adapter/src/db/mapping.db.js b/infrastructure/web3-adapter/src/db/mapping.db.js deleted file mode 100644 index 74e34eca..00000000 --- a/infrastructure/web3-adapter/src/db/mapping.db.js +++ /dev/null @@ -1,132 +0,0 @@ -"use strict"; -var __importDefault = (this && this.__importDefault) || function (mod) { - return (mod && mod.__esModule) ? mod : { "default": mod }; -}; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.MappingDatabase = void 0; -const node_path_1 = require("node:path"); -const node_util_1 = require("node:util"); -const sqlite3_1 = __importDefault(require("sqlite3")); -class MappingDatabase { - constructor(dbPath) { - // Ensure the directory exists - const fullPath = (0, node_path_1.join)(dbPath, "mappings.db"); - this.db = new sqlite3_1.default.Database(fullPath); - // Promisify database methods - this.runAsync = (0, node_util_1.promisify)(this.db.run.bind(this.db)); - this.getAsync = (0, node_util_1.promisify)(this.db.get.bind(this.db)); - this.allAsync = (0, node_util_1.promisify)(this.db.all.bind(this.db)); - // Initialize the database with the required tables - this.initialize(); - } - async initialize() { - await this.runAsync(` - CREATE TABLE IF NOT EXISTS id_mappings ( - local_id TEXT NOT NULL, - global_id TEXT NOT NULL, - created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, - PRIMARY KEY (global_id) - ) - `); - await this.runAsync(` - CREATE INDEX IF NOT EXISTS idx_local_id ON id_mappings(local_id) - `); - } - /** - * Store a mapping between local and global IDs - */ - async storeMapping(params) { - // Validate inputs - if (!params.localId || !params.globalId) { - throw new Error("Invalid mapping parameters: all fields are required"); - } - console.log("storing mapping g:l", params.globalId, params.localId); - // Check if mapping already exists - const existingMapping = await this.getGlobalId(params.localId); - if (existingMapping) { - return; - } - await this.runAsync(`INSERT INTO id_mappings (local_id, global_id) - VALUES (?, ?)`, [params.localId, params.globalId]); - const storedMapping = await this.getGlobalId(params.localId); - if (storedMapping !== params.globalId) { - console.log("storedMappingError", storedMapping, params.globalId); - console.error("Failed to store mapping"); - return; - } - } - /** - * Get the global ID for a local ID - */ - async getGlobalId(localId) { - if (!localId) { - return null; - } - try { - const result = await this.getAsync(`SELECT global_id - FROM id_mappings - WHERE local_id = ?`, [localId]); - return result?.global_id ?? null; - } - catch (error) { - console.error("Error getting global ID:", error); - return null; - } - } - /** - * Get the local ID for a global ID - */ - async getLocalId(globalId) { - if (!globalId) { - return null; - } - try { - const result = await this.getAsync(`SELECT local_id - FROM id_mappings - WHERE global_id = ?`, [globalId]); - return result?.local_id ?? null; - } - catch (error) { - return null; - } - } - /** - * Delete a mapping - */ - async deleteMapping(localId) { - if (!localId) { - return; - } - await this.runAsync(`DELETE FROM id_mappings - WHERE local_id = ?`, [localId]); - } - /** - * Get all mappings - */ - async getAllMappings() { - try { - const results = await this.allAsync(`SELECT local_id, global_id - FROM id_mappings`); - return results.map(({ local_id, global_id }) => ({ - localId: local_id, - globalId: global_id, - })); - } - catch (error) { - return []; - } - } - /** - * Close the database connection - */ - close() { - try { - this.db.close(); - } - catch (error) { - console.error("Error closing database connection:", error); - } - } -} -exports.MappingDatabase = MappingDatabase; -//# sourceMappingURL=mapping.db.js.map \ No newline at end of file diff --git a/infrastructure/web3-adapter/src/db/mapping.db.js.map b/infrastructure/web3-adapter/src/db/mapping.db.js.map deleted file mode 100644 index 0448d0fb..00000000 --- a/infrastructure/web3-adapter/src/db/mapping.db.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"mapping.db.js","sourceRoot":"","sources":["mapping.db.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/infrastructure/web3-adapter/src/evault/evault.d.ts b/infrastructure/web3-adapter/src/evault/evault.d.ts deleted file mode 100644 index 7236b2b7..00000000 --- a/infrastructure/web3-adapter/src/evault/evault.d.ts +++ /dev/null @@ -1,44 +0,0 @@ -export interface MetaEnvelope { - id?: string | null; - schemaId: string; - data: Record; - w3id: string; -} -export declare class EVaultClient { - private registryUrl; - private platform; - private clients; - private endpoints; - private tokenInfo; - private isDisposed; - constructor(registryUrl: string, platform: string); - /** - * Cleanup method to properly dispose of resources - */ - dispose(): void; - /** - * Retry wrapper with exponential backoff - */ - private withRetry; - /** - * Requests a platform token from the registry - * @returns Promise - The platform token - */ - private requestPlatformToken; - /** - * Checks if token needs refresh - */ - private isTokenExpired; - /** - * Ensures we have a valid platform token, requesting one if needed - * @returns Promise - The platform token - */ - private ensurePlatformToken; - private resolveEndpoint; - private ensureClient; - storeMetaEnvelope(envelope: MetaEnvelope): Promise; - storeReference(referenceId: string, w3id: string): Promise; - fetchMetaEnvelope(id: string, w3id: string): Promise; - updateMetaEnvelopeById(id: string, envelope: MetaEnvelope): Promise; -} -//# sourceMappingURL=evault.d.ts.map \ No newline at end of file diff --git a/infrastructure/web3-adapter/src/evault/evault.d.ts.map b/infrastructure/web3-adapter/src/evault/evault.d.ts.map deleted file mode 100644 index c0503d98..00000000 --- a/infrastructure/web3-adapter/src/evault/evault.d.ts.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"evault.d.ts","sourceRoot":"","sources":["evault.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,YAAY;IACzB,EAAE,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IAEjB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC1B,IAAI,EAAE,MAAM,CAAC;CAChB;AAkHD,qBAAa,YAAY;IAOjB,OAAO,CAAC,WAAW;IACnB,OAAO,CAAC,QAAQ;IAPpB,OAAO,CAAC,OAAO,CAAyC;IACxD,OAAO,CAAC,SAAS,CAAkC;IACnD,OAAO,CAAC,SAAS,CAA0B;IAC3C,OAAO,CAAC,UAAU,CAAS;gBAGf,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,MAAM;IAG5B;;OAEG;IACI,OAAO,IAAI,IAAI;IAStB;;OAEG;YACW,SAAS;IAoCvB;;;OAGG;YACW,oBAAoB;IAmClC;;OAEG;IACH,OAAO,CAAC,cAAc;IAStB;;;OAGG;YACW,mBAAmB;YAOnB,eAAe;YAoBf,YAAY;IAiCpB,iBAAiB,CAAC,QAAQ,EAAE,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC;IAyB1D,cAAc,CAAC,WAAW,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAuBhE,iBAAiB,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC;IAoBlE,sBAAsB,CACxB,EAAE,EAAE,MAAM,EACV,QAAQ,EAAE,YAAY,GACvB,OAAO,CAAC,IAAI,CAAC;CA8BnB"} \ No newline at end of file diff --git a/infrastructure/web3-adapter/src/evault/evault.js b/infrastructure/web3-adapter/src/evault/evault.js deleted file mode 100644 index f6257985..00000000 --- a/infrastructure/web3-adapter/src/evault/evault.js +++ /dev/null @@ -1,280 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.EVaultClient = void 0; -const graphql_request_1 = require("graphql-request"); -const uuid_1 = require("uuid"); -// Configuration constants -const CONFIG = { - REQUEST_TIMEOUT: 30000, // 30 seconds - CONNECTION_TIMEOUT: 10000, // 10 seconds - TOKEN_REFRESH_THRESHOLD: 5 * 60 * 1000, // 5 minutes before expiry - MAX_RETRIES: 3, - RETRY_DELAY: 1000, // 1 second base delay - CONNECTION_POOL_SIZE: 10, -}; -const STORE_META_ENVELOPE = ` - mutation StoreMetaEnvelope($input: MetaEnvelopeInput!) { - storeMetaEnvelope(input: $input) { - metaEnvelope { - id - ontology - parsed - } - } - } -`; -const FETCH_META_ENVELOPE = ` - query FetchMetaEnvelope($id: ID!) { - metaEnvelope(id: $id) { - id - ontology - parsed - } - } -`; -const UPDATE_META_ENVELOPE = ` - mutation UpdateMetaEnvelopeById($id: String!, $input: MetaEnvelopeInput!) { - updateMetaEnvelopeById(id: $id, input: $input) { - metaEnvelope { - id - ontology - parsed - } - envelopes { - id - ontology - value - valueType - } - } - } -`; -class EVaultClient { - constructor(registryUrl, platform) { - this.registryUrl = registryUrl; - this.platform = platform; - this.clients = new Map(); - this.endpoints = new Map(); - this.tokenInfo = null; - this.isDisposed = false; - } - /** - * Cleanup method to properly dispose of resources - */ - dispose() { - if (this.isDisposed) - return; - this.isDisposed = true; - this.clients.clear(); - this.endpoints.clear(); - this.tokenInfo = null; - } - /** - * Retry wrapper with exponential backoff - */ - async withRetry(operation, maxRetries = CONFIG.MAX_RETRIES) { - let lastError; - for (let attempt = 0; attempt <= maxRetries; attempt++) { - try { - return await operation(); - } - catch (error) { - lastError = error; - // Don't retry on the last attempt - if (attempt === maxRetries) - break; - // Don't retry on certain errors - if (error instanceof Error) { - const isRetryable = !(error.message.includes("401") || - error.message.includes("403") || - error.message.includes("404")); - if (!isRetryable) - break; - } - // Exponential backoff - const delay = CONFIG.RETRY_DELAY * 2 ** attempt; - await new Promise((resolve) => setTimeout(resolve, delay)); - } - } - // biome-ignore lint/style/noNonNullAssertion: - throw lastError; - } - /** - * Requests a platform token from the registry - * @returns Promise - The platform token - */ - async requestPlatformToken() { - try { - const response = await fetch(new URL("/platforms/certification", this.registryUrl).toString(), { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify({ platform: this.platform }), - }); - if (!response.ok) { - throw new Error(`HTTP error! status: ${response.status}`); - } - const data = (await response.json()); - const now = Date.now(); - const expiresAt = data.expiresAt || now + 3600000; // Default 1 hour - return { - token: data.token, - expiresAt, - obtainedAt: now, - }; - } - catch (error) { - console.error("Error requesting platform token:", error); - throw new Error("Failed to request platform token"); - } - } - /** - * Checks if token needs refresh - */ - isTokenExpired() { - if (!this.tokenInfo) - return true; - const now = Date.now(); - const timeUntilExpiry = this.tokenInfo.expiresAt - now; - return timeUntilExpiry <= CONFIG.TOKEN_REFRESH_THRESHOLD; - } - /** - * Ensures we have a valid platform token, requesting one if needed - * @returns Promise - The platform token - */ - async ensurePlatformToken() { - if (!this.tokenInfo || this.isTokenExpired()) { - this.tokenInfo = await this.requestPlatformToken(); - } - return this.tokenInfo.token; - } - async resolveEndpoint(w3id) { - try { - const enrichedW3id = w3id.startsWith("@") ? w3id : `@${w3id}`; - console.log("fetching endpoint for :", enrichedW3id); - const response = await fetch(new URL(`/resolve?w3id=${enrichedW3id}`, this.registryUrl).toString()); - if (!response.ok) { - throw new Error(`HTTP error! status: ${response.status}`); - } - const data = await response.json(); - return new URL("/graphql", data.uri).toString(); - } - catch (error) { - console.error("Error resolving eVault endpoint:", error); - throw new Error("Failed to resolve eVault endpoint"); - } - } - async ensureClient(w3id) { - if (this.isDisposed) { - throw new Error("EVaultClient has been disposed"); - } - // Check if we already have a client for this specific w3id - if (this.clients.has(w3id)) { - const client = this.clients.get(w3id); - const endpoint = this.endpoints.get(w3id); - console.log('reusing existing client for w3id:', w3id, 'endpoint:', endpoint); - return client; - } - // Resolve endpoint for this specific w3id - const endpoint = await this.resolveEndpoint(w3id).catch(() => null); - if (!endpoint) - throw new Error("Failed to resolve endpoint"); - // Get platform token and create client with authorization header - const token = await this.ensurePlatformToken(); - const client = new graphql_request_1.GraphQLClient(endpoint, { - headers: { - authorization: `Bearer ${token}`, - }, - }); - // Cache the client and endpoint for this specific w3id - this.clients.set(w3id, client); - this.endpoints.set(w3id, endpoint); - console.log('created new client for w3id:', w3id, 'endpoint:', endpoint); - return client; - } - async storeMetaEnvelope(envelope) { - return this.withRetry(async () => { - const client = await this.ensureClient(envelope.w3id).catch(() => { - return null; - }); - if (!client) - return (0, uuid_1.v4)(); - console.log("sending to eVault: ", envelope.w3id); - console.log("sending payload", envelope); - const response = await client - .request(STORE_META_ENVELOPE, { - input: { - ontology: envelope.schemaId, - payload: envelope.data, - acl: ["*"], - }, - }) - .catch(() => null); - if (!response) - return (0, uuid_1.v4)(); - return response.storeMetaEnvelope.metaEnvelope.id; - }); - } - async storeReference(referenceId, w3id) { - return this.withRetry(async () => { - const client = await this.ensureClient(w3id); - const response = await client - .request(STORE_META_ENVELOPE, { - input: { - ontology: "reference", - payload: { - _by_reference: referenceId, - }, - acl: ["*"], - }, - }) - .catch(() => null); - if (!response) { - console.error("Failed to store reference"); - throw new Error("Failed to store reference"); - } - }); - } - async fetchMetaEnvelope(id, w3id) { - return this.withRetry(async () => { - const client = await this.ensureClient(w3id); - try { - const response = await client.request(FETCH_META_ENVELOPE, { - id, - w3id, - }); - return response.metaEnvelope; - } - catch (error) { - console.error("Error fetching meta envelope:", error); - throw error; - } - }); - } - async updateMetaEnvelopeById(id, envelope) { - return this.withRetry(async () => { - console.log("sending to eVault", envelope.w3id); - const client = await this.ensureClient(envelope.w3id).catch(() => null); - if (!client) - throw new Error("Failed to establish client connection"); - try { - const variables = { - id, - input: { - ontology: envelope.schemaId, - payload: envelope.data, - acl: ["*"], - }, - }; - const response = await client.request(UPDATE_META_ENVELOPE, variables); - } - catch (error) { - console.error("Error updating meta envelope:", error); - throw error; - } - }); - } -} -exports.EVaultClient = EVaultClient; -//# sourceMappingURL=evault.js.map \ No newline at end of file diff --git a/infrastructure/web3-adapter/src/evault/evault.js.map b/infrastructure/web3-adapter/src/evault/evault.js.map deleted file mode 100644 index 3ee7579f..00000000 --- a/infrastructure/web3-adapter/src/evault/evault.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"evault.js","sourceRoot":"","sources":["evault.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/infrastructure/web3-adapter/src/index.d.ts b/infrastructure/web3-adapter/src/index.d.ts deleted file mode 100644 index 27ebc6df..00000000 --- a/infrastructure/web3-adapter/src/index.d.ts +++ /dev/null @@ -1,97 +0,0 @@ -import { MappingDatabase } from "./db"; -import { EVaultClient } from "./evault/evault"; -import type { IMapping } from "./mapper/mapper.types"; -/** - * Standalone function to spin up an eVault - * @param registryUrl - URL of the registry service - * @param provisionerUrl - URL of the provisioner service - * @param verificationCode - Optional verification code, defaults to demo code - * @returns Promise with eVault details (w3id, uri) - */ -export declare function spinUpEVault(registryUrl: string, provisionerUrl: string, verificationCode?: string): Promise<{ - w3id: string; - uri: string; -}>; -/** - * Standalone function to create a group eVault with GroupManifest - * @param registryUrl - URL of the registry service - * @param provisionerUrl - URL of the provisioner service - * @param groupData - Group data for the manifest - * @param verificationCode - Optional verification code, defaults to demo code - * @returns Promise with eVault details (w3id, uri, manifestId) - */ -export declare function createGroupEVault(registryUrl: string, provisionerUrl: string, groupData: { - name: string; - avatar?: string; - description?: string; - members: string[]; - admins: string[]; - owner: string; - charter?: string; -}, verificationCode?: string): Promise<{ - w3id: string; - uri: string; - manifestId: string; -}>; -export declare class Web3Adapter { - private readonly config; - mapping: Record; - mappingDb: MappingDatabase; - evaultClient: EVaultClient; - lockedIds: string[]; - platform: string; - constructor(config: { - schemasPath: string; - dbPath: string; - registryUrl: string; - platform: string; - provisionerUrl?: string; - }); - readPaths(): Promise; - addToLockedIds(id: string): void; - handleChange(props: { - data: Record; - tableName: string; - participants?: string[]; - }): Promise<{ - id: string; - w3id: string; - data: Record; - schemaId: string; - } | undefined>; - fromGlobal(props: { - data: Record; - mapping: IMapping; - }): Promise>; - /** - * Spins up an eVault by getting entropy from registry and provisioning it - * @param verificationCode - Optional verification code, defaults to demo code - * @param provisionerUrl - Optional provisioner URL, defaults to config - * @returns Promise with eVault details (w3id, uri) - */ - spinUpEVault(verificationCode?: string, provisionerUrl?: string): Promise<{ - w3id: string; - uri: string; - }>; - /** - * Creates a group eVault with GroupManifest - * @param groupData - Group data for the manifest - * @param verificationCode - Optional verification code, defaults to demo code - * @param provisionerUrl - Optional provisioner URL, defaults to config - * @returns Promise with eVault details (w3id, uri, manifestId) - */ - createGroupEVault(groupData: { - name: string; - avatar?: string; - description?: string; - members: string[]; - admins: string[]; - owner: string; - charter?: string; - }, verificationCode?: string, provisionerUrl?: string): Promise<{ - w3id: string; - uri: string; - manifestId: string; - }>; -} -//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/infrastructure/web3-adapter/src/index.d.ts.map b/infrastructure/web3-adapter/src/index.d.ts.map deleted file mode 100644 index f284e846..00000000 --- a/infrastructure/web3-adapter/src/index.d.ts.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/infrastructure/web3-adapter/src/index.js b/infrastructure/web3-adapter/src/index.js deleted file mode 100644 index a7d3c7e2..00000000 --- a/infrastructure/web3-adapter/src/index.js +++ /dev/null @@ -1,314 +0,0 @@ -"use strict"; -var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - var desc = Object.getOwnPropertyDescriptor(m, k); - if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { - desc = { enumerable: true, get: function() { return m[k]; } }; - } - Object.defineProperty(o, k2, desc); -}) : (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - o[k2] = m[k]; -})); -var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { - Object.defineProperty(o, "default", { enumerable: true, value: v }); -}) : function(o, v) { - o["default"] = v; -}); -var __importStar = (this && this.__importStar) || (function () { - var ownKeys = function(o) { - ownKeys = Object.getOwnPropertyNames || function (o) { - var ar = []; - for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; - return ar; - }; - return ownKeys(o); - }; - return function (mod) { - if (mod && mod.__esModule) return mod; - var result = {}; - if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); - __setModuleDefault(result, mod); - return result; - }; -})(); -var __importDefault = (this && this.__importDefault) || function (mod) { - return (mod && mod.__esModule) ? mod : { "default": mod }; -}; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.Web3Adapter = void 0; -exports.spinUpEVault = spinUpEVault; -exports.createGroupEVault = createGroupEVault; -const fs = __importStar(require("node:fs/promises")); -const node_path_1 = __importDefault(require("node:path")); -const axios_1 = __importDefault(require("axios")); -const uuid_1 = require("uuid"); -const db_1 = require("./db"); -const evault_1 = require("./evault/evault"); -const logging_1 = require("./logging"); -const mapper_1 = require("./mapper/mapper"); -/** - * Standalone function to spin up an eVault - * @param registryUrl - URL of the registry service - * @param provisionerUrl - URL of the provisioner service - * @param verificationCode - Optional verification code, defaults to demo code - * @returns Promise with eVault details (w3id, uri) - */ -async function spinUpEVault(registryUrl, provisionerUrl, verificationCode) { - const DEMO_CODE_W3DS = "d66b7138-538a-465f-a6ce-f6985854c3f4"; - const finalVerificationCode = verificationCode || DEMO_CODE_W3DS; - try { - const entropyResponse = await axios_1.default.get(new URL("/entropy", registryUrl).toString()); - const registryEntropy = entropyResponse.data.token; - const namespace = (0, uuid_1.v4)(); - const provisionResponse = await axios_1.default.post(new URL("/provision", provisionerUrl).toString(), { - registryEntropy, - namespace, - verificationId: finalVerificationCode, - }); - if (!provisionResponse.data.success) { - throw new Error(`Failed to provision eVault: ${provisionResponse.data.message || "Unknown error"}`); - } - return { - w3id: provisionResponse.data.w3id, - uri: provisionResponse.data.uri, - }; - } - catch (error) { - if (axios_1.default.isAxiosError(error)) { - throw new Error(`Failed to spin up eVault: ${error.response?.data?.message || error.message}`); - } - throw new Error(`Failed to spin up eVault: ${error instanceof Error ? error.message : "Unknown error"}`); - } -} -/** - * Standalone function to create a group eVault with GroupManifest - * @param registryUrl - URL of the registry service - * @param provisionerUrl - URL of the provisioner service - * @param groupData - Group data for the manifest - * @param verificationCode - Optional verification code, defaults to demo code - * @returns Promise with eVault details (w3id, uri, manifestId) - */ -async function createGroupEVault(registryUrl, provisionerUrl, groupData, verificationCode) { - const DEMO_CODE_W3DS = "d66b7138-538a-465f-a6ce-f6985854c3f4"; - const finalVerificationCode = verificationCode || DEMO_CODE_W3DS; - try { - // Step 1: Spin up the eVault - const evault = await spinUpEVault(registryUrl, provisionerUrl, finalVerificationCode); - // Step 2: Create GroupManifest with exponential backoff - const manifestId = await createGroupManifestWithRetry(registryUrl, evault.w3id, groupData); - return { - w3id: evault.w3id, - uri: evault.uri, - manifestId, - }; - } - catch (error) { - if (axios_1.default.isAxiosError(error)) { - throw new Error(`Failed to create group eVault: ${error.response?.data?.message || error.message}`); - } - throw new Error(`Failed to create group eVault: ${error instanceof Error ? error.message : "Unknown error"}`); - } -} -/** - * Create GroupManifest in eVault with exponential backoff retry mechanism - */ -async function createGroupManifestWithRetry(registryUrl, w3id, groupData, maxRetries = 10) { - const now = new Date().toISOString(); - const groupManifest = { - eName: w3id, - name: groupData.name, - avatar: groupData.avatar, - description: groupData.description, - members: groupData.members, - charter: groupData.charter, - admins: groupData.admins, - owner: groupData.owner, - createdAt: now, - updatedAt: now, - }; - for (let attempt = 1; attempt <= maxRetries; attempt++) { - try { - console.log(`Attempting to create GroupManifest in eVault (attempt ${attempt}/${maxRetries})`); - const response = await axios_1.default.get(new URL(`resolve?w3id=${w3id}`, registryUrl).toString()); - const endpoint = new URL("/graphql", response.data.uri).toString(); - const { GraphQLClient } = await Promise.resolve().then(() => __importStar(require("graphql-request"))); - const client = new GraphQLClient(endpoint); - const STORE_META_ENVELOPE = ` - mutation StoreMetaEnvelope($input: MetaEnvelopeInput!) { - storeMetaEnvelope(input: $input) { - metaEnvelope { - id - ontology - parsed - } - } - } - `; - const result = await client.request(STORE_META_ENVELOPE, { - input: { - ontology: "550e8400-e29b-41d4-a716-446655440001", // GroupManifest schema ID - payload: groupManifest, - acl: ["*"], - }, - }); - const manifestId = result.storeMetaEnvelope.metaEnvelope.id; - console.log("GroupManifest created successfully in eVault:", manifestId); - return manifestId; - } - catch (error) { - console.error(`Failed to create GroupManifest in eVault (attempt ${attempt}/${maxRetries}):`, error); - if (attempt === maxRetries) { - console.error("Max retries reached, giving up on GroupManifest creation"); - throw error; - } - // Wait before retrying (exponential backoff) - const delay = Math.min(1000 * 2 ** (attempt - 1), 10000); - console.log(`Waiting ${delay}ms before retry...`); - await new Promise((resolve) => setTimeout(resolve, delay)); - } - } - throw new Error("Failed to create GroupManifest after all retries"); -} -class Web3Adapter { - constructor(config) { - this.config = config; - this.mapping = {}; - this.lockedIds = []; - this.readPaths(); - this.mappingDb = new db_1.MappingDatabase(config.dbPath); - this.evaultClient = new evault_1.EVaultClient(config.registryUrl, config.platform); - this.platform = config.platform; - } - async readPaths() { - const allRawFiles = await fs.readdir(this.config.schemasPath); - const mappingFiles = allRawFiles.filter((p) => p.endsWith(".json")); - for (const mappingFile of mappingFiles) { - const mappingFileContent = await fs.readFile(node_path_1.default.join(this.config.schemasPath, mappingFile)); - const mappingParsed = JSON.parse(mappingFileContent.toString()); - this.mapping[mappingParsed.tableName] = mappingParsed; - } - } - addToLockedIds(id) { - this.lockedIds.push(id); - console.log("Added", this.lockedIds); - setTimeout(() => { - this.lockedIds = this.lockedIds.filter((f) => f !== id); - }, 15000); - } - async handleChange(props) { - const { data, tableName, participants } = props; - const existingGlobalId = await this.mappingDb.getGlobalId(data.id); - if (!this.mapping[tableName]) - return; - if (this.mapping[tableName].readOnly) { - // early return on mappings which are readonly so as to not - // sync any update to the eVault which is not warranted - return; - } - console.log("We get here?"); - // If we already have a mapping, use that global ID - logging_1.logger.info({ - message: "Handling change", - dataId: data.id, - tableName, - existingGlobalId, - participants, - }); - if (existingGlobalId) { - if (this.lockedIds.includes(existingGlobalId)) - return; - const global = await (0, mapper_1.toGlobal)({ - data, - mapping: this.mapping[tableName], - mappingStore: this.mappingDb, - }); - this.evaultClient - .updateMetaEnvelopeById(existingGlobalId, { - id: existingGlobalId, - w3id: global.ownerEvault, - data: global.data, - schemaId: this.mapping[tableName].schemaId, - }) - .catch(() => console.error("failed to sync update")); - return { - id: existingGlobalId, - w3id: global.ownerEvault, - data: global.data, - schemaId: this.mapping[tableName].schemaId, - }; - } - const global = await (0, mapper_1.toGlobal)({ - data, - mapping: this.mapping[tableName], - mappingStore: this.mappingDb, - }); - let globalId; - if (global.ownerEvault) { - globalId = await this.evaultClient.storeMetaEnvelope({ - id: null, - w3id: global.ownerEvault, - data: global.data, - schemaId: this.mapping[tableName].schemaId, - }); - console.log("created new meta-env", globalId); - } - else { - return; - } - // Store the mapping - await this.mappingDb.storeMapping({ - localId: data.id, - globalId, - }); - // Handle references for other participants - const otherEvaults = (participants ?? []).filter((i) => i !== global.ownerEvault); - for (const evault of otherEvaults) { - await this.evaultClient.storeReference(`${global.ownerEvault}/${globalId}`, evault); - } - return { - id: globalId, - w3id: global.ownerEvault, - data: global.data, - schemaId: this.mapping[tableName].schemaId, - }; - } - async fromGlobal(props) { - const { data, mapping } = props; - const local = await (0, mapper_1.fromGlobal)({ - data, - mapping, - mappingStore: this.mappingDb, - }); - return local; - } - /** - * Spins up an eVault by getting entropy from registry and provisioning it - * @param verificationCode - Optional verification code, defaults to demo code - * @param provisionerUrl - Optional provisioner URL, defaults to config - * @returns Promise with eVault details (w3id, uri) - */ - async spinUpEVault(verificationCode, provisionerUrl) { - const finalProvisionerUrl = provisionerUrl || this.config.provisionerUrl; - if (!finalProvisionerUrl) { - throw new Error("Provisioner URL is required. Please provide it in config or as parameter."); - } - return spinUpEVault(this.config.registryUrl, finalProvisionerUrl, verificationCode); - } - /** - * Creates a group eVault with GroupManifest - * @param groupData - Group data for the manifest - * @param verificationCode - Optional verification code, defaults to demo code - * @param provisionerUrl - Optional provisioner URL, defaults to config - * @returns Promise with eVault details (w3id, uri, manifestId) - */ - async createGroupEVault(groupData, verificationCode, provisionerUrl) { - const finalProvisionerUrl = provisionerUrl || this.config.provisionerUrl; - if (!finalProvisionerUrl) { - throw new Error("Provisioner URL is required. Please provide it in config or as parameter."); - } - return createGroupEVault(this.config.registryUrl, finalProvisionerUrl, groupData, verificationCode); - } -} -exports.Web3Adapter = Web3Adapter; -//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/infrastructure/web3-adapter/src/index.js.map b/infrastructure/web3-adapter/src/index.js.map deleted file mode 100644 index ccd8103e..00000000 --- a/infrastructure/web3-adapter/src/index.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/infrastructure/web3-adapter/src/index.ts b/infrastructure/web3-adapter/src/index.ts index 71d39d76..21be3051 100644 --- a/infrastructure/web3-adapter/src/index.ts +++ b/infrastructure/web3-adapter/src/index.ts @@ -312,17 +312,8 @@ export class Web3Adapter { return; } - console.log("We get here?"); - // If we already have a mapping, use that global ID - - logger.info({ - message: "Handling change", - dataId: data.id, - tableName, - existingGlobalId, - participants, - }); + if (existingGlobalId) { if (this.lockedIds.includes(existingGlobalId)) return; const global = await toGlobal({ @@ -340,11 +331,18 @@ export class Web3Adapter { }) .catch(() => console.error("failed to sync update")); + logger.info({ + tableName, + id: existingGlobalId, + platform: this.platform, + w3id: global.ownerEvault, + }); + + return { id: existingGlobalId, w3id: global.ownerEvault as string, - data: global.data, - schemaId: this.mapping[tableName].schemaId, + schemaId: this.mapping[tableName].tableName, }; } @@ -384,6 +382,13 @@ export class Web3Adapter { ); } + logger.info({ + tableName, + id: globalId, + w3id: global.ownerEvault, + platform: this.platform + }); + return { id: globalId, w3id: global.ownerEvault as string, diff --git a/infrastructure/web3-adapter/src/logging/index.d.ts b/infrastructure/web3-adapter/src/logging/index.d.ts deleted file mode 100644 index 7fec87f5..00000000 --- a/infrastructure/web3-adapter/src/logging/index.d.ts +++ /dev/null @@ -1,3 +0,0 @@ -export * from "./transport"; -export * from "./logger"; -//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/infrastructure/web3-adapter/src/logging/index.d.ts.map b/infrastructure/web3-adapter/src/logging/index.d.ts.map deleted file mode 100644 index 65a5999e..00000000 --- a/infrastructure/web3-adapter/src/logging/index.d.ts.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,cAAc,UAAU,CAAC"} \ No newline at end of file diff --git a/infrastructure/web3-adapter/src/logging/index.js b/infrastructure/web3-adapter/src/logging/index.js deleted file mode 100644 index 06388ce6..00000000 --- a/infrastructure/web3-adapter/src/logging/index.js +++ /dev/null @@ -1,19 +0,0 @@ -"use strict"; -var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - var desc = Object.getOwnPropertyDescriptor(m, k); - if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { - desc = { enumerable: true, get: function() { return m[k]; } }; - } - Object.defineProperty(o, k2, desc); -}) : (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - o[k2] = m[k]; -})); -var __exportStar = (this && this.__exportStar) || function(m, exports) { - for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p); -}; -Object.defineProperty(exports, "__esModule", { value: true }); -__exportStar(require("./transport"), exports); -__exportStar(require("./logger"), exports); -//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/infrastructure/web3-adapter/src/logging/index.js.map b/infrastructure/web3-adapter/src/logging/index.js.map deleted file mode 100644 index 72bdfc16..00000000 --- a/infrastructure/web3-adapter/src/logging/index.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,8CAA4B;AAC5B,2CAAyB"} \ No newline at end of file diff --git a/infrastructure/web3-adapter/src/logging/logger.d.ts b/infrastructure/web3-adapter/src/logging/logger.d.ts deleted file mode 100644 index 93d8f742..00000000 --- a/infrastructure/web3-adapter/src/logging/logger.d.ts +++ /dev/null @@ -1,3 +0,0 @@ -import pino from "pino"; -export declare const logger: pino.Logger; -//# sourceMappingURL=logger.d.ts.map \ No newline at end of file diff --git a/infrastructure/web3-adapter/src/logging/logger.d.ts.map b/infrastructure/web3-adapter/src/logging/logger.d.ts.map deleted file mode 100644 index 607ec511..00000000 --- a/infrastructure/web3-adapter/src/logging/logger.d.ts.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["logger.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,MAAM,CAAC;AAGxB,eAAO,MAAM,MAAM,6BAAkB,CAAC"} \ No newline at end of file diff --git a/infrastructure/web3-adapter/src/logging/logger.js b/infrastructure/web3-adapter/src/logging/logger.js deleted file mode 100644 index 71ce7443..00000000 --- a/infrastructure/web3-adapter/src/logging/logger.js +++ /dev/null @@ -1,10 +0,0 @@ -"use strict"; -var __importDefault = (this && this.__importDefault) || function (mod) { - return (mod && mod.__esModule) ? mod : { "default": mod }; -}; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.logger = void 0; -const pino_1 = __importDefault(require("pino")); -const transport_1 = require("./transport"); -exports.logger = (0, pino_1.default)(transport_1.transport); -//# sourceMappingURL=logger.js.map \ No newline at end of file diff --git a/infrastructure/web3-adapter/src/logging/logger.js.map b/infrastructure/web3-adapter/src/logging/logger.js.map deleted file mode 100644 index bdbf0d3d..00000000 --- a/infrastructure/web3-adapter/src/logging/logger.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"logger.js","sourceRoot":"","sources":["logger.ts"],"names":[],"mappings":";;;;;;AAAA,gDAAwB;AACxB,2CAAwC;AAE3B,QAAA,MAAM,GAAG,IAAA,cAAI,EAAC,qBAAS,CAAC,CAAC"} \ No newline at end of file diff --git a/infrastructure/web3-adapter/src/logging/transport.d.ts b/infrastructure/web3-adapter/src/logging/transport.d.ts deleted file mode 100644 index a84a6199..00000000 --- a/infrastructure/web3-adapter/src/logging/transport.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -export declare const transport: any; -//# sourceMappingURL=transport.d.ts.map \ No newline at end of file diff --git a/infrastructure/web3-adapter/src/logging/transport.d.ts.map b/infrastructure/web3-adapter/src/logging/transport.d.ts.map deleted file mode 100644 index ecf54686..00000000 --- a/infrastructure/web3-adapter/src/logging/transport.d.ts.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"transport.d.ts","sourceRoot":"","sources":["transport.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,SAAS,KAYpB,CAAC"} \ No newline at end of file diff --git a/infrastructure/web3-adapter/src/logging/transport.js b/infrastructure/web3-adapter/src/logging/transport.js deleted file mode 100644 index a6962369..00000000 --- a/infrastructure/web3-adapter/src/logging/transport.js +++ /dev/null @@ -1,18 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.transport = void 0; -const pino_1 = require("pino"); -exports.transport = (0, pino_1.transport)({ - target: "pino-loki", - options: { - host: process.env.LOKI_URL || "http://localhost:3100", - labels: { - app: "web3-adapter", - }, - basicAuth: { - username: process.env.LOKI_USERNAME || "admin", - password: process.env.LOKI_PASSWORD || "admin", - }, - }, -}); -//# sourceMappingURL=transport.js.map \ No newline at end of file diff --git a/infrastructure/web3-adapter/src/logging/transport.js.map b/infrastructure/web3-adapter/src/logging/transport.js.map deleted file mode 100644 index e0e660c7..00000000 --- a/infrastructure/web3-adapter/src/logging/transport.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"transport.js","sourceRoot":"","sources":["transport.ts"],"names":[],"mappings":";;;AAAA,+BAAkD;AAGrC,QAAA,SAAS,GAAG,IAAA,gBAAa,EAAc;IAChD,MAAM,EAAE,WAAW;IACnB,OAAO,EAAE;QACL,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC,QAAQ,IAAI,uBAAuB;QACrD,MAAM,EAAE;YACJ,GAAG,EAAE,cAAc;SACtB;QACD,SAAS,EAAE;YACP,QAAQ,EAAE,OAAO,CAAC,GAAG,CAAC,aAAa,IAAI,OAAO;YAC9C,QAAQ,EAAE,OAAO,CAAC,GAAG,CAAC,aAAa,IAAI,OAAO;SACjD;KACJ;CACJ,CAAC,CAAC"} \ No newline at end of file diff --git a/infrastructure/web3-adapter/src/mapper/mapper.d.ts b/infrastructure/web3-adapter/src/mapper/mapper.d.ts deleted file mode 100644 index 09a3f57b..00000000 --- a/infrastructure/web3-adapter/src/mapper/mapper.d.ts +++ /dev/null @@ -1,5 +0,0 @@ -import type { IMapperResponse, IMappingConversionOptions } from "./mapper.types"; -export declare function getValueByPath(obj: Record, path: string): any; -export declare function fromGlobal({ data, mapping, mappingStore, }: IMappingConversionOptions): Promise>; -export declare function toGlobal({ data, mapping, mappingStore, }: IMappingConversionOptions): Promise; -//# sourceMappingURL=mapper.d.ts.map \ No newline at end of file diff --git a/infrastructure/web3-adapter/src/mapper/mapper.d.ts.map b/infrastructure/web3-adapter/src/mapper/mapper.d.ts.map deleted file mode 100644 index 56c11346..00000000 --- a/infrastructure/web3-adapter/src/mapper/mapper.d.ts.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"mapper.d.ts","sourceRoot":"","sources":["mapper.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACR,eAAe,EACf,yBAAyB,EAC5B,MAAM,gBAAgB,CAAC;AAGxB,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,IAAI,EAAE,MAAM,GAAG,GAAG,CA2B1E;AAwBD,wBAAsB,UAAU,CAAC,EAC7B,IAAI,EACJ,OAAO,EACP,YAAY,GACf,EAAE,yBAAyB,GAAG,OAAO,CAAC,IAAI,CAAC,eAAe,EAAE,aAAa,CAAC,CAAC,CA4E3E;AA8BD,wBAAsB,QAAQ,CAAC,EAC3B,IAAI,EACJ,OAAO,EACP,YAAY,GACf,EAAE,yBAAyB,GAAG,OAAO,CAAC,eAAe,CAAC,CA8GtD"} \ No newline at end of file diff --git a/infrastructure/web3-adapter/src/mapper/mapper.js b/infrastructure/web3-adapter/src/mapper/mapper.js deleted file mode 100644 index 4ffb8db4..00000000 --- a/infrastructure/web3-adapter/src/mapper/mapper.js +++ /dev/null @@ -1,234 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.getValueByPath = getValueByPath; -exports.fromGlobal = fromGlobal; -exports.toGlobal = toGlobal; -// biome-ignore lint/suspicious/noExplicitAny: -function getValueByPath(obj, path) { - // Handle array mapping case (e.g., "images[].src") - if (path.includes("[]")) { - const [arrayPath, fieldPath] = path.split("[]"); - const array = getValueByPath(obj, arrayPath); - if (!Array.isArray(array)) { - return []; - } - // If there's a field path after [], map through the array - if (fieldPath) { - return array.map((item) => getValueByPath(item, fieldPath.slice(1))); // Remove the leading dot - } - return array; - } - // Handle regular path case - const parts = path.split("."); - // biome-ignore lint/suspicious/noExplicitAny: - return parts.reduce((acc, part) => { - if (acc === null || acc === undefined) - return undefined; - return acc[part]; - }, obj); -} -async function extractOwnerEvault(data, ownerEnamePath) { - if (!ownerEnamePath || ownerEnamePath === "null") { - return null; - } - if (!ownerEnamePath.includes("(")) { - return data[ownerEnamePath] || null; - } - const [_, fieldPathRaw] = ownerEnamePath.split("("); - const fieldPath = fieldPathRaw.replace(")", ""); - let value = getValueByPath(data, fieldPath); - if (Array.isArray(value)) - return value[0]; - console.log("OWNER PATH", value); - if (value.includes("(") && value.includes(")")) { - value = value.split("(")[1].split(")")[0]; - } - return value || null; -} -async function fromGlobal({ data, mapping, mappingStore, }) { - const result = {}; - for (const [localKey, globalPathRaw] of Object.entries(mapping.localToUniversalMap)) { - let value; - const targetKey = localKey; - let tableRef = null; - const internalFnMatch = globalPathRaw.match(/^__(\w+)\((.+)\)$/); - if (internalFnMatch) { - const [, outerFn, innerExpr] = internalFnMatch; - if (outerFn === "date") { - const calcMatch = innerExpr.match(/^calc\((.+)\)$/); - if (calcMatch) { - const calcResult = evaluateCalcExpression(calcMatch[1], data); - value = - calcResult !== undefined - ? new Date(calcResult).toISOString() - : undefined; - } - else { - const rawVal = getValueByPath(data, innerExpr); - if (typeof rawVal === "number") { - value = new Date(rawVal).toISOString(); - } - else if (rawVal?._seconds) { - value = new Date(rawVal._seconds * 1000).toISOString(); - } - else if (rawVal instanceof Date) { - value = rawVal.toISOString(); - } - else { - value = undefined; - } - } - } - else if (outerFn === "calc") { - value = evaluateCalcExpression(innerExpr, data); - } - result[targetKey] = value; - continue; - } - let pathRef = globalPathRaw; - if (globalPathRaw.includes("(") && globalPathRaw.includes(")")) { - tableRef = globalPathRaw.split("(")[0]; - } - if (pathRef.includes(",")) { - pathRef = pathRef.split(",")[1]; - } - value = getValueByPath(data, pathRef); - if (tableRef) { - if (Array.isArray(value)) { - value = await Promise.all(value.map(async (v) => { - const localId = await mappingStore.getLocalId(v); - return localId ? `${tableRef}(${localId})` : null; - })); - } - else { - value = await mappingStore.getLocalId(value); - value = value ? `${tableRef}(${value})` : null; - } - } - result[localKey] = value; - } - return { - data: result, - }; -} -function evaluateCalcExpression(expr, -// biome-ignore lint/suspicious/noExplicitAny: -context) { - const tokens = expr - .split(/[^\w.]+/) - .map((t) => t.trim()) - .filter(Boolean); - let resolvedExpr = expr; - for (const token of tokens) { - const value = getValueByPath(context, token); - if (typeof value !== "undefined") { - resolvedExpr = resolvedExpr.replace(new RegExp(`\\b${token.replace(".", "\\.")}\\b`, "g"), value); - } - } - try { - return Function(`use strict"; return (${resolvedExpr})`)(); - } - catch { - return undefined; - } -} -async function toGlobal({ data, mapping, mappingStore, }) { - const result = {}; - for (const [localKey, globalPathRaw] of Object.entries(mapping.localToUniversalMap)) { - // biome-ignore lint/suspicious/noExplicitAny: - let value; - let targetKey = globalPathRaw; - if (globalPathRaw.includes(",")) { - const [_, alias] = globalPathRaw.split(","); - targetKey = alias; - } - if (localKey.includes("[]")) { - const [arrayPath, innerPathRaw] = localKey.split("[]"); - const cleanInnerPath = innerPathRaw.startsWith(".") - ? innerPathRaw.slice(1) - : innerPathRaw; - const array = getValueByPath(data, arrayPath); - value = Array.isArray(array) - ? array.map((item) => getValueByPath(item, cleanInnerPath)) - : undefined; - result[targetKey] = value; - continue; - } - const internalFnMatch = globalPathRaw.match(/^__(\w+)\((.+)\)$/); - if (internalFnMatch) { - const [, outerFn, innerExpr] = internalFnMatch; - if (outerFn === "date") { - const calcMatch = innerExpr.match(/^calc\((.+)\)$/); - if (calcMatch) { - const calcResult = evaluateCalcExpression(calcMatch[1], data); - value = - calcResult !== undefined - ? new Date(calcResult).toISOString() - : undefined; - } - else { - const rawVal = getValueByPath(data, innerExpr); - if (typeof rawVal === "number") { - value = new Date(rawVal).toISOString(); - } - else if (rawVal?._seconds) { - value = new Date(rawVal._seconds * 1000).toISOString(); - } - else if (rawVal instanceof Date) { - value = rawVal.toISOString(); - } - else { - value = undefined; - } - } - } - else if (outerFn === "calc") { - value = evaluateCalcExpression(innerExpr, data); - } - result[targetKey] = value; - continue; - } - const relationMatch = globalPathRaw.match(/^(\w+)\((.+?)\)(\[\])?$/); - if (relationMatch) { - const [, tableRef, pathInData, isArray] = relationMatch; - const refValue = getValueByPath(data, pathInData); - if (isArray) { - value = Array.isArray(refValue) - ? refValue.map((v) => `@${v}`) - : []; - } - else { - value = refValue ? `@${refValue}` : undefined; - } - result[targetKey] = value; - continue; - } - let pathRef = globalPathRaw.includes(",") - ? globalPathRaw - : localKey; - let tableRef = null; - if (globalPathRaw.includes("(") && globalPathRaw.includes(")")) { - pathRef = globalPathRaw.split("(")[1].split(")")[0]; - tableRef = globalPathRaw.split("(")[0]; - } - if (globalPathRaw.includes(",")) { - pathRef = pathRef.split(",")[0]; - } - value = getValueByPath(data, pathRef); - if (tableRef) { - if (Array.isArray(value)) { - value = await Promise.all(value.map(async (v) => (await mappingStore.getGlobalId(v)) ?? undefined)); - } - else { - value = (await mappingStore.getGlobalId(value)) ?? undefined; - } - } - result[targetKey] = value; - } - const ownerEvault = await extractOwnerEvault(data, mapping.ownerEnamePath); - return { - ownerEvault, - data: result, - }; -} -//# sourceMappingURL=mapper.js.map \ No newline at end of file diff --git a/infrastructure/web3-adapter/src/mapper/mapper.js.map b/infrastructure/web3-adapter/src/mapper/mapper.js.map deleted file mode 100644 index 78cdb3e9..00000000 --- a/infrastructure/web3-adapter/src/mapper/mapper.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"mapper.js","sourceRoot":"","sources":["mapper.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/infrastructure/web3-adapter/src/mapper/mapper.types.d.ts b/infrastructure/web3-adapter/src/mapper/mapper.types.d.ts deleted file mode 100644 index e233dd4c..00000000 --- a/infrastructure/web3-adapter/src/mapper/mapper.types.d.ts +++ /dev/null @@ -1,47 +0,0 @@ -import type { MappingDatabase } from "../db"; -export interface IMapping { - /** - * Name of the local table, this would be consumed by other schemas to - * identify relations - */ - tableName: string; - /** - * Schema Identifier for the global schema this table maps to - */ - schemaId: string; - /** - * Path used to determine which eVault owns this entry. - * - * This can be a direct field on the table or a nested path via a foreign table. - * - * - For direct fields, use the field name (e.g. `"ename"`). - * - For nested ownership, use a function-like syntax to reference another table - * and field (e.g. `"user(createdBy.ename)"` means follow the `createdBy` field, - * then resolve `ename` from the `user` table). - * - * Use `tableName(fieldPath)` to reference a field from another table. - * - * @example "ename" — direct reference to a field on the same table - * @example "user(createdBy.ename)" — nested reference via the `user` table - */ - ownerEnamePath: string; - /** - * String to String mapping between what path maps to what global ontology - */ - localToUniversalMap: Record; - /** - * If true, this mapping will not trigger handleChange and will be treated as read-only. - * Useful for entities that should not be synced to eVaults. - */ - readOnly?: boolean; -} -export interface IMappingConversionOptions { - data: Record; - mapping: IMapping; - mappingStore: MappingDatabase; -} -export interface IMapperResponse { - ownerEvault: string | null; - data: Record; -} -//# sourceMappingURL=mapper.types.d.ts.map \ No newline at end of file diff --git a/infrastructure/web3-adapter/src/mapper/mapper.types.d.ts.map b/infrastructure/web3-adapter/src/mapper/mapper.types.d.ts.map deleted file mode 100644 index 0219bb33..00000000 --- a/infrastructure/web3-adapter/src/mapper/mapper.types.d.ts.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"mapper.types.d.ts","sourceRoot":"","sources":["mapper.types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,OAAO,CAAC;AAE7C,MAAM,WAAW,QAAQ;IACrB;;;OAGG;IACH,SAAS,EAAE,MAAM,CAAC;IAElB;;OAEG;IACH,QAAQ,EAAE,MAAM,CAAC;IAEjB;;;;;;;;;;;;;;OAcG;IACH,cAAc,EAAE,MAAM,CAAC;IAEvB;;OAEG;IACH,mBAAmB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAE5C;;;OAGG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,MAAM,WAAW,yBAAyB;IACtC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC9B,OAAO,EAAE,QAAQ,CAAC;IAClB,YAAY,EAAE,eAAe,CAAC;CACjC;AAED,MAAM,WAAW,eAAe;IAC5B,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACjC"} \ No newline at end of file diff --git a/infrastructure/web3-adapter/src/mapper/mapper.types.js b/infrastructure/web3-adapter/src/mapper/mapper.types.js deleted file mode 100644 index ea11c714..00000000 --- a/infrastructure/web3-adapter/src/mapper/mapper.types.js +++ /dev/null @@ -1,3 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -//# sourceMappingURL=mapper.types.js.map \ No newline at end of file diff --git a/infrastructure/web3-adapter/src/mapper/mapper.types.js.map b/infrastructure/web3-adapter/src/mapper/mapper.types.js.map deleted file mode 100644 index 4d49fa79..00000000 --- a/infrastructure/web3-adapter/src/mapper/mapper.types.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"mapper.types.js","sourceRoot":"","sources":["mapper.types.ts"],"names":[],"mappings":""} \ No newline at end of file diff --git a/platforms/eVoting/src/app/(app)/[id]/page.tsx b/platforms/eVoting/src/app/(app)/[id]/page.tsx index 5efc5469..9a503ccd 100644 --- a/platforms/eVoting/src/app/(app)/[id]/page.tsx +++ b/platforms/eVoting/src/app/(app)/[id]/page.tsx @@ -10,6 +10,7 @@ import { Clock, Users, BarChart3, + Shield, } from "lucide-react"; import { Button } from "@/components/ui/button"; import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group"; @@ -19,21 +20,35 @@ import { useToast } from "@/hooks/use-toast"; import { useAuth } from "@/lib/auth-context"; import { pollApi, type Poll } from "@/lib/pollApi"; import Link from "next/link"; + +import BlindVotingInterface from "@/components/blind-voting-interface"; +import VotingInterface from "@/components/voting-interface"; import { SigningInterface } from "@/components/signing-interface"; export default function Vote({ params }: { params: Promise<{ id: string }> }) { const { id } = use(params); const pollId = id || null; const { toast } = useToast(); - const { isAuthenticated, isLoading: authLoading } = useAuth(); - const [selectedOption, setSelectedOption] = useState(null); + const { isAuthenticated, isLoading: authLoading, user } = useAuth(); + const [selectedPoll, setSelectedPoll] = useState(null); + const [isLoading, setIsLoading] = useState(true); - const [rankVotes, setRankVotes] = useState<{ [key: number]: number }>({}); + const [showMyVote, setShowMyVote] = useState(false); // For viewing private poll votes + const [showSigningInterface, setShowSigningInterface] = useState(false); + + // Add missing variables for BlindVotingInterface + const [hasVoted, setHasVoted] = useState(false); + const [blindVoteResults, setBlindVoteResults] = useState(null); + const [isLoadingBlindResults, setIsLoadingBlindResults] = useState(false); + + // Add state variables for different voting modes + const [selectedOption, setSelectedOption] = useState(null); const [pointVotes, setPointVotes] = useState<{ [key: number]: number }>({}); + const [rankVotes, setRankVotes] = useState<{ [key: number]: number }>({}); const [timeRemaining, setTimeRemaining] = useState(""); - // Calculate total points for points-based voting - const totalPoints = Object.values(pointVotes).reduce((sum, points) => sum + (points || 0), 0); + // Calculate total points for point voting + const totalPoints = Object.values(pointVotes).reduce((sum, points) => sum + points, 0); // TODO: Redirect to login if not authenticated // useEffect(() => { @@ -57,9 +72,33 @@ export default function Vote({ params }: { params: Promise<{ id: string }> }) { } }, [pollId]); - const [selectedPoll, setSelectedPoll] = useState(null); - const [isLoading, setIsLoading] = useState(true); - const [showSigningInterface, setShowSigningInterface] = useState(false); + // Mock onVoteSubmitted function for blind voting + const onVoteSubmitted = () => { + setHasVoted(true); + // Refresh poll data after blind vote submission + fetchPoll(); + // Also refresh blind vote results + fetchBlindVoteResults(); + }; + + // Fetch blind vote results + const fetchBlindVoteResults = async () => { + if (!pollId || selectedPoll?.visibility !== "private") return; + + try { + setIsLoadingBlindResults(true); + const apiBaseUrl = process.env.NEXT_PUBLIC_EVOTING_BASE_URL || 'http://localhost:7777'; + const response = await fetch(`${apiBaseUrl}/api/polls/${pollId}/blind-tally`); + if (response.ok) { + const results = await response.json(); + setBlindVoteResults(results); + } + } catch (error) { + console.error("Failed to fetch blind vote results:", error); + } finally { + setIsLoadingBlindResults(false); + } + }; // Fetch poll data const fetchPoll = async () => { @@ -79,6 +118,20 @@ export default function Vote({ params }: { params: Promise<{ id: string }> }) { fetchPoll(); }, [pollId]); + // Fetch blind vote results when poll loads (for private polls) + useEffect(() => { + if (selectedPoll && selectedPoll.visibility === "private") { + fetchBlindVoteResults(); + } + }, [selectedPoll]); + + // Fetch blind vote results when poll expires (for private polls) + useEffect(() => { + if (selectedPoll && selectedPoll.visibility === "private" && timeRemaining === "Voting has ended") { + fetchBlindVoteResults(); + } + }, [timeRemaining, selectedPoll]); + // Check if voting is still allowed const isVotingAllowed = selectedPoll && @@ -145,12 +198,12 @@ export default function Vote({ params }: { params: Promise<{ id: string }> }) { // Fetch vote status and results const fetchVoteData = async () => { - if (!pollId) return; + if (!pollId || !user?.id) return; try { const [voteStatusData, resultsData] = await Promise.all([ - pollApi.getUserVote(pollId), + pollApi.getUserVote(pollId, user.id), pollApi.getPollResults(pollId) ]); setVoteStatus(voteStatusData); @@ -162,7 +215,39 @@ export default function Vote({ params }: { params: Promise<{ id: string }> }) { useEffect(() => { fetchVoteData(); - }, [pollId]); + }, [pollId, user?.id]); + + + + if (isLoading) { + return ( +
+
+
+ ); + } + + if (!selectedPoll) { + return ( +
+
+

+ Vote Not Found +

+

+ The vote you're looking for doesn't exist or has been + removed. +

+ + + +
+
+ ); + } const handleVoteSubmit = async () => { if (!selectedPoll || !pollId) return; @@ -196,36 +281,6 @@ export default function Vote({ params }: { params: Promise<{ id: string }> }) { setShowSigningInterface(true); }; - if (isLoading) { - return ( -
-
-
- ); - } - - if (!selectedPoll) { - return ( -
-
-

- Vote Not Found -

-

- The vote you're looking for doesn't exist or has been - removed. -

- - - -
-
- ); - } - return (
@@ -360,26 +415,45 @@ export default function Vote({ params }: { params: Promise<{ id: string }> }) {
- {/* Show results with user's choice highlighted */} -
-
- -
-

- You voted for:{" "} - { - selectedPoll.options[ - parseInt(voteStatus.vote?.optionId || "0") - ] - } -

-

- Here are the current results for this - poll. -

+ {/* Show results with user's choice highlighted - HIDE for private polls */} + {selectedPoll.visibility !== "private" && ( +
+
+ +
+

+ You voted for:{" "} + { + selectedPoll.options[ + parseInt(voteStatus.vote?.optionId || "0") + ] + } +

+

+ Here are the current results for this + poll. +

+
-
+ )} + + {/* For private polls, show a different message */} + {selectedPoll.visibility === "private" && ( +
+
+ +
+

+ Private Poll - Your vote is hidden +

+

+ This is a private poll. Your individual vote remains hidden until revealed. +

+
+
+
+ )}
{/* Poll Statistics */} @@ -445,7 +519,7 @@ export default function Vote({ params }: { params: Promise<{ id: string }> }) {
-
+
{/* Final Results */}

@@ -453,10 +527,59 @@ export default function Vote({ params }: { params: Promise<{ id: string }> }) { Final Results

- {resultsData ? ( + {/* For private polls, show blind vote results */} + {selectedPoll.visibility === "private" && blindVoteResults ? ( <> - - + {blindVoteResults.optionResults && blindVoteResults.optionResults.length > 0 ? ( + blindVoteResults.optionResults.map((result, index) => { + const isWinner = result.voteCount === Math.max(...blindVoteResults.optionResults.map(r => r.voteCount)); + const percentage = blindVoteResults.totalVotes > 0 ? (result.voteCount / blindVoteResults.totalVotes) * 100 : 0; + return ( +
+
+
+ + {result.optionText || `Option ${index + 1}`} + + {isWinner && ( + + 🏆 Winner + + )} +
+ + {result.voteCount} votes ({percentage.toFixed(1)}%) + +
+
+
+
+
+ ); + }) + ) : ( +
+ No blind vote results available. +
+ )} + + ) : resultsData ? ( + <> + {/* For public polls, show regular results */} {resultsData.results && resultsData.results.length > 0 ? ( resultsData.results.map((result, index) => { const isWinner = result.votes === Math.max(...resultsData.results.map(r => r.votes)); @@ -481,7 +604,7 @@ export default function Vote({ params }: { params: Promise<{ id: string }> }) { )}
- {selectedPoll.mode === "rank" + {selectedPoll.mode === "rank" ? `${result.votes} points` : `${result.votes} votes`} ({result.percentage.toFixed(1)}%) @@ -534,224 +657,278 @@ export default function Vote({ params }: { params: Promise<{ id: string }> }) { ) : (
- {/* Voting Interface based on poll mode */} - {selectedPoll.mode === "normal" && ( -
-

- Select your choice: -

- - setSelectedOption(Number.parseInt(value)) - } - disabled={!isVotingAllowed} - > -
- {selectedPoll.options.map((option, index) => ( -
- - + {/* Check if this is a private poll that requires blind voting */} + {selectedPoll.visibility === "private" ? ( + + ) : ( + <> + {/* Regular Voting Interface based on poll mode */} + {selectedPoll.mode === "normal" && ( +
+

+ Select your choice: +

+ + setSelectedOption(Number.parseInt(value)) + } + disabled={!isVotingAllowed} + > +
+ {selectedPoll.options.map((option, index) => ( +
+ + +
+ ))}
- ))} +
- -
- )} + )} - {selectedPoll.mode === "point" && ( -
-
-

- Distribute your points -

- -
-
-

- You have 100 points to distribute. Assign points to each option based on your preference. -

-
-
- {selectedPoll.options.map((option, index) => ( -
-
- -
-
- { - const value = parseInt(e.target.value) || 0; - setPointVotes(prev => ({ - ...prev, - [index]: value - })); - }} - className="w-20 px-3 py-2 border border-gray-300 rounded-md text-center" - disabled={!isVotingAllowed} - /> - points -
+ {selectedPoll.mode === "point" && ( +
+
+

+ Distribute your points +

+
- ))} -
-
- - Total Points Used: - - - {totalPoints}/100 - +
+

+ You have 100 points to distribute. Assign points to each option based on your preference. +

-
-
-
- )} - - {selectedPoll.mode === "rank" && ( -
-
-

- {(() => { - const currentRank = Object.keys(rankVotes).length + 1; - const maxRanks = Math.min(selectedPoll.options.length, 3); - - if (currentRank > maxRanks) { - return "Ranking Complete"; - } - - const rankText = currentRank === 1 ? "1st" : currentRank === 2 ? "2nd" : currentRank === 3 ? "3rd" : `${currentRank}th`; - return `What's your ${rankText} choice?`; - })()} -

- -
-
-

- Select your choices one by one, starting with your most preferred option. -

-
- { - const optionIndex = parseInt(value); - const currentRank = Object.keys(rankVotes).length + 1; - setRankVotes(prev => ({ - ...prev, - [currentRank]: optionIndex - })); - setSelectedOption(optionIndex); - }} - disabled={!isVotingAllowed} - > -
- {selectedPoll.options.map((option, index) => { - const isRanked = Object.values(rankVotes).includes(index); - const rank = Object.entries(rankVotes).find(([_, optionIndex]) => optionIndex === index)?.[0]; - - return ( +
+ {selectedPoll.options.map((option, index) => (
-
- {!isRanked ? ( - - ) : ( -
- {rank} -
- )} -
- ); - })} + ))} +
+
+ + Total Points Used: + + + {totalPoints}/100 + +
+
+
- -
+ )} + + {selectedPoll.mode === "rank" && ( +
+
+

+ {(() => { + const currentRank = Object.keys(rankVotes).length + 1; + const maxRanks = Math.min(selectedPoll.options.length, 3); + + if (currentRank > maxRanks) { + return "Ranking Complete"; + } + + const rankText = currentRank === 1 ? "1st" : currentRank === 2 ? "2nd" : currentRank === 3 ? "3rd" : `${currentRank}th`; + return `What's your ${rankText} choice?`; + })()} +

+ +
+
+

+ Rank your top 3 choices from most preferred (1) to least preferred (3). +

+
+
+ {selectedPoll.options.map((option, index) => { + const rank = rankVotes[index]; + const isRanked = rank !== undefined; + return ( +
+
+ +
+
+ + rank +
+
+ ); + })} +
+
+ + Total Rankings Used: + + + {Object.keys(rankVotes).length}/{Math.min(selectedPoll.options.length, 3)} + +
+
+
+
+ )} + + {/* Submit button for regular voting */} +
+ +
+ )} +
+ )} -
- + // Add a small delay to ensure backend has processed the vote + setTimeout(async () => { + try { + await fetchPoll(); + await fetchVoteData(); + } catch (error) { + console.error("Error during data refresh:", error); + } + }, 2000); // 2 second delay + + toast({ + title: "Success!", + description: "Your vote has been signed and submitted.", + }); + }} + onCancel={() => { + setShowSigningInterface(false); + }} + />
)} @@ -811,45 +988,90 @@ export default function Vote({ params }: { params: Promise<{ id: string }> }) {
)} - {/* Signing Interface Modal */} - {showSigningInterface && ( + + + {/* View My Vote Modal for Private Polls */} + {showMyVote && (
-
- { - setShowSigningInterface(false); - - // Add a small delay to ensure backend has processed the vote - setTimeout(async () => { - try { - await fetchPoll(); - await fetchVoteData(); - } catch (error) { - console.error("Error during data refresh:", error); - } - }, 2000); // 2 second delay - - toast({ - title: "Success!", - description: "Your vote has been signed and submitted.", - }); - }} - onCancel={() => { - setShowSigningInterface(false); - }} - /> +
+
+

+ + Your Private Vote +

+ +
+ +
+
+

+ This is your private vote choice. Only you can see this information. +

+
+ + {voteStatus?.vote && ( +
+

Poll: {selectedPoll?.title}

+ + {selectedPoll?.mode === "normal" && ( +
+

+ Your choice: {selectedPoll.options[parseInt(voteStatus.vote.optionId || "0")]} +

+
+ )} + + {selectedPoll?.mode === "point" && voteStatus.vote.points && ( +
+

Your point distribution:

+
+ {Object.entries(voteStatus.vote.points).map(([index, points]) => ( +
+ Option {parseInt(index) + 1}: + {points} points +
+ ))} +
+
+ )} + + {selectedPoll?.mode === "rank" && voteStatus.vote.ranks && ( +
+

Your ranking:

+
+ {Object.entries(voteStatus.vote.ranks).map(([rank, index]) => ( +
+ {rank === "1" ? "1st" : rank === "2" ? "2nd" : rank === "3" ? "3rd" : `${rank}th`} choice: + Option {parseInt(index) + 1} +
+ ))} +
+
+ )} +
+ )} + +
+ +
+
)}
); -} +} \ No newline at end of file diff --git a/platforms/eVoting/src/app/(app)/create/page.tsx b/platforms/eVoting/src/app/(app)/create/page.tsx index c342f623..5dc8a6d0 100644 --- a/platforms/eVoting/src/app/(app)/create/page.tsx +++ b/platforms/eVoting/src/app/(app)/create/page.tsx @@ -1,6 +1,6 @@ "use client"; -import { useState, useEffect } from "react"; +import React, { useState, useEffect } from "react"; import { useForm } from "react-hook-form"; import { zodResolver } from "@hookform/resolvers/zod"; import { z } from "zod"; @@ -12,6 +12,7 @@ import { ChartLine, ListOrdered, CircleUser, + Vote, Users, } from "lucide-react"; import { Button } from "@/components/ui/button"; @@ -97,6 +98,13 @@ export default function CreatePoll() { const watchedMode = watch("mode"); const watchedVisibility = watch("visibility"); + // Force simple voting when private visibility is selected + React.useEffect(() => { + if (watchedVisibility === "private" && watchedMode !== "normal") { + setValue("mode", "normal"); + } + }, [watchedVisibility, watchedMode, setValue]); + const addOption = () => { const newOptions = [...options, ""]; setOptions(newOptions); diff --git a/platforms/eVoting/src/app/api/blind-vote/session/route.ts b/platforms/eVoting/src/app/api/blind-vote/session/route.ts new file mode 100644 index 00000000..369f8bfb --- /dev/null +++ b/platforms/eVoting/src/app/api/blind-vote/session/route.ts @@ -0,0 +1,44 @@ +import { NextRequest, NextResponse } from 'next/server'; + +export async function POST(request: NextRequest) { + try { + const { pollId, userId } = await request.json(); + + // Validate required fields + if (!pollId || !userId) { + return NextResponse.json( + { error: 'Missing required fields: pollId, userId' }, + { status: 400 } + ); + } + + // Forward the request to the eVoting API + const evotingApiUrl = process.env.NEXT_PUBLIC_EVOTING_BASE_URL || 'http://localhost:3001'; + const response = await fetch(`${evotingApiUrl}/api/blind-vote/session`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ pollId, userId }) + }); + + if (!response.ok) { + const errorData = await response.text(); + console.error('eVoting API error:', response.status, errorData); + return NextResponse.json( + { error: 'Failed to create blind vote session' }, + { status: response.status } + ); + } + + const result = await response.json(); + return NextResponse.json(result); + + } catch (error) { + console.error('Error creating blind vote session:', error); + return NextResponse.json( + { error: 'Internal server error' }, + { status: 500 } + ); + } +} \ No newline at end of file diff --git a/platforms/eVoting/src/app/api/votes/blind/route.ts b/platforms/eVoting/src/app/api/votes/blind/route.ts new file mode 100644 index 00000000..6d43bdb8 --- /dev/null +++ b/platforms/eVoting/src/app/api/votes/blind/route.ts @@ -0,0 +1,49 @@ +import { NextRequest, NextResponse } from 'next/server'; + +export async function POST(request: NextRequest) { + try { + const { pollId, commitment, proof } = await request.json(); + + // Validate required fields + if (!pollId || !commitment || !proof) { + return NextResponse.json( + { error: 'Missing required fields: pollId, commitment, proof' }, + { status: 400 } + ); + } + + // Get the user's session token (this will be handled by Next.js auth) + // For now, we'll need to implement proper session handling + + // Forward the request to the eVoting API + const evotingApiUrl = process.env.NEXT_PUBLIC_EVOTING_BASE_URL || 'http://localhost:3001'; + const response = await fetch(`${evotingApiUrl}/api/votes/blind`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + // TODO: Add proper authentication header + // 'Authorization': `Bearer ${sessionToken}` + }, + body: JSON.stringify({ pollId, commitment, proof }) + }); + + if (!response.ok) { + const errorData = await response.text(); + console.error('eVoting API error:', response.status, errorData); + return NextResponse.json( + { error: 'Failed to submit blind vote to eVoting API' }, + { status: response.status } + ); + } + + const result = await response.json(); + return NextResponse.json(result); + + } catch (error) { + console.error('Error handling blind vote submission:', error); + return NextResponse.json( + { error: 'Internal server error' }, + { status: 500 } + ); + } +} \ No newline at end of file diff --git a/platforms/eVoting/src/components/blind-voting-interface.tsx b/platforms/eVoting/src/components/blind-voting-interface.tsx new file mode 100644 index 00000000..9ef1e28c --- /dev/null +++ b/platforms/eVoting/src/components/blind-voting-interface.tsx @@ -0,0 +1,147 @@ +import React, { useState, useEffect } from 'react'; +import { QRCodeSVG } from 'qrcode.react'; +import { Vote, UserX, Shield } from 'lucide-react'; +import { Button } from "@/components/ui/button"; +import { useToast } from "@/hooks/use-toast"; +import type { Poll } from "@shared/schema"; + +interface BlindVotingInterfaceProps { + poll: Poll; + userId: string; + hasVoted: boolean; + onVoteSubmitted: () => void; +} + +export default function BlindVotingInterface({ poll, userId, hasVoted, onVoteSubmitted }: BlindVotingInterfaceProps) { + + const [deepLink, setDeepLink] = useState(''); + const [isLoading, setIsLoading] = useState(false); + const [error, setError] = useState(''); + const { toast } = useToast(); + + const createBlindVotingDeepLink = async () => { + try { + setIsLoading(true); + setError(''); + + // Create the QR code data that the eID wallet expects + const apiBaseUrl = process.env.NEXT_PUBLIC_EVOTING_BASE_URL || 'http://localhost:7777'; + + // Generate a session ID for this voting session + const sessionId = `session_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`; + + // Create the poll data for blind voting in the format the eID wallet expects + const pollData = { + type: "blind-vote", + sessionId: sessionId, + pollId: poll.id, + platformUrl: apiBaseUrl, + timestamp: Date.now() + }; + + // Encode the poll data as base64 + const encodedData = btoa(JSON.stringify(pollData)); + + // Create the redirect URI where the signed vote will be sent + const redirectUri = `${apiBaseUrl}/api/votes/${poll.id}/blind`; + + // Create the w3ds://sign URI that the eID wallet expects + const link = `w3ds://sign?session=${sessionId}&data=${encodeURIComponent(encodedData)}&redirect_uri=${encodeURIComponent(redirectUri)}&platform_url=${encodeURIComponent(apiBaseUrl)}`; + + console.log('🔍 Generated w3ds://sign URI:', link); + console.log('🔍 Session ID:', sessionId); + console.log('🔍 Base64 data:', encodedData); + console.log('🔍 Redirect URI:', redirectUri); + console.log('🔍 Platform URL:', apiBaseUrl); + console.log('🔍 Environment variable NEXT_PUBLIC_EVOTING_BASE_URL:', process.env.NEXT_PUBLIC_EVOTING_BASE_URL); + console.log('🔍 Full redirect URI being sent:', redirectUri); + + setDeepLink(link); + } catch (error) { + console.error('Error creating blind voting deep link:', error); + setError('Failed to create blind voting deep link'); + } finally { + setIsLoading(false); + } + }; + + useEffect(() => { + if (!deepLink) { + createBlindVotingDeepLink(); + } + }, []); + + // Note: SSE subscription removed as it's not needed for the new blind voting system + // The eID wallet handles the voting process locally and submits directly to the API + + if (hasVoted) { + return ( +
+ +

Blind Vote Submitted

+

Your private vote has been submitted successfully

+

The vote will remain hidden until revealed

+
+ ); + } + + return ( +
+ {/* Blind Voting Info */} +
+
+ +

Private Blind Voting

+
+

+ This is a private poll. Your vote will be hidden using cryptographic commitments + until you choose to reveal it. Use your eID wallet to submit your vote securely. +

+
+ + {/* Responsive QR Code Section */} +
+ {/* Mobile: Show button, Desktop: Show QR */} +
+ +
+ + {/* Desktop: Show QR code */} +
+
+ +
+ +
+

+ Scan this QR code with your eID wallet to submit your private vote +

+
+
+
+ + {/* Instructions */} +
+

How Blind Voting Works:

+
    +
  1. Scan the QR code with your eID wallet
  2. +
  3. Select your vote (Yes/No) in the wallet
  4. +
  5. The wallet creates a cryptographic commitment
  6. +
  7. Your vote is submitted without revealing your choice
  8. +
  9. You can reveal your vote later if needed
  10. +
+
+
+ ); +} \ No newline at end of file diff --git a/platforms/eVoting/src/components/voting-interface.tsx b/platforms/eVoting/src/components/voting-interface.tsx index c048450b..1300cd34 100644 --- a/platforms/eVoting/src/components/voting-interface.tsx +++ b/platforms/eVoting/src/components/voting-interface.tsx @@ -1,12 +1,12 @@ import { useState } from "react"; -import { useMutation, useQueryClient } from "@tanstack/react-query"; -import { Vote, CheckCircle } from "lucide-react"; +import { Vote, CheckCircle, Eye, UserX } from "lucide-react"; import { Button } from "@/components/ui/button"; import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group"; import { Label } from "@/components/ui/label"; import { useToast } from "@/hooks/use-toast"; -import { apiRequest } from "@/lib/queryClient"; -import type { Poll } from "@shared/schema"; +import { apiClient } from "@/lib/apiClient"; +import type { Poll } from "@/lib/pollApi"; +import BlindVotingInterface from "./blind-voting-interface"; interface VotingInterfaceProps { poll: Poll; @@ -17,40 +17,38 @@ interface VotingInterfaceProps { export default function VotingInterface({ poll, userId, hasVoted, onVoteSubmitted }: VotingInterfaceProps) { const [selectedOption, setSelectedOption] = useState(null); + const [isSubmitting, setIsSubmitting] = useState(false); const { toast } = useToast(); - const queryClient = useQueryClient(); - const submitVoteMutation = useMutation({ - mutationFn: async (optionId: number) => { - return await apiRequest("POST", "/api/votes", { + // Check if this is a private poll that requires blind voting + const isPrivatePoll = poll.visibility === "private"; + + const handleSubmitVote = async () => { + if (selectedOption === null) return; + + try { + setIsSubmitting(true); + await apiClient.post("/api/votes", { pollId: poll.id, userId, - optionId, - }); - }, - onSuccess: () => { - queryClient.invalidateQueries({ queryKey: ["/api/polls"] }); - queryClient.invalidateQueries({ - queryKey: ["/api/polls", poll.id, "vote-status", userId] + voteData: [selectedOption.toString()], // Send as array of strings as expected by NormalVoteData + mode: "normal" }); + toast({ title: "Success!", description: "Your vote has been submitted", }); onVoteSubmitted(); - }, - onError: (error: any) => { + } catch (error: any) { toast({ title: "Error", description: error.message || "Failed to submit vote", variant: "destructive", }); - }, - }); - - const handleSubmitVote = () => { - if (selectedOption === null) return; - submitVoteMutation.mutate(selectedOption); + } finally { + setIsSubmitting(false); + } }; if (hasVoted) { @@ -63,6 +61,18 @@ export default function VotingInterface({ poll, userId, hasVoted, onVoteSubmitte ); } + // For private polls, show the blind voting interface + if (isPrivatePoll) { + return ( + + ); + } + return (
setSelectedOption(parseInt(value))} className="space-y-3" > - {(poll.options as Array<{id: number, text: string}>).map((option) => ( -
+ {poll.options.map((option, index) => ( +
))} @@ -88,10 +98,10 @@ export default function VotingInterface({ poll, userId, hasVoted, onVoteSubmitte