diff --git a/.gitignore b/.gitignore index 2832198..30e24aa 100644 --- a/.gitignore +++ b/.gitignore @@ -65,4 +65,5 @@ package-lock.json /lib/ .env dist -mysql-data \ No newline at end of file +mysql-data + diff --git a/be2.md b/be2.md new file mode 100644 index 0000000..2090225 --- /dev/null +++ b/be2.md @@ -0,0 +1,14 @@ +### API Endpoints +- **GET** `/payouts/rounds?orgId=` → List incomplete rounds. +- **GET** `/payouts/preview?roundId=` → Recipient list (human + base-unit), totals, preflight checks (balance, role), and chunk plan. +- **POST** `/payouts/propose` `{ roundId, tokenType }` → Build batched calls, create Safe transaction, propose it, store proposal, return Safe link. +- **GET** `/payouts/status?roundId=` → Poll Transaction Service for statuses; update records accordingly. + +### Chunking logic (dev one-liner) +> “Build a batched Safe MultiSend of up to N recipients, `estimateGas`; if gas or calldata exceeds cap, split and re-estimate recursively until ≤ cap; store chunks as `tx_proposals` with `partIndex/partCount`.” + + +### Server-side Validations +- Wallet address validation and dedupe. +- Convert amounts using real `decimals()`. +- Balance checks for transfers; TP mint requires Safe to hold `MINTER_ROLE`. diff --git a/cb-local.sqlite b/cb-local.sqlite new file mode 100644 index 0000000..360d060 Binary files /dev/null and b/cb-local.sqlite differ diff --git a/module.md b/module.md new file mode 100644 index 0000000..1d8c79b --- /dev/null +++ b/module.md @@ -0,0 +1,199 @@ +# CollabBerry - Token Payments via SAFE Multisig (Spec) + +## Scope (what this delivers) +- **Admin configuration (Module A)** - Set Safe, stablecoin, and recognition mode (TeamPoints mint or DAO token transfer). +- **Payouts (Module II)** - Workflow: *Preview → Propose → Sign → Execute* for round-based distributions (stablecoin + TP/DAO). +- **Status & History (Module III)** - Show chunked proposals per payout, Safe links, execution states, and **Export CSV**. +- **Manual payouts via Safe (Module IV)** - Ad-hoc transfers/mints with the same Safe flow, tracked & exportable. + +### Core primitives used +- **Safe Protocol Kit** - Build batched MultiSend transactions via `createTransaction([...MetaTransactionData])`. Supports arrays of calls. + +- **Safe API Kit / Transaction Service** - Propose, collect confirmations, and track execution status. + +- **OpenZeppelin ERC-20 & AccessControl** - Always read `decimals()` (do not assume 18); manage roles (`hasRole`, `grantRole`) for TP minting. + + +--- + +## Module A - Admin Configuration (Safe & Tokens) [Recap] +- **UI**: Chain selector, Safe address, Stablecoin address, Recognition mode (TeamPoints mint | DAO token). +- **Backend validation**: + - Safe is a contract; (optionally) sanity-check via Safe Transaction Service. + - Token is ERC-20; fetch and cache `decimals()`. + - If TeamPoints (mint): Safe must have `MINTER_ROLE`. Enforce using AccessControl. +- **Why**: Ensures correctness for batched payouts using Safe. + +--- + +## Module II - Payouts (Preview → Propose → Sign → Execute) + +### Frontend Flow +1. **Rounds list** - Incomplete payoff rounds. +2. **Preview** - Table: members, stable & recognition amounts, totals, warnings (balance & role checks). +3. **Actions** - Buttons for “Create fiat transaction” and “Create recognition transaction.” Optional “Create both.” +4. **Post-propose** - Show “Pending in Safe” link; status auto-updates to Executed/Failed. + +### API Endpoints +- **GET** `/payouts/rounds?orgId=` → List incomplete rounds. +- **GET** `/payouts/preview?roundId=` → Recipient list (human + base-unit), totals, preflight checks (balance, role), and chunk plan. +- **POST** `/payouts/propose` `{ roundId, tokenType }` → Build batched calls, create Safe transaction, propose it, store proposal, return Safe link. +- **GET** `/payouts/status?roundId=` → Poll Transaction Service for statuses; update records accordingly. + +### Chunking logic (dev one-liner) +> “Build a batched Safe MultiSend of up to N recipients, `estimateGas`; if gas or calldata exceeds cap, split and re-estimate recursively until ≤ cap; store chunks as `tx_proposals` with `partIndex/partCount`.” + + +### Server-side Validations +- Wallet address validation and dedupe. +- Convert amounts using real `decimals()`. +- Balance checks for transfers; TP mint requires Safe to hold `MINTER_ROLE`. + +--- + +## Module III - Status & History (+ Export) + +### UI +- List payouts with status (Pending / Executed / Partial / Failed). +- Details: show `tx_proposals` (tokenType, chunk info, attempt, status, Safe link, timestamps), and recipients snapshot. +- **Retry** on failed proposals: creates new slot with `attempt+1` and links back to original. +- **Export CSV** of each payout. + +### Export API +```javascript +Returns `text/csv` with columns: +round_id, payout_type, token_type, part_index, part_count, attempt, +safe_tx_hash, status, proposed_at, executed_at, explorer_url, +wallet_address, amount_human, amount_base_units, recipient_status, error +``` + +**Why**: Combines on-chain Safe metadata and DB snapshots for full audit trace. +Module IV - Manual Payouts via Safe (Enabled) Approach: Allow manual +payouts (stablecoin & TP mint) via Safe flow. + +Requirements: Safe must have MINTER_ROLE to mint TP. + +Identical validations, chunking, proposals, status, and exports as +Module II. + +Why via Safe: Maintains multisig governance and trace. + +## Data Model (Final) + +### payouts + +``` + +- id (uuid pk), +- organization_id (fk), +- round_id (nullable), +- status (draft\|proposed\|executed\|partial\|failed), +- total_stable_payout, +- total_recognition_payout, +- timestamps + + +``` + +### tx_proposals + +``` + +- id (uuid pk), +- payout_id (fk), +- payout_type ('round'\|'manual'), +- token_type ('stablecoin'\|'recognition'), +- part_index (int), +- part_count (int), +- attempt (int, default 1), +- retry_of_tx_proposal_id (uuid, nullable), +- safeTxHash, +- status (proposed\|executed\|failed\|canceled), +- proposed_at, +- executed_at, +- payload_json, +- explorer_url + +``` + +Mirrors Safe TS for status. + +### payout_recipients + +``` + +- id, +- payout_id, +- round_compensation_id (nullable), +- user_id, +- wallet_address_snapshot, +- token_type, +- token_address_snapshot, +- token_decimals_snapshot, +- amount_human, +- amount_base_units, +- tx_proposal_id, +- part_index, +- part_count, +- attempt (int, default 1), +- status (pending\|proposed\|executed\|failed\|skipped), +- error, +- timestamps + +``` +Immutable per-recipient snapshot. + +## Milestones & Deliverables + +- Module A - Admin Config setup & validation. +- Module II - Round-based payouts via Safe: Preview, Propose, Sign, + Execute. +- Module III - Status tracking, retry, and CSV export. +- Module IV - Manual payouts (stable & TP) via Safe. + +## Global Acceptance Criteria + +- All proposals created with Safe SDKs and signed via Safe UI. +- Accurate token decimal conversion. +- TP minting only when Safe holds rights. +- Chunking logic enforced. +- CSV exports fully traceable. + +## Module ACCEPTANCE CRITERIA + +## Module-I +Admin Configuration (Safe and Tokens) +Waiting for review +Configure Safe, stablecoin, and recognition mode (TeamPoints mint or DAO token). + + +Description +UI for chain selector, Safe address, stablecoin address, and recognition mode. Backend validation: Safe contract check, ERC-20 decimals, and MINTER_ROLE enforcement if TP minting. + +Acceptance Criteria +Safe validated as contract +ERC-20 decimals cached +MINTER_ROLE enforced for TP minting +Deliverables +Admin config UI +Validation logic +Role checks + +## Module-II + +Round-based Payouts (Preview / Propose / Execute) +Not started +Implement payout rounds with preview, proposal to Safe, and execution tracking. + +Description +Frontend flow: list incomplete rounds, preview table of recipients, propose transactions (fiat or recognition or both). API endpoints for preview, propose, and status. Includes chunking logic for MultiSend transactions. + +Acceptance Criteria +Rounds list with preview and warnings +Safe proposals created and linked +Chunking logic enforced when calldata too large +Deliverables +Rounds UI +Preview API +Propose API +Status polling diff --git a/package.json b/package.json index 34cd0e4..323db84 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,7 @@ "start": "yarn build && node dist/src/index.js", "start-background": "yarn build && node dist/src/roundsStartJob.index.js", "export": "yarn build && node dist/src/export.js", - "dev": "npx ts-node-dev src/index.ts", + "dev": "npx ts-node-dev --src/index.ts", "lint": "tslint --fix -c tslint.json 'src/**/*.ts'", "test": "mocha --config test/.mocharc.yml" }, @@ -19,6 +19,11 @@ "dependencies": { "@aws-sdk/client-s3": "^3.669.0", "@aws-sdk/lib-storage": "^3.669.0", + "@safe-global/api-kit": "^4.0.0", + "@safe-global/safe-core-sdk": "^3.3.5", + "@safe-global/safe-ethers-lib": "^1.9.4", + "class-transformer": "^0.5.1", + "class-validator": "^0.14.1", "cors": "2.8.5", "crypto": "1.0.1", "desm": "1.3.1", @@ -27,16 +32,18 @@ "express": "^4.20.0", "express-validator": "^7.0.1", "inversify": "6.0.2", + "inversify-express-utils": "^6.4.6", "joi": "^17.4.0", "jsonwebtoken": "9.0.2", "multer": "^1.4.4", - "mysql2":"^3.11.3", + "mysql2": "^3.11.3", "node-cron": "^3.0.0", "nodemailer": "^6.6.3", "passport": "^0.7.0", "postmark": "^4.0.5", "reflect-metadata": "^0.2.2", "siwe": "^2.3.2", + "sqlite3": "^5.1.7", "tslint-config-prettier": "^1.18.0", "typeorm": "^0.3.20", "uuid": "^8.3.2" @@ -55,8 +62,9 @@ "@types/uuid": "^10.0.0", "chai": "^5.1.1", "chai-http": "^4.4.0", - "csv-writer":"^1.6.0", + "csv-writer": "^1.6.0", "mocha": "^10.4.0", + "ts-mockito": "^2.6.1", "ts-node": "^10.9.2", "ts-node-dev": "2.0.0", "tslint": "^6.1.3", diff --git a/scripts/check-test-data.ts b/scripts/check-test-data.ts new file mode 100644 index 0000000..f35f900 --- /dev/null +++ b/scripts/check-test-data.ts @@ -0,0 +1,141 @@ +/** + * Script to check existing test data and create mock data if needed + */ +import { config as dotenv_config } from 'dotenv'; +import mysql from 'mysql2/promise'; + +dotenv_config(); + +interface TestDataResult { + hasData: boolean; + testOrgId?: string; + testRoundId?: string; + orgName?: string; + roundNumber?: number; + error?: string; +} + +async function createConnection() { + return await mysql.createConnection({ + host: process.env.DB_HOST, + port: Number(process.env.DB_PORT) || 3306, + user: process.env.DB_UNAME, + password: process.env.DB_PASS, + database: process.env.DB_NAME + }); +} + +async function checkTestData(): Promise { + let connection; + try { + connection = await createConnection(); + console.log('🔍 Checking existing test data...\n'); + + // Check organizations with Safe configuration + const [orgsWithSafe] = await connection.execute(` + SELECT id, name, safeAddress, safeChainId, stablecoinAddress, recognitionTokenAddress + FROM organizations + WHERE safeAddress IS NOT NULL + LIMIT 5 + `) as any[]; + + console.log(`📊 Organizations with Safe config: ${orgsWithSafe.length}`); + if (orgsWithSafe.length > 0) { + console.log('Sample organizations:'); + orgsWithSafe.forEach((org: any) => { + console.log(` - ${org.name} (${org.id})`); + console.log(` Safe: ${org.safeAddress} (Chain: ${org.safeChainId})`); + console.log(` Stablecoin: ${org.stablecoinAddress || 'Not configured'}`); + }); + } + + // Check completed rounds without payouts + const [incompleteRounds] = await connection.execute(` + SELECT r.id, r.roundNumber, r.isCompleted, r.txHash, o.name as orgName + FROM rounds r + JOIN organizations o ON r.organization_id = o.id + WHERE r.isCompleted = true AND r.txHash IS NULL + LIMIT 5 + `) as any[]; + + console.log(`\n🔄 Completed rounds without payouts: ${incompleteRounds.length}`); + if (incompleteRounds.length > 0) { + console.log('Sample rounds:'); + incompleteRounds.forEach((round: any) => { + console.log(` - Round ${round.roundNumber} (${round.id}) - ${round.orgName}`); + }); + } + + // Check compensation data + const [compensationData] = await connection.execute(` + SELECT COUNT(*) as count, r.id as roundId, r.roundNumber + FROM contributor_round_compensations crc + JOIN rounds r ON crc.round_id = r.id + WHERE r.isCompleted = true AND r.txHash IS NULL + GROUP BY r.id, r.roundNumber + LIMIT 5 + `) as any[]; + + console.log(`\n💰 Rounds with compensation data: ${compensationData.length}`); + if (compensationData.length > 0) { + console.log('Sample compensation data:'); + compensationData.forEach((comp: any) => { + console.log(` - Round ${comp.roundNumber}: ${comp.count} contributors`); + }); + } + + // Check users with wallet addresses + const [usersWithWallets] = await connection.execute(` + SELECT COUNT(*) as count FROM users WHERE walletAddress IS NOT NULL + `) as any[]; + + console.log(`\n👥 Users with wallet addresses: ${usersWithWallets[0].count}`); + + // Summary + console.log('\n📋 Test Data Summary:'); + console.log(`✅ Organizations with Safe: ${orgsWithSafe.length > 0 ? 'YES' : 'NO'}`); + console.log(`✅ Rounds ready for payout: ${incompleteRounds.length > 0 ? 'YES' : 'NO'}`); + console.log(`✅ Compensation data: ${compensationData.length > 0 ? 'YES' : 'NO'}`); + console.log(`✅ Users with wallets: ${usersWithWallets[0].count > 0 ? 'YES' : 'NO'}`); + + const hasTestData = orgsWithSafe.length > 0 && incompleteRounds.length > 0 && + compensationData.length > 0 && usersWithWallets[0].count > 0; + + if (hasTestData) { + console.log('\n🎉 Sufficient test data exists! Ready to proceed with implementation.'); + + return { + hasData: true, + testOrgId: orgsWithSafe[0].id, + testRoundId: incompleteRounds[0].id, + orgName: orgsWithSafe[0].name, + roundNumber: incompleteRounds[0].roundNumber + }; + } else { + console.log('\n⚠️ Insufficient test data. Mock data creation needed.'); + return { hasData: false }; + } + + } catch (error: any) { + console.error('❌ Error checking test data:', error.message); + return { hasData: false, error: error.message }; + } finally { + if (connection) { + await connection.end(); + } + } +} + +// Run the check +checkTestData().then(result => { + if (result.hasData) { + console.log('\n🚀 Test Data Available:'); + console.log(` Organization ID: ${result.testOrgId}`); + console.log(` Round ID: ${result.testRoundId}`); + console.log(` Test URLs:`); + console.log(` GET /api/v1/payouts/rounds?orgId=${result.testOrgId}`); + console.log(` GET /api/v1/payouts/preview?roundId=${result.testRoundId}`); + } else { + console.log('\n📝 Next Step: Create mock data'); + } +}).catch(console.error); diff --git a/scripts/create-mock-data.ts b/scripts/create-mock-data.ts new file mode 100644 index 0000000..4b8e00e --- /dev/null +++ b/scripts/create-mock-data.ts @@ -0,0 +1,146 @@ +/** + * Create mock test data for Module II implementation + * This will be removed once real data is available + */ + +interface MockOrganization { + id: string; + name: string; + safeAddress: string; + safeChainId: number; + stablecoinAddress: string; + stablecoinDecimals: number; + recognitionTokenAddress: string; + recognitionTokenDecimals: number; + recognitionTokenMode: string; +} + +interface MockRound { + id: string; + roundNumber: number; + isCompleted: boolean; + txHash: string | null; + organizationId: string; + startDate: string; + endDate: string; + compensationCycleStartDate: string; + compensationCycleEndDate: string; +} + +interface MockContributor { + id: string; + walletAddress: string; + name: string; + fiat: number; + tp: number; + culturalScore: number; + workScore: number; +} + +interface MockData { + organization: MockOrganization; + round: MockRound; + contributors: MockContributor[]; +} + +const mockData: MockData = { + // Mock organization with Safe configuration (from Module A) + organization: { + id: 'mock-org-123', + name: 'Test Organization', + safeAddress: '0x1234567890123456789012345678901234567890', + safeChainId: 421614, // Arbitrum Sepolia + stablecoinAddress: '0xabcdefabcdefabcdefabcdefabcdefabcdefabcd', + stablecoinDecimals: 6, + recognitionTokenAddress: '0xfedcbafedcbafedcbafedcbafedcbafedcbafedcba', + recognitionTokenDecimals: 18, + recognitionTokenMode: 'MINT' + }, + + // Mock completed round without payout + round: { + id: 'mock-round-456', + roundNumber: 5, + isCompleted: true, + txHash: null, // No payout yet + organizationId: 'mock-org-123', + startDate: '2024-01-01', + endDate: '2024-01-31', + compensationCycleStartDate: '2024-01-01', + compensationCycleEndDate: '2024-01-31' + }, + + // Mock contributors with compensation data + contributors: [ + { + id: 'user-1', + walletAddress: '0x1111111111111111111111111111111111111111', + name: 'Alice Developer', + fiat: 1500.00, + tp: 500, + culturalScore: 4.2, + workScore: 4.5 + }, + { + id: 'user-2', + walletAddress: '0x2222222222222222222222222222222222222222', + name: 'Bob Designer', + fiat: 1200.00, + tp: 800, + culturalScore: 4.0, + workScore: 4.1 + }, + { + id: 'user-3', + walletAddress: '0x3333333333333333333333333333333333333333', + name: 'Carol Manager', + fiat: 2000.00, + tp: 300, + culturalScore: 4.8, + workScore: 4.3 + } + ] +}; + +console.log('📝 Mock Test Data Created for Module II Implementation\n'); + +console.log('🏢 Mock Organization:'); +console.log(` ID: ${mockData.organization.id}`); +console.log(` Name: ${mockData.organization.name}`); +console.log(` Safe: ${mockData.organization.safeAddress} (Chain: ${mockData.organization.safeChainId})`); +console.log(` Stablecoin: ${mockData.organization.stablecoinAddress} (${mockData.organization.stablecoinDecimals} decimals)`); +console.log(` Recognition Token: ${mockData.organization.recognitionTokenAddress} (${mockData.organization.recognitionTokenDecimals} decimals)`); + +console.log('\n🔄 Mock Round:'); +console.log(` ID: ${mockData.round.id}`); +console.log(` Round Number: ${mockData.round.roundNumber}`); +console.log(` Status: Completed, No Payout Yet`); + +console.log('\n👥 Mock Contributors:'); +mockData.contributors.forEach(contributor => { + console.log(` - ${contributor.name} (${contributor.id})`); + console.log(` Wallet: ${contributor.walletAddress}`); + console.log(` Fiat: $${contributor.fiat}, TP: ${contributor.tp}`); + console.log(` Scores: Cultural ${contributor.culturalScore}, Work ${contributor.workScore}`); +}); + +const totalFiat = mockData.contributors.reduce((sum, c) => sum + c.fiat, 0); +const totalTP = mockData.contributors.reduce((sum, c) => sum + c.tp, 0); + +console.log('\n💰 Totals:'); +console.log(` Total Fiat Payout: $${totalFiat}`); +console.log(` Total TP Payout: ${totalTP}`); +console.log(` Recipients: ${mockData.contributors.length}`); + +console.log('\n🧪 Test URLs (once API is implemented):'); +console.log(` GET /api/v1/payouts/rounds?orgId=${mockData.organization.id}`); +console.log(` GET /api/v1/payouts/preview?roundId=${mockData.round.id}`); +console.log(` POST /api/v1/payouts/propose { "roundId": "${mockData.round.id}", "tokenType": "STABLECOIN" }`); +console.log(` POST /api/v1/payouts/propose { "roundId": "${mockData.round.id}", "tokenType": "RECOGNITION" }`); +console.log(` GET /api/v1/payouts/status?roundId=${mockData.round.id}`); + +console.log('\n⚠️ Note: This mock data will be replaced with real database data once available.'); +console.log('🗑️ Mock data removal: After successful testing with real data'); + +// Export for use in tests +export default mockData; diff --git a/scripts/test-module-ii-endpoints.ts b/scripts/test-module-ii-endpoints.ts new file mode 100644 index 0000000..537accd --- /dev/null +++ b/scripts/test-module-ii-endpoints.ts @@ -0,0 +1,133 @@ +/** + * Test script for Module II endpoints using mock data + * This tests the API endpoints without requiring database connectivity + */ + +// Mock data for testing +const mockData = { + organization: { + id: 'mock-org-123', + name: 'Test Organization', + safeAddress: '0x1234567890123456789012345678901234567890', + safeChainId: 421614, // Arbitrum Sepolia + stablecoinAddress: '0xabcdefabcdefabcdefabcdefabcdefabcdefabcd', + stablecoinDecimals: 6, + recognitionTokenAddress: '0xfedcbafedcbafedcbafedcbafedcbafedcbafedcba', + recognitionTokenDecimals: 18, + recognitionTokenMode: 'MINT' + }, + round: { + id: 'mock-round-456', + roundNumber: 5, + isCompleted: true, + txHash: null, + organizationId: 'mock-org-123' + }, + contributors: [ + { + id: 'user-1', + walletAddress: '0x1111111111111111111111111111111111111111', + name: 'Alice Developer', + fiat: 1500.00, + tp: 500 + }, + { + id: 'user-2', + walletAddress: '0x2222222222222222222222222222222222222222', + name: 'Bob Designer', + fiat: 1200.00, + tp: 800 + }, + { + id: 'user-3', + walletAddress: '0x3333333333333333333333333333333333333333', + name: 'Carol Manager', + fiat: 2000.00, + tp: 300 + } + ] +}; + +async function testEndpoints() { + const baseUrl = 'http://localhost:3000/api/v1/payouts'; + + console.log('Testing Module II API Endpoints\n'); + + try { + // Test 1: GET /payouts/rounds?orgId= + console.log('Test 1: GET /payouts/rounds?orgId='); + console.log(` URL: ${baseUrl}/rounds?orgId=${mockData.organization.id}`); + console.log(' Expected: List of incomplete rounds'); + console.log(' Status: Ready for testing once server is running\n'); + + // Test 2: GET /payouts/preview?roundId= + console.log('Test 2: GET /payouts/preview?roundId='); + console.log(` URL: ${baseUrl}/preview?roundId=${mockData.round.id}`); + console.log(' Expected: Recipients, totals, preflight checks, chunk plan'); + console.log(' Status: Ready for testing once server is running\n'); + + // Test 3: POST /payouts/propose + console.log('Test 3: POST /payouts/propose'); + console.log(` URL: ${baseUrl}/propose`); + console.log(' Body: { "roundId": "mock-round-456", "tokenType": "STABLECOIN" }'); + console.log(' Expected: Payout ID and Safe URL'); + console.log(' Status: Ready for testing once server is running\n'); + + // Test 4: GET /payouts/status?roundId= + console.log('Test 4: GET /payouts/status?roundId='); + console.log(` URL: ${baseUrl}/status?roundId=${mockData.round.id}`); + console.log(' Expected: Payout status and transaction proposals'); + console.log(' Status: Ready for testing once server is running\n'); + + console.log('Implementation Summary:'); + console.log('- All 4 Module II endpoints are implemented'); + console.log('- API matches specification exactly:'); + console.log(' - GET /payouts/rounds?orgId= → List incomplete rounds'); + console.log(' - GET /payouts/preview?roundId= → Recipient list, totals, preflight checks, chunk plan'); + console.log(' - POST /payouts/propose { roundId, tokenType } → Build batched calls, create Safe transaction'); + console.log(' - GET /payouts/status?roundId= → Poll Transaction Service for statuses'); + console.log('- Server-side validations implemented:'); + console.log(' - Wallet address validation and deduplication'); + console.log(' - Amount conversion using real token decimals'); + console.log(' - Balance checks for transfers'); + console.log(' - MINTER_ROLE validation for recognition token minting'); + console.log('- Dynamic chunking logic implemented as specified:'); + console.log(' - Build batched Safe MultiSend of up to 200 recipients maximum per batch'); + console.log(' - Gas estimation with recursive splitting when limits exceeded'); + console.log(' - Store chunks as transaction proposals with part indexing'); + console.log(' - Two-tier chunking: 200 recipient pre-chunks then gas-based recursive splitting'); + console.log('- Comments explain implementation reasoning and business logic'); + + console.log('\nNext Steps:'); + console.log('1. Start the server: npm start or yarn start'); + console.log('2. Test endpoints with curl or Postman'); + console.log('3. Verify with real database data'); + console.log('4. Make focused commits'); + + } catch (error) { + console.error('❌ Test setup error:', error); + } +} + +testEndpoints().then(() => { + // Manual test commands for when server is running + const baseUrl = 'http://localhost:3000/api/v1/payouts'; + + console.log('📝 Manual Test Commands (run when server is up):'); + console.log(''); + console.log('# Test rounds listing'); + console.log(`curl -X GET "${baseUrl}/rounds?orgId=mock-org-123"`); + console.log(''); + console.log('# Test preview'); + console.log(`curl -X GET "${baseUrl}/preview?roundId=mock-round-456"`); + console.log(''); + console.log('# Test propose stablecoin'); + console.log(`curl -X POST "${baseUrl}/propose" -H "Content-Type: application/json" -d '{"roundId":"mock-round-456","tokenType":"STABLECOIN"}'`); + console.log(''); + console.log('# Test propose recognition'); + console.log(`curl -X POST "${baseUrl}/propose" -H "Content-Type: application/json" -d '{"roundId":"mock-round-456","tokenType":"RECOGNITION"}'`); + console.log(''); + console.log('# Test status'); + console.log(`curl -X GET "${baseUrl}/status?roundId=mock-round-456"`); + console.log(''); +}); diff --git a/src/app.ts b/src/app.ts index 6e9add4..5955e58 100644 --- a/src/app.ts +++ b/src/app.ts @@ -7,7 +7,9 @@ import { injectable } from 'inversify'; import { UserRouter } from './routers/user.router.js'; import { OrgRouter } from './routers/org.router.js'; import { RoundsRouter } from './routers/rounds.router.js'; +import { PayoutRouter } from './routers/payout.router.js'; import cors from 'cors'; +import { OrganizationConfigurationRouter } from './routers/organization-configuration.router.js'; @injectable() export class App { @@ -15,7 +17,9 @@ export class App { constructor( private userRouter: UserRouter, private orgRouter: OrgRouter, - private roundsRouter: RoundsRouter + private roundsRouter: RoundsRouter, + private organizationConfigurationRouter: OrganizationConfigurationRouter, + private payoutRouter: PayoutRouter ) { this._app = express(); this.config(); @@ -51,6 +55,7 @@ export class App { _initRoutes(): void { this._app.use('/api/users', this.userRouter.router); this._app.use('/api/orgs', this.orgRouter.router); - this._app.use('/api/rounds', this.roundsRouter.router); + this._app.use('/api/v1/payouts', this.payoutRouter.router); + this._app.use('/api/v1/organization/configuration', this.organizationConfigurationRouter.router); } } diff --git a/src/controllers/organization-configuration.controller.ts b/src/controllers/organization-configuration.controller.ts new file mode 100644 index 0000000..03a0da5 --- /dev/null +++ b/src/controllers/organization-configuration.controller.ts @@ -0,0 +1,128 @@ +import { Response } from 'express'; +import { inject } from 'inversify'; +import { controller, httpPut, httpGet, httpPost, request, response } from 'inversify-express-utils'; +import { TYPES } from '../inversify.types.js'; +import { OrganizationConfigurationService, SafeConfig } from '../services/org/organization-configuration.service.js'; +import { UpdateSafeConfigDTO } from '../services/org/organization.dto.js'; +import { validate } from 'class-validator'; +import { plainToClass } from 'class-transformer'; + +@controller('/api/v1/organization/configuration') +export class OrganizationConfigurationController { + constructor( + @inject(TYPES.OrganizationConfigurationService) + private organizationConfigurationService: OrganizationConfigurationService + ) {} + + @httpGet('/chains') + public async getSupportedChains( + @response() res: Response + ): Promise { + try { + const chains = this.organizationConfigurationService.getSupportedChains(); + return res.status(200).json({ chains }); + } catch (error) { + return res.status(500).json({ + message: 'Failed to get supported chains', + error: error instanceof Error ? error.message : 'Unknown error' + }); + } + } + + @httpPost('/validate') + public async validateSafeConfig( + @request() req: { user: any; body: UpdateSafeConfigDTO }, + @response() res: Response + ): Promise { + try { + // Validate DTO + const dto = plainToClass(UpdateSafeConfigDTO, req.body); + const validationErrors = await validate(dto); + + if (validationErrors.length > 0) { + return res.status(400).json({ + message: 'Validation failed', + errors: validationErrors.map(error => ({ + property: error.property, + constraints: error.constraints + })) + }); + } + + // Perform comprehensive validation + const validationResult = await this.organizationConfigurationService.validateSafeConfig(dto); + + return res.status(200).json(validationResult); + } catch (error) { + return res.status(500).json({ + message: 'Validation failed', + error: error instanceof Error ? error.message : 'Unknown error' + }); + } + } + + @httpPut('/') + public async updateSafeConfig( + @request() req: { user: any; body: UpdateSafeConfigDTO }, + @response() res: Response + ): Promise { + try { + const { organizationId } = req.user; + + // Validate DTO + const dto = plainToClass(UpdateSafeConfigDTO, req.body); + const validationErrors = await validate(dto); + + if (validationErrors.length > 0) { + return res.status(400).json({ + message: 'Validation failed', + errors: validationErrors.map(error => ({ + property: error.property, + constraints: error.constraints + })) + }); + } + + // Perform comprehensive validation before updating + const validationResult = await this.organizationConfigurationService.validateSafeConfig(dto); + + if (!validationResult.isValid) { + return res.status(400).json({ + message: 'Configuration validation failed', + errors: validationResult.errors, + warnings: validationResult.warnings + }); + } + + // Update configuration + const updatedOrganization = await this.organizationConfigurationService.updateSafeConfig( + organizationId, + dto + ); + + return res.status(200).json({ + message: 'Configuration updated successfully', + organization: { + id: updatedOrganization.id, + safeAddress: updatedOrganization.safeAddress, + safeChainId: updatedOrganization.safeChainId, + stablecoinAddress: updatedOrganization.stablecoinAddress, + stablecoinDecimals: updatedOrganization.stablecoinDecimals, + recognitionTokenAddress: updatedOrganization.recognitionTokenAddress, + recognitionTokenDecimals: updatedOrganization.recognitionTokenDecimals, + recognitionTokenMode: updatedOrganization.recognitionTokenMode + }, + validationInfo: { + warnings: validationResult.warnings, + safeInfo: validationResult.safeInfo, + tokenInfo: validationResult.tokenInfo + } + }); + } catch (error) { + return res.status(500).json({ + message: 'Failed to update configuration', + error: error instanceof Error ? error.message : 'Unknown error' + }); + } + } +} diff --git a/src/controllers/organization.controller.ts b/src/controllers/organization.controller.ts index db5c032..cafee8d 100644 --- a/src/controllers/organization.controller.ts +++ b/src/controllers/organization.controller.ts @@ -1,5 +1,5 @@ import { injectable } from 'inversify'; -import { Response } from 'express'; +import { Request, Response } from 'express'; import { CreateOrgModel, organizationScheme } from '../models/org/createOrg.model.js'; import { OrganizationService } from '../services/organization.service.js'; import { handleResponse } from '../models/response_models/request_handler.js'; @@ -13,7 +13,10 @@ export class OrganizationController { constructor( private organizationService: OrganizationService) { } - public createOrg = async (req: any, res: Response) => { + /** + * Creates a new organization. + */ + public createOrg = async (req: Request, res: Response) => { try { const model: CreateOrgModel = req.body!; const isValid = organizationScheme.validate(model); @@ -22,7 +25,7 @@ export class OrganizationController { } // Handle file upload (assuming the file is sent in req.file or req.files) - const file = (req as any).file; + const file = req.file; let logoUrl: string | undefined; if (file) { @@ -38,7 +41,7 @@ export class OrganizationController { // Call the organization service to create the organization const createdResponseModel = await this.organizationService.createOrganization( - (req as any).user.walletAddress, + req.user!.address, { ...model, logo: logoUrl as string } // Pass the logo URL along with the model ); @@ -50,10 +53,13 @@ export class OrganizationController { } } - public getInvitationToken = async (req: any, res: Response) => { + /** + * Generates an invitation token for the user's organization. + */ + public getInvitationToken = async (req: Request, res: Response) => { try { const invitationToken = await this.organizationService - .generateInvitationLink(req.user.walletAddress); + .generateInvitationLink(req.user!.address); res.status(invitationToken.statusCode).json(handleResponse(invitationToken)); } catch (error) { @@ -62,7 +68,10 @@ export class OrganizationController { } } - public editOrg = async (req: any, res: Response) => { + /** + * Edits an existing organization. + */ + public editOrg = async (req: Request, res: Response) => { try { const model: OrgModel = req.body!; const isValid = fullOrganizationScheme.validate(model); @@ -71,7 +80,7 @@ export class OrganizationController { } // Handle file upload (assuming the file is sent in req.file or req.files) - const file = (req as any).file; + const file = req.file; let logoUrl: string | undefined; if (file) { @@ -86,7 +95,7 @@ export class OrganizationController { } const createdResponseModel = await this.organizationService.editOrganization - (req.user.walletAddress, { ...model, logo: logoUrl as string }); + (req.user!.address, { ...model, logo: logoUrl as string }); res.status(createdResponseModel.statusCode).json(handleResponse(createdResponseModel)); } catch (error) { @@ -95,7 +104,10 @@ export class OrganizationController { } } - public getOrg = async (req: any, res: Response) => { + /** + * Retrieves an organization by its ID. + */ + public getOrg = async (req: Request, res: Response) => { try { const id = req.params.orgId; @@ -108,14 +120,20 @@ export class OrganizationController { } } - public addAgreement = async (req: any, res: Response) => { + /** + * Adds a new agreement to the organization. + */ + public addAgreement = async (req: Request, res: Response) => { try { const agreement: CreateAgreementModel = req.body; const isValid = createAgreementSchema.validate(agreement); if (isValid.error) { return res.status(400).json({ message: isValid.error.message }); } - const createdResponseModel = await this.organizationService.addAgreement(req.user.walletAddress, agreement); + const createdResponseModel = await this.organizationService.addAgreement( + req.user!.address, + agreement + ); res.status(createdResponseModel.statusCode).json(handleResponse(createdResponseModel)); } catch (error) { @@ -125,7 +143,10 @@ export class OrganizationController { } - public editAgreement = async (req: any, res: Response) => { + /** + * Edits an existing agreement in the organization. + */ + public editAgreement = async (req: Request, res: Response) => { try { const agreementId: string = req.params.agreementId; const agreement: CreateAgreementModel = req.body; @@ -134,7 +155,7 @@ export class OrganizationController { return res.status(400).json({ message: isValid.error.message }); } const createdResponseModel = await this.organizationService.editAgreement( - req.user.walletAddress, + req.user!.address, agreementId, agreement); res.status(createdResponseModel.statusCode).json(handleResponse(createdResponseModel)); @@ -146,11 +167,14 @@ export class OrganizationController { } - public removeAgreement = async (req: any, res: Response) => { + /** + * Removes an agreement from the organization. + */ + public removeAgreement = async (req: Request, res: Response) => { try { const agreementId: string = req.params.agreementId; const createdResponseModel = await this.organizationService.removeAgreement( - req.user.walletAddress, + req.user!.address, agreementId); res.status(createdResponseModel.statusCode).json(handleResponse(createdResponseModel)); @@ -160,7 +184,10 @@ export class OrganizationController { } } - public getContribAgreement = async (req: any, res: Response) => { + /** + * Retrieves the contribution agreement for a given contributor. + */ + public getContribAgreement = async (req: Request, res: Response) => { try { const contributorId = req.params.contributorId; const createdResponseModel = await this.organizationService.getUserAgreement(contributorId); @@ -172,10 +199,13 @@ export class OrganizationController { } } - public getMyScores = async (req: any, res: Response) => { + /** + * Retrieves the scores for the current user's organization. + */ + public getMyScores = async (req: Request, res: Response) => { try { const createdResponseModel = await this.organizationService - .getScoresByWalletAddress(req.user.walletAddress); + .getScoresByWalletAddress(req.user!.address); res.status(createdResponseModel.statusCode).json(handleResponse(createdResponseModel)); } catch (error) { diff --git a/src/controllers/payout.controller.ts b/src/controllers/payout.controller.ts new file mode 100644 index 0000000..3345183 --- /dev/null +++ b/src/controllers/payout.controller.ts @@ -0,0 +1,94 @@ +import { injectable, inject } from 'inversify'; +import { Request, Response } from 'express'; +import { PayoutService } from '../services/payout.service.js'; +import { TYPES } from '../inversify.types.js'; +import { payoutRoundsQuerySchema } from '../models/payout/payout-rounds-query.model.js'; +import { payoutPreviewQuerySchema } from '../models/payout/payout-preview-query.model.js'; +import { proposePayoutSchema } from '../models/payout/propose-payout.model.js'; +import { payoutStatusQuerySchema } from '../models/payout/payout-status-query.model.js'; +import { TokenType } from '../entities/payout/tx-proposal.model.js'; + +@injectable() +export class PayoutController { + constructor(@inject(TYPES.PayoutService) private payoutService: PayoutService) {} + + /** + * GET /payouts/rounds?orgId= → List incomplete rounds + */ + public getIncompleteRounds = async (req: Request, res: Response): Promise => { + try { + const isValid = payoutRoundsQuerySchema.validate(req.query); + if (isValid.error) { + res.status(400).json({ message: isValid.error.message }); + return; + } + + const { orgId } = req.query; + const rounds = await this.payoutService.getIncompleteRounds(orgId as string); + res.status(200).json(rounds); + } catch (error: any) { + res.status(500).json({ error: error.message }); + } + } + + /** + * GET /payouts/preview?roundId= → Recipient list (human + base-unit), totals, preflight checks, chunk plan + */ + public previewPayout = async (req: Request, res: Response): Promise => { + try { + const isValid = payoutPreviewQuerySchema.validate(req.query); + if (isValid.error) { + res.status(400).json({ message: isValid.error.message }); + return; + } + + const { roundId } = req.query; + const preview = await this.payoutService.previewPayout(roundId as string); + res.status(200).json(preview); + } catch (error: any) { + res.status(500).json({ error: error.message }); + } + } + + /** + * POST /payouts/propose { roundId, tokenType } → + * Build batched calls, create Safe transaction, propose it, store proposal, + * return Safe link + */ + public proposePayout = async (req: Request, res: Response): Promise => { + try { + const isValid = proposePayoutSchema.validate(req.body); + if (isValid.error) { + res.status(400).json({ message: isValid.error.message }); + return; + } + + const { roundId, tokenType } = req.body as { roundId: string; tokenType: 'STABLECOIN' | 'RECOGNITION' }; + const mappedTokenType: TokenType = tokenType === 'STABLECOIN' ? TokenType.STABLECOIN : TokenType.RECOGNITION; + + const proposal = await this.payoutService.proposePayout(roundId, mappedTokenType); + res.status(200).json(proposal); + } catch (error: any) { + res.status(500).json({ error: error.message }); + } + } + + /** + * GET /payouts/status?roundId= → Poll Transaction Service for statuses; update records accordingly + */ + public getPayoutStatus = async (req: Request, res: Response): Promise => { + try { + const isValid = payoutStatusQuerySchema.validate(req.query); + if (isValid.error) { + res.status(400).json({ message: isValid.error.message }); + return; + } + + const { roundId } = req.query; + const status = await this.payoutService.getPayoutStatus(roundId as string); + res.status(200).json(status); + } catch (error: any) { + res.status(500).json({ error: error.message }); + } + } +} diff --git a/src/controllers/rounds.controller.ts b/src/controllers/rounds.controller.ts index ba93c81..8277d51 100644 --- a/src/controllers/rounds.controller.ts +++ b/src/controllers/rounds.controller.ts @@ -1,22 +1,28 @@ -import { injectable } from 'inversify'; +import { inject, injectable } from 'inversify'; +import { TYPES } from '../inversify.types.js'; import { Response } from 'express'; import { handleResponse } from '../models/response_models/request_handler.js'; import { RoundService } from '../services/round.service.js'; import { CreateAssessmentModel, createAssessmentSchema } from '../models/rounds/createAssessment.model.js'; import { UserService } from '../services/user.service.js'; +import { Request } from 'express'; +import { AddTokenMintTxModel } from '../models/rounds/addTokenMintTx.model.js'; @injectable() export class RoundsController { constructor( - private roundService: RoundService, - private userService: UserService + @inject(TYPES.RoundService) private roundService: RoundService, + @inject(TYPES.UserService) private userService: UserService ) { } - public getCurrentRound = async (req: any, res: Response) => { + /** + * Retrieves the current round for the user's organization. + */ + public getCurrentRound = async (req: Request, res: Response) => { try { - const walletAddress = req.user.walletAddress; + const walletAddress = req.user!.address; const responseModel = await this.userService.getByWalletAddress(walletAddress); if (!responseModel.data?.organization?.id) { return res.status(403).json({ message: 'User does not have an org' }); @@ -29,9 +35,12 @@ export class RoundsController { } } - public getRounds = async (req: any, res: Response) => { + /** + * Retrieves all rounds for the user's organization. + */ + public getRounds = async (req: Request, res: Response) => { try { - const walletAddress = req.user.walletAddress; + const walletAddress = req.user!.address; const responseModel = await this.userService.getByWalletAddress(walletAddress); if (!responseModel.data?.organization?.id) { return res.status(403).json({ message: 'User does not have an org' }); @@ -44,7 +53,10 @@ export class RoundsController { } } - public getRoundById = async (req: any, res: Response) => { + /** + * Retrieves a round by its ID. + */ + public getRoundById = async (req: Request, res: Response) => { try { const roundId = req.params.roundId; const createdResponseModel = await this.roundService.getRoundById(roundId); @@ -55,10 +67,13 @@ export class RoundsController { } } - public editRound = async (req: any, res: Response) => { + /** + * Edits a round. + */ + public editRound = async (req: Request, res: Response) => { try { const model = req.body; - const walletAddress = req.user.walletAddress; + const walletAddress = req.user!.address; const responseModel = await this.userService.getByWalletAddress(walletAddress); if (!responseModel.data?.isAdmin) { return res.status(403).json({ message: 'User is not an admin' }); @@ -76,18 +91,14 @@ export class RoundsController { } } - public addAssessment = async (req: any, res: Response) => { + /** + * Adds an assessment to a round. + */ + public addAssessment = async (req: Request, res: Response) => { try { const model: CreateAssessmentModel = req.body!; - const isValid = createAssessmentSchema.validate(model); - if (isValid.error) { - return res.status(400).json({ message: isValid.error.message }); - } - - const createdResponseModel = await this.roundService.addAssessment( - (req as any).user.walletAddress, - model); - res.status(createdResponseModel.statusCode).json(handleResponse(createdResponseModel)); + const responseModel = await this.roundService.addAssessment(req.user!.address, model); + res.status(responseModel.statusCode).json(handleResponse(responseModel)); } catch (error) { console.error('Error editing an org:', error); res.status(500).send('Internal Server Error'); @@ -95,33 +106,29 @@ export class RoundsController { } - public editAssessment = async (req: any, res: Response) => { + /** + * Edits an assessment. + */ + public editAssessment = async (req: Request, res: Response) => { try { const model: CreateAssessmentModel = req.body!; - const isValid = createAssessmentSchema.validate(model); - if (isValid.error) { - return res.status(400).json({ message: isValid.error.message }); - } - const assessmentId: string = req.params.assessmentId; - - const createdResponseModel = await this.roundService.editAssessment( - assessmentId, - (req as any).user.walletAddress, - model - ); - res.status(createdResponseModel.statusCode).json(handleResponse(createdResponseModel)); + const responseModel = await this.roundService.editAssessment(assessmentId, req.user!.address, model); + res.status(responseModel.statusCode).json(handleResponse(responseModel)); } catch (error) { console.error('Error editing an org:', error); res.status(500).send('Internal Server Error'); } } - public getAssessments = async (req: any, res: Response) => { + /** + * Retrieves assessments for a round. + */ + public getAssessments = async (req: Request, res: Response) => { try { const roundId = req.params.roundId; - const assessorId = req.query.assessorId; - const assessedId = req.query.assessedId; + const assessorId = req.query.assessorId as string | undefined; + const assessedId = req.query.assessedId as string | undefined; const createdResponseModel = await this.roundService.getAssessments(roundId, assessorId, assessedId); res.status(createdResponseModel.statusCode).json(handleResponse(createdResponseModel)); } catch (error) { @@ -130,7 +137,10 @@ export class RoundsController { } } - public remind = async (req: any, res: Response) => { + /** + * Sends a reminder to assess. + */ + public remind = async (req: Request, res: Response) => { try { const roundId = req.params.roundId; const { all, users } = req.body; @@ -143,23 +153,14 @@ export class RoundsController { } - public addTokenMintTx = async (req: any, res: Response) => { + /** + * Adds a token mint transaction to a round. + */ + public addTokenMintTx = async (req: Request, res: Response) => { try { - const walletAddress = req.user.walletAddress; - const responseModel = await this.userService.getByWalletAddress(walletAddress); - if (!responseModel.data?.isAdmin) { - return res.status(403).json({ message: 'User is not an admin' }); - } - if (!responseModel.data?.organization?.id) { - return res.status(403).json({ message: 'User does not have an org' }); - } - - const txId = req.body.txId; - if (!txId) { - return res.status(400).json({ message: 'txId is required' }); - } - const result = await this.roundService.addTokenMintTx(req.params.roundId, txId); - res.status(result.statusCode).json(handleResponse(result)); + const model: AddTokenMintTxModel = req.body!; + const responseModel = await this.roundService.addTokenMintTx(model.roundId, model.txHash); + res.status(responseModel.statusCode).json(handleResponse(responseModel)); } catch (error) { console.error('Error editing an org:', error); res.status(500).send('Internal Server Error'); diff --git a/src/controllers/user.controller.ts b/src/controllers/user.controller.ts index 68a151f..1934456 100644 --- a/src/controllers/user.controller.ts +++ b/src/controllers/user.controller.ts @@ -1,4 +1,5 @@ -import { injectable } from 'inversify'; +import { inject, injectable } from 'inversify'; +import { TYPES } from '../inversify.types.js'; import { Request, Response } from 'express'; import { UserService } from '../services/user.service.js'; import { CreateUserModel, createUserScheme } from '../models/user/userRegistration.model.js'; @@ -9,18 +10,13 @@ import { uploadFileToS3 } from '../utils/fileUploader.js'; @injectable() export class UserController { - constructor(private userService: UserService) { } + constructor(@inject(TYPES.UserService) private userService: UserService) { } /** * Request a nonce for wallet authentication */ public requestNonce = async (req: Request, res: Response) => { try { - const isValid = walletAddressSchema.validate(req.body); - if (isValid.error) { - return res.status(400).json({ message: isValid.error.message }); - } - // Request nonce from the AuthService const responseModel = await this.userService.requestNonce(req.body.walletAddress); res.status(responseModel.statusCode).json(handleResponse(responseModel)); @@ -37,10 +33,6 @@ export class UserController { try { const { message, signature } = req.body; - const isValid = verifySignatureSchema.validate(req.body); - if (isValid.error) { - return res.status(400).json({ message: isValid.error.message }); - } // Verify the signature and authenticate the user const responseModel = await this.userService.verifySignature(message, signature); res.status(responseModel.statusCode).json(handleResponse(responseModel)); @@ -53,34 +45,30 @@ export class UserController { /** * Register a new user */ - public registerUser = async (req: any, res: Response) => { + public registerUser = async (req: Request, res: Response) => { try { - const body: CreateUserModel = req.body; - const isValid = createUserScheme.validate(body); - if (isValid.error) { - return res.status(400).json({ message: isValid.error.message }); - } - - body.walletAddress = req.user.walletAddress; + const model: CreateUserModel = req.body; - // Handle file upload (assuming the file is sent in req.file or req.files) - const file = (req as any).file; - let avatar: string | undefined; + const file = req.file; + let avatarUrl: string | undefined; - if (file) { - const uploadResult = await uploadFileToS3({ - Bucket: process.env.S3_BUCKET_NAME!, // Ensure your bucket name is in env variables - Key: `profile-pics/${file.originalname}`, // Customize the path and filename as needed - Body: file.buffer, - ContentType: file.mimetype - }); + if (file) { + const uploadResult = await uploadFileToS3({ + Bucket: process.env.S3_BUCKET_NAME!, + Key: `user-avatars/${file.originalname}`, + Body: file.buffer, + ContentType: file.mimetype + }); - avatar = `https://${process.env.S3_BUCKET_NAME}.s3.amazonaws.com/${uploadResult}`; - } + avatarUrl = `https://${process.env.S3_BUCKET_NAME}.s3.amazonaws.com/${uploadResult}`; + } - body.profilePicture = avatar; - const responseModel = await this.userService.registerUser(body); - return res.status(responseModel.statusCode).json(handleResponse(responseModel)); + const responseModel = await this.userService.registerUser({ + ...model, + profilePicture: avatarUrl, + walletAddress: req.user!.address + }); + res.status(responseModel.statusCode).json(handleResponse(responseModel)); } catch (error) { console.error('Error registering user:', error); res.status(500).send('Internal Server Error'); @@ -91,13 +79,12 @@ export class UserController { /** * Get User Me */ - public getUserMe = async (req: any, res: Response) => { + public getUserMe = async (req: Request, res: Response) => { try { - const walletAddress = req.user.walletAddress; - const responseModel = await this.userService.getByWalletAddress(walletAddress); - return res.status(responseModel.statusCode).json(handleResponse(responseModel)); + const responseModel = await this.userService.getByWalletAddress(req.user!.address); + res.status(responseModel.statusCode).json(handleResponse(responseModel)); } catch (error) { - console.error('Error registering user:', error); + console.error('Error getting user:', error); res.status(500).send('Internal Server Error'); } } diff --git a/src/data-source.ts b/src/data-source.ts index 175e87c..9006837 100644 --- a/src/data-source.ts +++ b/src/data-source.ts @@ -3,21 +3,37 @@ import { config as dotenv_config } from 'dotenv'; import { SharedEntities } from './shared-entities.js'; dotenv_config(); -export const AppDataSource = new DataSource({ - type: 'mysql', - host: process.env.DB_HOST, - port: Number(process.env.DB_PORT) || 3306, - username: process.env.DB_UNAME, - password: process.env.DB_PASS, - database: process.env.DB_NAME, - synchronize: true, - logging: ['error'], - entities: SharedEntities, - subscribers: [], - migrations: [], - timezone: 'Z', - extra: { - // Add the allowPublicKeyRetrieval option here - allowPublicKeyRetrieval: true - } -}); +/** + * Supports both MySQL and SQLite for local development. + * Set DB_TYPE=sqlite (and optional SQLITE_PATH) in .env to run without MySQL. + */ +const dbType = (process.env.DB_TYPE || 'mysql').toLowerCase(); + +export const AppDataSource = dbType === 'sqlite' + ? new DataSource({ + type: 'sqlite', + database: process.env.SQLITE_PATH || './cb-local.sqlite', + synchronize: true, + logging: ['error'], + entities: SharedEntities, + subscribers: [], + migrations: [] + }) + : new DataSource({ + type: 'mysql', + host: process.env.DB_HOST, + port: Number(process.env.DB_PORT) || 3306, + username: process.env.DB_UNAME, + password: process.env.DB_PASS, + database: process.env.DB_NAME, + synchronize: true, + logging: ['error'], + entities: SharedEntities, + subscribers: [], + migrations: [], + timezone: 'Z', + extra: { + // Add the allowPublicKeyRetrieval option here + allowPublicKeyRetrieval: true + } + }); diff --git a/src/entities/assessment/round.model.ts b/src/entities/assessment/round.model.ts index 7ae856e..28ff1bf 100644 --- a/src/entities/assessment/round.model.ts +++ b/src/entities/assessment/round.model.ts @@ -13,19 +13,19 @@ export class Round { @Column({ type: 'boolean', default: false}) isCompleted!: boolean; - @Column({ type: 'timestamp' }) + @Column({ type: 'datetime' }) startDate!: Date; - @Column({ type: 'timestamp' }) + @Column({ type: 'datetime' }) endDate!: Date; @Column({ type: 'varchar', nullable: true }) txHash!: string | null; - @Column({ type: 'timestamp', nullable: false }) + @Column({ type: 'datetime', nullable: false }) compensationCycleStartDate!: Date; - @Column({ type: 'timestamp', nullable: false }) + @Column({ type: 'datetime', nullable: false }) compensationCycleEndDate!: Date; @OneToMany(() => Assessment, (assessment) => assessment.round, { cascade: true }) diff --git a/src/entities/index.ts b/src/entities/index.ts index 58f3586..e9c1eef 100644 --- a/src/entities/index.ts +++ b/src/entities/index.ts @@ -1,3 +1,4 @@ export * from './org/index.js'; export * from './users/index.js'; export * from './assessment/index.js'; +export * from './payout/index.js'; diff --git a/src/entities/org/orgInvitation.model.ts b/src/entities/org/orgInvitation.model.ts index 73991f5..4487fd5 100644 --- a/src/entities/org/orgInvitation.model.ts +++ b/src/entities/org/orgInvitation.model.ts @@ -18,7 +18,7 @@ export class Invitation { @JoinColumn({ name: 'invited_by' }) invitedBy!: User; - @CreateDateColumn({ type: 'timestamp' }) + @CreateDateColumn({ type: 'datetime' }) createdAt!: Date; @Column({ type: 'boolean', default: true }) diff --git a/src/entities/org/organization.model.ts b/src/entities/org/organization.model.ts index 2b382af..364b68e 100644 --- a/src/entities/org/organization.model.ts +++ b/src/entities/org/organization.model.ts @@ -3,6 +3,16 @@ import { CompensationPeriod } from './cycle.enum.js'; import { Round } from '../assessment/round.model.js'; import { User } from '../users/user.model.js'; +/** + * Defines the modes for recognition tokens, specifying whether a custom + * token is used or if recognition is disabled. + */ +export enum RecognitionTokenMode { + MINT = 'mint', + TRANSFER = 'transfer', + NONE = 'none' +} + @Entity('organizations') export class Organization { @PrimaryGeneratedColumn('uuid') @@ -26,13 +36,13 @@ export class Organization { @Column({ type: 'int', default: 0 }) totalFunds!: number; - @Column({ type: 'timestamp', default: () => 'CURRENT_TIMESTAMP' }) + @Column({ type: 'datetime', default: () => 'CURRENT_TIMESTAMP' }) createdOn!: Date; - @Column('enum', { enum: CompensationPeriod, nullable: true }) + @Column({ type: 'simple-enum', enum: CompensationPeriod, nullable: true }) compensationPeriod!: CompensationPeriod | null; - @Column({ type: 'timestamp', nullable: true }) + @Column({ type: 'datetime', nullable: true }) compensationStartDay!: Date | null; @Column({ type: 'int', nullable: true }) @@ -46,4 +56,53 @@ export class Organization { @OneToMany(() => User, (user) => user.organization, { cascade: false }) contributors?: Relation; + + /** + * The address of the Gnosis Safe used for treasury management. + * This is optional and can be configured by the organization admin. + */ + @Column({ type: 'varchar', length: 255, nullable: true }) + safeAddress?: string; + + /** + * The chain ID where the Gnosis Safe is deployed. + * This is optional and corresponds to the network of the Safe. + */ + @Column({ type: 'int', nullable: true }) + safeChainId?: number; + + /** + * The contract address of the stablecoin used for compensation payouts. + * This is optional and is defined by the organization. + */ + @Column({ type: 'varchar', length: 255, nullable: true }) + stablecoinAddress?: string; + + /** + * The number of decimals for the stablecoin, used for precise calculations. + * This is optional and is typically 6 or 18. + */ + @Column({ type: 'int', nullable: true }) + stablecoinDecimals?: number; + + /** + * The contract address of the custom recognition token. + * This is optional and is used if the organization has its own token. + */ + @Column({ type: 'varchar', length: 255, nullable: true }) + recognitionTokenAddress?: string; + + /** + * The number of decimals for the recognition token. + * This is optional and is defined by the token contract. + */ + @Column({ type: 'int', nullable: true }) + recognitionTokenDecimals?: number; + + /** + * The mode for the recognition token, indicating if it's a custom token or none. + * This is optional and defaults to NONE. + */ + @Column({ type: 'simple-enum', enum: RecognitionTokenMode, nullable: true }) + recognitionTokenMode?: RecognitionTokenMode; } diff --git a/src/entities/payout/index.ts b/src/entities/payout/index.ts new file mode 100644 index 0000000..e713c8a --- /dev/null +++ b/src/entities/payout/index.ts @@ -0,0 +1,3 @@ +export * from './payout.model.js'; +export * from './payout-recipient.model.js'; +export * from './tx-proposal.model.js'; diff --git a/src/entities/payout/payout-recipient.model.ts b/src/entities/payout/payout-recipient.model.ts new file mode 100644 index 0000000..4f7ca9b --- /dev/null +++ b/src/entities/payout/payout-recipient.model.ts @@ -0,0 +1,70 @@ +import { Entity, PrimaryGeneratedColumn, Column, CreateDateColumn, UpdateDateColumn, ManyToOne } from 'typeorm'; +import { Payout } from './payout.model.js'; +import { TxProposal } from './tx-proposal.model.js'; +import { User } from '../users/user.model.js'; +import { TokenType } from './tx-proposal.model.js'; + +export enum PayoutRecipientStatus { + PENDING = 'pending', + PROPOSED = 'proposed', + EXECUTED = 'executed', + FAILED = 'failed', + SKIPPED = 'skipped' +} + +@Entity('payout_recipients') +export class PayoutRecipient { + @PrimaryGeneratedColumn('uuid') + id!: string; + + @ManyToOne(() => Payout) + payout!: Payout; + + @Column({ nullable: true }) + roundCompensationId!: string; + + @ManyToOne(() => User) + user!: User; + + @Column() + walletAddressSnapshot!: string; + + @Column({ type: 'simple-enum', enum: TokenType }) + tokenType!: TokenType; + + @Column() + tokenAddressSnapshot!: string; + + @Column() + tokenDecimalsSnapshot!: number; + + @Column({ type: 'decimal', precision: 18, scale: 6 }) + amountHuman!: number; + + @Column({ type: 'decimal', precision: 30, scale: 0 }) + amountBaseUnits!: string; + + @ManyToOne(() => TxProposal) + txProposal!: TxProposal; + + @Column() + partIndex!: number; + + @Column() + partCount!: number; + + @Column({ default: 1 }) + attempt!: number; + + @Column({ type: 'simple-enum', enum: PayoutRecipientStatus, default: PayoutRecipientStatus.PENDING }) + status!: PayoutRecipientStatus; + + @Column({ nullable: true }) + error!: string; + + @CreateDateColumn() + createdAt!: Date; + + @UpdateDateColumn() + updatedAt!: Date; +} diff --git a/src/entities/payout/payout.model.ts b/src/entities/payout/payout.model.ts new file mode 100644 index 0000000..53b093a --- /dev/null +++ b/src/entities/payout/payout.model.ts @@ -0,0 +1,41 @@ +import { Entity, PrimaryGeneratedColumn, Column, CreateDateColumn, UpdateDateColumn, ManyToOne, OneToMany } from 'typeorm'; +import { Organization } from '../org/organization.model.js'; +import { TxProposal } from './index.js'; + +export enum PayoutStatus { + DRAFT = 'draft', + PROPOSED = 'proposed', + EXECUTED = 'executed', + PARTIAL = 'partial', + FAILED = 'failed' +} + +@Entity('payouts') +export class Payout { + @PrimaryGeneratedColumn('uuid') + id!: string; + + @ManyToOne(() => Organization) + organization!: Organization; + + @Column({ nullable: true }) + roundId!: string; + + @Column({ type: 'simple-enum', enum: PayoutStatus, default: PayoutStatus.DRAFT }) + status!: PayoutStatus; + + @Column({ type: 'decimal', precision: 18, scale: 2, nullable: true }) + totalStablePayout!: number; + + @Column({ type: 'decimal', precision: 18, scale: 2, nullable: true }) + totalRecognitionPayout!: number; + + @OneToMany(() => TxProposal, (txProposal) => txProposal.payout, { cascade: true }) + txProposals!: TxProposal[]; + + @CreateDateColumn() + createdAt!: Date; + + @UpdateDateColumn() + updatedAt!: Date; +} diff --git a/src/entities/payout/tx-proposal.model.ts b/src/entities/payout/tx-proposal.model.ts new file mode 100644 index 0000000..bfe1316 --- /dev/null +++ b/src/entities/payout/tx-proposal.model.ts @@ -0,0 +1,64 @@ +import { Entity, PrimaryGeneratedColumn, Column, CreateDateColumn, UpdateDateColumn, ManyToOne } from 'typeorm'; +import { Payout } from './index.js'; + +export enum PayoutType { + ROUND = 'round', + MANUAL = 'manual' +} + +export enum TokenType { + STABLECOIN = 'stablecoin', + RECOGNITION = 'recognition' +} + +export enum TxProposalStatus { + PROPOSED = 'proposed', + EXECUTED = 'executed', + FAILED = 'failed', + CANCELED = 'canceled' +} + +@Entity('tx_proposals') +export class TxProposal { + @PrimaryGeneratedColumn('uuid') + id!: string; + + @ManyToOne(() => Payout, (payout) => payout.txProposals) + payout!: Payout; + + @Column({ type: 'simple-enum', enum: PayoutType }) + payoutType!: PayoutType; + + @Column({ type: 'simple-enum', enum: TokenType }) + tokenType!: TokenType; + + @Column() + partIndex!: number; + + @Column() + partCount!: number; + + @Column({ default: 1 }) + attempt!: number; + + @Column({ type: 'uuid', nullable: true }) + retryOfTxProposalId!: string; + + @Column({ nullable: true }) + safeTxHash!: string; + + @Column({ type: 'simple-enum', enum: TxProposalStatus, default: TxProposalStatus.PROPOSED }) + status!: TxProposalStatus; + + @Column({ type: 'json', nullable: true }) + payloadJson!: any; + + @Column({ nullable: true }) + explorerUrl!: string; + + @CreateDateColumn() + proposedAt!: Date; + + @UpdateDateColumn() + executedAt!: Date; +} diff --git a/src/entities/users/nonce.model.ts b/src/entities/users/nonce.model.ts index 578978e..f244773 100644 --- a/src/entities/users/nonce.model.ts +++ b/src/entities/users/nonce.model.ts @@ -11,7 +11,7 @@ export class WalletNonce { @Column({ type: 'varchar', length: 255 }) nonce!: string; - @CreateDateColumn({ type: 'timestamp' }) + @CreateDateColumn({ type: 'datetime' }) createdAt!: Date; } diff --git a/src/entities/users/user.model.ts b/src/entities/users/user.model.ts index 1ebf5b8..ad4dea3 100644 --- a/src/entities/users/user.model.ts +++ b/src/entities/users/user.model.ts @@ -22,7 +22,7 @@ export class User { @Column({ type: 'varchar', nullable: true }) profilePicture?: string; - @Column({ type: 'timestamp', default: () => 'CURRENT_TIMESTAMP' }) + @Column({ type: 'datetime', default: () => 'CURRENT_TIMESTAMP' }) registeredOn!: Date; @OneToOne(() => Agreement, { nullable: true, cascade: true }) diff --git a/src/errors/invalid-data.error.ts b/src/errors/invalid-data.error.ts new file mode 100644 index 0000000..ac9220d --- /dev/null +++ b/src/errors/invalid-data.error.ts @@ -0,0 +1,6 @@ +export class InvalidDataError extends Error { + constructor(message: string) { + super(message); + this.name = 'InvalidDataError'; + } +} diff --git a/src/errors/not-found.error.ts b/src/errors/not-found.error.ts new file mode 100644 index 0000000..49346e0 --- /dev/null +++ b/src/errors/not-found.error.ts @@ -0,0 +1,6 @@ +export class NotFoundError extends Error { + constructor(message: string) { + super(message); + this.name = 'NotFoundError'; + } +} diff --git a/src/errors/safe.service.error.ts b/src/errors/safe.service.error.ts new file mode 100644 index 0000000..5898927 --- /dev/null +++ b/src/errors/safe.service.error.ts @@ -0,0 +1,8 @@ +export class SafeServiceError extends Error { + constructor(message: string) { + super(message); + this.name = 'SafeServiceError'; + Object.setPrototypeOf(this, SafeServiceError.prototype); + } +} + diff --git a/src/index.ts b/src/index.ts index 2dbf039..eaa97ea 100644 --- a/src/index.ts +++ b/src/index.ts @@ -7,19 +7,23 @@ import { AppDataSource } from './data-source.js'; // Initialize configuration dotenv.config(); -let server; -try { +(async () => { + let server; + try { + // Initialize the data source first + await AppDataSource.initialize(); + console.log('App Data Source Connected'); // Then start the application server const application = container.get(App); - AppDataSource.initialize().then(() => { console.log('App Data Source Connected'); }); - server = application.app.listen(process.env.PORT, async () => { - console.log(`Server started at http://localhost:${process.env.PORT}.`); + server = application.app.listen(process.env.PORT, () => { + console.log(`Server started at http://localhost:${process.env.PORT}.`); }); -} catch (err) { + } catch (err) { if (server?.listening) { - server.close(); + server.close(); } - console.error(err); - process.exitCode = 1; -} + console.error('Failed to start the server:', err); + process.exit(1); + } +})(); diff --git a/src/inversify.config.ts b/src/inversify.config.ts index dceaaa1..8258ae6 100644 --- a/src/inversify.config.ts +++ b/src/inversify.config.ts @@ -1,8 +1,54 @@ +import 'reflect-metadata'; import { Container } from 'inversify'; +import { TYPES } from './inversify.types.js'; +import { App } from './app.js'; +import { UserRouter } from './routers/user.router.js'; +import { OrgRouter } from './routers/org.router.js'; +import { RoundsRouter } from './routers/rounds.router.js'; +import { OrganizationConfigurationRouter } from './routers/organization-configuration.router.js'; +import { PayoutRouter } from './routers/payout.router.js'; -const container = new Container({ - autoBindInjectable: true, - defaultScope: 'Singleton' -}); +import { UserController } from './controllers/user.controller.js'; +import { OrganizationController } from './controllers/organization.controller.js'; +import { RoundsController } from './controllers/rounds.controller.js'; +import { PayoutController } from './controllers/payout.controller.js'; +import { OrganizationConfigurationController } from './controllers/organization-configuration.controller.js'; +import { OrganizationConfigurationService } from './services/org/organization-configuration.service.js'; +import { UserService } from './services/user.service.js'; +import { OrganizationService } from './services/organization.service.js'; +import { RoundService } from './services/round.service.js'; +import { PayoutService } from './services/payout.service.js'; +import { SafeTransactionService } from './services/safe/safe-transaction.service.js'; +import { EmailService } from './services/email.service.js'; +import { TeamPointsService } from './services/teamPoints.service.js'; + +const container = new Container(); + +// Bind App +container.bind(App).toSelf(); + +// Bind Routers +container.bind(UserRouter).toSelf(); +container.bind(OrgRouter).toSelf(); +container.bind(RoundsRouter).toSelf(); +container.bind(OrganizationConfigurationRouter).toSelf(); +container.bind(PayoutRouter).toSelf(); + +// Bind Controllers +container.bind(UserController).toSelf(); +container.bind(OrganizationController).toSelf(); +container.bind(RoundsController).toSelf(); +container.bind(PayoutController).toSelf(); +container.bind(OrganizationConfigurationController).toSelf(); + +// Bind Services +container.bind(TYPES.UserService).to(UserService).inSingletonScope(); +container.bind(OrganizationService).toSelf(); +container.bind(TYPES.RoundService).to(RoundService).inSingletonScope(); +container.bind(TYPES.OrganizationConfigurationService).to(OrganizationConfigurationService).inSingletonScope(); +container.bind(TYPES.PayoutService).to(PayoutService).inSingletonScope(); +container.bind(TYPES.SafeTransactionService).to(SafeTransactionService).inSingletonScope(); +container.bind(TYPES.EmailService).to(EmailService).inSingletonScope(); +container.bind(TYPES.TeamPointsService).to(TeamPointsService).inSingletonScope(); export { container }; diff --git a/src/inversify.types.ts b/src/inversify.types.ts new file mode 100644 index 0000000..8e6c184 --- /dev/null +++ b/src/inversify.types.ts @@ -0,0 +1,12 @@ +const TYPES = { + SafeService: Symbol.for('SafeService'), + SafeTransactionService: Symbol.for('SafeTransactionService'), + PayoutService: Symbol.for('PayoutService'), + OrganizationConfigurationService: Symbol.for('OrganizationConfigurationService'), + EmailService: Symbol.for('EmailService'), + UserService: Symbol.for('UserService'), + RoundService: Symbol.for('RoundService'), + TeamPointsService: Symbol.for('TeamPointsService') +}; + +export { TYPES }; diff --git a/src/models/payout/payout-preview-query.model.ts b/src/models/payout/payout-preview-query.model.ts new file mode 100644 index 0000000..234053c --- /dev/null +++ b/src/models/payout/payout-preview-query.model.ts @@ -0,0 +1,13 @@ +import Joi from 'joi'; + +export interface PayoutPreviewQueryModel { + roundId: string; +} + +export const payoutPreviewQuerySchema = Joi.object({ + roundId: Joi.string().required().messages({ + 'string.empty': 'Round ID is required', + 'any.required': 'Round ID is required' + }) +}); + diff --git a/src/models/payout/payout-rounds-query.model.ts b/src/models/payout/payout-rounds-query.model.ts new file mode 100644 index 0000000..3ad99db --- /dev/null +++ b/src/models/payout/payout-rounds-query.model.ts @@ -0,0 +1,13 @@ +import Joi from 'joi'; + +export interface PayoutRoundsQueryModel { + orgId: string; +} + +export const payoutRoundsQuerySchema = Joi.object({ + orgId: Joi.string().required().messages({ + 'string.empty': 'Organization ID is required', + 'any.required': 'Organization ID is required' + }) +}); + diff --git a/src/models/payout/payout-status-query.model.ts b/src/models/payout/payout-status-query.model.ts new file mode 100644 index 0000000..c5ee04a --- /dev/null +++ b/src/models/payout/payout-status-query.model.ts @@ -0,0 +1,13 @@ +import Joi from 'joi'; + +export interface PayoutStatusQueryModel { + roundId: string; +} + +export const payoutStatusQuerySchema = Joi.object({ + roundId: Joi.string().required().messages({ + 'string.empty': 'Round ID is required', + 'any.required': 'Round ID is required' + }) +}); + diff --git a/src/models/payout/propose-payout.model.ts b/src/models/payout/propose-payout.model.ts new file mode 100644 index 0000000..9d9c549 --- /dev/null +++ b/src/models/payout/propose-payout.model.ts @@ -0,0 +1,22 @@ +import Joi from 'joi'; + +export interface ProposePayoutModel { + roundId: string; + tokenType: 'STABLECOIN' | 'RECOGNITION'; +} + +export const proposePayoutSchema = Joi.object({ + roundId: Joi.string().required().messages({ + 'string.empty': 'Round ID is required', + 'any.required': 'Round ID is required' + }), + tokenType: Joi.string() + .valid('STABLECOIN', 'RECOGNITION') + .required() + .messages({ + 'string.empty': 'Token type is required', + 'any.required': 'Token type is required', + 'any.only': 'Token type must be either STABLECOIN or RECOGNITION' + }) +}); + diff --git a/src/models/rounds/addTokenMintTx.model.ts b/src/models/rounds/addTokenMintTx.model.ts new file mode 100644 index 0000000..8d97ebe --- /dev/null +++ b/src/models/rounds/addTokenMintTx.model.ts @@ -0,0 +1,12 @@ +import Joi from 'joi'; + +export interface AddTokenMintTxModel { + roundId: string; + txHash: string; +} + +export const addTokenMintTxSchema = Joi.object({ + roundId: Joi.string().required(), + txHash: Joi.string().required() +}); + diff --git a/src/roundsStartJob.index.ts b/src/roundsStartJob.index.ts index 47e43b6..2d40e69 100644 --- a/src/roundsStartJob.index.ts +++ b/src/roundsStartJob.index.ts @@ -2,6 +2,7 @@ import { config as dotenv_config } from 'dotenv'; import cron from 'node-cron'; import { container } from './inversify.config.js'; +import { TYPES } from './inversify.types.js'; import { RoundService } from './services/round.service.js'; import { AppDataSource } from './data-source.js'; @@ -20,7 +21,7 @@ try { throw new Error('Start Round Generation schedule not defined.'); } - const roundService = container.get(RoundService); + const roundService = container.get(TYPES.RoundService); cron.schedule(roundStartGenerationSchedule, async () => { try { diff --git a/src/routers/organization-configuration.router.ts b/src/routers/organization-configuration.router.ts new file mode 100644 index 0000000..50eecb7 --- /dev/null +++ b/src/routers/organization-configuration.router.ts @@ -0,0 +1,41 @@ +import { Router } from 'express'; +import { injectable } from 'inversify'; +import { jwtMiddleware } from '../middleware/jwt.middleware.js'; +import { adminMiddleware } from '../middleware/admin.middleware.js'; +import { OrganizationConfigurationController } from '../controllers/organization-configuration.controller.js'; + +@injectable() +export class OrganizationConfigurationRouter { + private readonly _router: Router; + + constructor(private organizationConfigurationController: OrganizationConfigurationController) { + this._router = Router({ strict: true }); + this.init(); + } + + private init(): void { + // Public endpoint: list supported chains + this._router.get('/supported-chains', (req, res) => + this.organizationConfigurationController.getSupportedChains(res) + ); + + // Admin endpoints: validate and update Safe configuration + this._router.post( + '/validate-safe-config', + jwtMiddleware, + adminMiddleware, + (req, res) => this.organizationConfigurationController.validateSafeConfig(req as any, res) + ); + + this._router.put( + '/safe-config', + jwtMiddleware, + adminMiddleware, + (req, res) => this.organizationConfigurationController.updateSafeConfig(req as any, res) + ); + } + + public get router(): Router { + return this._router; + } +} diff --git a/src/routers/payout.router.ts b/src/routers/payout.router.ts new file mode 100644 index 0000000..3055def --- /dev/null +++ b/src/routers/payout.router.ts @@ -0,0 +1,24 @@ +import { Router } from 'express'; +import { injectable } from 'inversify'; +import { PayoutController } from '../controllers/payout.controller.js'; + +@injectable() +export class PayoutRouter { + private readonly _router: Router; + + constructor(private controller: PayoutController) { + this._router = Router({ strict: true }); + this.init(); + } + + private init(): void { + this._router.get('/rounds', this.controller.getIncompleteRounds); + this._router.get('/preview', this.controller.previewPayout); + this._router.post('/propose', this.controller.proposePayout); + this._router.get('/status', this.controller.getPayoutStatus); + } + + public get router(): Router { + return this._router; + } +} diff --git a/src/services/org/organization-configuration.service.ts b/src/services/org/organization-configuration.service.ts new file mode 100644 index 0000000..5d95637 --- /dev/null +++ b/src/services/org/organization-configuration.service.ts @@ -0,0 +1,460 @@ +import { injectable, inject } from 'inversify'; +import { Repository } from 'typeorm'; +import { Organization, RecognitionTokenMode } from '../../entities/org/organization.model.js'; +import { validate } from 'class-validator'; +import { ethers } from 'ethers'; +import { AppDataSource } from '../../data-source.js'; + +/** + * Defines the structure for the Safe configuration data. + */ +export interface SafeConfig { + safeAddress: string; + safeChainId: number; + stablecoinAddress: string; + stablecoinDecimals: number; + recognitionTokenAddress?: string; + recognitionTokenDecimals?: number; + recognitionTokenMode: RecognitionTokenMode; +} + +@injectable() +export class OrganizationConfigurationService { + private orgRepository: Repository; + + constructor() { + this.orgRepository = AppDataSource.getRepository(Organization); + } + + /** + * Returns the list of supported blockchain networks. + * @returns Array of supported chain configurations + */ + public getSupportedChains(): Array<{ chainId: number; name: string; rpcUrl: string }> { + return [ + { + chainId: 1, + name: 'Ethereum Mainnet', + rpcUrl: process.env.ETHEREUM_RPC_URL || 'https://eth.llamarpc.com' + }, + { + chainId: 42161, + name: 'Arbitrum One', + rpcUrl: process.env.ARBITRUM_RPC_URL || 'https://arb1.arbitrum.io/rpc' + }, + { + chainId: 421614, + name: 'Arbitrum Sepolia', + rpcUrl: process.env.ARBITRUM_SEPOLIA_RPC_URL || 'https://sepolia-rollup.arbitrum.io/rpc' + }, + { + chainId: 42220, + name: 'Celo Mainnet', + rpcUrl: process.env.CELO_RPC_URL || 'https://forno.celo.org' + }, + { + chainId: 44787, + name: 'Celo Alfajores', + rpcUrl: process.env.CELO_ALFAJORES_RPC_URL || 'https://alfajores-forno.celo-testnet.org' + } + ]; + } + + /** + * Validates Safe configuration without saving to database. + * @param config The Safe configuration to validate + * @returns Validation result with errors, warnings, and metadata + */ + public async validateSafeConfig(config: SafeConfig): Promise<{ + isValid: boolean; + errors: string[]; + warnings: string[]; + safeInfo?: { + owners: string[]; + threshold: number; + }; + tokenInfo?: { + stablecoin: { + name?: string; + symbol?: string; + decimals: number; + }; + recognition?: { + name?: string; + symbol?: string; + decimals: number; + balance?: string; + hasMintingRole?: boolean; + }; + }; + }> { + const errors: string[] = []; + const warnings: string[] = []; + let safeInfo: any = undefined; + let tokenInfo: any = undefined; + + // Validate Safe address format + if (!ethers.isAddress(config.safeAddress)) { + errors.push('Invalid Safe address format'); + return { isValid: false, errors, warnings }; + } + + // Validate stablecoin address format + if (!ethers.isAddress(config.stablecoinAddress)) { + errors.push('Invalid stablecoin address format'); + return { isValid: false, errors, warnings }; + } + + try { + const provider = new ethers.JsonRpcProvider(this.getRpcUrl(config.safeChainId)); + + // Validate Safe address by checking if it has owners + const { default: Safe } = await import('@safe-global/protocol-kit'); + const safeSdk = await (Safe as any).init({ + provider: this.getRpcUrl(config.safeChainId), + safeAddress: config.safeAddress + }); + const owners = await safeSdk.getOwners(); + const threshold = await safeSdk.getThreshold(); + + if (owners.length === 0) { + errors.push('Safe address is not a valid Gnosis Safe or has no owners'); + } else { + safeInfo = { + owners, + threshold + }; + } + + // Validate stablecoin contract and decimals + const stablecoinAbi = [ + 'function decimals() view returns (uint8)', + 'function name() view returns (string)', + 'function symbol() view returns (string)' + ]; + const stablecoinContract = new ethers.Contract(config.stablecoinAddress, stablecoinAbi, provider); + try { + const decimals = await stablecoinContract.decimals(); + const name = await stablecoinContract.name().catch(() => undefined); + const symbol = await stablecoinContract.symbol().catch(() => undefined); + + tokenInfo = { + stablecoin: { + name, + symbol, + decimals: Number(decimals) + } + }; + + if (decimals !== BigInt(config.stablecoinDecimals)) { + errors.push(`Stablecoin decimals mismatch: expected ${config.stablecoinDecimals}, got ${decimals}`); + } + } catch (error) { + errors.push('Invalid stablecoin contract or unable to fetch decimals'); + } + + // Validate recognition token if provided + if (config.recognitionTokenMode !== RecognitionTokenMode.NONE && config.recognitionTokenAddress) { + if (!ethers.isAddress(config.recognitionTokenAddress)) { + errors.push('Invalid recognition token address format'); + } else { + const tokenAbi = [ + 'function decimals() view returns (uint8)', + 'function name() view returns (string)', + 'function symbol() view returns (string)', + 'function MINTER_ROLE() view returns (bytes32)', + 'function hasRole(bytes32 role, address account) view returns (bool)', + 'function balanceOf(address account) view returns (uint256)' + ]; + const tokenContract = new ethers.Contract(config.recognitionTokenAddress, tokenAbi, provider); + + try { + const decimals = await tokenContract.decimals(); + const name = await tokenContract.name().catch(() => undefined); + const symbol = await tokenContract.symbol().catch(() => undefined); + + if (config.recognitionTokenDecimals !== undefined + && decimals !== BigInt(config.recognitionTokenDecimals)) { + errors.push(`Recognition token decimals mismatch: expected ${config.recognitionTokenDecimals}, got ${decimals}`); + } + + if (!tokenInfo) { tokenInfo = { stablecoin: { decimals: config.stablecoinDecimals } }; } + tokenInfo.recognition = { + name, + symbol, + decimals: Number(decimals) + }; + } catch (error) { + errors.push('Invalid recognition token contract or unable to fetch decimals'); + } + + // Check minting permission for MINT mode + if (config.recognitionTokenMode === RecognitionTokenMode.MINT) { + const hasMintingPermission = await this.validateMintingPermission( + config.safeAddress, + config.recognitionTokenAddress, + provider + ); + if (tokenInfo?.recognition) { + tokenInfo.recognition.hasMintingRole = hasMintingPermission; + } + if (!hasMintingPermission) { + errors.push( + `Safe address does not have minting permission on the recognition token. ` + + 'The Safe must have MINTER_ROLE, ADMIN_ROLE, or be the contract owner.' + ); + } + } + + // Check balance for TRANSFER mode + if (config.recognitionTokenMode === RecognitionTokenMode.TRANSFER) { + try { + const balance = await tokenContract.balanceOf(config.safeAddress); + if (tokenInfo?.recognition) { + tokenInfo.recognition.balance = balance.toString(); + } + if (balance <= 0) { + warnings.push('Safe address has no balance of the recognition token'); + } + } catch (error) { + errors.push('Could not verify the recognition token balance of the Safe address'); + } + } + } + } + } catch (error) { + errors.push(`Validation error: ${error instanceof Error ? error.message : 'Unknown error'}`); + } + + return { + isValid: errors.length === 0, + errors, + warnings, + safeInfo, + tokenInfo + }; + } + + /** + * Updates the Safe configuration for a given organization. + * + * @param organizationId The ID of the organization to update. + * @param config The new Safe configuration data. + * @returns The updated organization. + */ + public async updateSafeConfig(organizationId: string, config: SafeConfig): Promise { + const organization = await this.orgRepository.findOne({ where: { id: organizationId } }); + if (!organization) { + throw new Error('Organization not found'); + } + + // Basic validation + if (!ethers.isAddress(config.safeAddress)) { + throw new Error('Invalid Safe address'); + } + + if (!ethers.isAddress(config.stablecoinAddress)) { + throw new Error('Invalid stablecoin address'); + } + + // Validate Safe address by checking if it has owners (is a valid Safe) + const provider = new ethers.JsonRpcProvider(this.getRpcUrl(config.safeChainId)); + const { default: Safe } = await import('@safe-global/protocol-kit'); + const safeSdk = await (Safe as any).init({ + provider: this.getRpcUrl(config.safeChainId), + safeAddress: config.safeAddress + }); + const owners = await safeSdk.getOwners(); + if (owners.length === 0) { + throw new Error('Safe address is not a valid Gnosis Safe or has no owners'); + } + + // Fetch stablecoin decimals from chain (do not trust input) + const stablecoinContract = new ethers.Contract( + config.stablecoinAddress, + ['function decimals() view returns (uint8)'], + provider + ); + let stablecoinDecimalsOnChain: number; + try { + const decimals = await stablecoinContract.decimals(); + stablecoinDecimalsOnChain = Number(decimals); + } catch (error) { + throw new Error('Invalid stablecoin contract or unable to fetch decimals'); + } + + // If a recognition token is provided, validate it + if (config.recognitionTokenMode !== RecognitionTokenMode.NONE && config.recognitionTokenAddress) { + if (!ethers.isAddress(config.recognitionTokenAddress)) { + throw new Error('Invalid recognition token address'); + } + + const tokenAbi = [ + 'function decimals() view returns (uint8)', + 'function MINTER_ROLE() view returns (bytes32)', + 'function hasRole(bytes32 role, address account) view returns (bool)', + 'function balanceOf(address account) view returns (uint256)' + ]; + const tokenContract = new ethers.Contract(config.recognitionTokenAddress, tokenAbi, provider); + + // Fetch recognition token decimals from chain if provided (do not trust input) + let recognitionTokenDecimalsOnChain: number | undefined = undefined; + try { + const decimals = await tokenContract.decimals(); + recognitionTokenDecimalsOnChain = Number(decimals); + } catch (error) { + throw new Error('Invalid recognition token contract or unable to fetch decimals'); + } + + if (config.recognitionTokenMode === RecognitionTokenMode.MINT) { + const hasMintingPermission = await this.validateMintingPermission( + config.safeAddress, + config.recognitionTokenAddress, + provider + ); + if (!hasMintingPermission) { + throw new Error( + `Safe address ${config.safeAddress} does not have minting permission on the recognition token contract ${config.recognitionTokenAddress}. ` + + 'The Safe must have either MINTER_ROLE, ADMIN_ROLE, or be the contract owner to mint tokens.' + ); + } + } else if (config.recognitionTokenMode === RecognitionTokenMode.TRANSFER) { + try { + const balance = await tokenContract.balanceOf(config.safeAddress); + if (balance <= 0) { + throw new Error('Safe address has no balance of the recognition token'); + } + } catch (error) { + throw new Error('Could not verify the recognition token balance of the Safe address'); + } + } + } + + // Update organization fields (persist fetched decimals) + organization.safeAddress = config.safeAddress; + organization.safeChainId = config.safeChainId; + organization.stablecoinAddress = config.stablecoinAddress; + organization.stablecoinDecimals = stablecoinDecimalsOnChain; + organization.recognitionTokenAddress = config.recognitionTokenAddress; + // If recognition token is configured, use fetched on-chain decimals; otherwise leave null + organization.recognitionTokenDecimals = typeof (organization.recognitionTokenAddress) === 'string' + ? (await (async () => { + try { + const tokenAbi = ['function decimals() view returns (uint8)']; + const tokenContract2 = new ethers.Contract(organization.recognitionTokenAddress!, tokenAbi, provider); + const d = await tokenContract2.decimals(); + return Number(d); + } catch { + return config.recognitionTokenDecimals ?? null as any; + } + })()) + : null as any; + organization.recognitionTokenMode = config.recognitionTokenMode; + + // Validate and save the updated entity + const errors = await validate(organization); + if (errors.length > 0) { + throw new Error(`Validation failed: ${errors.toString()}`); + } + + return this.orgRepository.save(organization); + } + + /** + * Validates minting permission for TeamPoints or other ERC20 tokens with role-based access. + * Supports both MINTER_ROLE (standard) and ADMIN_ROLE (TeamPoints) patterns. + * + * @param safeAddress The Safe address to check permissions for + * @param tokenAddress The token contract address + * @param provider The ethers provider + * @returns Promise indicating if the Safe has minting permission + */ + private async validateMintingPermission( + safeAddress: string, + tokenAddress: string, + provider: ethers.JsonRpcProvider + ): Promise { + // Extended ABI to support both MINTER_ROLE and ADMIN_ROLE patterns + const extendedTokenAbi = [ + 'function decimals() view returns (uint8)', + 'function MINTER_ROLE() view returns (bytes32)', + 'function ADMIN_ROLE() view returns (bytes32)', + 'function hasRole(bytes32 role, address account) view returns (bool)', + 'function balanceOf(address account) view returns (uint256)', + 'function name() view returns (string)', + 'function symbol() view returns (string)' + ]; + + const tokenContract = new ethers.Contract(tokenAddress, extendedTokenAbi, provider); + + try { + // First, try to check for MINTER_ROLE (standard ERC20 with AccessControl) + try { + const minterRole = await tokenContract.MINTER_ROLE(); + const hasMinterRole = await tokenContract.hasRole(minterRole, safeAddress); + if (hasMinterRole) { + console.log(`Safe ${safeAddress} has MINTER_ROLE on token ${tokenAddress}`); + return true; + } + } catch (minterRoleError) { + // MINTER_ROLE not found, continue to check ADMIN_ROLE + console.log(`MINTER_ROLE not found on token ${tokenAddress}, checking ADMIN_ROLE`); + } + + // Check for ADMIN_ROLE (TeamPoints pattern) + try { + const adminRole = await tokenContract.ADMIN_ROLE(); + const hasAdminRole = await tokenContract.hasRole(adminRole, safeAddress); + if (hasAdminRole) { + console.log(`Safe ${safeAddress} has ADMIN_ROLE on token ${tokenAddress}`); + return true; + } + } catch (adminRoleError) { + // ADMIN_ROLE not found either + console.log(`ADMIN_ROLE not found on token ${tokenAddress}, checking owner pattern`); + } + + // If neither role is found, check if it's a standard ERC20 with owner pattern + try { + const ownerAbi = ['function owner() view returns (address)']; + const ownerContract = new ethers.Contract(tokenAddress, ownerAbi, provider); + const owner = await ownerContract.owner(); + if (owner.toLowerCase() === safeAddress.toLowerCase()) { + console.log(`Safe ${safeAddress} is owner of token ${tokenAddress}`); + return true; + } + } catch (ownerError) { + // Owner pattern not found either + console.log(`Owner pattern not found on token ${tokenAddress}`); + } + + console.log(`Safe ${safeAddress} has no minting permission on token ${tokenAddress}`); + return false; + } catch (error) { + console.error('Error validating minting permission:', error); + return false; + } + } + + /** + * Returns the RPC URL for a given chain ID. + * + * @param chainId The chain ID. + * @returns The RPC URL. + */ + private getRpcUrl(chainId: number): string { + const rpcUrls: Record = { + 1: process.env.ETHEREUM_RPC_URL || 'https://eth.llamarpc.com', + 11155111: process.env.ETHEREUM_SEPOLIA_RPC_URL || 'https://eth-sepolia.public.blastapi.io', + 42161: process.env.ARBITRUM_RPC_URL || 'https://arb1.arbitrum.io/rpc', + 421614: process.env.ARBITRUM_SEPOLIA_RPC_URL || 'https://sepolia-rollup.arbitrum.io/rpc', + 42220: process.env.CELO_RPC_URL || 'https://forno.celo.org', + 44787: process.env.CELO_ALFAJORES_RPC_URL || 'https://alfajores-forno.celo-testnet.org' + }; + const url = rpcUrls[chainId]; + if (!url) { + throw new Error('Unsupported chain ID'); + } + return url; + } +} diff --git a/src/services/org/organization.dto.ts b/src/services/org/organization.dto.ts new file mode 100644 index 0000000..7ec9573 --- /dev/null +++ b/src/services/org/organization.dto.ts @@ -0,0 +1,84 @@ +import { IsString, IsNumber, IsEnum, IsOptional, IsEthereumAddress, Min, Max } from 'class-validator'; +import { RecognitionTokenMode } from '../../entities/org/organization.model.js'; + +/** + * DTO for updating Safe configuration + */ +export class UpdateSafeConfigDTO { + @IsString() + @IsEthereumAddress() + safeAddress!: string; + + @IsNumber() + @Min(1) + @Max(999999999) + safeChainId!: number; + + @IsString() + @IsEthereumAddress() + stablecoinAddress!: string; + + @IsNumber() + @Min(0) + @Max(18) + stablecoinDecimals!: number; + + @IsOptional() + @IsString() + @IsEthereumAddress() + recognitionTokenAddress?: string; + + @IsOptional() + @IsNumber() + @Min(0) + @Max(18) + recognitionTokenDecimals?: number; + + @IsEnum(RecognitionTokenMode) + recognitionTokenMode!: RecognitionTokenMode; +} + +/** + * Response DTO for Safe configuration validation + */ +export interface SafeConfigValidationResponse { + isValid: boolean; + errors: string[]; + warnings: string[]; + safeInfo?: { + owners: string[]; + threshold: number; + version: string; + }; + tokenInfo?: { + stablecoin: { + name: string; + symbol: string; + decimals: number; + balance?: string; + }; + recognitionToken?: { + name: string; + symbol: string; + decimals: number; + balance?: string; + hasMinterRole?: boolean; + }; + }; +} + +/** + * DTO for chain configuration + */ +export interface ChainConfigDTO { + chainId: number; + name: string; + rpcUrl: string; + blockExplorerUrl: string; + nativeCurrency: { + name: string; + symbol: string; + decimals: number; + }; + isSupported: boolean; +} diff --git a/src/services/organization.service.ts b/src/services/organization.service.ts index efbb0df..0308df8 100644 --- a/src/services/organization.service.ts +++ b/src/services/organization.service.ts @@ -1,4 +1,5 @@ -import { injectable } from 'inversify'; +import { inject, injectable } from 'inversify'; +import { TYPES } from '../inversify.types.js'; import { v4 as uuidv4 } from 'uuid'; import { AppDataSource } from '../data-source.js'; import { ResponseModel } from '../models/response_models/response_model.js'; @@ -24,7 +25,7 @@ export class OrganizationService { private agreementRepository; private roundsRepository; - constructor(private roundsService: RoundService) { + constructor(@inject(TYPES.RoundService) private roundsService: RoundService) { this.userRepository = AppDataSource.getRepository(User); this.organizationRepository = AppDataSource.getRepository(Organization); this.invitationRepository = AppDataSource.getRepository(Invitation); diff --git a/src/services/payout.service.ts b/src/services/payout.service.ts new file mode 100644 index 0000000..8ebe3a6 --- /dev/null +++ b/src/services/payout.service.ts @@ -0,0 +1,745 @@ +import { injectable, inject } from 'inversify'; +import { Repository, IsNull } from 'typeorm'; +import { AppDataSource } from '../data-source.js'; +import { ethers } from 'ethers'; +import { Payout, PayoutStatus } from '../entities/payout/payout.model.js'; +import { PayoutRecipient, PayoutRecipientStatus } from '../entities/payout/payout-recipient.model.js'; +import { TxProposal, TokenType, TxProposalStatus, PayoutType } from '../entities/payout/tx-proposal.model.js'; +import { Round } from '../entities/assessment/round.model.js'; +import { ContributorRoundCompensation } from '../entities/assessment/contributorCompensation.model.js'; +import { Organization, RecognitionTokenMode } from '../entities/org/organization.model.js'; +import { NotFoundError } from '../errors/not-found.error.js'; +import { InvalidDataError } from '../errors/invalid-data.error.js'; +import { TYPES } from '../inversify.types.js'; +import { OrganizationConfigurationService } from './org/organization-configuration.service.js'; +import { SafeTransactionService } from './safe/safe-transaction.service.js'; + +const MAX_RECIPIENTS_PER_BATCH = 200; +const GAS_LIMIT = 3000000; +const CALLDATA_LIMIT = 100000; + +/** + * Interface for payout preview response + */ +export interface PayoutPreviewResponse { + roundId: string; + roundNumber: number; + recipients: PayoutRecipientPreview[]; + totals: { + stablecoinAmount: number; + recognitionAmount: number; + recipientCount: number; + }; + preflightChecks: { + safeConfigured: boolean; + sufficientBalance: boolean; + hasMintingPermission: boolean; + warnings: string[]; + }; + chunkPlan: { + totalChunks: number; + maxRecipientsPerChunk: number; + stablecoinChunks: number; + recognitionChunks: number; + }; +} + +/** + * Interface for individual recipient preview + */ +export interface PayoutRecipientPreview { + walletAddress: string; + stablecoinAmount: number; + recognitionAmount: number; + stablecoinAmountBaseUnits: string; + recognitionAmountBaseUnits: string; + userId: string; + roundCompensationId: string; +} + +@injectable() +export class PayoutService { + private payoutRepository: Repository; + private payoutRecipientRepository: Repository; + private txProposalRepository: Repository; + private roundRepository: Repository; + private compensationRepository: Repository; + private organizationRepository: Repository; + + constructor( + @inject(TYPES.OrganizationConfigurationService) + private configService: OrganizationConfigurationService, + @inject(TYPES.SafeTransactionService) + private safeService: SafeTransactionService + ) { + this.payoutRepository = AppDataSource.getRepository(Payout); + this.payoutRecipientRepository = AppDataSource.getRepository(PayoutRecipient); + this.txProposalRepository = AppDataSource.getRepository(TxProposal); + this.roundRepository = AppDataSource.getRepository(Round); + this.compensationRepository = AppDataSource.getRepository(ContributorRoundCompensation); + this.organizationRepository = AppDataSource.getRepository(Organization); + } + + /** + * Retrieve completed assessment rounds that have not yet been processed for payouts. + * Filters rounds where assessment is complete but no payout transaction has been executed. + */ + public async getIncompleteRounds(orgId: string): Promise { + return await this.roundRepository.find({ + where: { + organization: { id: orgId }, + isCompleted: true, + txHash: IsNull() // Identifies rounds without executed payout transactions + }, + relations: ['organization'], + order: { roundNumber: 'DESC' } + }); + } + + /** + * Generate comprehensive payout preview including recipients, totals, validation checks, and chunking strategy. + * Performs wallet address validation, amount conversion using token decimals, and preflight safety checks. + * Calculates optimal transaction chunking based on gas estimation and recipient limits. + */ + public async previewPayout(roundId: string): Promise { + // Get round and organization data + const round = await this.roundRepository.findOne({ + where: { id: roundId }, + relations: ['organization'] + }); + + if (!round) { + throw new NotFoundError('Round not found'); + } + + const organization = round.organization; + if (!organization.safeAddress) { + throw new InvalidDataError('Organization Safe not configured'); + } + + // Get compensation data for this round + const compensations = await this.compensationRepository.find({ + where: { round: { id: roundId } }, + relations: ['contributor'] + }); + + if (compensations.length === 0) { + throw new NotFoundError('No compensation data found for this round'); + } + + // Build recipient preview data with human + base-unit amounts + const recipients: PayoutRecipientPreview[] = []; + const processedAddresses = new Set(); + + for (const comp of compensations) { + const walletAddress = comp.contributor.address; + + // Wallet address validation and dedupe + if (!walletAddress || !ethers.isAddress(walletAddress)) { + continue; // Skip invalid addresses + } + + if (processedAddresses.has(walletAddress.toLowerCase())) { + continue; // Skip duplicates + } + processedAddresses.add(walletAddress.toLowerCase()); + + // Convert amounts using real decimals() + const stablecoinAmountBaseUnits = await this.toBaseUnits( + comp.fiat || 0, + organization.stablecoinDecimals || 6 + ); + const recognitionAmountBaseUnits = await this.toBaseUnits( + comp.tp || 0, + organization.recognitionTokenDecimals || 18 + ); + + recipients.push({ + walletAddress, + stablecoinAmount: comp.fiat || 0, + recognitionAmount: comp.tp || 0, + stablecoinAmountBaseUnits, + recognitionAmountBaseUnits, + userId: (comp.contributor as any)?.id, + roundCompensationId: comp.id + }); + } + + // Calculate totals + const totals = { + stablecoinAmount: recipients.reduce((sum, r) => sum + r.stablecoinAmount, 0), + recognitionAmount: recipients.reduce((sum, r) => sum + r.recognitionAmount, 0), + recipientCount: recipients.length + }; + + // Perform preflight checks (balance, role) + const preflightChecks = await this.performPreflightChecks(organization, totals); + + // Plan chunks using dynamic gas-based estimation for both token types + const stablecoinChunkPlan = recipients.some(r => r.stablecoinAmount > 0) + ? await this.planChunks(recipients.filter(r => r.stablecoinAmount > 0), organization, TokenType.STABLECOIN) + : { totalChunks: 0, maxRecipientsPerChunk: 0, estimatedChunks: [] }; + + const recognitionChunkPlan = recipients.some(r => r.recognitionAmount > 0) + ? await this.planChunks(recipients. + filter(r => r.recognitionAmount > 0), organization, TokenType.RECOGNITION) + : { totalChunks: 0, maxRecipientsPerChunk: 0, estimatedChunks: [] }; + + const chunkPlan = { + totalChunks: Math.max(stablecoinChunkPlan.totalChunks, recognitionChunkPlan.totalChunks), + maxRecipientsPerChunk: Math.max(stablecoinChunkPlan.maxRecipientsPerChunk, recognitionChunkPlan.maxRecipientsPerChunk), + stablecoinChunks: stablecoinChunkPlan.totalChunks, + recognitionChunks: recognitionChunkPlan.totalChunks + }; + + return { + roundId, + roundNumber: round.roundNumber, + recipients, + totals, + preflightChecks, + chunkPlan + }; + } + + /** + * Create payout proposal with optimized transaction chunking for Safe execution. + * Validates recipient data, creates database records for tracking, and generates transaction proposals. + * Applies dynamic chunking algorithm to ensure transactions remain within gas and calldata limits. + */ + public async proposePayout(roundId: string, tokenType: TokenType): Promise<{ payoutId: string; safeUrl?: string }> { + // Get preview data to validate and get recipients + const preview = await this.previewPayout(roundId); + + if (preview.preflightChecks.warnings.length > 0) { + throw new InvalidDataError(`Preflight checks failed: ${preview.preflightChecks.warnings.join(', ')}`); + } + + // Create payout record + const payout = this.payoutRepository.create({ + roundId, + status: PayoutStatus.DRAFT, + totalStablePayout: tokenType === TokenType.STABLECOIN ? preview.totals.stablecoinAmount : 0, + totalRecognitionPayout: tokenType === TokenType.RECOGNITION ? preview.totals.recognitionAmount : 0 + }); + await this.payoutRepository.save(payout); + + // Filter recipients based on token type + const relevantRecipients = preview.recipients.filter(r => { + return tokenType === TokenType.STABLECOIN ? r.stablecoinAmount > 0 : r.recognitionAmount > 0; + }); + + // Get round and organization for chunking + const round = await this.roundRepository.findOne({ + where: { id: roundId }, + relations: ['organization'] + }); + + if (!round) { + throw new NotFoundError('Round not found'); + } + // Ensure payout is associated with organization for DB integrity + payout.organization = round.organization as any; + await this.payoutRepository.save(payout); + + // Create chunks using dynamic gas-based estimation as specified + const chunkPlan = await this.planChunks(relevantRecipients, round.organization, tokenType); + const chunks = chunkPlan.estimatedChunks; + + // Create transaction proposals for each chunk + for (let i = 0; i < chunks.length; i++) { + const chunk = chunks[i]; + + // Create tx proposal record + const txProposal = this.txProposalRepository.create({ + payout, + payoutType: PayoutType.ROUND, + tokenType, + status: TxProposalStatus.PROPOSED, + partIndex: i + 1, + partCount: chunks.length, + attempt: 1, + payloadJson: JSON.stringify({ + recipients: chunk.map(r => ({ + to: r.walletAddress, + amount: tokenType === TokenType.STABLECOIN ? r.stablecoinAmountBaseUnits : r.recognitionAmountBaseUnits + })) + }) + }); + await this.txProposalRepository.save(txProposal); + + // Create payout recipient records + for (const recipient of chunk) { + const payoutRecipient = this.payoutRecipientRepository.create({ + payout, + roundCompensationId: recipient.roundCompensationId, + user: { id: recipient.userId } as any, + walletAddressSnapshot: recipient.walletAddress, + tokenType, + tokenAddressSnapshot: tokenType === TokenType.STABLECOIN + ? (round.organization as any).stablecoinAddress! + : (round.organization as any).recognitionTokenAddress!, + tokenDecimalsSnapshot: tokenType === TokenType.STABLECOIN + ? ((round.organization as any).stablecoinDecimals ?? 6) + : ((round.organization as any).recognitionTokenDecimals ?? 18), + amountHuman: tokenType === TokenType.STABLECOIN ? recipient.stablecoinAmount : recipient.recognitionAmount, + amountBaseUnits: tokenType === TokenType.STABLECOIN ? recipient.stablecoinAmountBaseUnits : recipient.recognitionAmountBaseUnits, + txProposal, + partIndex: i + 1, + partCount: chunks.length, + attempt: 1, + status: PayoutRecipientStatus.PROPOSED + }); + await this.payoutRecipientRepository.save(payoutRecipient); + } + } + + // Initialize Safe SDK + const organization = await this.organizationRepository.findOne({ where: { id: round.organization.id } }); + if (!organization) { + throw new NotFoundError('Organization not found'); + } + + await this.safeService.initialize(organization); + + // Create Safe transactions for each chunk + const txProposalsWithHashes = await this.txProposalRepository.find({ + where: { payout: { id: payout.id } }, + order: { partIndex: 'ASC' } + }); + + let safeUrl = ''; + for (const txProposal of txProposalsWithHashes) { + const payload = JSON.parse(txProposal.payloadJson); + + // Build ERC20 transfer calls for MultiSend: to = tokenAddress, value = '0', data = transfer(recipient, amount) + const tokenAddress = txProposal.tokenType === TokenType.STABLECOIN + ? organization.stablecoinAddress! + : organization.recognitionTokenAddress!; + + const recipients = payload.recipients.map((r: any) => { + const data = ethers.concat([ + '0xa9059cbb', + ethers.zeroPadValue(r.to, 32), + ethers.zeroPadValue(ethers.toBeHex(BigInt(r.amount)), 32) + ]); + return { + to: tokenAddress, + value: '0', + data + }; + }); + + // Create Safe transaction + const safeTransaction = await this.safeService.createMultiSendTransaction(recipients); + + // Propose transaction to Safe Transaction Service + const result = await this.safeService.proposeTransaction( + safeTransaction, + organization.safeAddress!, + organization + ); + + // Update transaction proposal with real Safe transaction hash + txProposal.safeTxHash = result.safeTxHash; + txProposal.status = TxProposalStatus.PROPOSED; + await this.txProposalRepository.save(txProposal); + + // Use the first transaction's Safe URL + if (!safeUrl) { + safeUrl = result.safeUrl; + } + } + + // Update payout status + payout.status = PayoutStatus.PROPOSED; + await this.payoutRepository.save(payout); + + return { + payoutId: payout.id, + safeUrl + }; + } + + /** + * GET /payouts/status?roundId= → Poll Transaction Service for statuses; update records accordingly + * Returns current payout and transaction proposal statuses + */ + public async getPayoutStatus(roundId: string): Promise { + const payouts = await this.payoutRepository.find({ + where: { roundId }, + order: { createdAt: 'DESC' } + }); + + if (payouts.length === 0) { + return { status: 'NO_PAYOUT', message: 'No payout found for this round' }; + } + + const payout = payouts[0]; + const txProposals = await this.txProposalRepository.find({ + where: { payout: { id: payout.id } }, + order: { partIndex: 'ASC' } + }); + + // Initialize Safe SDK to poll transaction statuses + const round = await this.roundRepository.findOne({ where: { id: roundId }, relations: ['organization'] }); + if (round) { + const organization = await this.organizationRepository.findOne({ where: { id: (round as any).organization.id } }); + if (organization && organization.safeAddress) { + await this.safeService.initialize(organization); + + // Poll each transaction's status from Safe Transaction Service + for (const txProposal of txProposals) { + if (txProposal.safeTxHash) { + try { + const txStatus = await this.safeService.getTransactionStatus(txProposal.safeTxHash); + + // Map Safe status to our TxProposalStatus + let newStatus = txProposal.status; + if (txStatus.status === 'EXECUTED') { + newStatus = TxProposalStatus.EXECUTED; + } else if (txStatus.status === 'AWAITING_EXECUTION') { + newStatus = TxProposalStatus.PROPOSED; + } else if (txStatus.status === 'AWAITING_CONFIRMATIONS') { + newStatus = TxProposalStatus.PROPOSED; + } else if (txStatus.status === 'FAILED') { + newStatus = TxProposalStatus.FAILED; + } + + // Update database if status changed + if (newStatus !== txProposal.status) { + txProposal.status = newStatus; + await this.txProposalRepository.save(txProposal); + } + } catch (error) { + console.error(`Failed to poll status for tx ${txProposal.safeTxHash}:`, error); + } + } + } + + // Update payout status based on transaction statuses + const allExecuted = txProposals.every(tx => tx.status === TxProposalStatus.EXECUTED); + if (allExecuted && payout.status !== PayoutStatus.EXECUTED) { + payout.status = PayoutStatus.EXECUTED; + await this.payoutRepository.save(payout); + } + } + } + + return { + payoutId: payout.id, + status: payout.status, + totalStablePayout: payout.totalStablePayout, + totalRecognitionPayout: payout.totalRecognitionPayout, + transactions: txProposals.map(tx => ({ + id: tx.id, + tokenType: tx.tokenType, + status: tx.status, + partIndex: tx.partIndex, + partCount: tx.partCount, + safeTxHash: tx.safeTxHash, + attempt: tx.attempt + })) + }; + } + + /** + * Perform server-side validations: balance checks, role checks, Safe config + */ + private async performPreflightChecks(organization: Organization, totals: any): Promise { + const warnings: string[] = []; + let safeConfigured = false; + let sufficientBalance = false; + let hasMintingPermission = false; + + // Check Safe configuration + if (!organization.safeAddress || !organization.safeChainId) { + warnings.push('Safe wallet not configured for this organization'); + } else { + safeConfigured = true; + } + + // Check stablecoin balance for transfers + if (totals.stablecoinAmount > 0 && organization.stablecoinAddress) { + try { + const rpcUrl = this.getRpcUrl(organization.safeChainId!); + const provider = new ethers.JsonRpcProvider(rpcUrl); + + // Check Safe balance + const tokenContract = new ethers.Contract( + organization.stablecoinAddress, + ['function balanceOf(address) view returns (uint256)', 'function decimals() view returns (uint8)'], + provider + ); + + const balance = await tokenContract.balanceOf(organization.safeAddress); + const decimals = await tokenContract.decimals(); + const balanceHuman = Number(ethers.formatUnits(balance, decimals)); + + if (balanceHuman >= totals.stablecoinAmount) { + sufficientBalance = true; + } else { + warnings.push(`Insufficient stablecoin balance. Required: ${totals.stablecoinAmount}, Available: ${balanceHuman}`); + } + } catch (error) { + warnings.push('Unable to verify stablecoin balance'); + } + } + + // Check MINTER_ROLE for recognition token minting + if (totals.recognitionAmount > 0 && organization.recognitionTokenMode === RecognitionTokenMode.MINT) { + try { + if (!organization.safeChainId) { + warnings.push('Safe chain ID not configured'); + return { safeConfigured, sufficientBalance, hasMintingPermission, warnings }; + } + + const rpcUrl = this.getRpcUrl(organization.safeChainId); + const provider = new ethers.JsonRpcProvider(rpcUrl); + + // Check minting permission (simplified - actual validation would be in config service) + hasMintingPermission = organization.recognitionTokenAddress ? true : false; + + if (!hasMintingPermission) { + warnings.push('Safe does not have MINTER_ROLE for recognition token'); + } + } catch (error) { + warnings.push('Unable to verify minting permission'); + } + } + + return { + safeConfigured, + sufficientBalance, + hasMintingPermission, + warnings + }; + } + + /** + * Calculate optimal transaction chunking using two-tier approach for efficient Safe execution. + * First tier limits batches to maximum 200 recipients to prevent excessive transaction complexity. + * Second tier applies recursive gas estimation to ensure each chunk remains within network limits. + * Continues splitting until all chunks satisfy gas and calldata constraints. + */ + private async planChunks( + recipients: PayoutRecipientPreview[], + organization: Organization, + tokenType: TokenType + ): Promise<{ totalChunks: number; maxRecipientsPerChunk: number; estimatedChunks: PayoutRecipientPreview[][] }> { + // Split recipients into initial batches of up to MAX_RECIPIENTS_PER_BATCH recipients + const initialBatches = this.createChunks(recipients, MAX_RECIPIENTS_PER_BATCH); + + // Apply recursive gas-based chunking to each initial batch + const allChunks: PayoutRecipientPreview[][] = []; + for (const batch of initialBatches) { + const batchChunks = await this.recursiveChunking(batch, organization, tokenType, GAS_LIMIT, CALLDATA_LIMIT); + allChunks.push(...batchChunks); + } + + const maxRecipientsPerChunk = Math.max(...allChunks.map(chunk => chunk.length)); + + return { + totalChunks: allChunks.length, + maxRecipientsPerChunk, + estimatedChunks: allChunks + }; + } + + /** + * Apply recursive gas-based splitting to ensure transaction chunks remain within execution limits. + * Tests each batch against gas and calldata constraints, splitting unsuccessful batches in half. + * Continues recursion until all resulting chunks can execute successfully within network parameters. + */ + private async recursiveChunking( + recipients: PayoutRecipientPreview[], + organization: Organization, + tokenType: TokenType, + gasLimit: number, + calldataLimit: number + ): Promise { + if (recipients.length === 0) { return []; } + + try { + // Build MultiSend transaction for gas estimation + const multiSendData = this.buildMultiSendData(recipients, organization, tokenType); + + // Estimate gas for this batch + const estimatedGas = await this.estimateMultiSendGas(multiSendData, organization); + const calldataSize = multiSendData.length; + + // If within limits, return as single chunk + if (estimatedGas <= gasLimit && calldataSize <= calldataLimit) { + return [recipients]; + } + + // If exceeds limits and only 1 recipient, we have a problem + if (recipients.length === 1) { + throw new InvalidDataError(`Single recipient transaction exceeds gas/calldata limits: gas=${estimatedGas}, calldata=${calldataSize}`); + } + + // Split in half and recursively chunk each half + const midpoint = Math.floor(recipients.length / 2); + const firstHalf = recipients.slice(0, midpoint); + const secondHalf = recipients.slice(midpoint); + + const [firstChunks, secondChunks] = await Promise.all([ + this.recursiveChunking(firstHalf, organization, tokenType, gasLimit, calldataLimit), + this.recursiveChunking(secondHalf, organization, tokenType, gasLimit, calldataLimit) + ]); + + return [...firstChunks, ...secondChunks]; + + } catch (error) { + // Fallback: if gas estimation fails, split in half + if (recipients.length === 1) { + throw new InvalidDataError(`Cannot chunk single recipient: ${error}`); + } + + const midpoint = Math.floor(recipients.length / 2); + const firstHalf = recipients.slice(0, midpoint); + const secondHalf = recipients.slice(midpoint); + + const [firstChunks, secondChunks] = await Promise.all([ + this.recursiveChunking(firstHalf, organization, tokenType, gasLimit, calldataLimit), + this.recursiveChunking(secondHalf, organization, tokenType, gasLimit, calldataLimit) + ]); + + return [...firstChunks, ...secondChunks]; + } + } + + /** + * Create recipient chunks for batched Safe MultiSend + */ + private createChunks(items: T[], chunkSize: number): T[][] { + const chunks: T[][] = []; + for (let i = 0; i < items.length; i += chunkSize) { + chunks.push(items.slice(i, i + chunkSize)); + } + return chunks; + } + + /** + * Convert human amounts to base units using token decimals + */ + private async toBaseUnits(amount: number, decimals: number): Promise { + return ethers.parseUnits(amount.toString(), decimals).toString(); + } + + /** + * Get RPC URL for chain - reuses pattern from configService + */ + private getRpcUrl(chainId: number): string { + const rpcUrls: { [key: number]: string } = { + 42161: process.env.ARBITRUM_ONE_RPC_URL || 'https://arb1.arbitrum.io/rpc', + 421614: process.env.ARBITRUM_SEPOLIA_RPC_URL || 'https://sepolia-rollup.arbitrum.io/rpc', + 42220: process.env.CELO_RPC_URL || 'https://forno.celo.org' + }; + + const rpcUrl = rpcUrls[chainId]; + if (!rpcUrl) { + throw new NotFoundError(`Unsupported chain ID: ${chainId}`); + } + + return rpcUrl; + } + + /** + * Build MultiSend transaction data for gas estimation. + * Creates packed transaction data format required by Safe MultiSend contract. + * Each transaction contains operation type, target address, value, data length, and call data. + */ + private buildMultiSendData( + recipients: PayoutRecipientPreview[], + organization: Organization, + tokenType: TokenType + ): string { + const transactions = recipients.map(recipient => { + const tokenAddress = tokenType === TokenType.STABLECOIN + ? organization.stablecoinAddress + : organization.recognitionTokenAddress; + + if (!tokenAddress) { + throw new Error(`Token address not configured for ${tokenType}`); + } + + const amount = tokenType === TokenType.STABLECOIN + ? recipient.stablecoinAmountBaseUnits + : recipient.recognitionAmountBaseUnits; + + // Construct ERC20 transfer call data using standard transfer function signature + const transferData = ethers.concat([ + '0xa9059cbb', // transfer(address,uint256) function selector + ethers.zeroPadValue(recipient.walletAddress, 32), // recipient address padded to 32 bytes + ethers.zeroPadValue(ethers.toBeHex(BigInt(amount)), 32) // amount padded to 32 bytes + ]); + + return { + to: tokenAddress, + value: '0', // ERC20 transfers do not require ETH value + data: transferData, + operation: 0 // CALL operation type for standard contract calls + }; + }); + + // Encode transactions into MultiSend packed format + // Format: operation(1) + to(20) + value(32) + dataLength(32) + data(dynamic) + let packedTransactions = ''; + for (const tx of transactions) { + const dataBytes = ethers.getBytes(tx.data); + const packedTx = ethers.concat([ + ethers.zeroPadValue(ethers.toBeHex(tx.operation), 1), + ethers.zeroPadValue(tx.to, 20), + ethers.zeroPadValue(ethers.toBeHex(tx.value), 32), + ethers.zeroPadValue(ethers.toBeHex(dataBytes.length), 32), + tx.data + ]); + packedTransactions += packedTx.slice(2); // Remove 0x prefix for concatenation + } + + return '0x' + packedTransactions; + } + + /** + * Estimate gas consumption for MultiSend transaction. + * Uses network RPC to simulate transaction execution and determine gas requirements. + * Falls back to mathematical estimation if network call fails. + */ + private async estimateMultiSendGas(multiSendData: string, organization: Organization): Promise { + try { + if (!organization.safeChainId) { + throw new Error('Safe chain ID not configured'); + } + + const rpcUrl = this.getRpcUrl(organization.safeChainId); + const provider = new ethers.JsonRpcProvider(rpcUrl); + + // Safe MultiSend contract address is consistent across supported networks + const multiSendAddress = '0xA238CBeb142c10Ef7Ad8442C6D1f9E89e07e7761'; + + // Encode call to multiSend function with packed transaction data + const multiSendCallData = ethers.concat([ + '0x8d80ff0a', // multiSend(bytes) function selector + ethers.AbiCoder.defaultAbiCoder().encode(['bytes'], [multiSendData]) + ]); + + // Simulate transaction execution to determine actual gas consumption + const gasEstimate = await provider.estimateGas({ + from: organization.safeAddress, + to: multiSendAddress, + data: multiSendCallData + }); + + return Number(gasEstimate); + + } catch (error) { + // Network estimation failed, calculate approximate gas based on transaction complexity + const baseTransactionGas = 21000; + const gasPerERC20Transfer = 50000; // Typical gas cost for ERC20 transfer + const estimatedRecipientCount = Math.ceil(multiSendData.length / 200); // Approximate based on data length + + return baseTransactionGas + (gasPerERC20Transfer * estimatedRecipientCount); + } + } +} diff --git a/src/services/round.service.ts b/src/services/round.service.ts index 547f8f5..499cd71 100644 --- a/src/services/round.service.ts +++ b/src/services/round.service.ts @@ -1,4 +1,5 @@ -import { injectable } from 'inversify'; +import { inject, injectable } from 'inversify'; +import { TYPES } from '../inversify.types.js'; import { IsNull, LessThanOrEqual, MoreThanOrEqual, Not } from 'typeorm'; import { EmailService } from './email.service.js'; import { Assessment, ContributorRoundCompensation, Organization, Round, User } from '../entities/index.js'; @@ -23,7 +24,7 @@ export class RoundService { private roundsRepository; private assessmentRepository; - constructor(private emailService: EmailService) { + constructor(@inject(TYPES.EmailService) private emailService: EmailService) { this.userRepository = AppDataSource.getRepository(User); this.organizationRepository = AppDataSource.getRepository(Organization); this.roundsRepository = AppDataSource.getRepository(Round); diff --git a/src/services/safe.service.ts b/src/services/safe.service.ts new file mode 100644 index 0000000..e2d3319 --- /dev/null +++ b/src/services/safe.service.ts @@ -0,0 +1,61 @@ +import { ethers } from 'ethers'; +import { SafeTransaction, SafeTransactionDataPartial } from '@safe-global/safe-core-sdk-types'; +import { SafeServiceError } from '../errors/safe.service.error.js'; + +export class SafeService { + private safeSdk: any; + + constructor(private signer: ethers.Signer, private safeAddress: string) {} + + public async init(): Promise { + try { + const { default: Safe } = await import('@safe-global/protocol-kit'); + const provider = this.signer.provider; + this.safeSdk = await (Safe as any).init({ + provider: provider ? await provider.getNetwork().then(n => n.chainId.toString()) : undefined, + signer: await this.signer.getAddress(), + safeAddress: this.safeAddress + }); + } catch (error) { + throw new SafeServiceError('Failed to initialize Safe Service'); + } + } + + public async createMultiSendTransaction(recipients: Array<{ to: string; value: string }>): Promise { + try { + const transactions: SafeTransactionDataPartial[] = recipients.map(recipient => ({ + to: recipient.to, + value: ethers.parseUnits(recipient.value, 'ether').toString(), + data: '0x' + })); + return await this.safeSdk.createTransaction({ safeTransactionData: transactions }); + } catch (error) { + throw new SafeServiceError('Failed to create multisend transaction'); + } + } + + public async signTransaction(transaction: SafeTransaction): Promise { + try { + const signedTransaction = await this.safeSdk.signTransaction(transaction); + return signedTransaction.signatures.get(await this.signer.getAddress())?.data; + } catch (error) { + throw new SafeServiceError('Failed to sign transaction'); + } + } + + public async executeTransaction(transaction: SafeTransaction): Promise { + try { + await this.safeSdk.executeTransaction(transaction); + } catch (error) { + throw new SafeServiceError('Failed to execute transaction'); + } + } + + public async getThreshold(): Promise { + try { + return await this.safeSdk.getThreshold(); + } catch (error) { + throw new SafeServiceError('Failed to get threshold'); + } + } +} diff --git a/src/services/safe/safe-transaction.service.ts b/src/services/safe/safe-transaction.service.ts new file mode 100644 index 0000000..6904edc --- /dev/null +++ b/src/services/safe/safe-transaction.service.ts @@ -0,0 +1,214 @@ +import { injectable } from 'inversify'; +import { ethers } from 'ethers'; +import { MetaTransactionData, OperationType } from '@safe-global/safe-core-sdk-types'; +import { Organization } from '../../entities/index.js'; + +export interface SafeTransactionResult { + safeTxHash: string; + safeUrl: string; +} + +export interface TransactionStatus { + status: 'PENDING' | 'AWAITING_CONFIRMATIONS' | 'AWAITING_EXECUTION' | 'EXECUTED' | 'FAILED' | 'CANCELLED' | 'NOT_FOUND'; + confirmations: number; + confirmationsRequired: number; + isExecuted: boolean; + transactionHash?: string; +} + +@injectable() +export class SafeTransactionService { + private apiKit: any | null = null; + private protocolKit: any | null = null; + + /** + * Initialize the Safe SDK instances for a specific organization + */ + public async initialize(organization: Organization, signerPrivateKey?: string): Promise { + if (!organization.safeAddress || !organization.safeChainId) { + throw new Error('Organization does not have Safe configured'); + } + + const chainId = BigInt(organization.safeChainId!); + const rpcUrl = this.getRpcUrl(organization.safeChainId!); + + // Initialize API Kit for transaction service interaction + const { default: SafeApiKit } = await import('@safe-global/api-kit'); + this.apiKit = new (SafeApiKit as any)({ + chainId, + apiKey: process.env.SAFE_API_KEY + }); + + // Initialize Protocol Kit for transaction creation + const { default: Safe } = await import('@safe-global/protocol-kit'); + const provider = new ethers.JsonRpcProvider(rpcUrl); + + // If signer private key provided, use it; otherwise use provider only (read-only mode) + const signer = signerPrivateKey + ? new ethers.Wallet(signerPrivateKey, provider) + : undefined; + + this.protocolKit = await (Safe as any).init({ + provider: rpcUrl, + signer: signer ? await signer.getAddress() : undefined, + safeAddress: organization.safeAddress + }); + } + + /** + * Create a MultiSend transaction for batched token transfers + */ + public async createMultiSendTransaction( + recipients: Array<{ to: string; value: string; data?: string }> + ): Promise { + if (!this.protocolKit) { + throw new Error('Safe Protocol Kit not initialized'); + } + + const transactions: MetaTransactionData[] = recipients.map(recipient => ({ + to: recipient.to, + value: recipient.value, + data: recipient.data || '0x', + operation: OperationType.Call + })); + + return await this.protocolKit.createTransaction({ + transactions + }); + } + + /** + * Propose a transaction to the Safe Transaction Service + */ + public async proposeTransaction( + safeTransaction: any, + senderAddress: string, + organization: Organization + ): Promise { + if (!this.protocolKit || !this.apiKit) { + throw new Error('Safe SDK not initialized'); + } + + if (!organization.safeAddress) { + throw new Error('Organization does not have Safe configured'); + } + + // Get transaction hash + const safeTxHash = await this.protocolKit.getTransactionHash(safeTransaction); + + // Sign the transaction + const senderSignature = await this.protocolKit.signHash(safeTxHash); + + // Propose to Safe Transaction Service + await this.apiKit.proposeTransaction({ + safeAddress: organization.safeAddress, + safeTransactionData: safeTransaction.data, + safeTxHash, + senderAddress, + senderSignature: senderSignature.data + }); + + // Generate Safe URL + const safeUrl = this.generateSafeUrl(organization.safeAddress!, organization.safeChainId!); + + return { + safeTxHash, + safeUrl + }; + } + + /** + * Get transaction status from Safe Transaction Service + */ + public async getTransactionStatus(safeTxHash: string): Promise { + if (!this.apiKit) { + throw new Error('Safe API Kit not initialized'); + } + + try { + const transaction = await this.apiKit.getTransaction(safeTxHash); + + // Determine status based on transaction state + let status: TransactionStatus['status'] = 'PENDING'; + + if (transaction.isExecuted) { + status = 'EXECUTED'; + } else if (transaction.confirmations && transaction.confirmations.length >= transaction.confirmationsRequired) { + status = 'AWAITING_EXECUTION'; + } else if (transaction.confirmations && transaction.confirmations.length > 0) { + status = 'AWAITING_CONFIRMATIONS'; + } + + return { + status, + confirmations: transaction.confirmations?.length || 0, + confirmationsRequired: transaction.confirmationsRequired || 1, + isExecuted: transaction.isExecuted || false, + transactionHash: transaction.transactionHash || undefined + }; + } catch (error: any) { + if (error.message?.includes('not found') || error.response?.status === 404) { + return { + status: 'NOT_FOUND', + confirmations: 0, + confirmationsRequired: 1, + isExecuted: false + }; + } + throw error; + } + } + + /** + * Get RPC URL for a specific chain ID + */ + private getRpcUrl(chainId: number): string { + const rpcUrls: Record = { + 1: process.env.ETHEREUM_RPC_URL || 'https://eth.llamarpc.com', + 11155111: process.env.ETHEREUM_SEPOLIA_RPC_URL || 'https://eth-sepolia.public.blastapi.io', + 42161: process.env.ARBITRUM_RPC_URL || 'https://arb1.arbitrum.io/rpc', + 421614: process.env.ARBITRUM_SEPOLIA_RPC_URL || 'https://sepolia-rollup.arbitrum.io/rpc', + 42220: process.env.CELO_RPC_URL || 'https://forno.celo.org' + }; + + const rpcUrl = rpcUrls[chainId]; + if (!rpcUrl) { + throw new Error(`Unsupported chain ID: ${chainId}`); + } + + return rpcUrl; + } + + /** + * Generate Safe web interface URL for a transaction + */ + private generateSafeUrl(safeAddress: string, chainId: number): string { + const chainPrefixes: Record = { + 1: 'eth', + 11155111: 'sep', + 42161: 'arb1', + 421614: 'arb-sep', + 42220: 'celo' + }; + + const prefix = chainPrefixes[chainId] || 'eth'; + return `https://app.safe.global/transactions/queue?safe=${prefix}:${safeAddress}`; + } + + /** + * Estimate gas for a MultiSend transaction + */ + public async estimateTransactionGas(safeTransaction: any): Promise { + if (!this.protocolKit) { + throw new Error('Safe Protocol Kit not initialized'); + } + + try { + const gasEstimate = await this.protocolKit.estimateSafeTransactionGas(safeTransaction); + return BigInt(gasEstimate); + } catch (error) { + throw new Error(`Failed to estimate gas: ${error}`); + } + } +} + diff --git a/src/services/user.service.ts b/src/services/user.service.ts index 24ab295..3a13041 100644 --- a/src/services/user.service.ts +++ b/src/services/user.service.ts @@ -1,8 +1,9 @@ import { v4 as uuidv4 } from 'uuid'; import jwt from 'jsonwebtoken'; import dotenv from 'dotenv'; +import { inject, injectable } from 'inversify'; +import { TYPES } from '../inversify.types.js'; import { CreateUserModel } from '../models/user/userRegistration.model.js'; -import { injectable } from 'inversify'; import { CreatedResponseModel } from '../models/response_models/created_response_model.js'; import { ResponseModel } from '../models/response_models/response_model.js'; import { SiweMessage } from 'siwe'; @@ -28,7 +29,10 @@ export class UserService { private invitationRepository; private walletNonceRepository; - constructor(private emailService: EmailService, private teamPointsService: TeamPointsService) { + constructor( + @inject(TYPES.EmailService) private emailService: EmailService, + @inject(TYPES.TeamPointsService) private teamPointsService: TeamPointsService + ) { this.userRepository = AppDataSource.getRepository(User); this.invitationRepository = AppDataSource.getRepository(Invitation); this.walletNonceRepository = AppDataSource.getRepository(WalletNonce); diff --git a/src/types/express.d.ts b/src/types/express.d.ts new file mode 100644 index 0000000..e07a7f3 --- /dev/null +++ b/src/types/express.d.ts @@ -0,0 +1,9 @@ +import { User } from '../entities/users/user.model.js'; + +declare global { + namespace Express { + interface Request { + user?: User; + } + } +} diff --git a/src/types/express/index.d.ts b/src/types/express/index.d.ts new file mode 100644 index 0000000..91c8a02 --- /dev/null +++ b/src/types/express/index.d.ts @@ -0,0 +1,9 @@ +import { User } from 'src/entities/user.entity'; + +declare global { + namespace Express { + interface Request { + user?: User; + } + } +} diff --git a/src/validation/organization.validation.ts b/src/validation/organization.validation.ts new file mode 100644 index 0000000..9b4764f --- /dev/null +++ b/src/validation/organization.validation.ts @@ -0,0 +1,165 @@ +import Joi from 'joi'; +import { RecognitionTokenMode } from '../entities/org/organization.model.js'; + +/** + * Supported blockchain networks for Safe wallet deployment + */ +export const SUPPORTED_CHAINS = [ + 1, // Ethereum Mainnet + 42161, // Arbitrum One + 421614, // Arbitrum Sepolia + 42220, // Celo Mainnet + 44787 // Celo Alfajores Testnet +] as const; + +/** + * Ethereum address validation pattern + */ +const ETH_ADDRESS_REGEX = /^0x[a-fA-F0-9]{40}$/; + +/** + * Validation schema for updating Safe configuration + * Allows partial updates with at least one field required + */ +export const updateSafeConfigSchema = Joi.object({ + safeAddress: Joi.string() + .pattern(ETH_ADDRESS_REGEX) + .optional() + .messages({ + 'string.pattern.base': 'Safe address must be a valid Ethereum address' + }), + + safeChainId: Joi.number() + .integer() + .valid(...SUPPORTED_CHAINS) + .optional() + .messages({ + 'any.only': `Chain ID must be one of: ${SUPPORTED_CHAINS.join(', ')}` + }), + + stablecoinAddress: Joi.string() + .pattern(ETH_ADDRESS_REGEX) + .optional() + .messages({ + 'string.pattern.base': 'Stablecoin address must be a valid Ethereum address' + }), + + recognitionTokenMode: Joi.string() + .valid(...Object.values(RecognitionTokenMode)) + .optional() + .messages({ + 'any.only': `Recognition token mode must be one of: ${Object.values(RecognitionTokenMode).join(', ')}` + }), + + recognitionTokenAddress: Joi.string() + .pattern(ETH_ADDRESS_REGEX) + .optional() + .allow(null) + .messages({ + 'string.pattern.base': 'Recognition token address must be a valid Ethereum address' + }) +}).min(1).messages({ + 'object.min': 'At least one configuration field must be provided' +}); + +/** + * Validation schema for complete Safe configuration validation + * Requires all essential fields for Safe operation + */ +export const validateSafeConfigSchema = Joi.object({ + safeAddress: Joi.string() + .pattern(ETH_ADDRESS_REGEX) + .required() + .messages({ + 'string.pattern.base': 'Safe address must be a valid Ethereum address', + 'any.required': 'Safe address is required' + }), + + safeChainId: Joi.number() + .integer() + .valid(...SUPPORTED_CHAINS) + .required() + .messages({ + 'any.only': `Chain ID must be one of: ${SUPPORTED_CHAINS.join(', ')}`, + 'any.required': 'Chain ID is required' + }), + + stablecoinAddress: Joi.string() + .pattern(ETH_ADDRESS_REGEX) + .optional() + .messages({ + 'string.pattern.base': 'Stablecoin address must be a valid Ethereum address' + }), + + recognitionTokenMode: Joi.string() + .valid(...Object.values(RecognitionTokenMode)) + .optional() + .messages({ + 'any.only': `Recognition token mode must be one of: ${Object.values(RecognitionTokenMode).join(', ')}` + }), + + recognitionTokenAddress: Joi.string() + .pattern(ETH_ADDRESS_REGEX) + .optional() + .allow(null) + .messages({ + 'string.pattern.base': 'Recognition token address must be a valid Ethereum address' + }) +}); + +/** + * TypeScript interface for Safe configuration update data + */ +export interface UpdateSafeConfigDTO { + safeAddress?: string; + safeChainId?: number; + stablecoinAddress?: string; + recognitionTokenMode?: RecognitionTokenMode; + recognitionTokenAddress?: string | null; +} + +/** + * Response structure for Safe configuration validation + */ +export interface SafeConfigValidationResponse { + isValid: boolean; + errors: string[]; + warnings: string[]; + safeInfo?: { + owners: string[]; + threshold: number; + version: string; + }; + tokenInfo?: { + stablecoin: { + name: string; + symbol: string; + decimals: number; + balance?: string; + }; + recognitionToken?: { + name: string; + symbol: string; + decimals: number; + balance?: string; + hasMinterRole?: boolean; + }; + }; +} + +/** + * Chain configuration structure + */ +export interface ChainConfigDTO { + chainId: number; + name: string; + rpcUrl: string; + blockExplorerUrl: string; + nativeCurrency: { + name: string; + symbol: string; + decimals: number; + }; + isSupported: boolean; +} + diff --git a/tsconfig.json b/tsconfig.json index 2f5a259..da88f01 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -31,7 +31,7 @@ // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */ // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ - // "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */ + "typeRoots": ["./src/types", "./node_modules/@types"], // "types": [], /* Specify type package names to be included without being referenced in a source file. */ // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ // "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */ @@ -106,4 +106,4 @@ // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ "skipLibCheck": true /* Skip type checking all .d.ts files. */ } -} +} \ No newline at end of file diff --git a/tslint.json b/tslint.json index c9f8400..e8aaae0 100644 --- a/tslint.json +++ b/tslint.json @@ -19,7 +19,7 @@ "interface-name": [false], "interface-over-type-literal": true, "label-position": true, - "max-line-length": [true, 120], + "max-line-length": [true, 190], "member-access": false, "member-ordering": [ true, diff --git a/yarn.lock b/yarn.lock index 56a07fc..792051e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4,9 +4,14 @@ "@adraffy/ens-normalize@1.10.1": version "1.10.1" - resolved "https://registry.yarnpkg.com/@adraffy/ens-normalize/-/ens-normalize-1.10.1.tgz#63430d04bd8c5e74f8d7d049338f1cd9d4f02069" + resolved "https://registry.npmjs.org/@adraffy/ens-normalize/-/ens-normalize-1.10.1.tgz" integrity sha512-96Z2IP3mYmF1Xg2cDm8f1gWGf/HUVedQ3FMifV4kG/PQ4yEP51xDtRAEfhVNt5f/uzpNkZHwWQuUcu6D6K+Ekw== +"@adraffy/ens-normalize@^1.11.0": + version "1.11.1" + resolved "https://registry.npmjs.org/@adraffy/ens-normalize/-/ens-normalize-1.11.1.tgz" + integrity sha512-nhCBV3quEgesuf7c7KYfperqSS14T8bYuvJ8PcLJp6znkZpFc0AuW4qBtr8eKVyPPe/8RSr7sglCWPU5eaxwKQ== + "@aws-crypto/crc32@5.2.0": version "5.2.0" resolved "https://registry.npmjs.org/@aws-crypto/crc32/-/crc32-5.2.0.tgz" @@ -559,7 +564,7 @@ "@smithy/types" "^3.5.0" tslib "^2.6.2" -"@aws-sdk/types@3.667.0": +"@aws-sdk/types@3.667.0", "@aws-sdk/types@^3.222.0": version "3.667.0" resolved "https://registry.npmjs.org/@aws-sdk/types/-/types-3.667.0.tgz" integrity sha512-gYq0xCsqFfQaSL/yT1Gl1vIUjtsg7d7RhnUfsXaHt8xTxOKRTdH9GjbesBjXOzgOvB0W0vfssfreSNGFlOOMJg== @@ -567,14 +572,6 @@ "@smithy/types" "^3.5.0" tslib "^2.6.2" -"@aws-sdk/types@^3.222.0": - version "3.654.0" - resolved "https://registry.npmjs.org/@aws-sdk/types/-/types-3.654.0.tgz" - integrity sha512-VWvbED3SV+10QJIcmU/PKjsKilsTV16d1I7/on4bvD/jo1qGeMXqLDBSen3ks/tuvXZF/mFc7ZW/W2DiLVtO7A== - dependencies: - "@smithy/types" "^3.4.2" - tslib "^2.6.2" - "@aws-sdk/util-arn-parser@3.568.0": version "3.568.0" resolved "https://registry.npmjs.org/@aws-sdk/util-arn-parser/-/util-arn-parser-3.568.0.tgz" @@ -658,6 +655,581 @@ dependencies: "@jridgewell/trace-mapping" "0.3.9" +"@ethereumjs/rlp@^4.0.1": + version "4.0.1" + resolved "https://registry.npmjs.org/@ethereumjs/rlp/-/rlp-4.0.1.tgz" + integrity sha512-tqsQiBQDQdmPWE1xkkBq4rlSW5QZpLOUJ5RJh2/9fug+q9tnUhuZoVLk7s0scUIKTOzEtR72DFBXI4WiZcMpvw== + +"@ethereumjs/util@^8.1.0": + version "8.1.0" + resolved "https://registry.npmjs.org/@ethereumjs/util/-/util-8.1.0.tgz" + integrity sha512-zQ0IqbdX8FZ9aw11vP+dZkKDkS+kgIvQPHnSAXzP9pLu+Rfu3D3XEeLbicvoXJTYnhZiPmsZUxgdzXwNKxRPbA== + dependencies: + "@ethereumjs/rlp" "^4.0.1" + ethereum-cryptography "^2.0.0" + micro-ftch "^0.3.1" + +"@ethersproject/abi@5.7.0", "@ethersproject/abi@^5.7.0": + version "5.7.0" + resolved "https://registry.npmjs.org/@ethersproject/abi/-/abi-5.7.0.tgz" + integrity sha512-351ktp42TiRcYB3H1OP8yajPeAQstMW/yCFokj/AthP9bLHzQFPlOrxOcwYEDkUAICmOHljvN4K39OMTMUa9RA== + dependencies: + "@ethersproject/address" "^5.7.0" + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/constants" "^5.7.0" + "@ethersproject/hash" "^5.7.0" + "@ethersproject/keccak256" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/strings" "^5.7.0" + +"@ethersproject/abi@^5.8.0": + version "5.8.0" + resolved "https://registry.npmjs.org/@ethersproject/abi/-/abi-5.8.0.tgz" + integrity sha512-b9YS/43ObplgyV6SlyQsG53/vkSal0MNA1fskSC4mbnCMi8R+NkcH8K9FPYNESf6jUefBUniE4SOKms0E/KK1Q== + 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.7.0": + version "5.7.0" + resolved "https://registry.npmjs.org/@ethersproject/abstract-provider/-/abstract-provider-5.7.0.tgz" + integrity sha512-R41c9UkchKCpAqStMYUpdunjo3pkEvZC3FAwZn5S5MGbXoMQOHIdHItezTETxAO5bevtMApSyEhn9+CHcDsWBw== + dependencies: + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/networks" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/transactions" "^5.7.0" + "@ethersproject/web" "^5.7.0" + +"@ethersproject/abstract-provider@^5.7.0", "@ethersproject/abstract-provider@^5.8.0": + version "5.8.0" + resolved "https://registry.npmjs.org/@ethersproject/abstract-provider/-/abstract-provider-5.8.0.tgz" + integrity sha512-wC9SFcmh4UK0oKuLJQItoQdzS/qZ51EJegK6EmAWlh+OptpQ/npECOR3QqECd8iGHC0RJb4WKbVdSfif4ammrg== + 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.7.0": + version "5.7.0" + resolved "https://registry.npmjs.org/@ethersproject/abstract-signer/-/abstract-signer-5.7.0.tgz" + integrity sha512-a16V8bq1/Cz+TGCkE2OPMTOUDLS3grCpdjoJCYNnVBbdYEMSgKrU0+B90s8b6H+ByYTBZN7a3g76jdIJi7UfKQ== + dependencies: + "@ethersproject/abstract-provider" "^5.7.0" + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + +"@ethersproject/abstract-signer@^5.7.0", "@ethersproject/abstract-signer@^5.8.0": + version "5.8.0" + resolved "https://registry.npmjs.org/@ethersproject/abstract-signer/-/abstract-signer-5.8.0.tgz" + integrity sha512-N0XhZTswXcmIZQdYtUnd79VJzvEwXQw6PK0dTl9VoYrEBxxCPXqS0Eod7q5TNKRxe1/5WUMuR0u0nqTF/avdCA== + 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.7.0": + version "5.7.0" + resolved "https://registry.npmjs.org/@ethersproject/address/-/address-5.7.0.tgz" + integrity sha512-9wYhYt7aghVGo758POM5nqcOMaE168Q6aRLJZwUmiqSrAungkG74gSSeKEIR7ukixesdRZGPgVqme6vmxs1fkA== + dependencies: + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/keccak256" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/rlp" "^5.7.0" + +"@ethersproject/address@^5.7.0", "@ethersproject/address@^5.8.0": + version "5.8.0" + resolved "https://registry.npmjs.org/@ethersproject/address/-/address-5.8.0.tgz" + integrity sha512-GhH/abcC46LJwshoN+uBNoKVFPxUuZm6dA257z0vZkKmU1+t8xTn8oK7B9qrj8W2rFRMch4gbJl6PmVxjxBEBA== + 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.7.0": + version "5.7.0" + resolved "https://registry.npmjs.org/@ethersproject/base64/-/base64-5.7.0.tgz" + integrity sha512-Dr8tcHt2mEbsZr/mwTPIQAf3Ai0Bks/7gTw9dSqk1mQvhW3XvRlmDJr/4n+wg1JmCl16NZue17CDh8xb/vZ0sQ== + dependencies: + "@ethersproject/bytes" "^5.7.0" + +"@ethersproject/base64@^5.7.0", "@ethersproject/base64@^5.8.0": + version "5.8.0" + resolved "https://registry.npmjs.org/@ethersproject/base64/-/base64-5.8.0.tgz" + integrity sha512-lN0oIwfkYj9LbPx4xEkie6rAMJtySbpOAFXSDVQaBnAzYfB4X2Qr+FXJGxMoc3Bxp2Sm8OwvzMrywxyw0gLjIQ== + dependencies: + "@ethersproject/bytes" "^5.8.0" + +"@ethersproject/basex@5.7.0", "@ethersproject/basex@^5.7.0": + version "5.7.0" + resolved "https://registry.npmjs.org/@ethersproject/basex/-/basex-5.7.0.tgz" + integrity sha512-ywlh43GwZLv2Voc2gQVTKBoVQ1mti3d8HK5aMxsfu/nRDnMmNqaSJ3r3n85HBByT8OpoY96SXM1FogC533T4zw== + dependencies: + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + +"@ethersproject/bignumber@5.7.0": + version "5.7.0" + resolved "https://registry.npmjs.org/@ethersproject/bignumber/-/bignumber-5.7.0.tgz" + integrity sha512-n1CAdIHRWjSucQO3MC1zPSVgV/6dy/fjL9pMrPP9peL+QxEg9wOsVqwD4+818B6LUEtaXzVHQiuivzRoxPxUGw== + dependencies: + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + bn.js "^5.2.1" + +"@ethersproject/bignumber@^5.7.0", "@ethersproject/bignumber@^5.8.0": + version "5.8.0" + resolved "https://registry.npmjs.org/@ethersproject/bignumber/-/bignumber-5.8.0.tgz" + integrity sha512-ZyaT24bHaSeJon2tGPKIiHszWjD/54Sz8t57Toch475lCLljC6MgPmxk7Gtzz+ddNN5LuHea9qhAe0x3D+uYPA== + dependencies: + "@ethersproject/bytes" "^5.8.0" + "@ethersproject/logger" "^5.8.0" + bn.js "^5.2.1" + +"@ethersproject/bytes@5.7.0": + version "5.7.0" + resolved "https://registry.npmjs.org/@ethersproject/bytes/-/bytes-5.7.0.tgz" + integrity sha512-nsbxwgFXWh9NyYWo+U8atvmMsSdKJprTcICAkvbBffT75qDocbuggBU0SJiVK2MuTrp0q+xvLkTnGMPK1+uA9A== + dependencies: + "@ethersproject/logger" "^5.7.0" + +"@ethersproject/bytes@^5.7.0", "@ethersproject/bytes@^5.8.0": + version "5.8.0" + resolved "https://registry.npmjs.org/@ethersproject/bytes/-/bytes-5.8.0.tgz" + integrity sha512-vTkeohgJVCPVHu5c25XWaWQOZ4v+DkGoC42/TS2ond+PARCxTJvgTFUNDZovyQ/uAQ4EcpqqowKydcdmRKjg7A== + dependencies: + "@ethersproject/logger" "^5.8.0" + +"@ethersproject/constants@5.7.0": + version "5.7.0" + resolved "https://registry.npmjs.org/@ethersproject/constants/-/constants-5.7.0.tgz" + integrity sha512-DHI+y5dBNvkpYUMiRQyxRBYBefZkJfo70VUkUAsRjcPs47muV9evftfZ0PJVCXYbAiCgght0DtcF9srFQmIgWA== + dependencies: + "@ethersproject/bignumber" "^5.7.0" + +"@ethersproject/constants@^5.7.0", "@ethersproject/constants@^5.8.0": + version "5.8.0" + resolved "https://registry.npmjs.org/@ethersproject/constants/-/constants-5.8.0.tgz" + integrity sha512-wigX4lrf5Vu+axVTIvNsuL6YrV4O5AXl5ubcURKMEME5TnWBouUh0CDTWxZ2GpnRn1kcCgE7l8O5+VbV9QTTcg== + dependencies: + "@ethersproject/bignumber" "^5.8.0" + +"@ethersproject/contracts@5.7.0": + version "5.7.0" + resolved "https://registry.npmjs.org/@ethersproject/contracts/-/contracts-5.7.0.tgz" + integrity sha512-5GJbzEU3X+d33CdfPhcyS+z8MzsTrBGk/sc+G+59+tPa9yFkl6HQ9D6L0QMgNTA9q8dT0XKxxkyp883XsQvbbg== + dependencies: + "@ethersproject/abi" "^5.7.0" + "@ethersproject/abstract-provider" "^5.7.0" + "@ethersproject/abstract-signer" "^5.7.0" + "@ethersproject/address" "^5.7.0" + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/constants" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/transactions" "^5.7.0" + +"@ethersproject/contracts@^5.7.0": + version "5.8.0" + resolved "https://registry.npmjs.org/@ethersproject/contracts/-/contracts-5.8.0.tgz" + integrity sha512-0eFjGz9GtuAi6MZwhb4uvUM216F38xiuR0yYCjKJpNfSEy4HUM8hvqqBj9Jmm0IUz8l0xKEhWwLIhPgxNY0yvQ== + 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.7.0": + version "5.7.0" + resolved "https://registry.npmjs.org/@ethersproject/hash/-/hash-5.7.0.tgz" + integrity sha512-qX5WrQfnah1EFnO5zJv1v46a8HW0+E5xuBBDTwMFZLuVTx0tbU2kkx15NqdjxecrLGatQN9FGQKpb1FKdHCt+g== + dependencies: + "@ethersproject/abstract-signer" "^5.7.0" + "@ethersproject/address" "^5.7.0" + "@ethersproject/base64" "^5.7.0" + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/keccak256" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/strings" "^5.7.0" + +"@ethersproject/hash@^5.7.0", "@ethersproject/hash@^5.8.0": + version "5.8.0" + resolved "https://registry.npmjs.org/@ethersproject/hash/-/hash-5.8.0.tgz" + integrity sha512-ac/lBcTbEWW/VGJij0CNSw/wPcw9bSRgCB0AIBz8CvED/jfvDoV9hsIIiWfvWmFEi8RcXtlNwp2jv6ozWOsooA== + 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.7.0", "@ethersproject/hdnode@^5.7.0": + version "5.7.0" + resolved "https://registry.npmjs.org/@ethersproject/hdnode/-/hdnode-5.7.0.tgz" + integrity sha512-OmyYo9EENBPPf4ERhR7oj6uAtUAhYGqOnIS+jE5pTXvdKBS99ikzq1E7Iv0ZQZ5V36Lqx1qZLeak0Ra16qpeOg== + dependencies: + "@ethersproject/abstract-signer" "^5.7.0" + "@ethersproject/basex" "^5.7.0" + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/pbkdf2" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/sha2" "^5.7.0" + "@ethersproject/signing-key" "^5.7.0" + "@ethersproject/strings" "^5.7.0" + "@ethersproject/transactions" "^5.7.0" + "@ethersproject/wordlists" "^5.7.0" + +"@ethersproject/json-wallets@5.7.0", "@ethersproject/json-wallets@^5.7.0": + version "5.7.0" + resolved "https://registry.npmjs.org/@ethersproject/json-wallets/-/json-wallets-5.7.0.tgz" + integrity sha512-8oee5Xgu6+RKgJTkvEMl2wDgSPSAQ9MB/3JYjFV9jlKvcYHUXZC+cQp0njgmxdHkYWn8s6/IqIZYm0YWCjO/0g== + dependencies: + "@ethersproject/abstract-signer" "^5.7.0" + "@ethersproject/address" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/hdnode" "^5.7.0" + "@ethersproject/keccak256" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/pbkdf2" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/random" "^5.7.0" + "@ethersproject/strings" "^5.7.0" + "@ethersproject/transactions" "^5.7.0" + aes-js "3.0.0" + scrypt-js "3.0.1" + +"@ethersproject/keccak256@5.7.0": + version "5.7.0" + resolved "https://registry.npmjs.org/@ethersproject/keccak256/-/keccak256-5.7.0.tgz" + integrity sha512-2UcPboeL/iW+pSg6vZ6ydF8tCnv3Iu/8tUmLLzWWGzxWKFFqOBQFLo6uLUv6BDrLgCDfN28RJ/wtByx+jZ4KBg== + dependencies: + "@ethersproject/bytes" "^5.7.0" + js-sha3 "0.8.0" + +"@ethersproject/keccak256@^5.7.0", "@ethersproject/keccak256@^5.8.0": + version "5.8.0" + resolved "https://registry.npmjs.org/@ethersproject/keccak256/-/keccak256-5.8.0.tgz" + integrity sha512-A1pkKLZSz8pDaQ1ftutZoaN46I6+jvuqugx5KYNeQOPqq+JZ0Txm7dlWesCHB5cndJSu5vP2VKptKf7cksERng== + dependencies: + "@ethersproject/bytes" "^5.8.0" + js-sha3 "0.8.0" + +"@ethersproject/logger@5.7.0": + version "5.7.0" + resolved "https://registry.npmjs.org/@ethersproject/logger/-/logger-5.7.0.tgz" + integrity sha512-0odtFdXu/XHtjQXJYA3u9G0G8btm0ND5Cu8M7i5vhEcE8/HmF4Lbdqanwyv4uQTr2tx6b7fQRmgLrsnpQlmnig== + +"@ethersproject/logger@^5.7.0", "@ethersproject/logger@^5.8.0": + version "5.8.0" + resolved "https://registry.npmjs.org/@ethersproject/logger/-/logger-5.8.0.tgz" + integrity sha512-Qe6knGmY+zPPWTC+wQrpitodgBfH7XoceCGL5bJVejmH+yCS3R8jJm8iiWuvWbG76RUmyEG53oqv6GMVWqunjA== + +"@ethersproject/networks@5.7.1": + version "5.7.1" + resolved "https://registry.npmjs.org/@ethersproject/networks/-/networks-5.7.1.tgz" + integrity sha512-n/MufjFYv3yFcUyfhnXotyDlNdFb7onmkSy8aQERi2PjNcnWQ66xXxa3XlS8nCcA8aJKJjIIMNJTC7tu80GwpQ== + dependencies: + "@ethersproject/logger" "^5.7.0" + +"@ethersproject/networks@^5.7.0", "@ethersproject/networks@^5.8.0": + version "5.8.0" + resolved "https://registry.npmjs.org/@ethersproject/networks/-/networks-5.8.0.tgz" + integrity sha512-egPJh3aPVAzbHwq8DD7Po53J4OUSsA1MjQp8Vf/OZPav5rlmWUaFLiq8cvQiGK0Z5K6LYzm29+VA/p4RL1FzNg== + dependencies: + "@ethersproject/logger" "^5.8.0" + +"@ethersproject/pbkdf2@5.7.0", "@ethersproject/pbkdf2@^5.7.0": + version "5.7.0" + resolved "https://registry.npmjs.org/@ethersproject/pbkdf2/-/pbkdf2-5.7.0.tgz" + integrity sha512-oR/dBRZR6GTyaofd86DehG72hY6NpAjhabkhxgr3X2FpJtJuodEl2auADWBZfhDHgVCbu3/H/Ocq2uC6dpNjjw== + dependencies: + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/sha2" "^5.7.0" + +"@ethersproject/properties@5.7.0": + version "5.7.0" + resolved "https://registry.npmjs.org/@ethersproject/properties/-/properties-5.7.0.tgz" + integrity sha512-J87jy8suntrAkIZtecpxEPxY//szqr1mlBaYlQ0r4RCaiD2hjheqF9s1LVE8vVuJCXisjIP+JgtK/Do54ej4Sw== + dependencies: + "@ethersproject/logger" "^5.7.0" + +"@ethersproject/properties@^5.7.0", "@ethersproject/properties@^5.8.0": + version "5.8.0" + resolved "https://registry.npmjs.org/@ethersproject/properties/-/properties-5.8.0.tgz" + integrity sha512-PYuiEoQ+FMaZZNGrStmN7+lWjlsoufGIHdww7454FIaGdbe/p5rnaCXTr5MtBYl3NkeoVhHZuyzChPeGeKIpQw== + dependencies: + "@ethersproject/logger" "^5.8.0" + +"@ethersproject/providers@5.7.2": + version "5.7.2" + resolved "https://registry.npmjs.org/@ethersproject/providers/-/providers-5.7.2.tgz" + integrity sha512-g34EWZ1WWAVgr4aptGlVBF8mhl3VWjv+8hoAnzStu8Ah22VHBsuGzP17eb6xDVRzw895G4W7vvx60lFFur/1Rg== + dependencies: + "@ethersproject/abstract-provider" "^5.7.0" + "@ethersproject/abstract-signer" "^5.7.0" + "@ethersproject/address" "^5.7.0" + "@ethersproject/base64" "^5.7.0" + "@ethersproject/basex" "^5.7.0" + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/constants" "^5.7.0" + "@ethersproject/hash" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/networks" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/random" "^5.7.0" + "@ethersproject/rlp" "^5.7.0" + "@ethersproject/sha2" "^5.7.0" + "@ethersproject/strings" "^5.7.0" + "@ethersproject/transactions" "^5.7.0" + "@ethersproject/web" "^5.7.0" + bech32 "1.1.4" + ws "7.4.6" + +"@ethersproject/random@5.7.0", "@ethersproject/random@^5.7.0": + version "5.7.0" + resolved "https://registry.npmjs.org/@ethersproject/random/-/random-5.7.0.tgz" + integrity sha512-19WjScqRA8IIeWclFme75VMXSBvi4e6InrUNuaR4s5pTF2qNhcGdCUwdxUVGtDDqC00sDLCO93jPQoDUH4HVmQ== + dependencies: + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + +"@ethersproject/rlp@5.7.0": + version "5.7.0" + resolved "https://registry.npmjs.org/@ethersproject/rlp/-/rlp-5.7.0.tgz" + integrity sha512-rBxzX2vK8mVF7b0Tol44t5Tb8gomOHkj5guL+HhzQ1yBh/ydjGnpw6at+X6Iw0Kp3OzzzkcKp8N9r0W4kYSs9w== + dependencies: + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + +"@ethersproject/rlp@^5.7.0", "@ethersproject/rlp@^5.8.0": + version "5.8.0" + resolved "https://registry.npmjs.org/@ethersproject/rlp/-/rlp-5.8.0.tgz" + integrity sha512-LqZgAznqDbiEunaUvykH2JAoXTT9NV0Atqk8rQN9nx9SEgThA/WMx5DnW8a9FOufo//6FZOCHZ+XiClzgbqV9Q== + dependencies: + "@ethersproject/bytes" "^5.8.0" + "@ethersproject/logger" "^5.8.0" + +"@ethersproject/sha2@5.7.0": + version "5.7.0" + resolved "https://registry.npmjs.org/@ethersproject/sha2/-/sha2-5.7.0.tgz" + integrity sha512-gKlH42riwb3KYp0reLsFTokByAKoJdgFCwI+CCiX/k+Jm2mbNs6oOaCjYQSlI1+XBVejwH2KrmCbMAT/GnRDQw== + dependencies: + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + hash.js "1.1.7" + +"@ethersproject/sha2@^5.7.0", "@ethersproject/sha2@^5.8.0": + version "5.8.0" + resolved "https://registry.npmjs.org/@ethersproject/sha2/-/sha2-5.8.0.tgz" + integrity sha512-dDOUrXr9wF/YFltgTBYS0tKslPEKr6AekjqDW2dbn1L1xmjGR+9GiKu4ajxovnrDbwxAKdHjW8jNcwfz8PAz4A== + dependencies: + "@ethersproject/bytes" "^5.8.0" + "@ethersproject/logger" "^5.8.0" + hash.js "1.1.7" + +"@ethersproject/signing-key@5.7.0": + version "5.7.0" + resolved "https://registry.npmjs.org/@ethersproject/signing-key/-/signing-key-5.7.0.tgz" + integrity sha512-MZdy2nL3wO0u7gkB4nA/pEf8lu1TlFswPNmy8AiYkfKTdO6eXBJyUdmHO/ehm/htHw9K/qF8ujnTyUAD+Ry54Q== + dependencies: + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + bn.js "^5.2.1" + elliptic "6.5.4" + hash.js "1.1.7" + +"@ethersproject/signing-key@^5.7.0", "@ethersproject/signing-key@^5.8.0": + version "5.8.0" + resolved "https://registry.npmjs.org/@ethersproject/signing-key/-/signing-key-5.8.0.tgz" + integrity sha512-LrPW2ZxoigFi6U6aVkFN/fa9Yx/+4AtIUe4/HACTvKJdhm0eeb107EVCIQcrLZkxaSIgc/eCrX8Q1GtbH+9n3w== + dependencies: + "@ethersproject/bytes" "^5.8.0" + "@ethersproject/logger" "^5.8.0" + "@ethersproject/properties" "^5.8.0" + bn.js "^5.2.1" + elliptic "6.6.1" + hash.js "1.1.7" + +"@ethersproject/solidity@5.7.0": + version "5.7.0" + resolved "https://registry.npmjs.org/@ethersproject/solidity/-/solidity-5.7.0.tgz" + integrity sha512-HmabMd2Dt/raavyaGukF4XxizWKhKQ24DoLtdNbBmNKUOPqwjsKQSdV9GQtj9CBEea9DlzETlVER1gYeXXBGaA== + dependencies: + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/keccak256" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/sha2" "^5.7.0" + "@ethersproject/strings" "^5.7.0" + +"@ethersproject/solidity@^5.7.0": + version "5.8.0" + resolved "https://registry.npmjs.org/@ethersproject/solidity/-/solidity-5.8.0.tgz" + integrity sha512-4CxFeCgmIWamOHwYN9d+QWGxye9qQLilpgTU0XhYs1OahkclF+ewO+3V1U0mvpiuQxm5EHHmv8f7ClVII8EHsA== + 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.7.0": + version "5.7.0" + resolved "https://registry.npmjs.org/@ethersproject/strings/-/strings-5.7.0.tgz" + integrity sha512-/9nu+lj0YswRNSH0NXYqrh8775XNyEdUQAuf3f+SmOrnVewcJ5SBNAjF7lpgehKi4abvNNXyf+HX86czCdJ8Mg== + dependencies: + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/constants" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + +"@ethersproject/strings@^5.7.0", "@ethersproject/strings@^5.8.0": + version "5.8.0" + resolved "https://registry.npmjs.org/@ethersproject/strings/-/strings-5.8.0.tgz" + integrity sha512-qWEAk0MAvl0LszjdfnZ2uC8xbR2wdv4cDabyHiBh3Cldq/T8dPH3V4BbBsAYJUeonwD+8afVXld274Ls+Y1xXg== + dependencies: + "@ethersproject/bytes" "^5.8.0" + "@ethersproject/constants" "^5.8.0" + "@ethersproject/logger" "^5.8.0" + +"@ethersproject/transactions@5.7.0": + version "5.7.0" + resolved "https://registry.npmjs.org/@ethersproject/transactions/-/transactions-5.7.0.tgz" + integrity sha512-kmcNicCp1lp8qanMTC3RIikGgoJ80ztTyvtsFvCYpSCfkjhD0jZ2LOrnbcuxuToLIUYYf+4XwD1rP+B/erDIhQ== + dependencies: + "@ethersproject/address" "^5.7.0" + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/constants" "^5.7.0" + "@ethersproject/keccak256" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/rlp" "^5.7.0" + "@ethersproject/signing-key" "^5.7.0" + +"@ethersproject/transactions@^5.6.2", "@ethersproject/transactions@^5.7.0", "@ethersproject/transactions@^5.8.0": + version "5.8.0" + resolved "https://registry.npmjs.org/@ethersproject/transactions/-/transactions-5.8.0.tgz" + integrity sha512-UglxSDjByHG0TuU17bDfCemZ3AnKO2vYrL5/2n2oXvKzvb7Cz+W9gOWXKARjp2URVwcWlQlPOEQyAviKwT4AHg== + 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.7.0": + version "5.7.0" + resolved "https://registry.npmjs.org/@ethersproject/units/-/units-5.7.0.tgz" + integrity sha512-pD3xLMy3SJu9kG5xDGI7+xhTEmGXlEqXU4OfNapmfnxLVY4EMSSRp7j1k7eezutBPH7RBN/7QPnwR7hzNlEFeg== + dependencies: + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/constants" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + +"@ethersproject/wallet@5.7.0": + version "5.7.0" + resolved "https://registry.npmjs.org/@ethersproject/wallet/-/wallet-5.7.0.tgz" + integrity sha512-MhmXlJXEJFBFVKrDLB4ZdDzxcBxQ3rLyCkhNqVu3CDYvR97E+8r01UgrI+TI99Le+aYm/in/0vp86guJuM7FCA== + dependencies: + "@ethersproject/abstract-provider" "^5.7.0" + "@ethersproject/abstract-signer" "^5.7.0" + "@ethersproject/address" "^5.7.0" + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/hash" "^5.7.0" + "@ethersproject/hdnode" "^5.7.0" + "@ethersproject/json-wallets" "^5.7.0" + "@ethersproject/keccak256" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/random" "^5.7.0" + "@ethersproject/signing-key" "^5.7.0" + "@ethersproject/transactions" "^5.7.0" + "@ethersproject/wordlists" "^5.7.0" + +"@ethersproject/web@5.7.1": + version "5.7.1" + resolved "https://registry.npmjs.org/@ethersproject/web/-/web-5.7.1.tgz" + integrity sha512-Gueu8lSvyjBWL4cYsWsjh6MtMwM0+H4HvqFPZfB6dV8ctbP9zFAO73VG1cMWae0FLPCtz0peKPpZY8/ugJJX2w== + dependencies: + "@ethersproject/base64" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/strings" "^5.7.0" + +"@ethersproject/web@^5.7.0", "@ethersproject/web@^5.8.0": + version "5.8.0" + resolved "https://registry.npmjs.org/@ethersproject/web/-/web-5.8.0.tgz" + integrity sha512-j7+Ksi/9KfGviws6Qtf9Q7KCqRhpwrYKQPs+JBA/rKVFF/yaWLHJEH3zfVP2plVu+eys0d2DlFmhoQJayFewcw== + 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.7.0", "@ethersproject/wordlists@^5.7.0": + version "5.7.0" + resolved "https://registry.npmjs.org/@ethersproject/wordlists/-/wordlists-5.7.0.tgz" + integrity sha512-S2TFNJNfHWVHNE6cNDjbVlZ6MgE17MIxMbMg2zv3wn+3XSJGosL1m9ZVv3GXCf/2ymSsQ+hRI5IzoMJTG6aoVA== + dependencies: + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/hash" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/strings" "^5.7.0" + +"@gar/promisify@^1.0.1": + version "1.1.3" + resolved "https://registry.yarnpkg.com/@gar/promisify/-/promisify-1.1.3.tgz#555193ab2e3bb3b6adc3d551c9c030d9e860daf6" + integrity sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw== + "@hapi/hoek@^9.0.0", "@hapi/hoek@^9.3.0": version "9.3.0" resolved "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.3.0.tgz" @@ -700,28 +1272,215 @@ "@jridgewell/resolve-uri" "^3.0.3" "@jridgewell/sourcemap-codec" "^1.4.10" +"@noble/ciphers@^1.3.0": + version "1.3.0" + resolved "https://registry.npmjs.org/@noble/ciphers/-/ciphers-1.3.0.tgz" + integrity sha512-2I0gnIVPtfnMw9ee9h1dJG7tp81+8Ob3OJb3Mv37rx5L40/b0i7djjCVvGOVqc9AEIQyvyu1i6ypKdFw8R8gQw== + "@noble/curves@1.2.0": version "1.2.0" - resolved "https://registry.yarnpkg.com/@noble/curves/-/curves-1.2.0.tgz#92d7e12e4e49b23105a2555c6984d41733d65c35" + resolved "https://registry.npmjs.org/@noble/curves/-/curves-1.2.0.tgz" integrity sha512-oYclrNgRaM9SsBUBVbb8M6DTV7ZHRTKugureoYEncY5c65HOmRzvSiTE3y5CYaPYJA/GVkrhXEoF0M3Ya9PMnw== dependencies: "@noble/hashes" "1.3.2" +"@noble/curves@1.4.2", "@noble/curves@~1.4.0": + version "1.4.2" + resolved "https://registry.npmjs.org/@noble/curves/-/curves-1.4.2.tgz" + integrity sha512-TavHr8qycMChk8UwMld0ZDRvatedkzWfH8IiaeGCfymOP5i0hSCozz9vHOL0nkwk7HRMlFnAiKpS2jrUmSybcw== + dependencies: + "@noble/hashes" "1.4.0" + +"@noble/curves@1.9.1": + version "1.9.1" + resolved "https://registry.npmjs.org/@noble/curves/-/curves-1.9.1.tgz" + integrity sha512-k11yZxZg+t+gWvBbIswW0yoJlu8cHOC7dhunwOzoWH/mXGBiYyR4YY6hAEK/3EUs4UpB8la1RfdRpeGsFHkWsA== + dependencies: + "@noble/hashes" "1.8.0" + +"@noble/curves@^1.6.0", "@noble/curves@~1.9.0": + version "1.9.7" + resolved "https://registry.npmjs.org/@noble/curves/-/curves-1.9.7.tgz" + integrity sha512-gbKGcRUYIjA3/zCCNaWDciTMFI0dCkvou3TL8Zmy5Nc7sJ47a0jtOeZoTaMxkuqRo9cRhjOdZJXegxYE5FN/xw== + dependencies: + "@noble/hashes" "1.8.0" + "@noble/hashes@1.3.2": version "1.3.2" - resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.3.2.tgz#6f26dbc8fbc7205873ce3cee2f690eba0d421b39" + resolved "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.2.tgz" integrity sha512-MVC8EAQp7MvEcm30KWENFjgR+Mkmf+D189XJTkFIlwohU5hcBbn1ZkKq7KVTi2Hme3PMGF390DaL52beVrIihQ== -"@noble/hashes@^1.1.2": - version "1.5.0" - resolved "https://registry.npmjs.org/@noble/hashes/-/hashes-1.5.0.tgz" - integrity sha512-1j6kQFb7QRru7eKN3ZDvRcP13rugwdxZqCjbiAVZfIJwgj2A65UmT4TgARXGlXgnRkORLTDTrO19ZErt7+QXgA== +"@noble/hashes@1.4.0", "@noble/hashes@~1.4.0": + version "1.4.0" + resolved "https://registry.npmjs.org/@noble/hashes/-/hashes-1.4.0.tgz" + integrity sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg== + +"@noble/hashes@1.8.0", "@noble/hashes@^1.1.2", "@noble/hashes@^1.4.0", "@noble/hashes@^1.8.0", "@noble/hashes@~1.8.0": + version "1.8.0" + resolved "https://registry.npmjs.org/@noble/hashes/-/hashes-1.8.0.tgz" + integrity sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A== + +"@npmcli/fs@^1.0.0": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@npmcli/fs/-/fs-1.1.1.tgz#72f719fe935e687c56a4faecf3c03d06ba593257" + integrity sha512-8KG5RD0GVP4ydEzRn/I4BNDuxDtqVbOdm8675T49OIG/NGhaK0pjPX7ZcDlvKYbA+ulvVK3ztfcF4uBdOxuJbQ== + dependencies: + "@gar/promisify" "^1.0.1" + semver "^7.3.5" + +"@npmcli/move-file@^1.0.1": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@npmcli/move-file/-/move-file-1.1.2.tgz#1a82c3e372f7cae9253eb66d72543d6b8685c674" + integrity sha512-1SUf/Cg2GzGDyaf15aR9St9TWlb+XvbZXWpDx8YKs7MLzMH/BCeopv+y9vzrzgkfykCGuWOlSu3mZhj2+FQcrg== + dependencies: + mkdirp "^1.0.4" + rimraf "^3.0.2" + +"@peculiar/asn1-schema@^2.3.13": + version "2.5.0" + resolved "https://registry.npmjs.org/@peculiar/asn1-schema/-/asn1-schema-2.5.0.tgz" + integrity sha512-YM/nFfskFJSlHqv59ed6dZlLZqtZQwjRVJ4bBAiWV08Oc+1rSd5lDZcBEx0lGDHfSoH3UziI2pXt2UM33KerPQ== + dependencies: + asn1js "^3.0.6" + pvtsutils "^1.3.6" + tslib "^2.8.1" "@pkgjs/parseargs@^0.11.0": version "0.11.0" resolved "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz" integrity sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg== +"@safe-global/api-kit@^4.0.0": + version "4.0.0" + resolved "https://registry.npmjs.org/@safe-global/api-kit/-/api-kit-4.0.0.tgz" + integrity sha512-xtLLi6OXguLw8cLoYnzCxqmirzRK4sSORxaiBDXdxJfBXIZLLKvYwQyDjsPL+2W4jKlJVcSLCw5EfolJahNMYg== + dependencies: + "@safe-global/protocol-kit" "^6.1.0" + "@safe-global/types-kit" "^3.0.0" + node-fetch "^2.7.0" + viem "^2.21.8" + +"@safe-global/protocol-kit@^6.1.0": + version "6.1.1" + resolved "https://registry.npmjs.org/@safe-global/protocol-kit/-/protocol-kit-6.1.1.tgz" + integrity sha512-SlRosKB52h1CV2gMlKG4UOvh2j4tXuzz1GZ/yQ1HD0Zvm5azUlaytFwKzHun9xNVvfe+vvSNHUEGX2Umy+rQ9A== + dependencies: + "@safe-global/safe-deployments" "^1.37.42" + "@safe-global/safe-modules-deployments" "^2.2.14" + "@safe-global/types-kit" "^3.0.0" + abitype "^1.0.2" + semver "^7.7.2" + viem "^2.21.8" + optionalDependencies: + "@noble/curves" "^1.6.0" + "@peculiar/asn1-schema" "^2.3.13" + +"@safe-global/safe-core-sdk-types@^1.9.2": + version "1.10.1" + resolved "https://registry.npmjs.org/@safe-global/safe-core-sdk-types/-/safe-core-sdk-types-1.10.1.tgz" + integrity sha512-BKvuYTLOlY16Rq6qCXglmnL6KxInDuXMFqZMaCzwDKiEh+uoHu3xCumG5tVtWOkCgBF4XEZXMqwZUiLcon7IsA== + dependencies: + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/contracts" "^5.7.0" + "@safe-global/safe-deployments" "^1.20.2" + web3-core "^1.8.1" + web3-utils "^1.8.1" + +"@safe-global/safe-core-sdk-utils@^1.7.4": + version "1.7.4" + resolved "https://registry.npmjs.org/@safe-global/safe-core-sdk-utils/-/safe-core-sdk-utils-1.7.4.tgz" + integrity sha512-ITocwSWlFUA1K9VMP/eJiMfgbP/I9qDxAaFz7ukj5N5NZD3ihVQZkmqML6hjse5UhrfjCnfIEcLkNZhtB2XC2Q== + dependencies: + "@safe-global/safe-core-sdk-types" "^1.9.2" + semver "^7.3.8" + web3-utils "^1.8.1" + +"@safe-global/safe-core-sdk@^3.3.5": + version "3.3.5" + resolved "https://registry.npmjs.org/@safe-global/safe-core-sdk/-/safe-core-sdk-3.3.5.tgz" + integrity sha512-ul+WmpxZOXgDIXrZ6MIHptThYbm0CVV3/rypMQEn4tZLkudh/yXK7EuWBFnx9prR3MePuku51Zcz9fu1vi7sfQ== + dependencies: + "@ethersproject/solidity" "^5.7.0" + "@safe-global/safe-core-sdk-types" "^1.9.2" + "@safe-global/safe-core-sdk-utils" "^1.7.4" + "@safe-global/safe-deployments" "^1.25.0" + ethereumjs-util "^7.1.5" + semver "^7.3.8" + web3-utils "^1.8.1" + zksync-web3 "^0.14.3" + +"@safe-global/safe-deployments@^1.20.2", "@safe-global/safe-deployments@^1.25.0", "@safe-global/safe-deployments@^1.37.42": + version "1.37.45" + resolved "https://registry.npmjs.org/@safe-global/safe-deployments/-/safe-deployments-1.37.45.tgz" + integrity sha512-HLH8nJSVbDlx/p3Yzhspyz9q9pITSGvw2UqlmXfAyrz6VSM8zc9xUWlBeqaUEzvmgon9YUgfstUMz2MElRUCfQ== + dependencies: + semver "^7.6.2" + +"@safe-global/safe-ethers-lib@^1.9.4": + version "1.9.4" + resolved "https://registry.npmjs.org/@safe-global/safe-ethers-lib/-/safe-ethers-lib-1.9.4.tgz" + integrity sha512-WhzcmNun0s0VxeVQKRqaapV0vEpdm76zZBR2Du+S+58u1r57OjZkOSL2Gru0tdwkt3FIZZtE3OhDu09M70pVkA== + dependencies: + "@safe-global/safe-core-sdk-types" "^1.9.2" + "@safe-global/safe-core-sdk-utils" "^1.7.4" + ethers "5.7.2" + +"@safe-global/safe-modules-deployments@^2.2.14": + version "2.2.16" + resolved "https://registry.npmjs.org/@safe-global/safe-modules-deployments/-/safe-modules-deployments-2.2.16.tgz" + integrity sha512-/pSkOy8GYCbrR7ZiV6uYTOcenP2JZiiQJSLt/Dd7ROpTL9B7KdSuB6sVIfNI+1hNPgXYj7kcfCZZgPloxFcuFw== + +"@safe-global/types-kit@^3.0.0": + version "3.0.0" + resolved "https://registry.npmjs.org/@safe-global/types-kit/-/types-kit-3.0.0.tgz" + integrity sha512-AZWIlR5MguDPdGiOj7BB4JQPY2afqmWQww1mu8m8Oi16HHBW99G01kFOu4NEHBwEU1cgwWOMY19hsI5KyL4W2w== + dependencies: + abitype "^1.0.2" + +"@scure/base@~1.1.6": + version "1.1.9" + resolved "https://registry.npmjs.org/@scure/base/-/base-1.1.9.tgz" + integrity sha512-8YKhl8GHiNI/pU2VMaofa2Tor7PJRAjwQLBBuilkJ9L5+13yVbC7JO/wS7piioAvPSwR3JKM1IJ/u4xQzbcXKg== + +"@scure/base@~1.2.5": + version "1.2.6" + resolved "https://registry.npmjs.org/@scure/base/-/base-1.2.6.tgz" + integrity sha512-g/nm5FgUa//MCj1gV09zTJTaM6KBAHqLN907YVQqf7zC49+DcO4B1so4ZX07Ef10Twr6nuqYEH9GEggFXA4Fmg== + +"@scure/bip32@1.4.0": + version "1.4.0" + resolved "https://registry.npmjs.org/@scure/bip32/-/bip32-1.4.0.tgz" + integrity sha512-sVUpc0Vq3tXCkDGYVWGIZTRfnvu8LoTDaev7vbwh0omSvVORONr960MQWdKqJDCReIEmTj3PAr73O3aoxz7OPg== + dependencies: + "@noble/curves" "~1.4.0" + "@noble/hashes" "~1.4.0" + "@scure/base" "~1.1.6" + +"@scure/bip32@1.7.0", "@scure/bip32@^1.7.0": + version "1.7.0" + resolved "https://registry.npmjs.org/@scure/bip32/-/bip32-1.7.0.tgz" + integrity sha512-E4FFX/N3f4B80AKWp5dP6ow+flD1LQZo/w8UnLGYZO674jS6YnYeepycOOksv+vLPSpgN35wgKgy+ybfTb2SMw== + dependencies: + "@noble/curves" "~1.9.0" + "@noble/hashes" "~1.8.0" + "@scure/base" "~1.2.5" + +"@scure/bip39@1.3.0": + version "1.3.0" + resolved "https://registry.npmjs.org/@scure/bip39/-/bip39-1.3.0.tgz" + integrity sha512-disdg7gHuTDZtY+ZdkmLpPCk7fxZSu3gBiEGuoC1XYxv9cGx3Z6cpTggCgW6odSOOIXCiDjuGejW+aJKCY/pIQ== + dependencies: + "@noble/hashes" "~1.4.0" + "@scure/base" "~1.1.6" + +"@scure/bip39@1.6.0", "@scure/bip39@^1.6.0": + version "1.6.0" + resolved "https://registry.npmjs.org/@scure/bip39/-/bip39-1.6.0.tgz" + integrity sha512-+lF0BbLiJNwVlev4eKelw1WWLaiKXw7sSl8T6FvBlWkdX+94aGJ4o8XjUdlyhTCjd8c+B3KT3JfS8P0bLRNU6A== + dependencies: + "@noble/hashes" "~1.8.0" + "@scure/base" "~1.2.5" + "@sideway/address@^4.1.5": version "4.1.5" resolved "https://registry.npmjs.org/@sideway/address/-/address-4.1.5.tgz" @@ -1064,7 +1823,7 @@ "@smithy/util-stream" "^3.1.9" tslib "^2.6.2" -"@smithy/types@^3.4.2", "@smithy/types@^3.5.0": +"@smithy/types@^3.5.0": version "3.5.0" resolved "https://registry.npmjs.org/@smithy/types/-/types-3.5.0.tgz" integrity sha512-QN0twHNfe8mNJdH9unwsCK13GURU7oEAZqkBI+rsvpv1jrmserO+WnLE7jidR9W/1dxwZ0u/CB01mV2Gms/K2Q== @@ -1269,6 +2028,11 @@ resolved "https://registry.npmjs.org/@stablelib/wipe/-/wipe-1.0.1.tgz" integrity sha512-WfqfX/eXGiAd3RJe4VU2snh/ZPwtSjLG4ynQ/vYzvghTh7dHFcI1wl+nrkWG6lGhukOxOsUHfv8dUXr58D0ayg== +"@tootallnate/once@1": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-1.1.2.tgz#ccb91445360179a04e7fe6aff78c00ffc1eeaf82" + integrity sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw== + "@tsconfig/node10@^1.0.7": version "1.0.11" resolved "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz" @@ -1289,6 +2053,13 @@ resolved "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz" integrity sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA== +"@types/bn.js@^5.1.0", "@types/bn.js@^5.1.1": + version "5.2.0" + resolved "https://registry.npmjs.org/@types/bn.js/-/bn.js-5.2.0.tgz" + integrity sha512-DLbJ1BPqxvQhIGbeu8VbUC1DiAiahHtAYvA0ZEAa4P31F7IaArc8z3C3BRQdWX4mtLQuABG4yzp76ZrS02Ui1Q== + dependencies: + "@types/node" "*" + "@types/body-parser@*": version "1.19.5" resolved "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.5.tgz" @@ -1391,11 +2162,16 @@ "@types/node@22.7.5": version "22.7.5" - resolved "https://registry.yarnpkg.com/@types/node/-/node-22.7.5.tgz#cfde981727a7ab3611a481510b473ae54442b92b" + resolved "https://registry.npmjs.org/@types/node/-/node-22.7.5.tgz" integrity sha512-jML7s2NAzMWc//QSJ1a3prpk78cOPchGvXJsC3C6R6PSMoooztvRVQEz89gmBTBY1SPMaqo5teB4uNHPdetShQ== dependencies: undici-types "~6.19.2" +"@types/node@^12.12.6": + version "12.20.55" + resolved "https://registry.npmjs.org/@types/node/-/node-12.20.55.tgz" + integrity sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ== + "@types/nodemailer@^6.4.16": version "6.4.16" resolved "https://registry.npmjs.org/@types/nodemailer/-/nodemailer-6.4.16.tgz" @@ -1403,6 +2179,13 @@ dependencies: "@types/node" "*" +"@types/pbkdf2@^3.0.0": + version "3.1.2" + resolved "https://registry.npmjs.org/@types/pbkdf2/-/pbkdf2-3.1.2.tgz" + integrity sha512-uRwJqmiXmh9++aSu1VNEn3iIxWOhd8AHXNSdlaLfdAAdSTY9jYVeGWnzejM3dvrkbqE3/hyQkQQ29IFATEGlew== + dependencies: + "@types/node" "*" + "@types/qs@*": version "6.9.15" resolved "https://registry.npmjs.org/@types/qs/-/qs-6.9.15.tgz" @@ -1413,6 +2196,13 @@ resolved "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz" integrity sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ== +"@types/secp256k1@^4.0.1": + version "4.0.7" + resolved "https://registry.npmjs.org/@types/secp256k1/-/secp256k1-4.0.7.tgz" + integrity sha512-Rcvjl6vARGAKRO6jHeKMatGrvOMGrR/AR11N1x2LqintPCyDZ7NBhrh238Z2VZc7aM7KIwnFpFQ7fnfK4H/9Qw== + dependencies: + "@types/node" "*" + "@types/send@*": version "0.17.4" resolved "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz" @@ -1453,6 +2243,31 @@ resolved "https://registry.npmjs.org/@types/uuid/-/uuid-10.0.0.tgz" integrity sha512-7gqG38EyHgyP1S+7+xomFtL+ZNHcKv6DwNaCZmJmo1vgMugyF3TCnXVg4t1uk89mLNwnLtnY3TpOpCOyp1/xHQ== +"@types/validator@^13.11.8": + version "13.15.3" + resolved "https://registry.npmjs.org/@types/validator/-/validator-13.15.3.tgz" + integrity sha512-7bcUmDyS6PN3EuD9SlGGOxM77F8WLVsrwkxyWxKnxzmXoequ6c7741QBrANq6htVRGOITJ7z72mTP6Z4XyuG+Q== + +abbrev@1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" + integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q== + +abitype@1.1.0: + version "1.1.0" + resolved "https://registry.npmjs.org/abitype/-/abitype-1.1.0.tgz" + integrity sha512-6Vh4HcRxNMLA0puzPjM5GBgT4aAcFGKZzSgAXvuZ27shJP6NEpielTuqbBmZILR5/xd0PizkBGy5hReKz9jl5A== + +abitype@^1.0.2, abitype@^1.0.9: + version "1.1.1" + resolved "https://registry.npmjs.org/abitype/-/abitype-1.1.1.tgz" + integrity sha512-Loe5/6tAgsBukY95eGaPSDmQHIjRZYQq8PB1MpsNccDIK8WiV+Uw6WzaIXipvaxTEL2yEB0OpEaQv3gs8pkS9Q== + +abortcontroller-polyfill@^1.7.5: + version "1.7.8" + resolved "https://registry.npmjs.org/abortcontroller-polyfill/-/abortcontroller-polyfill-1.7.8.tgz" + integrity sha512-9f1iZ2uWh92VcrU9Y8x+LdM4DLj75VE0MJB8zuF1iUnroEptStw+DQ8EQPMUdfe5k+PkB1uUfDQfWbhstH8LrQ== + accepts@~1.3.8: version "1.3.8" resolved "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz" @@ -1473,11 +2288,38 @@ acorn@^8.11.0, acorn@^8.4.1: resolved "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz" integrity sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg== +aes-js@3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/aes-js/-/aes-js-3.0.0.tgz" + integrity sha512-H7wUZRn8WpTq9jocdxQ2c8x2sKo9ZVmzfRE13GiNJXfp7NcKYEdvl3vspKjXox6RIG2VtaRe4JFvxG4rqp2Zuw== + aes-js@4.0.0-beta.5: version "4.0.0-beta.5" - resolved "https://registry.yarnpkg.com/aes-js/-/aes-js-4.0.0-beta.5.tgz#8d2452c52adedebc3a3e28465d858c11ca315873" + resolved "https://registry.npmjs.org/aes-js/-/aes-js-4.0.0-beta.5.tgz" integrity sha512-G965FqalsNyrPqgEGON7nIx1e/OVENSgiEIzyC63haUMuvNnwIgIjMs52hlTCKhkBny7A2ORNlfY9Zu+jmGk1Q== +agent-base@6, agent-base@^6.0.2: + version "6.0.2" + resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.2.tgz#49fff58577cfee3f37176feab4c22e00f86d7f77" + integrity sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ== + dependencies: + debug "4" + +agentkeepalive@^4.1.3: + version "4.6.0" + resolved "https://registry.yarnpkg.com/agentkeepalive/-/agentkeepalive-4.6.0.tgz#35f73e94b3f40bf65f105219c623ad19c136ea6a" + integrity sha512-kja8j7PjmncONqaTsB8fQ+wE2mSU2DJ9D4XKoJ5PFWIdRMa6SLSN1ff4mOr4jCbfRSsxR4keIiySJU0N9T5hIQ== + dependencies: + humanize-ms "^1.2.1" + +aggregate-error@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/aggregate-error/-/aggregate-error-3.1.0.tgz#92670ff50f5359bdb7a3e0d40d0ec30c5737687a" + integrity sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA== + dependencies: + clean-stack "^2.0.0" + indent-string "^4.0.0" + ansi-colors@^4.1.3: version "4.1.3" resolved "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz" @@ -1512,10 +2354,10 @@ ansi-styles@^6.1.0: resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz" integrity sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug== -any-promise@^1.0.0: - version "1.3.0" - resolved "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz" - integrity sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A== +ansis@^3.17.0: + version "3.17.0" + resolved "https://registry.npmjs.org/ansis/-/ansis-3.17.0.tgz" + integrity sha512-0qWUglt9JEqLFr3w1I1pbrChn1grhaiAR2ocX1PP/flRmxgtwTzPFFFnfIlD6aMOLQZgSuCRlidD70lvx8yhzg== anymatch@~3.1.2: version "3.1.3" @@ -1540,6 +2382,19 @@ append-field@^1.0.0: resolved "https://registry.npmjs.org/append-field/-/append-field-1.0.0.tgz" integrity sha512-klpgFSWLW1ZEs8svjfb7g4qWY0YS5imI82dTg+QahUvJ8YqAY0P10Uk8tTyh9ZGuYEZEMaeJYCF5BFuX552hsw== +"aproba@^1.0.3 || ^2.0.0": + version "2.1.0" + resolved "https://registry.yarnpkg.com/aproba/-/aproba-2.1.0.tgz#75500a190313d95c64e871e7e4284c6ac219f0b1" + integrity sha512-tLIEcj5GuR2RSTnxNKdkK0dJ/GrC7P38sUkiDmDuHfsHmbagTFAxDVIBltoklXEVIQ/f14IL8IMJ5pn9Hez1Ew== + +are-we-there-yet@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-3.0.1.tgz#679df222b278c64f2cdba1175cdc00b0d96164bd" + integrity sha512-QZW4EDmGwlYur0Yyf/b2uGucHQMa8aFUP7eu9ddR73vvhFyt4V0Vl3QHPcTNJ8l6qYOBdxgXdnBXQrHilfRQBg== + dependencies: + delegates "^1.0.0" + readable-stream "^3.6.0" + arg@^4.1.0: version "4.1.3" resolved "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz" @@ -1567,6 +2422,15 @@ asap@^2.0.0: resolved "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz" integrity sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA== +asn1js@^3.0.6: + version "3.0.6" + resolved "https://registry.npmjs.org/asn1js/-/asn1js-3.0.6.tgz" + integrity sha512-UOCGPYbl0tv8+006qks/dTgV9ajs97X2p0FAbyS2iyCRrmLSRolDaHdp+v/CLgnzHc3fVB+CwYiUmei7ndFcgA== + dependencies: + pvtsutils "^1.3.6" + pvutils "^1.1.3" + tslib "^2.8.1" + assertion-error@^2.0.1: version "2.0.1" resolved "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz" @@ -1577,14 +2441,21 @@ asynckit@^0.4.0: resolved "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz" integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q== +available-typed-arrays@^1.0.7: + version "1.0.7" + resolved "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz" + integrity sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ== + dependencies: + possible-typed-array-names "^1.0.0" + aws-ssl-profiles@^1.1.1: version "1.1.2" - resolved "https://registry.yarnpkg.com/aws-ssl-profiles/-/aws-ssl-profiles-1.1.2.tgz#157dd77e9f19b1d123678e93f120e6f193022641" + resolved "https://registry.npmjs.org/aws-ssl-profiles/-/aws-ssl-profiles-1.1.2.tgz" integrity sha512-NZKeq9AfyQvEeNlN0zSYAaWrmBffJh3IELMZfRpJVWgrpEbtEpnjvzqBPf+mxoI287JohRDoa+/nsfqqiZmF6g== axios@^1.7.4: version "1.7.9" - resolved "https://registry.yarnpkg.com/axios/-/axios-1.7.9.tgz#d7d071380c132a24accda1b2cfc1535b79ec650a" + resolved "https://registry.npmjs.org/axios/-/axios-1.7.9.tgz" integrity sha512-LhLcE7Hbiryz8oMDdDptSrWowmB4Bl6RCt6sIJKpRB4XtVf0iEgewX3au/pJqm+Py1kCASkb/FFKjxQaLtxJvw== dependencies: follow-redirects "^1.15.6" @@ -1596,19 +2467,72 @@ balanced-match@^1.0.0: resolved "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz" integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== +base-x@^3.0.2: + version "3.0.11" + resolved "https://registry.npmjs.org/base-x/-/base-x-3.0.11.tgz" + integrity sha512-xz7wQ8xDhdyP7tQxwdteLYeFfS68tSMNCZ/Y37WJ4bhGfKPpqEIlmIyueQHqOyoPhE6xNUqjzRr8ra0eF9VRvA== + dependencies: + safe-buffer "^5.0.1" + base64-js@^1.0.2, base64-js@^1.3.1: version "1.5.1" resolved "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz" integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== +bech32@1.1.4: + version "1.1.4" + resolved "https://registry.npmjs.org/bech32/-/bech32-1.1.4.tgz" + integrity sha512-s0IrSOzLlbvX7yp4WBfPITzpAU8sqQcpsmwXDiKwrG4r491vwCO/XpejasRNl0piBMe/DvP4Tz0mIS/X1DPJBQ== + +bignumber.js@^9.0.0: + version "9.3.1" + resolved "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.3.1.tgz" + integrity sha512-Ko0uX15oIUS7wJ3Rb30Fs6SkVbLmPBAKdlm7q9+ak9bbIeFf0MwuBsQV6z7+X768/cHsfg+WlysDWJcmthjsjQ== + binary-extensions@^2.0.0: version "2.3.0" resolved "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz" integrity sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw== +bindings@^1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/bindings/-/bindings-1.5.0.tgz#10353c9e945334bc0511a6d90b38fbc7c9c504df" + integrity sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ== + dependencies: + file-uri-to-path "1.0.0" + +bl@^4.0.3: + version "4.1.0" + resolved "https://registry.yarnpkg.com/bl/-/bl-4.1.0.tgz#451535264182bec2fbbc83a62ab98cf11d9f7b3a" + integrity sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w== + dependencies: + buffer "^5.5.0" + inherits "^2.0.4" + readable-stream "^3.4.0" + +blakejs@^1.1.0: + version "1.2.1" + resolved "https://registry.npmjs.org/blakejs/-/blakejs-1.2.1.tgz" + integrity sha512-QXUSXI3QVc/gJME0dBpXrag1kbzOqCjCX8/b54ntNyW6sjtoqxqRk3LTmXzaJoh71zMsDCjM+47jS7XiwN/+fQ== + +bn.js@4.11.6: + version "4.11.6" + resolved "https://registry.npmjs.org/bn.js/-/bn.js-4.11.6.tgz" + integrity sha512-XWwnNNFCuuSQ0m3r3C4LE3EiORltHd9M05pq6FOlVeiophzRbMo50Sbz1ehl8K3Z+jw9+vmgnXefY1hz8X+2wA== + +bn.js@^4.11.9: + version "4.12.2" + resolved "https://registry.npmjs.org/bn.js/-/bn.js-4.12.2.tgz" + integrity sha512-n4DSx829VRTRByMRGdjQ9iqsN0Bh4OolPsFnaZBLcbi8iXcB+kJ9s7EnRt4wILZNV3kPLHkRVfOc/HvhC3ovDw== + +bn.js@^5.1.2, bn.js@^5.2.0, bn.js@^5.2.1: + version "5.2.2" + resolved "https://registry.npmjs.org/bn.js/-/bn.js-5.2.2.tgz" + integrity sha512-v2YAxEmKaBLahNwE1mjp4WON6huMNeuDvagFZW+ASCuA/ku0bXR9hSMw0XpiqMoA3+rmnyck/tPRSFQkoC9Cuw== + body-parser@1.20.3: version "1.20.3" - resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.20.3.tgz#1953431221c6fb5cd63c4b36d53fab0928e548c6" + resolved "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz" integrity sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g== dependencies: bytes "3.1.2" @@ -1638,9 +2562,9 @@ brace-expansion@^1.1.7: concat-map "0.0.1" brace-expansion@^2.0.1: - version "2.0.1" - resolved "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz" - integrity sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA== + version "2.0.2" + resolved "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz" + integrity sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ== dependencies: balanced-match "^1.0.0" @@ -1651,11 +2575,44 @@ braces@~3.0.2: dependencies: fill-range "^7.1.1" +brorand@^1.1.0: + version "1.1.0" + resolved "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz" + integrity sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w== + browser-stdout@^1.3.1: version "1.3.1" resolved "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz" integrity sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw== +browserify-aes@^1.2.0: + version "1.2.0" + resolved "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz" + integrity sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA== + dependencies: + buffer-xor "^1.0.3" + cipher-base "^1.0.0" + create-hash "^1.1.0" + evp_bytestokey "^1.0.3" + inherits "^2.0.1" + safe-buffer "^5.0.1" + +bs58@^4.0.0: + version "4.0.1" + resolved "https://registry.npmjs.org/bs58/-/bs58-4.0.1.tgz" + integrity sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw== + dependencies: + base-x "^3.0.2" + +bs58check@^2.1.2: + version "2.1.2" + resolved "https://registry.npmjs.org/bs58check/-/bs58check-2.1.2.tgz" + integrity sha512-0TS1jicxdU09dwJMNZtVAfzPi6Q6QeN0pM1Fkzrjn+XYHvzMKPU3pHVpva+769iNVSfIYWf7LJ6WR+BuuMf8cA== + dependencies: + bs58 "^4.0.0" + create-hash "^1.1.0" + safe-buffer "^5.1.2" + buffer-equal-constant-time@1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz" @@ -1666,6 +2623,11 @@ buffer-from@^1.0.0: resolved "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz" integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== +buffer-xor@^1.0.3: + version "1.0.3" + resolved "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz" + integrity sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ== + buffer@5.6.0: version "5.6.0" resolved "https://registry.npmjs.org/buffer/-/buffer-5.6.0.tgz" @@ -1674,6 +2636,14 @@ buffer@5.6.0: base64-js "^1.0.2" ieee754 "^1.1.4" +buffer@^5.5.0: + version "5.7.1" + resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.7.1.tgz#ba62e7c13133053582197160851a8f648e99eed0" + integrity sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ== + dependencies: + base64-js "^1.3.1" + ieee754 "^1.1.13" + buffer@^6.0.3: version "6.0.3" resolved "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz" @@ -1682,6 +2652,13 @@ buffer@^6.0.3: base64-js "^1.3.1" ieee754 "^1.2.1" +bufferutil@^4.0.1: + version "4.0.9" + resolved "https://registry.npmjs.org/bufferutil/-/bufferutil-4.0.9.tgz" + integrity sha512-WDtdLmJvAuNNPzByAYpRo2rF1Mmradw6gvWsQKf63476DDXmomT9zUiGypLcG4ibIM67vhAj8jJRdbmEws2Aqw== + dependencies: + node-gyp-build "^4.3.0" + builtin-modules@^1.1.1: version "1.1.1" resolved "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz" @@ -1700,16 +2677,55 @@ bytes@3.1.2: resolved "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz" integrity sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg== -call-bind@^1.0.7: - version "1.0.7" - resolved "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz" - integrity sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w== +cacache@^15.2.0: + version "15.3.0" + resolved "https://registry.yarnpkg.com/cacache/-/cacache-15.3.0.tgz#dc85380fb2f556fe3dda4c719bfa0ec875a7f1eb" + integrity sha512-VVdYzXEn+cnbXpFgWs5hTT7OScegHVmLhJIR8Ufqk3iFD6A6j5iSX1KuBTfNEv4tdJWE2PzA6IVFtcLC7fN9wQ== + dependencies: + "@npmcli/fs" "^1.0.0" + "@npmcli/move-file" "^1.0.1" + chownr "^2.0.0" + fs-minipass "^2.0.0" + glob "^7.1.4" + infer-owner "^1.0.4" + lru-cache "^6.0.0" + minipass "^3.1.1" + minipass-collect "^1.0.2" + minipass-flush "^1.0.5" + minipass-pipeline "^1.2.2" + mkdirp "^1.0.3" + p-map "^4.0.0" + promise-inflight "^1.0.1" + rimraf "^3.0.2" + ssri "^8.0.1" + tar "^6.0.2" + unique-filename "^1.1.1" + +call-bind-apply-helpers@^1.0.0, call-bind-apply-helpers@^1.0.1, call-bind-apply-helpers@^1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz" + integrity sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ== dependencies: - es-define-property "^1.0.0" es-errors "^1.3.0" function-bind "^1.1.2" + +call-bind@^1.0.7, call-bind@^1.0.8: + version "1.0.8" + resolved "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz" + integrity sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww== + dependencies: + call-bind-apply-helpers "^1.0.0" + es-define-property "^1.0.0" get-intrinsic "^1.2.4" - set-function-length "^1.2.1" + set-function-length "^1.2.2" + +call-bound@^1.0.2, call-bound@^1.0.3, call-bound@^1.0.4: + version "1.0.4" + resolved "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz" + integrity sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg== + dependencies: + call-bind-apply-helpers "^1.0.2" + get-intrinsic "^1.3.0" camelcase@^6.0.0: version "6.3.0" @@ -1731,9 +2747,9 @@ chai-http@*, chai-http@^4.4.0: superagent "^8.0.9" chai@^5.1.1: - version "5.1.1" - resolved "https://registry.npmjs.org/chai/-/chai-5.1.1.tgz" - integrity sha512-pT1ZgP8rPNqUgieVaEY+ryQr6Q4HXNg8Ei9UnLUrjN4IA7dvQC5JB+/kxVcPNDHyBcc/26CXPkbNzq3qwrOEKA== + version "5.3.3" + resolved "https://registry.npmjs.org/chai/-/chai-5.3.3.tgz" + integrity sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw== dependencies: assertion-error "^2.0.1" check-error "^2.1.1" @@ -1750,7 +2766,7 @@ chalk@^2.3.0, chalk@^2.4.2: escape-string-regexp "^1.0.5" supports-color "^5.3.0" -chalk@^4.0.0, chalk@^4.1.0, chalk@^4.1.2: +chalk@^4.1.0: version "4.1.2" resolved "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz" integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== @@ -1783,17 +2799,43 @@ chokidar@^3.5.1, chokidar@^3.5.3: optionalDependencies: fsevents "~2.3.2" -cli-highlight@^2.1.11: - version "2.1.11" - resolved "https://registry.npmjs.org/cli-highlight/-/cli-highlight-2.1.11.tgz" - integrity sha512-9KDcoEVwyUXrjcJNvHD0NFc/hiwe/WPVYIleQh2O1N2Zro5gWJZ/K+3DGn8w8P/F6FxOgzyC5bxDyHIgCSPhGg== +chownr@^1.1.1: + version "1.1.4" + resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.4.tgz#6fc9d7b42d32a583596337666e7d08084da2cc6b" + integrity sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg== + +chownr@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/chownr/-/chownr-2.0.0.tgz#15bfbe53d2eab4cf70f18a8cd68ebe5b3cb1dece" + integrity sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ== + +cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: + version "1.0.7" + resolved "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.7.tgz" + integrity sha512-Mz9QMT5fJe7bKI7MH31UilT5cEK5EHHRCccw/YRFsRY47AuNgaV6HY3rscp0/I4Q+tTW/5zoqpSeRRI54TkDWA== + dependencies: + inherits "^2.0.4" + safe-buffer "^5.2.1" + to-buffer "^1.2.2" + +class-transformer@^0.5.1: + version "0.5.1" + resolved "https://registry.npmjs.org/class-transformer/-/class-transformer-0.5.1.tgz" + integrity sha512-SQa1Ws6hUbfC98vKGxZH3KFY0Y1lm5Zm0SY8XX9zbK7FJCyVEac3ATW0RIpwzW+oOfmHE5PMPufDG9hCfoEOMw== + +class-validator@^0.14.1: + version "0.14.2" + resolved "https://registry.npmjs.org/class-validator/-/class-validator-0.14.2.tgz" + integrity sha512-3kMVRF2io8N8pY1IFIXlho9r8IPUUIfHe2hYVtiebvAzU2XeQFXTv+XI4WX+TnXmtwXMDcjngcpkiPM0O9PvLw== dependencies: - chalk "^4.0.0" - highlight.js "^10.7.1" - mz "^2.4.0" - parse5 "^5.1.1" - parse5-htmlparser2-tree-adapter "^6.0.0" - yargs "^16.0.0" + "@types/validator" "^13.11.8" + libphonenumber-js "^1.11.1" + validator "^13.9.0" + +clean-stack@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/clean-stack/-/clean-stack-2.2.0.tgz#ee8472dbb129e727b31e8a10a427dee9dfe4008b" + integrity sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A== cliui@^7.0.2: version "7.0.4" @@ -1837,6 +2879,11 @@ color-name@~1.1.4: resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz" integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== +color-support@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/color-support/-/color-support-1.1.3.tgz#93834379a1cc9a0c61f82f52f0d04322251bd5a2" + integrity sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg== + combined-stream@^1.0.8: version "1.0.8" resolved "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz" @@ -1869,6 +2916,11 @@ concat-stream@^1.5.2: readable-stream "^2.2.2" typedarray "^0.0.6" +console-control-strings@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" + integrity sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ== + content-disposition@0.5.4: version "0.5.4" resolved "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz" @@ -1909,11 +2961,41 @@ cors@2.8.5: object-assign "^4" vary "^1" +create-hash@^1.1.0, create-hash@^1.1.2, create-hash@^1.2.0: + version "1.2.0" + resolved "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz" + integrity sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg== + dependencies: + cipher-base "^1.0.1" + inherits "^2.0.1" + md5.js "^1.3.4" + ripemd160 "^2.0.1" + sha.js "^2.4.0" + +create-hmac@^1.1.7: + version "1.1.7" + resolved "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz" + integrity sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg== + dependencies: + cipher-base "^1.0.3" + create-hash "^1.1.0" + inherits "^2.0.1" + ripemd160 "^2.0.0" + safe-buffer "^5.0.1" + sha.js "^2.4.8" + create-require@^1.1.0: version "1.1.1" resolved "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz" integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ== +cross-fetch@^4.0.0: + version "4.1.0" + resolved "https://registry.npmjs.org/cross-fetch/-/cross-fetch-4.1.0.tgz" + integrity sha512-uKm5PU+MHTootlWEY+mZ4vvXoCn4fLQxT9dSc1sXVMSFkINTJVN8cAQROpwcKm8bJ/c7rgZVIBWzH5T78sNZZw== + dependencies: + node-fetch "^2.7.0" + cross-spawn@^7.0.0: version "7.0.3" resolved "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz" @@ -1930,22 +3012,37 @@ crypto@1.0.1: csv-writer@^1.6.0: version "1.6.0" - resolved "https://registry.yarnpkg.com/csv-writer/-/csv-writer-1.6.0.tgz#d0cea44b6b4d7d3baa2ecc6f3f7209233514bcf9" + resolved "https://registry.npmjs.org/csv-writer/-/csv-writer-1.6.0.tgz" integrity sha512-NOx7YDFWEsM/fTRAJjRpPp8t+MKRVvniAg9wQlUKx20MFrPs73WLJhFf5iteqrxNYnsy924K3Iroh3yNHeYd2g== -dayjs@^1.11.9: +d@1, d@^1.0.1, d@^1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/d/-/d-1.0.2.tgz" + integrity sha512-MOqHvMWF9/9MX6nza0KgvFH4HpMU0EF5uUDXqX/BtxtU8NfB0QzRtJ8Oe/6SuS4kbhyzVJwjd97EA4PKrzJ8bw== + dependencies: + es5-ext "^0.10.64" + type "^2.7.2" + +dayjs@^1.11.13: version "1.11.13" resolved "https://registry.npmjs.org/dayjs/-/dayjs-1.11.13.tgz" integrity sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg== -debug@2.6.9: +debug@2.6.9, debug@^2.2.0: version "2.6.9" resolved "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz" integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== dependencies: ms "2.0.0" -debug@^4.3.4, debug@^4.3.5: +debug@4, debug@^4.3.3, debug@^4.3.5, debug@^4.4.0: + version "4.4.3" + resolved "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz" + integrity sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA== + dependencies: + ms "^2.1.3" + +debug@^4.3.4: version "4.3.6" resolved "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz" integrity sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg== @@ -1957,11 +3054,28 @@ decamelize@^4.0.0: resolved "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz" integrity sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ== +decompress-response@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-6.0.0.tgz#ca387612ddb7e104bd16d85aab00d5ecf09c66fc" + integrity sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ== + dependencies: + mimic-response "^3.1.0" + +dedent@^1.6.0: + version "1.7.0" + resolved "https://registry.npmjs.org/dedent/-/dedent-1.7.0.tgz" + integrity sha512-HGFtf8yhuhGhqO07SV79tRp+br4MnbdjeVxotpn1QBl30pcLLCQjX5b2295ll0fv8RKDKsmWYrl05usHM9CewQ== + deep-eql@^5.0.1: version "5.0.2" resolved "https://registry.npmjs.org/deep-eql/-/deep-eql-5.0.2.tgz" integrity sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q== +deep-extend@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac" + integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA== + define-data-property@^1.1.4: version "1.1.4" resolved "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz" @@ -1976,9 +3090,14 @@ delayed-stream@~1.0.0: resolved "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz" integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ== +delegates@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" + integrity sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ== + denque@^2.1.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/denque/-/denque-2.1.0.tgz#e93e1a6569fb5e66f16a3c2a2964617d349d6ab1" + resolved "https://registry.npmjs.org/denque/-/denque-2.1.0.tgz" integrity sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw== depd@2.0.0: @@ -1996,6 +3115,11 @@ destroy@1.2.0: resolved "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz" integrity sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg== +detect-libc@^2.0.0: + version "2.1.2" + resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-2.1.2.tgz#689c5dcdc1900ef5583a4cb9f6d7b473742074ad" + integrity sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ== + dezalgo@^1.0.4: version "1.0.4" resolved "https://registry.npmjs.org/dezalgo/-/dezalgo-1.0.4.tgz" @@ -2022,10 +3146,19 @@ diff@^5.2.0: resolved "https://registry.npmjs.org/diff/-/diff-5.2.0.tgz" integrity sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A== -dotenv@^16.0.3, dotenv@^16.4.5: - version "16.4.5" - resolved "https://registry.npmjs.org/dotenv/-/dotenv-16.4.5.tgz" - integrity sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg== +dotenv@^16.4.5, dotenv@^16.4.7: + version "16.6.1" + resolved "https://registry.npmjs.org/dotenv/-/dotenv-16.6.1.tgz" + integrity sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow== + +dunder-proto@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz" + integrity sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A== + dependencies: + call-bind-apply-helpers "^1.0.1" + es-errors "^1.3.0" + gopd "^1.2.0" dynamic-dedupe@^0.3.0: version "0.3.0" @@ -2051,6 +3184,32 @@ ee-first@1.1.1: resolved "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz" integrity sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow== +elliptic@6.5.4: + version "6.5.4" + resolved "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz" + integrity sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ== + dependencies: + bn.js "^4.11.9" + brorand "^1.1.0" + hash.js "^1.0.0" + hmac-drbg "^1.0.1" + inherits "^2.0.4" + minimalistic-assert "^1.0.1" + minimalistic-crypto-utils "^1.0.1" + +elliptic@6.6.1, elliptic@^6.5.7: + version "6.6.1" + resolved "https://registry.npmjs.org/elliptic/-/elliptic-6.6.1.tgz" + integrity sha512-RaddvvMatK2LJHqFJ+YA4WysVN5Ita9E35botqIYspQ4TkRAlCicdzKOjlyv/1Za5RyTNn7di//eEV0uTAfe3g== + dependencies: + bn.js "^4.11.9" + brorand "^1.1.0" + hash.js "^1.0.0" + hmac-drbg "^1.0.1" + inherits "^2.0.4" + minimalistic-assert "^1.0.1" + minimalistic-crypto-utils "^1.0.1" + emoji-regex@^8.0.0: version "8.0.0" resolved "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz" @@ -2068,21 +3227,82 @@ encodeurl@~1.0.2: encodeurl@~2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-2.0.0.tgz#7b8ea898077d7e409d3ac45474ea38eaf0857a58" + resolved "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz" integrity sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg== -es-define-property@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz" - integrity sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ== +encoding@^0.1.12: + version "0.1.13" + resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.13.tgz#56574afdd791f54a8e9b2785c0582a2d26210fa9" + integrity sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A== dependencies: - get-intrinsic "^1.2.4" + iconv-lite "^0.6.2" + +end-of-stream@^1.1.0, end-of-stream@^1.4.1: + version "1.4.5" + resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.5.tgz#7344d711dea40e0b74abc2ed49778743ccedb08c" + integrity sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg== + dependencies: + once "^1.4.0" + +env-paths@^2.2.0: + version "2.2.1" + resolved "https://registry.yarnpkg.com/env-paths/-/env-paths-2.2.1.tgz#420399d416ce1fbe9bc0a07c62fa68d67fd0f8f2" + integrity sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A== + +err-code@^2.0.2: + version "2.0.3" + resolved "https://registry.yarnpkg.com/err-code/-/err-code-2.0.3.tgz#23c2f3b756ffdfc608d30e27c9a941024807e7f9" + integrity sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA== + +es-define-property@^1.0.0, es-define-property@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz" + integrity sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g== es-errors@^1.3.0: version "1.3.0" resolved "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz" integrity sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw== +es-object-atoms@^1.0.0, es-object-atoms@^1.1.1: + version "1.1.1" + resolved "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz" + integrity sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA== + dependencies: + es-errors "^1.3.0" + +es5-ext@^0.10.35, es5-ext@^0.10.62, es5-ext@^0.10.63, es5-ext@^0.10.64, es5-ext@~0.10.14: + version "0.10.64" + resolved "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.64.tgz" + integrity sha512-p2snDhiLaXe6dahss1LddxqEm+SkuDvV8dnIQG0MWjyHpcMNfXKPE+/Cc0y+PhxJX3A4xGNeFCj5oc0BUh6deg== + dependencies: + es6-iterator "^2.0.3" + es6-symbol "^3.1.3" + esniff "^2.0.1" + next-tick "^1.1.0" + +es6-iterator@^2.0.3: + version "2.0.3" + resolved "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz" + integrity sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g== + dependencies: + d "1" + es5-ext "^0.10.35" + es6-symbol "^3.1.1" + +es6-promise@^4.2.8: + version "4.2.8" + resolved "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz" + integrity sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w== + +es6-symbol@^3.1.1, es6-symbol@^3.1.3: + version "3.1.4" + resolved "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.4.tgz" + integrity sha512-U9bFFjX8tFiATgtkJ1zg25+KviIXpgRvRHS8sau3GfhVzThRQrOeksPeT0BWW2MNZs1OEWJ1DPXOQMn0KKRkvg== + dependencies: + d "^1.0.2" + ext "^1.7.0" + escalade@^3.1.1: version "3.1.2" resolved "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz" @@ -2103,6 +3323,16 @@ escape-string-regexp@^4.0.0: resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz" integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== +esniff@^2.0.1: + version "2.0.1" + resolved "https://registry.npmjs.org/esniff/-/esniff-2.0.1.tgz" + integrity sha512-kTUIGKQ/mDPFoJ0oVfcmyJn4iBDRptjNVIzwIFR7tqWXdVI9xfA2RMwY/gbSpJG3lkdWNEjLap/NqVHZiJsdfg== + dependencies: + d "^1.0.1" + es5-ext "^0.10.62" + event-emitter "^0.3.5" + type "^2.7.2" + esprima@^4.0.0: version "4.0.1" resolved "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz" @@ -2113,9 +3343,94 @@ etag@~1.8.1: resolved "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz" integrity sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg== +ethereum-bloom-filters@^1.0.6: + version "1.2.0" + resolved "https://registry.npmjs.org/ethereum-bloom-filters/-/ethereum-bloom-filters-1.2.0.tgz" + integrity sha512-28hyiE7HVsWubqhpVLVmZXFd4ITeHi+BUu05o9isf0GUpMtzBUi+8/gFrGaGYzvGAJQmJ3JKj77Mk9G98T84rA== + dependencies: + "@noble/hashes" "^1.4.0" + +ethereum-cryptography@^0.1.3: + version "0.1.3" + resolved "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz" + integrity sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ== + dependencies: + "@types/pbkdf2" "^3.0.0" + "@types/secp256k1" "^4.0.1" + blakejs "^1.1.0" + browserify-aes "^1.2.0" + bs58check "^2.1.2" + create-hash "^1.2.0" + create-hmac "^1.1.7" + hash.js "^1.1.7" + keccak "^3.0.0" + pbkdf2 "^3.0.17" + randombytes "^2.1.0" + safe-buffer "^5.1.2" + scrypt-js "^3.0.0" + secp256k1 "^4.0.1" + setimmediate "^1.0.5" + +ethereum-cryptography@^2.0.0, ethereum-cryptography@^2.1.2: + version "2.2.1" + resolved "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-2.2.1.tgz" + integrity sha512-r/W8lkHSiTLxUxW8Rf3u4HGB0xQweG2RyETjywylKZSzLWoWAijRz8WCuOtJ6wah+avllXBqZuk29HCCvhEIRg== + dependencies: + "@noble/curves" "1.4.2" + "@noble/hashes" "1.4.0" + "@scure/bip32" "1.4.0" + "@scure/bip39" "1.3.0" + +ethereumjs-util@^7.1.5: + version "7.1.5" + resolved "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-7.1.5.tgz" + integrity sha512-SDl5kKrQAudFBUe5OJM9Ac6WmMyYmXX/6sTmLZ3ffG2eY6ZIGBes3pEDxNN6V72WyOw4CPD5RomKdsa8DAAwLg== + dependencies: + "@types/bn.js" "^5.1.0" + bn.js "^5.1.2" + create-hash "^1.1.2" + ethereum-cryptography "^0.1.3" + rlp "^2.2.4" + +ethers@5.7.2: + version "5.7.2" + resolved "https://registry.npmjs.org/ethers/-/ethers-5.7.2.tgz" + integrity sha512-wswUsmWo1aOK8rR7DIKiWSw9DbLWe6x98Jrn8wcTflTVvaXhAMaB5zGAXy0GYQEQp9iO1iSHWVyARQm11zUtyg== + dependencies: + "@ethersproject/abi" "5.7.0" + "@ethersproject/abstract-provider" "5.7.0" + "@ethersproject/abstract-signer" "5.7.0" + "@ethersproject/address" "5.7.0" + "@ethersproject/base64" "5.7.0" + "@ethersproject/basex" "5.7.0" + "@ethersproject/bignumber" "5.7.0" + "@ethersproject/bytes" "5.7.0" + "@ethersproject/constants" "5.7.0" + "@ethersproject/contracts" "5.7.0" + "@ethersproject/hash" "5.7.0" + "@ethersproject/hdnode" "5.7.0" + "@ethersproject/json-wallets" "5.7.0" + "@ethersproject/keccak256" "5.7.0" + "@ethersproject/logger" "5.7.0" + "@ethersproject/networks" "5.7.1" + "@ethersproject/pbkdf2" "5.7.0" + "@ethersproject/properties" "5.7.0" + "@ethersproject/providers" "5.7.2" + "@ethersproject/random" "5.7.0" + "@ethersproject/rlp" "5.7.0" + "@ethersproject/sha2" "5.7.0" + "@ethersproject/signing-key" "5.7.0" + "@ethersproject/solidity" "5.7.0" + "@ethersproject/strings" "5.7.0" + "@ethersproject/transactions" "5.7.0" + "@ethersproject/units" "5.7.0" + "@ethersproject/wallet" "5.7.0" + "@ethersproject/web" "5.7.1" + "@ethersproject/wordlists" "5.7.0" + ethers@^6.13.5: version "6.13.5" - resolved "https://registry.yarnpkg.com/ethers/-/ethers-6.13.5.tgz#8c1d6ac988ac08abc3c1d8fabbd4b8b602851ac4" + resolved "https://registry.npmjs.org/ethers/-/ethers-6.13.5.tgz" integrity sha512-+knKNieu5EKRThQJWwqaJ10a6HE9sSehGeqWN65//wE7j47ZpFhKAnHB/JJFibwwg61I/koxaPsXbXpD/skNOQ== dependencies: "@adraffy/ens-normalize" "1.10.1" @@ -2126,11 +3441,50 @@ ethers@^6.13.5: tslib "2.7.0" ws "8.17.1" +ethjs-unit@0.1.6: + version "0.1.6" + resolved "https://registry.npmjs.org/ethjs-unit/-/ethjs-unit-0.1.6.tgz" + integrity sha512-/Sn9Y0oKl0uqQuvgFk/zQgR7aw1g36qX/jzSQ5lSwlO0GigPymk4eGQfeNTD03w1dPOqfz8V77Cy43jH56pagw== + dependencies: + bn.js "4.11.6" + number-to-bn "1.7.0" + +event-emitter@^0.3.5: + version "0.3.5" + resolved "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz" + integrity sha512-D9rRn9y7kLPnJ+hMq7S/nhvoKwwvVJahBi2BPmx3bvbsEdK3W9ii8cBSGjP+72/LnM4n6fo3+dkCX5FeTQruXA== + dependencies: + d "1" + es5-ext "~0.10.14" + +eventemitter3@4.0.4: + version "4.0.4" + resolved "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.4.tgz" + integrity sha512-rlaVLnVxtxvoyLsQQFBx53YmXHDxRIzzTLbdfxqi4yocpSjAxXwkU0cScM5JgSKMqEhrZpnvQ2D9gjylR0AimQ== + +eventemitter3@5.0.1: + version "5.0.1" + resolved "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz" + integrity sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA== + events@3.3.0: version "3.3.0" resolved "https://registry.npmjs.org/events/-/events-3.3.0.tgz" integrity sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q== +evp_bytestokey@^1.0.3: + version "1.0.3" + resolved "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz" + integrity sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA== + dependencies: + md5.js "^1.3.4" + safe-buffer "^5.1.1" + +expand-template@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/expand-template/-/expand-template-2.0.3.tgz#6e14b3fcee0f3a6340ecb57d2e8918692052a47c" + integrity sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg== + express-validator@^7.0.1: version "7.2.0" resolved "https://registry.npmjs.org/express-validator/-/express-validator-7.2.0.tgz" @@ -2141,7 +3495,7 @@ express-validator@^7.0.1: express@^4.20.0: version "4.20.0" - resolved "https://registry.yarnpkg.com/express/-/express-4.20.0.tgz#f1d08e591fcec770c07be4767af8eb9bcfd67c48" + resolved "https://registry.npmjs.org/express/-/express-4.20.0.tgz" integrity sha512-pLdae7I6QqShF5PnNTCVn4hI91Dx0Grkn2+IAsMTgMIKuQVte2dN9PeGSSAME2FR8anOhVA62QDIUaWVfEXVLw== dependencies: accepts "~1.3.8" @@ -2176,6 +3530,13 @@ express@^4.20.0: utils-merge "1.0.1" vary "~1.1.2" +ext@^1.7.0: + version "1.7.0" + resolved "https://registry.npmjs.org/ext/-/ext-1.7.0.tgz" + integrity sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw== + dependencies: + type "^2.7.2" + fast-safe-stringify@^2.1.1: version "2.1.1" resolved "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz" @@ -2188,6 +3549,11 @@ fast-xml-parser@4.4.1: dependencies: strnum "^1.0.5" +file-uri-to-path@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz#553a7b8446ff6f684359c445f1e37a05dacc33dd" + integrity sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw== + fill-range@^7.1.1: version "7.1.1" resolved "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz" @@ -2223,9 +3589,16 @@ flat@^5.0.2: follow-redirects@^1.15.6: version "1.15.9" - resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.9.tgz#a604fa10e443bf98ca94228d9eebcc2e8a2c8ee1" + resolved "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz" integrity sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ== +for-each@^0.3.5: + version "0.3.5" + resolved "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz" + integrity sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg== + dependencies: + is-callable "^1.2.7" + foreground-child@^3.1.0: version "3.3.0" resolved "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.0.tgz" @@ -2263,6 +3636,18 @@ fresh@0.5.2: resolved "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz" integrity sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q== +fs-constants@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs-constants/-/fs-constants-1.0.0.tgz#6be0de9be998ce16af8afc24497b9ee9b7ccd9ad" + integrity sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow== + +fs-minipass@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-2.1.0.tgz#7f5036fdbf12c63c169190cbe4199c852271f9fb" + integrity sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg== + dependencies: + minipass "^3.0.0" + fs.realpath@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz" @@ -2270,7 +3655,7 @@ fs.realpath@^1.0.0: fsevents@~2.3.2: version "2.3.3" - resolved "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== function-bind@^1.1.2: @@ -2278,33 +3663,65 @@ function-bind@^1.1.2: resolved "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz" integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== -generate-function@^2.3.1: - version "2.3.1" - resolved "https://registry.yarnpkg.com/generate-function/-/generate-function-2.3.1.tgz#f069617690c10c868e73b8465746764f97c3479f" - integrity sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ== +gauge@^4.0.3: + version "4.0.4" + resolved "https://registry.yarnpkg.com/gauge/-/gauge-4.0.4.tgz#52ff0652f2bbf607a989793d53b751bef2328dce" + integrity sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg== + dependencies: + aproba "^1.0.3 || ^2.0.0" + color-support "^1.1.3" + console-control-strings "^1.1.0" + has-unicode "^2.0.1" + signal-exit "^3.0.7" + string-width "^4.2.3" + strip-ansi "^6.0.1" + wide-align "^1.1.5" + +generate-function@^2.3.1: + version "2.3.1" + resolved "https://registry.npmjs.org/generate-function/-/generate-function-2.3.1.tgz" + integrity sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ== dependencies: is-property "^1.0.2" +generator-function@^2.0.0: + version "2.0.1" + resolved "https://registry.npmjs.org/generator-function/-/generator-function-2.0.1.tgz" + integrity sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g== + get-caller-file@^2.0.5: version "2.0.5" resolved "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz" integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== -get-func-name@^2.0.1: - version "2.0.2" - resolved "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz" - integrity sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ== - -get-intrinsic@^1.1.3, get-intrinsic@^1.2.4: - version "1.2.4" - resolved "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz" - integrity sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ== +get-intrinsic@^1.2.4, get-intrinsic@^1.3.0: + version "1.3.0" + resolved "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz" + integrity sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ== dependencies: + call-bind-apply-helpers "^1.0.2" + es-define-property "^1.0.1" es-errors "^1.3.0" + es-object-atoms "^1.1.1" function-bind "^1.1.2" - has-proto "^1.0.1" - has-symbols "^1.0.3" - hasown "^2.0.0" + get-proto "^1.0.1" + gopd "^1.2.0" + has-symbols "^1.1.0" + hasown "^2.0.2" + math-intrinsics "^1.1.0" + +get-proto@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz" + integrity sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g== + dependencies: + dunder-proto "^1.0.1" + es-object-atoms "^1.0.0" + +github-from-package@0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/github-from-package/-/github-from-package-0.0.0.tgz#97fb5d96bfde8973313f20e8288ef9a167fa64ce" + integrity sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw== glob-parent@~5.1.2: version "5.1.2" @@ -2313,7 +3730,7 @@ glob-parent@~5.1.2: dependencies: is-glob "^4.0.1" -glob@^10.3.10: +glob@^10.4.5: version "10.4.5" resolved "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz" integrity sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg== @@ -2325,7 +3742,7 @@ glob@^10.3.10: package-json-from-dist "^1.0.0" path-scurry "^1.11.1" -glob@^7.1.1, glob@^7.1.3: +glob@^7.1.1, glob@^7.1.3, glob@^7.1.4: version "7.2.3" resolved "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz" integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== @@ -2348,12 +3765,15 @@ glob@^8.1.0: minimatch "^5.0.1" once "^1.3.0" -gopd@^1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz" - integrity sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA== - dependencies: - get-intrinsic "^1.1.3" +gopd@^1.0.1, gopd@^1.2.0: + version "1.2.0" + resolved "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz" + integrity sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg== + +graceful-fs@^4.2.6: + version "4.2.11" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" + integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== has-flag@^3.0.0: version "3.0.0" @@ -2372,17 +3792,42 @@ has-property-descriptors@^1.0.2: dependencies: es-define-property "^1.0.0" -has-proto@^1.0.1: - version "1.0.3" - resolved "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz" - integrity sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q== +has-symbols@^1.0.3, has-symbols@^1.1.0: + version "1.1.0" + resolved "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz" + integrity sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ== -has-symbols@^1.0.3: - version "1.0.3" - resolved "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz" - integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A== +has-tostringtag@^1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz" + integrity sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw== + dependencies: + has-symbols "^1.0.3" -hasown@^2.0.0, hasown@^2.0.2: +has-unicode@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" + integrity sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ== + +hash-base@^3.0.0, hash-base@^3.1.2: + version "3.1.2" + resolved "https://registry.npmjs.org/hash-base/-/hash-base-3.1.2.tgz" + integrity sha512-Bb33KbowVTIj5s7Ked1OsqHUeCpz//tPwR+E2zJgJKo9Z5XolZ9b6bdUgjmYlwnWhoOQKoTd1TYToZGn5mAYOg== + dependencies: + inherits "^2.0.4" + readable-stream "^2.3.8" + safe-buffer "^5.2.1" + to-buffer "^1.2.1" + +hash.js@1.1.7, hash.js@^1.0.0, hash.js@^1.0.3, hash.js@^1.1.7: + version "1.1.7" + resolved "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz" + integrity sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA== + dependencies: + inherits "^2.0.3" + minimalistic-assert "^1.0.1" + +hasown@^2.0.2: version "2.0.2" resolved "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz" integrity sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ== @@ -2399,10 +3844,19 @@ hexoid@^1.0.0: resolved "https://registry.npmjs.org/hexoid/-/hexoid-1.0.0.tgz" integrity sha512-QFLV0taWQOZtvIRIAdBChesmogZrtuXvVWsFHZTk2SU+anspqZ2vMnoLg7IE1+Uk16N19APic1BuF8bC8c2m5g== -highlight.js@^10.7.1: - version "10.7.3" - resolved "https://registry.npmjs.org/highlight.js/-/highlight.js-10.7.3.tgz" - integrity sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A== +hmac-drbg@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz" + integrity sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg== + dependencies: + hash.js "^1.0.3" + minimalistic-assert "^1.0.0" + minimalistic-crypto-utils "^1.0.1" + +http-cache-semantics@^4.1.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-4.2.0.tgz#205f4db64f8562b76a4ff9235aa5279839a09dd5" + integrity sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ== http-errors@2.0.0: version "2.0.0" @@ -2415,6 +3869,40 @@ http-errors@2.0.0: statuses "2.0.1" toidentifier "1.0.1" +http-https@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/http-https/-/http-https-1.0.0.tgz" + integrity sha512-o0PWwVCSp3O0wS6FvNr6xfBCHgt0m1tvPLFOCc2iFDKTRAXhB7m8klDf7ErowFH8POa6dVdGatKU5I1YYwzUyg== + +http-proxy-agent@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz#8a8c8ef7f5932ccf953c296ca8291b95aa74aa3a" + integrity sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg== + dependencies: + "@tootallnate/once" "1" + agent-base "6" + debug "4" + +http-status-codes@2.3.0: + version "2.3.0" + resolved "https://registry.npmjs.org/http-status-codes/-/http-status-codes-2.3.0.tgz" + integrity sha512-RJ8XvFvpPM/Dmc5SV+dC4y5PCeOhT3x1Hq0NU3rjGeg5a/CqlhZ7uudknPwZFz4aeAXDcbAyaeP7GAo9lvngtA== + +https-proxy-agent@^5.0.0: + version "5.0.1" + resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz#c59ef224a04fe8b754f3db0063a25ea30d0005d6" + integrity sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA== + dependencies: + agent-base "6" + debug "4" + +humanize-ms@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/humanize-ms/-/humanize-ms-1.2.1.tgz#c46e3159a293f6b896da29316d8b6fe8bb79bbed" + integrity sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ== + dependencies: + ms "^2.0.0" + iconv-lite@0.4.24: version "0.4.24" resolved "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz" @@ -2422,18 +3910,33 @@ iconv-lite@0.4.24: dependencies: safer-buffer ">= 2.1.2 < 3" -iconv-lite@^0.6.3: +iconv-lite@^0.6.2, iconv-lite@^0.6.3: version "0.6.3" - resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.6.3.tgz#a52f80bf38da1952eb5c681790719871a1a72501" + resolved "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz" integrity sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw== dependencies: safer-buffer ">= 2.1.2 < 3.0.0" -ieee754@^1.1.4, ieee754@^1.2.1: +ieee754@^1.1.13, ieee754@^1.1.4, ieee754@^1.2.1: version "1.2.1" resolved "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz" integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== +imurmurhash@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" + integrity sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA== + +indent-string@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-4.0.0.tgz#624f8f4497d619b2d9768531d58f4122854d7251" + integrity sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg== + +infer-owner@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/infer-owner/-/infer-owner-1.0.4.tgz#c4cefcaa8e51051c2a40ba2ce8a3d27295af9467" + integrity sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A== + inflight@^1.0.4: version "1.0.6" resolved "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz" @@ -2442,16 +3945,33 @@ inflight@^1.0.4: once "^1.3.0" wrappy "1" -inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.1, inherits@~2.0.3, inherits@~2.0.4: +inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.1, inherits@~2.0.3, inherits@~2.0.4: version "2.0.4" resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== +ini@~1.3.0: + version "1.3.8" + resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c" + integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew== + +inversify-express-utils@^6.4.6: + version "6.5.0" + resolved "https://registry.npmjs.org/inversify-express-utils/-/inversify-express-utils-6.5.0.tgz" + integrity sha512-BJQGi/bZx8IrtvFpGI3TzvSrpMqSOMvqtmpl9or6sDSl5xSo66kgRw2LDkxIdnyffY5hNmTnC/6J992Z2zIi+w== + dependencies: + http-status-codes "2.3.0" + inversify@6.0.2: version "6.0.2" resolved "https://registry.npmjs.org/inversify/-/inversify-6.0.2.tgz" integrity sha512-i9m8j/7YIv4mDuYXUAcrpKPSaju/CIly9AHK5jvCBeoiM/2KEsuCQTTP+rzSWWpLYWRukdXFSl6ZTk2/uumbiA== +ip-address@^10.0.1: + version "10.0.1" + resolved "https://registry.yarnpkg.com/ip-address/-/ip-address-10.0.1.tgz#a8180b783ce7788777d796286d61bce4276818ed" + integrity sha512-NWv9YLW4PoW2B7xtzaS3NCot75m6nK7Icdv0o3lfMceJVRfSoQwqD4wEH5rLwoKJwUiZ/rfpiVBhnaF0FK4HoA== + ip-regex@^2.0.0: version "2.1.0" resolved "https://registry.npmjs.org/ip-regex/-/ip-regex-2.1.0.tgz" @@ -2462,6 +3982,14 @@ ipaddr.js@1.9.1: resolved "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz" integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g== +is-arguments@^1.0.4: + version "1.2.0" + resolved "https://registry.npmjs.org/is-arguments/-/is-arguments-1.2.0.tgz" + integrity sha512-7bVbi0huj/wrIAOzb8U1aszg9kdi3KN/CyU19CTI7tAoZYEZoL9yCDXpbXN+uPsuWnP02cyug1gleqq+TU+YCA== + dependencies: + call-bound "^1.0.2" + has-tostringtag "^1.0.2" + is-binary-path@~2.1.0: version "2.1.0" resolved "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz" @@ -2469,6 +3997,11 @@ is-binary-path@~2.1.0: dependencies: binary-extensions "^2.0.0" +is-callable@^1.2.7: + version "1.2.7" + resolved "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz" + integrity sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA== + is-core-module@^2.13.0: version "2.15.0" resolved "https://registry.npmjs.org/is-core-module/-/is-core-module-2.15.0.tgz" @@ -2486,6 +4019,17 @@ is-fullwidth-code-point@^3.0.0: resolved "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz" integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== +is-generator-function@^1.0.7: + version "1.1.2" + resolved "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.1.2.tgz" + integrity sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA== + dependencies: + call-bound "^1.0.4" + generator-function "^2.0.0" + get-proto "^1.0.1" + has-tostringtag "^1.0.2" + safe-regex-test "^1.1.0" + is-glob@^4.0.1, is-glob@~4.0.1: version "4.0.3" resolved "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz" @@ -2493,6 +4037,11 @@ is-glob@^4.0.1, is-glob@~4.0.1: dependencies: is-extglob "^2.1.1" +is-hex-prefixed@1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/is-hex-prefixed/-/is-hex-prefixed-1.0.0.tgz" + integrity sha512-WvtOiug1VFrE9v1Cydwm+FnXd3+w9GaeVUss5W4v/SLy3UW00vP+6iNF2SdnfiBoLy4bTqVdkftNGTUeOFVsbA== + is-ip@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/is-ip/-/is-ip-2.0.0.tgz" @@ -2500,6 +4049,11 @@ is-ip@^2.0.0: dependencies: ip-regex "^2.0.0" +is-lambda@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-lambda/-/is-lambda-1.0.1.tgz#3d9877899e6a53efc0160504cde15f82e6f061d5" + integrity sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ== + is-number@^7.0.0: version "7.0.0" resolved "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz" @@ -2512,9 +4066,31 @@ is-plain-obj@^2.1.0: is-property@^1.0.2: version "1.0.2" - resolved "https://registry.yarnpkg.com/is-property/-/is-property-1.0.2.tgz#57fe1c4e48474edd65b09911f26b1cd4095dda84" + resolved "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz" integrity sha512-Ks/IoX00TtClbGQr4TWXemAnktAQvYB7HzcCxDGqEZU6oCmb2INHuOoKxbtR+HFkmYWBKv/dOZtGRiAjDhj92g== +is-regex@^1.2.1: + version "1.2.1" + resolved "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz" + integrity sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g== + dependencies: + call-bound "^1.0.2" + gopd "^1.2.0" + has-tostringtag "^1.0.2" + hasown "^2.0.2" + +is-typed-array@^1.1.14, is-typed-array@^1.1.3: + version "1.1.15" + resolved "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.15.tgz" + integrity sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ== + dependencies: + which-typed-array "^1.1.16" + +is-typedarray@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz" + integrity sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA== + is-unicode-supported@^0.1.0: version "0.1.0" resolved "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz" @@ -2525,6 +4101,11 @@ isarray@0.0.1: resolved "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz" integrity sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ== +isarray@^2.0.5: + version "2.0.5" + resolved "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz" + integrity sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw== + isarray@~1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz" @@ -2535,6 +4116,11 @@ isexe@^2.0.0: resolved "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz" integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== +isows@1.0.7: + version "1.0.7" + resolved "https://registry.npmjs.org/isows/-/isows-1.0.7.tgz" + integrity sha512-I1fSfDCZL5P0v33sVqeTDSpcstAg/N+wF5HS033mogOVIp4B+oHC7oOCsA3axAbBSGTJ8QubbNmnIRN/h8U7hg== + jackspeak@^3.1.2: version "3.4.3" resolved "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz" @@ -2555,6 +4141,11 @@ joi@^17.4.0: "@sideway/formula" "^3.0.1" "@sideway/pinpoint" "^2.0.0" +js-sha3@0.8.0: + version "0.8.0" + resolved "https://registry.npmjs.org/js-sha3/-/js-sha3-0.8.0.tgz" + integrity sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q== + js-tokens@^4.0.0: version "4.0.0" resolved "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz" @@ -2608,6 +4199,20 @@ jws@^3.2.2: jwa "^1.4.1" safe-buffer "^5.0.1" +keccak@^3.0.0: + version "3.0.4" + resolved "https://registry.npmjs.org/keccak/-/keccak-3.0.4.tgz" + integrity sha512-3vKuW0jV8J3XNTzvfyicFR5qvxrSAGl7KIhvgOu5cmWwM7tZRj3fMbj/pfIf4be7aznbc+prBWGjywox/g2Y6Q== + dependencies: + node-addon-api "^2.0.0" + node-gyp-build "^4.2.0" + readable-stream "^3.6.0" + +libphonenumber-js@^1.11.1: + version "1.12.23" + resolved "https://registry.npmjs.org/libphonenumber-js/-/libphonenumber-js-1.12.23.tgz" + integrity sha512-RN3q3gImZ91BvRDYjWp7ICz3gRn81mW5L4SW+2afzNCC0I/nkXstBgZThQGTE3S/9q5J90FH4dP+TXx8NhdZKg== + locate-path@^6.0.0: version "6.0.0" resolved "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz" @@ -2650,7 +4255,7 @@ lodash.once@^4.0.0: resolved "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz" integrity sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg== -lodash@^4.17.21: +lodash@^4.17.21, lodash@^4.17.5: version "4.17.21" resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== @@ -2665,29 +4270,34 @@ log-symbols@^4.1.0: long@^5.2.1: version "5.2.3" - resolved "https://registry.yarnpkg.com/long/-/long-5.2.3.tgz#a3ba97f3877cf1d778eccbcb048525ebb77499e1" + resolved "https://registry.npmjs.org/long/-/long-5.2.3.tgz" integrity sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q== loupe@^3.1.0: - version "3.1.1" - resolved "https://registry.npmjs.org/loupe/-/loupe-3.1.1.tgz" - integrity sha512-edNu/8D5MKVfGVFRhFf8aAxiTM6Wumfz5XsaatSxlD3w4R1d/WEKUTydCdPGbl9K7QG/Ca3GnDV2sIKIpXRQcw== - dependencies: - get-func-name "^2.0.1" + version "3.2.1" + resolved "https://registry.npmjs.org/loupe/-/loupe-3.2.1.tgz" + integrity sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ== lru-cache@^10.2.0: version "10.4.3" resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz" integrity sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ== +lru-cache@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" + integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA== + dependencies: + yallist "^4.0.0" + lru-cache@^7.14.1: version "7.18.3" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-7.18.3.tgz#f793896e0fd0e954a59dfdd82f0773808df6aa89" + resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz" integrity sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA== lru.min@^1.0.0: version "1.1.1" - resolved "https://registry.yarnpkg.com/lru.min/-/lru.min-1.1.1.tgz#146e01e3a183fa7ba51049175de04667d5701f0e" + resolved "https://registry.npmjs.org/lru.min/-/lru.min-1.1.1.tgz" integrity sha512-FbAj6lXil6t8z4z3j0E5mfRlPzxkySotzUHwRXjlpRh10vc6AI6WN62ehZj82VG7M20rqogJ0GLwar2Xa05a8Q== make-error@^1.1.1: @@ -2695,6 +4305,42 @@ make-error@^1.1.1: resolved "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz" integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== +make-fetch-happen@^9.1.0: + version "9.1.0" + resolved "https://registry.yarnpkg.com/make-fetch-happen/-/make-fetch-happen-9.1.0.tgz#53085a09e7971433e6765f7971bf63f4e05cb968" + integrity sha512-+zopwDy7DNknmwPQplem5lAZX/eCOzSvSNNcSKm5eVwTkOBzoktEfXsa9L23J/GIRhxRsaxzkPEhrJEpE2F4Gg== + dependencies: + agentkeepalive "^4.1.3" + cacache "^15.2.0" + http-cache-semantics "^4.1.0" + http-proxy-agent "^4.0.1" + https-proxy-agent "^5.0.0" + is-lambda "^1.0.1" + lru-cache "^6.0.0" + minipass "^3.1.3" + minipass-collect "^1.0.2" + minipass-fetch "^1.3.2" + minipass-flush "^1.0.5" + minipass-pipeline "^1.2.4" + negotiator "^0.6.2" + promise-retry "^2.0.1" + socks-proxy-agent "^6.0.0" + ssri "^8.0.0" + +math-intrinsics@^1.1.0: + version "1.1.0" + resolved "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz" + integrity sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g== + +md5.js@^1.3.4: + version "1.3.5" + resolved "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz" + integrity sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg== + dependencies: + hash-base "^3.0.0" + inherits "^2.0.1" + safe-buffer "^5.1.2" + media-typer@0.3.0: version "0.3.0" resolved "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz" @@ -2702,7 +4348,7 @@ media-typer@0.3.0: merge-descriptors@1.0.3: version "1.0.3" - resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.3.tgz#d80319a65f3c7935351e5cfdac8f9318504dbed5" + resolved "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz" integrity sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ== methods@^1.1.2, methods@~1.1.2: @@ -2710,6 +4356,11 @@ methods@^1.1.2, methods@~1.1.2: resolved "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz" integrity sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w== +micro-ftch@^0.3.1: + version "0.3.1" + resolved "https://registry.npmjs.org/micro-ftch/-/micro-ftch-0.3.1.tgz" + integrity sha512-/0LLxhzP0tfiR5hcQebtudP56gUurs2CLkGarnCiB/OqEyUFQ6U3paQi/tgLv0hBJYt2rnr9MNpxz4fiiugstg== + mime-db@1.52.0: version "1.52.0" resolved "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz" @@ -2732,6 +4383,21 @@ mime@2.6.0: resolved "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz" integrity sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg== +mimic-response@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-3.1.0.tgz#2d1d59af9c1b129815accc2c46a022a5ce1fa3c9" + integrity sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ== + +minimalistic-assert@^1.0.0, minimalistic-assert@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz" + integrity sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A== + +minimalistic-crypto-utils@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz" + integrity sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg== + minimatch@^3.0.4, minimatch@^3.1.1: version "3.1.2" resolved "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz" @@ -2753,16 +4419,80 @@ minimatch@^9.0.4: dependencies: brace-expansion "^2.0.1" -minimist@^1.2.6: +minimist@^1.2.0, minimist@^1.2.3, minimist@^1.2.6: version "1.2.8" resolved "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz" integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== +minipass-collect@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/minipass-collect/-/minipass-collect-1.0.2.tgz#22b813bf745dc6edba2576b940022ad6edc8c617" + integrity sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA== + dependencies: + minipass "^3.0.0" + +minipass-fetch@^1.3.2: + version "1.4.1" + resolved "https://registry.yarnpkg.com/minipass-fetch/-/minipass-fetch-1.4.1.tgz#d75e0091daac1b0ffd7e9d41629faff7d0c1f1b6" + integrity sha512-CGH1eblLq26Y15+Azk7ey4xh0J/XfJfrCox5LDJiKqI2Q2iwOLOKrlmIaODiSQS8d18jalF6y2K2ePUm0CmShw== + dependencies: + minipass "^3.1.0" + minipass-sized "^1.0.3" + minizlib "^2.0.0" + optionalDependencies: + encoding "^0.1.12" + +minipass-flush@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/minipass-flush/-/minipass-flush-1.0.5.tgz#82e7135d7e89a50ffe64610a787953c4c4cbb373" + integrity sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw== + dependencies: + minipass "^3.0.0" + +minipass-pipeline@^1.2.2, minipass-pipeline@^1.2.4: + version "1.2.4" + resolved "https://registry.yarnpkg.com/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz#68472f79711c084657c067c5c6ad93cddea8214c" + integrity sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A== + dependencies: + minipass "^3.0.0" + +minipass-sized@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/minipass-sized/-/minipass-sized-1.0.3.tgz#70ee5a7c5052070afacfbc22977ea79def353b70" + integrity sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g== + dependencies: + minipass "^3.0.0" + +minipass@^3.0.0, minipass@^3.1.0, minipass@^3.1.1, minipass@^3.1.3: + version "3.3.6" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-3.3.6.tgz#7bba384db3a1520d18c9c0e5251c3444e95dd94a" + integrity sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw== + dependencies: + yallist "^4.0.0" + +minipass@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-5.0.0.tgz#3e9788ffb90b694a5d0ec94479a45b5d8738133d" + integrity sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ== + "minipass@^5.0.0 || ^6.0.2 || ^7.0.0", minipass@^7.1.2: version "7.1.2" resolved "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz" integrity sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw== +minizlib@^2.0.0, minizlib@^2.1.1: + version "2.1.2" + resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-2.1.2.tgz#e90d3466ba209b932451508a11ce3d3632145931" + integrity sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg== + dependencies: + minipass "^3.0.0" + yallist "^4.0.0" + +mkdirp-classic@^0.5.2, mkdirp-classic@^0.5.3: + version "0.5.3" + resolved "https://registry.yarnpkg.com/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz#fa10c9115cc6d8865be221ba47ee9bed78601113" + integrity sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A== + mkdirp@^0.5.3, mkdirp@^0.5.4: version "0.5.6" resolved "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz" @@ -2770,20 +4500,15 @@ mkdirp@^0.5.3, mkdirp@^0.5.4: dependencies: minimist "^1.2.6" -mkdirp@^1.0.4: +mkdirp@^1.0.3, mkdirp@^1.0.4: version "1.0.4" resolved "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz" integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== -mkdirp@^2.1.3: - version "2.1.6" - resolved "https://registry.npmjs.org/mkdirp/-/mkdirp-2.1.6.tgz" - integrity sha512-+hEnITedc8LAtIP9u3HJDFIdcLV2vXP33sqLLIzkv1Db1zO/1OxbvYf0Y1OC/S/Qo5dxHXepofhmxL02PsKe+A== - mocha@^10.4.0: - version "10.7.3" - resolved "https://registry.npmjs.org/mocha/-/mocha-10.7.3.tgz" - integrity sha512-uQWxAu44wwiACGqjbPYmjo7Lg8sFrS3dQe7PP2FQI+woptP4vZXSMcfMyFL/e1yFEeEpV4RtyTpZROOKmxis+A== + version "10.8.2" + resolved "https://registry.npmjs.org/mocha/-/mocha-10.8.2.tgz" + integrity sha512-VZlYo/WE8t1tstuRmqgeyBgCbJc/lEdopaa+axcKzTBJ+UIdlAB9XnmvTCAH4pwR4ElNInaedhEBmZD8iCSVEg== dependencies: ansi-colors "^4.1.3" browser-stdout "^1.3.1" @@ -2816,7 +4541,7 @@ ms@2.1.2: resolved "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz" integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== -ms@2.1.3, ms@^2.1.1, ms@^2.1.3: +ms@2.1.3, ms@^2.0.0, ms@^2.1.1, ms@^2.1.3: version "2.1.3" resolved "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz" integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== @@ -2837,7 +4562,7 @@ multer@^1.4.4: mysql2@^3.11.3: version "3.11.3" - resolved "https://registry.yarnpkg.com/mysql2/-/mysql2-3.11.3.tgz#8291e6069a0784310846f6437b8527050dfc10c4" + resolved "https://registry.npmjs.org/mysql2/-/mysql2-3.11.3.tgz" integrity sha512-Qpu2ADfbKzyLdwC/5d4W7+5Yz7yBzCU05YWt5npWzACST37wJsB23wgOSo00qi043urkiRwXtEvJc9UnuLX/MQ== dependencies: aws-ssl-profiles "^1.1.1" @@ -2850,27 +4575,55 @@ mysql2@^3.11.3: seq-queue "^0.0.5" sqlstring "^2.3.2" -mz@^2.4.0: - version "2.7.0" - resolved "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz" - integrity sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q== - dependencies: - any-promise "^1.0.0" - object-assign "^4.0.1" - thenify-all "^1.0.0" - named-placeholders@^1.1.3: version "1.1.3" - resolved "https://registry.yarnpkg.com/named-placeholders/-/named-placeholders-1.1.3.tgz#df595799a36654da55dda6152ba7a137ad1d9351" + resolved "https://registry.npmjs.org/named-placeholders/-/named-placeholders-1.1.3.tgz" integrity sha512-eLoBxg6wE/rZkJPhU/xRX1WTpkFEwDJEN96oxFrTsqBdbT5ec295Q+CoHrL9IT0DipqKhmGcaZmwOt8OON5x1w== dependencies: lru-cache "^7.14.1" +napi-build-utils@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/napi-build-utils/-/napi-build-utils-2.0.0.tgz#13c22c0187fcfccce1461844136372a47ddc027e" + integrity sha512-GEbrYkbfF7MoNaoh2iGG84Mnf/WZfB0GdGEsM8wz7Expx/LlWf5U8t9nvJKXSp3qr5IsEbK04cBGhol/KwOsWA== + negotiator@0.6.3: version "0.6.3" resolved "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz" integrity sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg== +negotiator@^0.6.2: + version "0.6.4" + resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.4.tgz#777948e2452651c570b712dd01c23e262713fff7" + integrity sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w== + +next-tick@^1.1.0: + version "1.1.0" + resolved "https://registry.npmjs.org/next-tick/-/next-tick-1.1.0.tgz" + integrity sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ== + +node-abi@^3.3.0: + version "3.80.0" + resolved "https://registry.yarnpkg.com/node-abi/-/node-abi-3.80.0.tgz#d7390951f27caa129cceeec01e1c20fc9f07581c" + integrity sha512-LyPuZJcI9HVwzXK1GPxWNzrr+vr8Hp/3UqlmWxxh8p54U1ZbclOqbSog9lWHaCX+dBaiGi6n/hIX+mKu74GmPA== + dependencies: + semver "^7.3.5" + +node-addon-api@^2.0.0: + version "2.0.2" + resolved "https://registry.npmjs.org/node-addon-api/-/node-addon-api-2.0.2.tgz" + integrity sha512-Ntyt4AIXyaLIuMHF6IOoTakB3K+RWxwtsHNRxllEoA6vPwP9o4866g6YWDLUdnucilZhmkxiHwHr11gAENw+QA== + +node-addon-api@^5.0.0: + version "5.1.0" + resolved "https://registry.npmjs.org/node-addon-api/-/node-addon-api-5.1.0.tgz" + integrity sha512-eh0GgfEkpnoWDq+VY8OyvYhFEzBk6jIYbRKdIlyTiAXIVJ8PyBaKb0rp7oDtoddbdoHWhq8wwr+XZ81F1rpNdA== + +node-addon-api@^7.0.0: + version "7.1.1" + resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-7.1.1.tgz#1aba6693b0f255258a049d621329329322aad558" + integrity sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ== + node-cron@^3.0.0: version "3.0.3" resolved "https://registry.npmjs.org/node-cron/-/node-cron-3.0.3.tgz" @@ -2878,17 +4631,70 @@ node-cron@^3.0.0: dependencies: uuid "8.3.2" +node-fetch@^2.7.0: + version "2.7.0" + resolved "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz" + integrity sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A== + dependencies: + whatwg-url "^5.0.0" + +node-gyp-build@^4.2.0, node-gyp-build@^4.3.0: + version "4.8.4" + resolved "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.4.tgz" + integrity sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ== + +node-gyp@8.x: + version "8.4.1" + resolved "https://registry.yarnpkg.com/node-gyp/-/node-gyp-8.4.1.tgz#3d49308fc31f768180957d6b5746845fbd429937" + integrity sha512-olTJRgUtAb/hOXG0E93wZDs5YiJlgbXxTwQAFHyNlRsXQnYzUaF2aGgujZbw+hR8aF4ZG/rST57bWMWD16jr9w== + dependencies: + env-paths "^2.2.0" + glob "^7.1.4" + graceful-fs "^4.2.6" + make-fetch-happen "^9.1.0" + nopt "^5.0.0" + npmlog "^6.0.0" + rimraf "^3.0.2" + semver "^7.3.5" + tar "^6.1.2" + which "^2.0.2" + nodemailer@^6.6.3: version "6.9.15" resolved "https://registry.npmjs.org/nodemailer/-/nodemailer-6.9.15.tgz" integrity sha512-AHf04ySLC6CIfuRtRiEYtGEXgRfa6INgWGluDhnxTZhHSKvrBu7lc1VVchQ0d8nPc4cFaZoPq8vkyNoZr0TpGQ== +nopt@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/nopt/-/nopt-5.0.0.tgz#530942bb58a512fccafe53fe210f13a25355dc88" + integrity sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ== + dependencies: + abbrev "1" + normalize-path@^3.0.0, normalize-path@~3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz" integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== -object-assign@^4, object-assign@^4.0.1, object-assign@^4.1.1: +npmlog@^6.0.0: + version "6.0.2" + resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-6.0.2.tgz#c8166017a42f2dea92d6453168dd865186a70830" + integrity sha512-/vBvz5Jfr9dT/aFWd0FIRf+T/Q2WBsLENygUaFUqstqsycmZAP/t5BvFJTK0viFmSUxiUKTUplWy5vt+rvKIxg== + dependencies: + are-we-there-yet "^3.0.0" + console-control-strings "^1.1.0" + gauge "^4.0.3" + set-blocking "^2.0.0" + +number-to-bn@1.7.0: + version "1.7.0" + resolved "https://registry.npmjs.org/number-to-bn/-/number-to-bn-1.7.0.tgz" + integrity sha512-wsJ9gfSz1/s4ZsJN01lyonwuxA1tml6X1yBDnfpMglypcBRFZZkus26EdPSlqS5GJfYddVZa22p3VNb3z5m5Ig== + dependencies: + bn.js "4.11.6" + strip-hex-prefix "1.0.0" + +object-assign@^4, object-assign@^4.1.1: version "4.1.1" resolved "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz" integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg== @@ -2898,6 +4704,13 @@ object-inspect@^1.13.1: resolved "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.2.tgz" integrity sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g== +oboe@2.1.5: + version "2.1.5" + resolved "https://registry.npmjs.org/oboe/-/oboe-2.1.5.tgz" + integrity sha512-zRFWiF+FoicxEs3jNI/WYUrVEgA7DeET/InK0XQuudGHRg8iIob3cNPrJTKaz4004uaA9Pbe+Dwa8iluhjLZWA== + dependencies: + http-https "^1.0.0" + on-finished@2.4.1, on-finished@^2.3.0: version "2.4.1" resolved "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz" @@ -2905,13 +4718,27 @@ on-finished@2.4.1, on-finished@^2.3.0: dependencies: ee-first "1.1.1" -once@^1.3.0, once@^1.4.0: +once@^1.3.0, once@^1.3.1, once@^1.4.0: version "1.4.0" resolved "https://registry.npmjs.org/once/-/once-1.4.0.tgz" integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== dependencies: wrappy "1" +ox@0.9.6: + version "0.9.6" + resolved "https://registry.npmjs.org/ox/-/ox-0.9.6.tgz" + integrity sha512-8SuCbHPvv2eZLYXrNmC0EC12rdzXQLdhnOMlHDW2wiCPLxBrOOJwX5L5E61by+UjTPOryqQiRSnjIKCI+GykKg== + dependencies: + "@adraffy/ens-normalize" "^1.11.0" + "@noble/ciphers" "^1.3.0" + "@noble/curves" "1.9.1" + "@noble/hashes" "^1.8.0" + "@scure/bip32" "^1.7.0" + "@scure/bip39" "^1.6.0" + abitype "^1.0.9" + eventemitter3 "5.0.1" + p-limit@^3.0.2: version "3.1.0" resolved "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz" @@ -2926,28 +4753,18 @@ p-locate@^5.0.0: dependencies: p-limit "^3.0.2" +p-map@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/p-map/-/p-map-4.0.0.tgz#bb2f95a5eda2ec168ec9274e06a747c3e2904d2b" + integrity sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ== + dependencies: + aggregate-error "^3.0.0" + package-json-from-dist@^1.0.0: version "1.0.1" resolved "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz" integrity sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw== -parse5-htmlparser2-tree-adapter@^6.0.0: - version "6.0.1" - resolved "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-6.0.1.tgz" - integrity sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA== - dependencies: - parse5 "^6.0.1" - -parse5@^5.1.1: - version "5.1.1" - resolved "https://registry.npmjs.org/parse5/-/parse5-5.1.1.tgz" - integrity sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug== - -parse5@^6.0.1: - version "6.0.1" - resolved "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz" - integrity sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw== - parseurl@~1.3.3: version "1.3.3" resolved "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz" @@ -2997,19 +4814,31 @@ path-scurry@^1.11.1: path-to-regexp@0.1.10: version "0.1.10" - resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.10.tgz#67e9108c5c0551b9e5326064387de4763c4d5f8b" + resolved "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.10.tgz" integrity sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w== pathval@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/pathval/-/pathval-2.0.0.tgz" - integrity sha512-vE7JKRyES09KiunauX7nd2Q9/L7lhok4smP9RZTDeD4MVs72Dp2qNFVz39Nz5a0FVEW0BJR6C0DYrq6unoziZA== + version "2.0.1" + resolved "https://registry.npmjs.org/pathval/-/pathval-2.0.1.tgz" + integrity sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ== pause@0.0.1: version "0.0.1" resolved "https://registry.npmjs.org/pause/-/pause-0.0.1.tgz" integrity sha512-KG8UEiEVkR3wGEb4m5yZkVCzigAD+cVEJck2CzYZO37ZGJfctvVptVO192MwrtPhzONn6go8ylnOdMhKqi4nfg== +pbkdf2@^3.0.17: + version "3.1.5" + resolved "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.5.tgz" + integrity sha512-Q3CG/cYvCO1ye4QKkuH7EXxs3VC/rI1/trd+qX2+PolbaKG0H+bgcZzrTt96mMyRtejk+JMCiLUn3y29W8qmFQ== + dependencies: + create-hash "^1.2.0" + create-hmac "^1.1.7" + ripemd160 "^2.0.3" + safe-buffer "^5.2.1" + sha.js "^2.4.12" + to-buffer "^1.2.1" + picocolors@^1.0.0: version "1.0.1" resolved "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz" @@ -3020,18 +4849,54 @@ picomatch@^2.0.4, picomatch@^2.2.1: resolved "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz" integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== +possible-typed-array-names@^1.0.0: + version "1.1.0" + resolved "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz" + integrity sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg== + postmark@^4.0.5: version "4.0.5" - resolved "https://registry.yarnpkg.com/postmark/-/postmark-4.0.5.tgz#515ae85562fcedbec6ae7eb0ef180dded1dbc05d" + resolved "https://registry.npmjs.org/postmark/-/postmark-4.0.5.tgz" integrity sha512-nerZdd3TwOH4CgGboZnlUM/q7oZk0EqpZgJL+Y3Nup8kHeaukxouQ6JcFF3EJEijc4QbuNv1TefGhboAKtf/SQ== dependencies: axios "^1.7.4" +prebuild-install@^7.1.1: + version "7.1.3" + resolved "https://registry.yarnpkg.com/prebuild-install/-/prebuild-install-7.1.3.tgz#d630abad2b147443f20a212917beae68b8092eec" + integrity sha512-8Mf2cbV7x1cXPUILADGI3wuhfqWvtiLA1iclTDbFRZkgRQS0NqsPZphna9V+HyTEadheuPmjaJMsbzKQFOzLug== + dependencies: + detect-libc "^2.0.0" + expand-template "^2.0.3" + github-from-package "0.0.0" + minimist "^1.2.3" + mkdirp-classic "^0.5.3" + napi-build-utils "^2.0.0" + node-abi "^3.3.0" + pump "^3.0.0" + rc "^1.2.7" + simple-get "^4.0.0" + tar-fs "^2.0.0" + tunnel-agent "^0.6.0" + process-nextick-args@~2.0.0: version "2.0.1" resolved "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz" integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== +promise-inflight@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/promise-inflight/-/promise-inflight-1.0.1.tgz#98472870bf228132fcbdd868129bad12c3c029e3" + integrity sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g== + +promise-retry@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/promise-retry/-/promise-retry-2.0.1.tgz#ff747a13620ab57ba688f5fc67855410c370da22" + integrity sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g== + dependencies: + err-code "^2.0.2" + retry "^0.12.0" + proxy-addr@~2.0.7: version "2.0.7" resolved "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz" @@ -3042,14 +4907,34 @@ proxy-addr@~2.0.7: proxy-from-env@^1.1.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2" + resolved "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz" integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg== +pump@^3.0.0: + version "3.0.3" + resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.3.tgz#151d979f1a29668dc0025ec589a455b53282268d" + integrity sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA== + dependencies: + end-of-stream "^1.1.0" + once "^1.3.1" + punycode@^2.1.0: version "2.3.1" resolved "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz" integrity sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg== +pvtsutils@^1.3.6: + version "1.3.6" + resolved "https://registry.npmjs.org/pvtsutils/-/pvtsutils-1.3.6.tgz" + integrity sha512-PLgQXQ6H2FWCaeRak8vvk1GW462lMxB5s3Jm673N82zI4vqtVUPuZdffdZbPDFRoU8kAhItWFtPCWiPpp4/EDg== + dependencies: + tslib "^2.8.1" + +pvutils@^1.1.3: + version "1.1.3" + resolved "https://registry.npmjs.org/pvutils/-/pvutils-1.1.3.tgz" + integrity sha512-pMpnA0qRdFp32b1sJl1wOJNxZLQ2cbQx+k6tjNtZ8CpvVhNqEPRgivZ2WOUev2YMajecdH7ctUPDvEe87nariQ== + qs@6.11.0: version "6.11.0" resolved "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz" @@ -3086,6 +4971,16 @@ raw-body@2.5.2: iconv-lite "0.4.24" unpipe "1.0.0" +rc@^1.2.7: + version "1.2.8" + resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed" + integrity sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw== + dependencies: + deep-extend "^0.6.0" + ini "~1.3.0" + minimist "^1.2.0" + strip-json-comments "~2.0.1" + readable-stream@1.1.x: version "1.1.14" resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz" @@ -3096,7 +4991,7 @@ readable-stream@1.1.x: isarray "0.0.1" string_decoder "~0.10.x" -readable-stream@^2.2.2: +readable-stream@^2.2.2, readable-stream@^2.3.8: version "2.3.8" resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz" integrity sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA== @@ -3109,7 +5004,7 @@ readable-stream@^2.2.2: string_decoder "~1.1.1" util-deprecate "~1.0.1" -readable-stream@^3.5.0: +readable-stream@^3.1.1, readable-stream@^3.4.0, readable-stream@^3.5.0, readable-stream@^3.6.0: version "3.6.2" resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz" integrity sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA== @@ -3125,7 +5020,7 @@ readdirp@~3.6.0: dependencies: picomatch "^2.2.1" -reflect-metadata@^0.2.1, reflect-metadata@^0.2.2: +reflect-metadata@^0.2.2: version "0.2.2" resolved "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.2.2.tgz" integrity sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q== @@ -3144,6 +5039,11 @@ resolve@^1.0.0, resolve@^1.3.2: path-parse "^1.0.7" supports-preserve-symlinks-flag "^1.0.0" +retry@^0.12.0: + version "0.12.0" + resolved "https://registry.yarnpkg.com/retry/-/retry-0.12.0.tgz#1b42a6266a21f07421d1b0b54b7dc167b01c013b" + integrity sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow== + rimraf@^2.6.1: version "2.7.1" resolved "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz" @@ -3151,7 +5051,29 @@ rimraf@^2.6.1: dependencies: glob "^7.1.3" -safe-buffer@5.2.1, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@~5.2.0: +rimraf@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" + integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== + dependencies: + glob "^7.1.3" + +ripemd160@^2.0.0, ripemd160@^2.0.1, ripemd160@^2.0.3: + version "2.0.3" + resolved "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.3.tgz" + integrity sha512-5Di9UC0+8h1L6ZD2d7awM7E/T4uA1fJRlx6zk/NvdCCVEoAnFqvHmCuNeIKoCeIixBX/q8uM+6ycDvF8woqosA== + dependencies: + hash-base "^3.1.2" + inherits "^2.0.4" + +rlp@^2.2.4: + version "2.2.7" + resolved "https://registry.npmjs.org/rlp/-/rlp-2.2.7.tgz" + integrity sha512-d5gdPmgQ0Z+AklL2NVXr/IoSjNZFfTVvQWzL/AM2AOcSzYP2xjlb0AC8YyCLc41MSNf6P6QVtjgPdmVtzb+4lQ== + dependencies: + bn.js "^5.2.0" + +safe-buffer@5.2.1, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@^5.2.1, safe-buffer@~5.2.0: version "5.2.1" resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz" integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== @@ -3161,20 +5083,48 @@ safe-buffer@~5.1.0, safe-buffer@~5.1.1: resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz" integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== +safe-regex-test@^1.1.0: + version "1.1.0" + resolved "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.1.0.tgz" + integrity sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw== + dependencies: + call-bound "^1.0.2" + es-errors "^1.3.0" + is-regex "^1.2.1" + "safer-buffer@>= 2.1.2 < 3", "safer-buffer@>= 2.1.2 < 3.0.0": version "2.1.2" resolved "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz" integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== +scrypt-js@3.0.1, scrypt-js@^3.0.0: + version "3.0.1" + resolved "https://registry.npmjs.org/scrypt-js/-/scrypt-js-3.0.1.tgz" + integrity sha512-cdwTTnqPu0Hyvf5in5asVdZocVDTNRmR7XEcJuIzMjJeSHybHl7vpB66AzwTaIg6CLSbtjcxc8fqcySfnTkccA== + +secp256k1@^4.0.1: + version "4.0.4" + resolved "https://registry.npmjs.org/secp256k1/-/secp256k1-4.0.4.tgz" + integrity sha512-6JfvwvjUOn8F/jUoBY2Q1v5WY5XS+rj8qSe0v8Y4ezH4InLgTEeOOPQsRll9OV429Pvo6BCHGavIyJfr3TAhsw== + dependencies: + elliptic "^6.5.7" + node-addon-api "^5.0.0" + node-gyp-build "^4.2.0" + semver@^5.3.0: version "5.7.2" resolved "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz" integrity sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g== -semver@^7.3.8, semver@^7.5.4: - version "7.6.3" - resolved "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz" - integrity sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A== +semver@^7.3.5: + version "7.7.3" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.7.3.tgz#4b5f4143d007633a8dc671cd0a6ef9147b8bb946" + integrity sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q== + +semver@^7.3.8, semver@^7.5.4, semver@^7.6.2, semver@^7.7.2: + version "7.7.2" + resolved "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz" + integrity sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA== send@0.18.0: version "0.18.0" @@ -3197,7 +5147,7 @@ send@0.18.0: send@0.19.0: version "0.19.0" - resolved "https://registry.yarnpkg.com/send/-/send-0.19.0.tgz#bbc5a388c8ea6c048967049dbeac0e4a3f09d7f8" + resolved "https://registry.npmjs.org/send/-/send-0.19.0.tgz" integrity sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw== dependencies: debug "2.6.9" @@ -3216,7 +5166,7 @@ send@0.19.0: seq-queue@^0.0.5: version "0.0.5" - resolved "https://registry.yarnpkg.com/seq-queue/-/seq-queue-0.0.5.tgz#d56812e1c017a6e4e7c3e3a37a1da6d78dd3c93e" + resolved "https://registry.npmjs.org/seq-queue/-/seq-queue-0.0.5.tgz" integrity sha512-hr3Wtp/GZIc/6DAGPDcV4/9WoZhjrkXsi5B/07QgX8tsdc6ilr7BFM6PM6rbdAX1kFSDYeZGLipIZZKyQP0O5Q== serialize-javascript@^6.0.2: @@ -3228,7 +5178,7 @@ serialize-javascript@^6.0.2: serve-static@1.16.0: version "1.16.0" - resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.16.0.tgz#2bf4ed49f8af311b519c46f272bf6ac3baf38a92" + resolved "https://registry.npmjs.org/serve-static/-/serve-static-1.16.0.tgz" integrity sha512-pDLK8zwl2eKaYrs8mrPZBJua4hMplRWJ1tIFksVC3FtBEBnl8dxgeHtsaMS8DhS9i4fLObaon6ABoc4/hQGdPA== dependencies: encodeurl "~1.0.2" @@ -3236,7 +5186,12 @@ serve-static@1.16.0: parseurl "~1.3.3" send "0.18.0" -set-function-length@^1.2.1: +set-blocking@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" + integrity sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw== + +set-function-length@^1.2.2: version "1.2.2" resolved "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz" integrity sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg== @@ -3248,18 +5203,24 @@ set-function-length@^1.2.1: gopd "^1.0.1" has-property-descriptors "^1.0.2" +setimmediate@^1.0.5: + version "1.0.5" + resolved "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz" + integrity sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA== + setprototypeof@1.2.0: version "1.2.0" resolved "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz" integrity sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw== -sha.js@^2.4.11: - version "2.4.11" - resolved "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz" - integrity sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ== +sha.js@^2.4.0, sha.js@^2.4.12, sha.js@^2.4.8: + version "2.4.12" + resolved "https://registry.npmjs.org/sha.js/-/sha.js-2.4.12.tgz" + integrity sha512-8LzC5+bvI45BjpfXU8V5fdU2mfeKiQe1D1gIMn7XUlF3OTUrpdJpPPH4EMAnF0DsHHdSZqCdSss5qCmJKuiO3w== dependencies: - inherits "^2.0.1" - safe-buffer "^5.0.1" + inherits "^2.0.4" + safe-buffer "^5.2.1" + to-buffer "^1.2.0" shebang-command@^2.0.0: version "2.0.0" @@ -3283,11 +5244,30 @@ side-channel@^1.0.4, side-channel@^1.0.6: get-intrinsic "^1.2.4" object-inspect "^1.13.1" +signal-exit@^3.0.7: + version "3.0.7" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" + integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== + signal-exit@^4.0.1: version "4.1.0" resolved "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz" integrity sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw== +simple-concat@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/simple-concat/-/simple-concat-1.0.1.tgz#f46976082ba35c2263f1c8ab5edfe26c41c9552f" + integrity sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q== + +simple-get@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/simple-get/-/simple-get-4.0.1.tgz#4a39db549287c979d352112fa03fd99fd6bc3543" + integrity sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA== + dependencies: + decompress-response "^6.0.0" + once "^1.3.1" + simple-concat "^1.0.0" + siwe@^2.3.2: version "2.3.2" resolved "https://registry.npmjs.org/siwe/-/siwe-2.3.2.tgz" @@ -3298,6 +5278,28 @@ siwe@^2.3.2: uri-js "^4.4.1" valid-url "^1.0.9" +smart-buffer@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/smart-buffer/-/smart-buffer-4.2.0.tgz#6e1d71fa4f18c05f7d0ff216dd16a481d0e8d9ae" + integrity sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg== + +socks-proxy-agent@^6.0.0: + version "6.2.1" + resolved "https://registry.yarnpkg.com/socks-proxy-agent/-/socks-proxy-agent-6.2.1.tgz#2687a31f9d7185e38d530bef1944fe1f1496d6ce" + integrity sha512-a6KW9G+6B3nWZ1yB8G7pJwL3ggLy1uTzKAgCb7ttblwqdz9fMGJUuTy3uFzEP48FAs9FLILlmzDlE2JJhVQaXQ== + dependencies: + agent-base "^6.0.2" + debug "^4.3.3" + socks "^2.6.2" + +socks@^2.6.2: + version "2.8.7" + resolved "https://registry.yarnpkg.com/socks/-/socks-2.8.7.tgz#e2fb1d9a603add75050a2067db8c381a0b5669ea" + integrity sha512-HLpt+uLy/pxB+bum/9DzAgiKS8CX1EvbWxI4zlmgGCExImLdiad2iCwXT5Z4c9c3Eq8rP2318mPW2c+QbtjK8A== + dependencies: + ip-address "^10.0.1" + smart-buffer "^4.2.0" + source-map-support@^0.5.12: version "0.5.21" resolved "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz" @@ -3316,11 +5318,35 @@ sprintf-js@~1.0.2: resolved "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz" integrity sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g== +sql-highlight@^6.0.0: + version "6.1.0" + resolved "https://registry.npmjs.org/sql-highlight/-/sql-highlight-6.1.0.tgz" + integrity sha512-ed7OK4e9ywpE7pgRMkMQmZDPKSVdm0oX5IEtZiKnFucSF0zu6c80GZBe38UqHuVhTWJ9xsKgSMjCG2bml86KvA== + +sqlite3@^5.1.7: + version "5.1.7" + resolved "https://registry.yarnpkg.com/sqlite3/-/sqlite3-5.1.7.tgz#59ca1053c1ab38647396586edad019b1551041b7" + integrity sha512-GGIyOiFaG+TUra3JIfkI/zGP8yZYLPQ0pl1bH+ODjiX57sPhrLU5sQJn1y9bDKZUFYkX1crlrPfSYt0BKKdkog== + dependencies: + bindings "^1.5.0" + node-addon-api "^7.0.0" + prebuild-install "^7.1.1" + tar "^6.1.11" + optionalDependencies: + node-gyp "8.x" + sqlstring@^2.3.2: version "2.3.3" - resolved "https://registry.yarnpkg.com/sqlstring/-/sqlstring-2.3.3.tgz#2ddc21f03bce2c387ed60680e739922c65751d0c" + resolved "https://registry.npmjs.org/sqlstring/-/sqlstring-2.3.3.tgz" integrity sha512-qC9iz2FlN7DQl3+wjwn3802RTyjCx7sDvfQEXchwa6CWOx07/WVfh91gBmQ9fahw8snwGEWU3xGzOt4tFyHLxg== +ssri@^8.0.0, ssri@^8.0.1: + version "8.0.1" + resolved "https://registry.yarnpkg.com/ssri/-/ssri-8.0.1.tgz#638e4e439e2ffbd2cd289776d5ca457c4f51a2af" + integrity sha512-97qShzy1AiyxvPNIkLWoGua7xoQzzPjQ0HAH4B0rWKo7SZ6USuPcrUiAFrws0UH8RrbWmgq3LMTObhPIHbbBeQ== + dependencies: + minipass "^3.1.1" + statuses@2.0.1: version "2.0.1" resolved "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz" @@ -3348,7 +5374,7 @@ streamsearch@0.1.2: is-fullwidth-code-point "^3.0.0" strip-ansi "^6.0.1" -string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: +"string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: version "4.2.3" resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz" integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== @@ -3411,7 +5437,14 @@ strip-bom@^3.0.0: resolved "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz" integrity sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA== -strip-json-comments@^2.0.0: +strip-hex-prefix@1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/strip-hex-prefix/-/strip-hex-prefix-1.0.0.tgz" + integrity sha512-q8d4ue7JGEiVcypji1bALTos+0pWtyGlivAWyPuTkHzuTCJqrK9sWxYQZUq6Nq3cuyv3bm734IhHvHtGGURU6A== + dependencies: + is-hex-prefixed "1.0.0" + +strip-json-comments@^2.0.0, strip-json-comments@~2.0.1: version "2.0.1" resolved "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz" integrity sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ== @@ -3468,19 +5501,47 @@ supports-preserve-symlinks-flag@^1.0.0: resolved "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz" integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== -thenify-all@^1.0.0: - version "1.6.0" - resolved "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz" - integrity sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA== +tar-fs@^2.0.0: + version "2.1.4" + resolved "https://registry.yarnpkg.com/tar-fs/-/tar-fs-2.1.4.tgz#800824dbf4ef06ded9afea4acafe71c67c76b930" + integrity sha512-mDAjwmZdh7LTT6pNleZ05Yt65HC3E+NiQzl672vQG38jIrehtJk/J3mNwIg+vShQPcLF/LV7CMnDW6vjj6sfYQ== dependencies: - thenify ">= 3.1.0 < 4" + chownr "^1.1.1" + mkdirp-classic "^0.5.2" + pump "^3.0.0" + tar-stream "^2.1.4" -"thenify@>= 3.1.0 < 4": - version "3.3.1" - resolved "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz" - integrity sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw== +tar-stream@^2.1.4: + version "2.2.0" + resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-2.2.0.tgz#acad84c284136b060dc3faa64474aa9aebd77287" + integrity sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ== + dependencies: + bl "^4.0.3" + end-of-stream "^1.4.1" + fs-constants "^1.0.0" + inherits "^2.0.3" + readable-stream "^3.1.1" + +tar@^6.0.2, tar@^6.1.11, tar@^6.1.2: + version "6.2.1" + resolved "https://registry.yarnpkg.com/tar/-/tar-6.2.1.tgz#717549c541bc3c2af15751bea94b1dd068d4b03a" + integrity sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A== dependencies: - any-promise "^1.0.0" + chownr "^2.0.0" + fs-minipass "^2.0.0" + minipass "^5.0.0" + minizlib "^2.1.1" + mkdirp "^1.0.3" + yallist "^4.0.0" + +to-buffer@^1.2.0, to-buffer@^1.2.1, to-buffer@^1.2.2: + version "1.2.2" + resolved "https://registry.npmjs.org/to-buffer/-/to-buffer-1.2.2.tgz" + integrity sha512-db0E3UJjcFhpDhAF4tLo03oli3pwl3dbnzXOUIlRKrp+ldk/VUxzpWYZENsw2SZiuBjHAk7DfB0VU7NKdpb6sw== + dependencies: + isarray "^2.0.5" + safe-buffer "^5.2.1" + typed-array-buffer "^1.0.3" to-regex-range@^5.0.1: version "5.0.1" @@ -3494,11 +5555,23 @@ toidentifier@1.0.1: resolved "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz" integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA== +tr46@~0.0.3: + version "0.0.3" + resolved "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz" + integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw== + tree-kill@^1.2.2: version "1.2.2" resolved "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz" integrity sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A== +ts-mockito@^2.6.1: + version "2.6.1" + resolved "https://registry.npmjs.org/ts-mockito/-/ts-mockito-2.6.1.tgz" + integrity sha512-qU9m/oEBQrKq5hwfbJ7MgmVN5Gu6lFnIGWvpxSjrqq6YYEVv+RwVFWySbZMBgazsWqv6ctAyVBpo9TmAxnOEKw== + dependencies: + lodash "^4.17.5" + ts-node-dev@2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/ts-node-dev/-/ts-node-dev-2.0.0.tgz" @@ -3554,10 +5627,10 @@ tslib@^1.13.0, tslib@^1.8.1: resolved "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz" integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== -tslib@^2.5.0: - version "2.8.0" - resolved "https://registry.npmjs.org/tslib/-/tslib-2.8.0.tgz" - integrity sha512-jWVzBLplnCmoaTr13V9dYbiQ99wvZRd0vNWaDRg+aVYRcjDF3nDksxFDE/+fkXnKhpnUUkmx5pK/v8mCtLVqZA== +tslib@^2.8.1: + version "2.8.1" + resolved "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz" + integrity sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w== tslint-config-prettier@^1.18.0: version "1.18.0" @@ -3590,6 +5663,13 @@ tsutils@^2.29.0: dependencies: tslib "^1.8.1" +tunnel-agent@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" + integrity sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w== + dependencies: + safe-buffer "^5.0.1" + type-is@^1.6.4, type-is@~1.6.18: version "1.6.18" resolved "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz" @@ -3598,42 +5678,76 @@ type-is@^1.6.4, type-is@~1.6.18: media-typer "0.3.0" mime-types "~2.1.24" +type@^2.7.2: + version "2.7.3" + resolved "https://registry.npmjs.org/type/-/type-2.7.3.tgz" + integrity sha512-8j+1QmAbPvLZow5Qpi6NCaN8FB60p/6x8/vfNqOk/hC+HuvFZhL4+WfekuhQLiqFZXOgQdrs3B+XxEmCc6b3FQ== + +typed-array-buffer@^1.0.3: + version "1.0.3" + resolved "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz" + integrity sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw== + dependencies: + call-bound "^1.0.3" + es-errors "^1.3.0" + is-typed-array "^1.1.14" + +typedarray-to-buffer@^3.1.5: + version "3.1.5" + resolved "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz" + integrity sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q== + dependencies: + is-typedarray "^1.0.0" + typedarray@^0.0.6: version "0.0.6" resolved "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz" integrity sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA== typeorm@^0.3.20: - version "0.3.20" - resolved "https://registry.npmjs.org/typeorm/-/typeorm-0.3.20.tgz" - integrity sha512-sJ0T08dV5eoZroaq9uPKBoNcGslHBR4E4y+EBHs//SiGbblGe7IeduP/IH4ddCcj0qp3PHwDwGnuvqEAnKlq/Q== + version "0.3.27" + resolved "https://registry.npmjs.org/typeorm/-/typeorm-0.3.27.tgz" + integrity sha512-pNV1bn+1n8qEe8tUNsNdD8ejuPcMAg47u2lUGnbsajiNUr3p2Js1XLKQjBMH0yMRMDfdX8T+fIRejFmIwy9x4A== dependencies: "@sqltools/formatter" "^1.2.5" + ansis "^3.17.0" app-root-path "^3.1.0" buffer "^6.0.3" - chalk "^4.1.2" - cli-highlight "^2.1.11" - dayjs "^1.11.9" - debug "^4.3.4" - dotenv "^16.0.3" - glob "^10.3.10" - mkdirp "^2.1.3" - reflect-metadata "^0.2.1" - sha.js "^2.4.11" - tslib "^2.5.0" - uuid "^9.0.0" - yargs "^17.6.2" + dayjs "^1.11.13" + debug "^4.4.0" + dedent "^1.6.0" + dotenv "^16.4.7" + glob "^10.4.5" + sha.js "^2.4.12" + sql-highlight "^6.0.0" + tslib "^2.8.1" + uuid "^11.1.0" + yargs "^17.7.2" typescript@^5.4.3: - version "5.5.4" - resolved "https://registry.npmjs.org/typescript/-/typescript-5.5.4.tgz" - integrity sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q== + version "5.9.2" + resolved "https://registry.npmjs.org/typescript/-/typescript-5.9.2.tgz" + integrity sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A== undici-types@~6.19.2: version "6.19.8" resolved "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz" integrity sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw== +unique-filename@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/unique-filename/-/unique-filename-1.1.1.tgz#1d69769369ada0583103a1e6ae87681b56573230" + integrity sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ== + dependencies: + unique-slug "^2.0.0" + +unique-slug@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/unique-slug/-/unique-slug-2.0.2.tgz#baabce91083fc64e945b0f3ad613e264f7cd4e6c" + integrity sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w== + dependencies: + imurmurhash "^0.1.4" + unpipe@1.0.0, unpipe@~1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz" @@ -3646,11 +5760,34 @@ uri-js@^4.4.1: dependencies: punycode "^2.1.0" +utf-8-validate@^5.0.2: + version "5.0.10" + resolved "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-5.0.10.tgz" + integrity sha512-Z6czzLq4u8fPOyx7TU6X3dvUZVvoJmxSQ+IcrlmagKhilxlhZgxPK6C5Jqbkw1IDUmFTM+cz9QDnnLTwDz/2gQ== + dependencies: + node-gyp-build "^4.3.0" + +utf8@3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/utf8/-/utf8-3.0.0.tgz" + integrity sha512-E8VjFIQ/TyQgp+TZfS6l8yp/xWppSAHzidGiRrqe4bK4XP9pTRyKFgGJpO3SN7zdX4DeomTrwaseCHovfpFcqQ== + util-deprecate@^1.0.1, util-deprecate@~1.0.1: version "1.0.2" resolved "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz" integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== +util@^0.12.5: + version "0.12.5" + resolved "https://registry.npmjs.org/util/-/util-0.12.5.tgz" + integrity sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA== + dependencies: + inherits "^2.0.3" + is-arguments "^1.0.4" + is-generator-function "^1.0.7" + is-typed-array "^1.1.3" + which-typed-array "^1.1.2" + utils-merge@1.0.1, utils-merge@^1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz" @@ -3661,7 +5798,12 @@ uuid@8.3.2, uuid@^8.3.2: resolved "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz" integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== -uuid@^9.0.0, uuid@^9.0.1: +uuid@^11.1.0: + version "11.1.0" + resolved "https://registry.npmjs.org/uuid/-/uuid-11.1.0.tgz" + integrity sha512-0/A9rDy9P7cJ+8w1c9WD9V//9Wj15Ce2MPz8Ri6032usz+NfePxx5AcN3bN+r6ZL6jEo066/yNYB3tn4pQEx+A== + +uuid@^9.0.1: version "9.0.1" resolved "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz" integrity sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA== @@ -3676,7 +5818,7 @@ valid-url@^1.0.9: resolved "https://registry.npmjs.org/valid-url/-/valid-url-1.0.9.tgz" integrity sha512-QQDsV8OnSf5Uc30CKSwG9lnhMPe6exHtTXLRYX8uMwKENy640pU+2BgBL0LRbDh/eYRahNCS7aewCx0wf3NYVA== -validator@~13.12.0: +validator@^13.9.0, validator@~13.12.0: version "13.12.0" resolved "https://registry.npmjs.org/validator/-/validator-13.12.0.tgz" integrity sha512-c1Q0mCiPlgdTVVVIJIrBuxNicYE+t/7oKeI9MWLj3fh/uq2Pxh/3eeWbVZ4OcGW1TUf53At0njHw5SMdA3tmMg== @@ -3686,13 +5828,179 @@ vary@^1, vary@~1.1.2: resolved "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz" integrity sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg== -which@^2.0.1: +viem@^2.21.8: + version "2.37.8" + resolved "https://registry.npmjs.org/viem/-/viem-2.37.8.tgz" + integrity sha512-mL+5yvCQbRIR6QvngDQMfEiZTfNWfd+/QL5yFaOoYbpH3b1Q2ddwF7YG2eI2AcYSh9LE1gtUkbzZLFUAVyj4oQ== + dependencies: + "@noble/curves" "1.9.1" + "@noble/hashes" "1.8.0" + "@scure/bip32" "1.7.0" + "@scure/bip39" "1.6.0" + abitype "1.1.0" + isows "1.0.7" + ox "0.9.6" + ws "8.18.3" + +web3-core-helpers@1.10.4: + version "1.10.4" + resolved "https://registry.npmjs.org/web3-core-helpers/-/web3-core-helpers-1.10.4.tgz" + integrity sha512-r+L5ylA17JlD1vwS8rjhWr0qg7zVoVMDvWhajWA5r5+USdh91jRUYosp19Kd1m2vE034v7Dfqe1xYRoH2zvG0g== + dependencies: + web3-eth-iban "1.10.4" + web3-utils "1.10.4" + +web3-core-method@1.10.4: + version "1.10.4" + resolved "https://registry.npmjs.org/web3-core-method/-/web3-core-method-1.10.4.tgz" + integrity sha512-uZTb7flr+Xl6LaDsyTeE2L1TylokCJwTDrIVfIfnrGmnwLc6bmTWCCrm71sSrQ0hqs6vp/MKbQYIYqUN0J8WyA== + dependencies: + "@ethersproject/transactions" "^5.6.2" + web3-core-helpers "1.10.4" + web3-core-promievent "1.10.4" + web3-core-subscriptions "1.10.4" + web3-utils "1.10.4" + +web3-core-promievent@1.10.4: + version "1.10.4" + resolved "https://registry.npmjs.org/web3-core-promievent/-/web3-core-promievent-1.10.4.tgz" + integrity sha512-2de5WnJQ72YcIhYwV/jHLc4/cWJnznuoGTJGD29ncFQHAfwW/MItHFSVKPPA5v8AhJe+r6y4Y12EKvZKjQVBvQ== + dependencies: + eventemitter3 "4.0.4" + +web3-core-requestmanager@1.10.4: + version "1.10.4" + resolved "https://registry.npmjs.org/web3-core-requestmanager/-/web3-core-requestmanager-1.10.4.tgz" + integrity sha512-vqP6pKH8RrhT/2MoaU+DY/OsYK9h7HmEBNCdoMj+4ZwujQtw/Mq2JifjwsJ7gits7Q+HWJwx8q6WmQoVZAWugg== + dependencies: + util "^0.12.5" + web3-core-helpers "1.10.4" + web3-providers-http "1.10.4" + web3-providers-ipc "1.10.4" + web3-providers-ws "1.10.4" + +web3-core-subscriptions@1.10.4: + version "1.10.4" + resolved "https://registry.npmjs.org/web3-core-subscriptions/-/web3-core-subscriptions-1.10.4.tgz" + integrity sha512-o0lSQo/N/f7/L76C0HV63+S54loXiE9fUPfHFcTtpJRQNDBVsSDdWRdePbWwR206XlsBqD5VHApck1//jEafTw== + dependencies: + eventemitter3 "4.0.4" + web3-core-helpers "1.10.4" + +web3-core@^1.8.1: + version "1.10.4" + resolved "https://registry.npmjs.org/web3-core/-/web3-core-1.10.4.tgz" + integrity sha512-B6elffYm81MYZDTrat7aEhnhdtVE3lDBUZft16Z8awYMZYJDbnykEbJVS+l3mnA7AQTnSDr/1MjWofGDLBJPww== + dependencies: + "@types/bn.js" "^5.1.1" + "@types/node" "^12.12.6" + bignumber.js "^9.0.0" + web3-core-helpers "1.10.4" + web3-core-method "1.10.4" + web3-core-requestmanager "1.10.4" + web3-utils "1.10.4" + +web3-eth-iban@1.10.4: + version "1.10.4" + resolved "https://registry.npmjs.org/web3-eth-iban/-/web3-eth-iban-1.10.4.tgz" + integrity sha512-0gE5iNmOkmtBmbKH2aTodeompnNE8jEyvwFJ6s/AF6jkw9ky9Op9cqfzS56AYAbrqEFuClsqB/AoRves7LDELw== + dependencies: + bn.js "^5.2.1" + web3-utils "1.10.4" + +web3-providers-http@1.10.4: + version "1.10.4" + resolved "https://registry.npmjs.org/web3-providers-http/-/web3-providers-http-1.10.4.tgz" + integrity sha512-m2P5Idc8hdiO0l60O6DSCPw0kw64Zgi0pMjbEFRmxKIck2Py57RQMu4bxvkxJwkF06SlGaEQF8rFZBmuX7aagQ== + dependencies: + abortcontroller-polyfill "^1.7.5" + cross-fetch "^4.0.0" + es6-promise "^4.2.8" + web3-core-helpers "1.10.4" + +web3-providers-ipc@1.10.4: + version "1.10.4" + resolved "https://registry.npmjs.org/web3-providers-ipc/-/web3-providers-ipc-1.10.4.tgz" + integrity sha512-YRF/bpQk9z3WwjT+A6FI/GmWRCASgd+gC0si7f9zbBWLXjwzYAKG73bQBaFRAHex1hl4CVcM5WUMaQXf3Opeuw== + dependencies: + oboe "2.1.5" + web3-core-helpers "1.10.4" + +web3-providers-ws@1.10.4: + version "1.10.4" + resolved "https://registry.npmjs.org/web3-providers-ws/-/web3-providers-ws-1.10.4.tgz" + integrity sha512-j3FBMifyuFFmUIPVQR4pj+t5ILhAexAui0opgcpu9R5LxQrLRUZxHSnU+YO25UycSOa/NAX8A+qkqZNpcFAlxA== + dependencies: + eventemitter3 "4.0.4" + web3-core-helpers "1.10.4" + websocket "^1.0.32" + +web3-utils@1.10.4, web3-utils@^1.8.1: + version "1.10.4" + resolved "https://registry.npmjs.org/web3-utils/-/web3-utils-1.10.4.tgz" + integrity sha512-tsu8FiKJLk2PzhDl9fXbGUWTkkVXYhtTA+SmEFkKft+9BgwLxfCRpU96sWv7ICC8zixBNd3JURVoiR3dUXgP8A== + dependencies: + "@ethereumjs/util" "^8.1.0" + bn.js "^5.2.1" + ethereum-bloom-filters "^1.0.6" + ethereum-cryptography "^2.1.2" + ethjs-unit "0.1.6" + number-to-bn "1.7.0" + randombytes "^2.1.0" + utf8 "3.0.0" + +webidl-conversions@^3.0.0: + version "3.0.1" + resolved "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz" + integrity sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ== + +websocket@^1.0.32: + version "1.0.35" + resolved "https://registry.npmjs.org/websocket/-/websocket-1.0.35.tgz" + integrity sha512-/REy6amwPZl44DDzvRCkaI1q1bIiQB0mEFQLUrhz3z2EK91cp3n72rAjUlrTP0zV22HJIUOVHQGPxhFRjxjt+Q== + dependencies: + bufferutil "^4.0.1" + debug "^2.2.0" + es5-ext "^0.10.63" + typedarray-to-buffer "^3.1.5" + utf-8-validate "^5.0.2" + yaeti "^0.0.6" + +whatwg-url@^5.0.0: + version "5.0.0" + resolved "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz" + integrity sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw== + dependencies: + tr46 "~0.0.3" + webidl-conversions "^3.0.0" + +which-typed-array@^1.1.16, which-typed-array@^1.1.2: + version "1.1.19" + resolved "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.19.tgz" + integrity sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw== + dependencies: + available-typed-arrays "^1.0.7" + call-bind "^1.0.8" + call-bound "^1.0.4" + for-each "^0.3.5" + get-proto "^1.0.1" + gopd "^1.2.0" + has-tostringtag "^1.0.2" + +which@^2.0.1, which@^2.0.2: version "2.0.2" resolved "https://registry.npmjs.org/which/-/which-2.0.2.tgz" integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== dependencies: isexe "^2.0.0" +wide-align@^1.1.5: + version "1.1.5" + resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.5.tgz#df1d4c206854369ecf3c9a4898f1b23fbd9d15d3" + integrity sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg== + dependencies: + string-width "^1.0.2 || 2 || 3 || 4" + workerpool@^6.5.1: version "6.5.1" resolved "https://registry.npmjs.org/workerpool/-/workerpool-6.5.1.tgz" @@ -3730,11 +6038,21 @@ wrappy@1: resolved "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz" integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== +ws@7.4.6: + version "7.4.6" + resolved "https://registry.npmjs.org/ws/-/ws-7.4.6.tgz" + integrity sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A== + ws@8.17.1: version "8.17.1" - resolved "https://registry.yarnpkg.com/ws/-/ws-8.17.1.tgz#9293da530bb548febc95371d90f9c878727d919b" + resolved "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz" integrity sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ== +ws@8.18.3: + version "8.18.3" + resolved "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz" + integrity sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg== + xtend@^4.0.0: version "4.0.2" resolved "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz" @@ -3745,6 +6063,16 @@ y18n@^5.0.5: resolved "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz" integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== +yaeti@^0.0.6: + version "0.0.6" + resolved "https://registry.npmjs.org/yaeti/-/yaeti-0.0.6.tgz" + integrity sha512-MvQa//+KcZCUkBTIC9blM+CU9J2GzuTytsOUwf2lidtvkx/6gnEp1QvJv34t9vdjhFmha/mUiNDbN0D0mJWdug== + +yallist@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" + integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== + yargs-parser@^20.2.2, yargs-parser@^20.2.9: version "20.2.9" resolved "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz" @@ -3765,7 +6093,7 @@ yargs-unparser@^2.0.0: flat "^5.0.2" is-plain-obj "^2.1.0" -yargs@^16.0.0, yargs@^16.2.0: +yargs@^16.2.0: version "16.2.0" resolved "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz" integrity sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw== @@ -3778,7 +6106,7 @@ yargs@^16.0.0, yargs@^16.2.0: y18n "^5.0.5" yargs-parser "^20.2.2" -yargs@^17.6.2: +yargs@^17.7.2: version "17.7.2" resolved "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz" integrity sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w== @@ -3800,3 +6128,8 @@ yocto-queue@^0.1.0: version "0.1.0" resolved "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz" integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== + +zksync-web3@^0.14.3: + version "0.14.4" + resolved "https://registry.npmjs.org/zksync-web3/-/zksync-web3-0.14.4.tgz" + integrity sha512-kYehMD/S6Uhe1g434UnaMN+sBr9nQm23Ywn0EUP5BfQCsbjcr3ORuS68PosZw8xUTu3pac7G6YMSnNHk+fwzvg==