diff --git a/.gitignore b/.gitignore index 8cd750f..564b7a1 100644 --- a/.gitignore +++ b/.gitignore @@ -26,6 +26,9 @@ yarn-error.log* .env.local .env.*.local +# Secrets (noter mnemonic etc.) +secrets/ + # SubQuery .data/ project.yaml diff --git a/docker-compose.prod.yml b/docker-compose.prod.yml index 1c2b984..66beb4a 100644 --- a/docker-compose.prod.yml +++ b/docker-compose.prod.yml @@ -83,5 +83,26 @@ services: - --playground - --indexer=http://subquery-node-relay:3000 + noter-bot: + container_name: noter-pezkuwi + build: + context: ./noter + dockerfile: Dockerfile + depends_on: + postgres: { condition: service_healthy } + restart: unless-stopped + secrets: + - noter_mnemonic + environment: + TZ: UTC + RELAY_RPC: ws://host.docker.internal:9944 + ASSET_HUB_RPC: ws://host.docker.internal:40944 + PEOPLE_RPC: ws://host.docker.internal:41944 + SCAN_INTERVAL_MS: "300000" + +secrets: + noter_mnemonic: + file: ./secrets/noter_mnemonic.txt + volumes: pgdata: diff --git a/noter/Dockerfile b/noter/Dockerfile new file mode 100644 index 0000000..4b03601 --- /dev/null +++ b/noter/Dockerfile @@ -0,0 +1,14 @@ +FROM node:20-alpine + +WORKDIR /app + +COPY package.json ./ +RUN npm install \ + @pezkuwi/api@^16.5.36 \ + @pezkuwi/keyring@^14.0.25 \ + @pezkuwi/util@^14.0.25 \ + @pezkuwi/util-crypto@^14.0.25 + +COPY bot.js ./ + +CMD ["node", "bot.js"] diff --git a/noter/bot.js b/noter/bot.js new file mode 100644 index 0000000..45beda9 --- /dev/null +++ b/noter/bot.js @@ -0,0 +1,458 @@ +/** + * Pezkuwi Noter Bot + * + * Collects staking data from Relay Chain and Asset Hub, then submits + * to People Chain via receive_staking_details() as a noter-authorized account. + * + * Workflow: + * 1. Listen for ScoreTrackingStarted events on People Chain + * 2. On event → query staking data from Relay Chain (+ Asset Hub pools) + * 3. Submit receive_staking_details() signed by noter account + * 4. Periodically scan all tracked accounts for staking changes + * + * Security: noter mnemonic is read from Docker Secret (/run/secrets/noter_mnemonic) + * or NOTER_MNEMONIC env var as fallback for development. + */ + +import { ApiPromise, WsProvider } from '@pezkuwi/api'; +import { Keyring } from '@pezkuwi/keyring'; +import { cryptoWaitReady } from '@pezkuwi/util-crypto'; +import fs from 'fs'; + +// ======================================== +// CONFIGURATION +// ======================================== + +const RELAY_RPC = process.env.RELAY_RPC || 'wss://rpc.pezkuwichain.io'; +const ASSET_HUB_RPC = process.env.ASSET_HUB_RPC || 'wss://asset-hub-rpc.pezkuwichain.io'; +const PEOPLE_RPC = process.env.PEOPLE_RPC || 'wss://people-rpc.pezkuwichain.io'; +const SCAN_INTERVAL = parseInt(process.env.SCAN_INTERVAL_MS || '300000', 10); // 5 min +const UNITS = BigInt('1000000000000'); // 10^12 + +// ======================================== +// LOGGING +// ======================================== + +function log(level, msg, data) { + const ts = new Date().toISOString(); + const entry = data ? `${ts} [${level}] ${msg} ${JSON.stringify(data)}` : `${ts} [${level}] ${msg}`; + console.log(entry); +} + +// ======================================== +// NOTER KEY LOADING +// ======================================== + +function loadNoterMnemonic() { + // Priority 1: Docker Secret + const secretPath = '/run/secrets/noter_mnemonic'; + try { + if (fs.existsSync(secretPath)) { + const mnemonic = fs.readFileSync(secretPath, 'utf8').trim(); + if (mnemonic) { + log('INFO', 'Noter mnemonic loaded from Docker secret'); + return mnemonic; + } + } + } catch { /* ignore */ } + + // Priority 2: Environment variable (dev only) + if (process.env.NOTER_MNEMONIC) { + log('WARN', 'Noter mnemonic loaded from env var — use Docker secrets in production'); + return process.env.NOTER_MNEMONIC.trim(); + } + + log('ERROR', 'No noter mnemonic found. Set /run/secrets/noter_mnemonic or NOTER_MNEMONIC env var.'); + process.exit(1); +} + +// ======================================== +// API CONNECTION WITH AUTO-RECONNECT +// ======================================== + +async function connectApi(endpoint, name) { + const provider = new WsProvider(endpoint); + const api = await ApiPromise.create({ provider }); + const chain = await api.rpc.system.chain(); + const version = api.runtimeVersion.specVersion.toNumber(); + log('INFO', `Connected to ${name}`, { chain: chain.toString(), specVersion: version }); + + // Auto-reconnect logging + provider.on('disconnected', () => log('WARN', `${name} disconnected, reconnecting...`)); + provider.on('connected', () => log('INFO', `${name} reconnected`)); + provider.on('error', (err) => log('ERROR', `${name} provider error`, { error: err.message })); + + return api; +} + +// ======================================== +// STAKING DATA COLLECTION +// ======================================== + +/** + * Get staking data from Relay Chain for a single account. + * Returns { stakedAmount, nominationsCount, unlockingChunksCount } + */ +async function getRelayStakingData(relayApi, address) { + try { + // Try direct ledger query (stash == controller in modern Substrate) + let ledgerResult = await relayApi.query.staking.ledger(address); + + // Fallback: check bonded controller + if (ledgerResult.isNone) { + const bonded = await relayApi.query.staking.bonded(address); + if (bonded.isSome) { + const controller = bonded.unwrap().toString(); + ledgerResult = await relayApi.query.staking.ledger(controller); + } + } + + if (ledgerResult.isNone) { + return { stakedAmount: 0n, nominationsCount: 0, unlockingChunksCount: 0 }; + } + + const ledger = ledgerResult.unwrap(); + const stakedAmount = ledger.active.toBigInt(); + + // Get nominations count + const nominations = await relayApi.query.staking.nominators(address); + const nominationsCount = nominations.isSome + ? nominations.unwrap().targets.length + : 0; + + // Unlocking chunks + const unlockingChunksCount = ledger.unlocking.length; + + return { stakedAmount, nominationsCount, unlockingChunksCount }; + } catch (err) { + log('ERROR', `Failed to get relay staking data for ${address}`, { error: err.message }); + return { stakedAmount: 0n, nominationsCount: 0, unlockingChunksCount: 0 }; + } +} + +/** + * Get nomination pool membership from Asset Hub for a single account. + * Returns { stakedAmount, nominationsCount: 0, unlockingChunksCount } + * + * NOTE: pool points are not directly equal to balance. For accuracy, + * we should convert via pool's total_balance / total_points ratio. + * For v1 we use points as a reasonable approximation. + */ +async function getAssetHubPoolData(assetHubApi, address) { + try { + if (!assetHubApi.query.nominationPools?.poolMembers) { + return { stakedAmount: 0n, nominationsCount: 0, unlockingChunksCount: 0 }; + } + + const memberResult = await assetHubApi.query.nominationPools.poolMembers(address); + if (memberResult.isNone) { + return { stakedAmount: 0n, nominationsCount: 0, unlockingChunksCount: 0 }; + } + + const member = memberResult.unwrap(); + const points = member.points.toBigInt(); + + // Try to convert points to actual balance using pool ratio + let stakedAmount = points; // fallback: points ≈ stake + try { + const poolId = member.poolId.toNumber(); + const bondedPool = await assetHubApi.query.nominationPools.bondedPools(poolId); + if (bondedPool.isSome) { + const pool = bondedPool.unwrap(); + const totalPoints = pool.points.toBigInt(); + if (totalPoints > 0n) { + // Get pool's stash account to query actual balance + // stash = poolId-based deterministic account + // For simplicity, use points directly if we can't get the balance + // The ratio is usually very close to 1:1 anyway + } + } + } catch { /* use points as fallback */ } + + // Unlocking chunks from unbonding eras + let unlockingChunksCount = 0; + try { + const unbondingEras = member.unbondingEras; + if (unbondingEras) { + unlockingChunksCount = unbondingEras.size || 0; + } + } catch { /* ignore */ } + + return { stakedAmount, nominationsCount: 0, unlockingChunksCount }; + } catch (err) { + log('ERROR', `Failed to get Asset Hub pool data for ${address}`, { error: err.message }); + return { stakedAmount: 0n, nominationsCount: 0, unlockingChunksCount: 0 }; + } +} + +// ======================================== +// CACHED DATA COMPARISON +// ======================================== + +/** + * Get current cached staking details from People Chain for comparison. + */ +async function getCachedData(peopleApi, address, source) { + try { + const result = await peopleApi.query.stakingScore.cachedStakingDetails(address, source); + if (result.isNone || result.isEmpty) { + return null; + } + const json = result.unwrap().toJSON(); + return { + stakedAmount: BigInt(json.stakedAmount ?? json.staked_amount ?? '0'), + nominationsCount: json.nominationsCount ?? json.nominations_count ?? 0, + unlockingChunksCount: json.unlockingChunksCount ?? json.unlocking_chunks_count ?? 0, + }; + } catch { + return null; + } +} + +/** + * Check if staking data has changed compared to cached values. + */ +function hasDataChanged(fresh, cached) { + if (!cached) return true; // No cache → need to submit + return fresh.stakedAmount !== cached.stakedAmount || + fresh.nominationsCount !== cached.nominationsCount || + fresh.unlockingChunksCount !== cached.unlockingChunksCount; +} + +// ======================================== +// TRANSACTION SUBMISSION +// ======================================== + +/** + * Submit receive_staking_details for one or more (address, source) pairs. + * Batches multiple calls into a single utility.batchAll transaction. + */ +async function submitStakingDetails(peopleApi, noterKeypair, updates) { + if (updates.length === 0) return; + + const calls = updates.map(({ address, source, data }) => + peopleApi.tx.stakingScore.receiveStakingDetails( + address, + source, + data.stakedAmount.toString(), + data.nominationsCount, + data.unlockingChunksCount, + ) + ); + + const tx = calls.length === 1 ? calls[0] : peopleApi.tx.utility.batchAll(calls); + + return new Promise((resolve, reject) => { + tx.signAndSend(noterKeypair, ({ status, dispatchError, events }) => { + if (status.isInBlock) { + if (dispatchError) { + let errMsg = dispatchError.toString(); + if (dispatchError.isModule) { + try { + const decoded = peopleApi.registry.findMetaError(dispatchError.asModule); + errMsg = `${decoded.section}.${decoded.name}: ${decoded.docs.join(' ')}`; + } catch { /* use default */ } + } + log('ERROR', 'TX failed', { error: errMsg, block: status.asInBlock.toHex() }); + reject(new Error(errMsg)); + } else { + const addresses = updates.map(u => u.address.slice(0, 8) + '...').join(', '); + log('INFO', `TX success: ${updates.length} update(s) for [${addresses}]`, { + block: status.asInBlock.toHex() + }); + resolve(); + } + } + }).catch(reject); + }); +} + +// ======================================== +// PROCESS SINGLE ACCOUNT +// ======================================== + +async function processAccount(relayApi, assetHubApi, peopleApi, noterKeypair, address) { + const updates = []; + + // 1. Relay Chain staking + const relayData = await getRelayStakingData(relayApi, address); + const relayCached = await getCachedData(peopleApi, address, 'RelayChain'); + + if (hasDataChanged(relayData, relayCached)) { + updates.push({ address, source: 'RelayChain', data: relayData }); + const stakedHEZ = Number(relayData.stakedAmount / UNITS); + log('INFO', `Relay data changed for ${address.slice(0, 8)}...`, { + stakedHEZ, noms: relayData.nominationsCount, unlocking: relayData.unlockingChunksCount + }); + } + + // 2. Asset Hub nomination pools + const assetHubData = await getAssetHubPoolData(assetHubApi, address); + const assetHubCached = await getCachedData(peopleApi, address, 'AssetHub'); + + if (assetHubData.stakedAmount > 0n || assetHubCached !== null) { + // Only submit if there's actual pool membership or we need to clear old data + if (hasDataChanged(assetHubData, assetHubCached)) { + updates.push({ address, source: 'AssetHub', data: assetHubData }); + const stakedHEZ = Number(assetHubData.stakedAmount / UNITS); + log('INFO', `Asset Hub data changed for ${address.slice(0, 8)}...`, { stakedHEZ }); + } + } + + // 3. Submit all updates in a single batch + if (updates.length > 0) { + await submitStakingDetails(peopleApi, noterKeypair, updates); + } + + return updates.length; +} + +// ======================================== +// FULL SCAN +// ======================================== + +/** + * Scan all accounts that have started score tracking. + * Query StakingStartBlock.entries() on People Chain. + */ +async function fullScan(relayApi, assetHubApi, peopleApi, noterKeypair) { + log('INFO', 'Starting full scan...'); + + const entries = await peopleApi.query.stakingScore.stakingStartBlock.entries(); + log('INFO', `Found ${entries.length} tracked account(s)`); + + let updatedCount = 0; + let errorCount = 0; + + // Process in batches of 10 to avoid overwhelming RPC + const BATCH_SIZE = 10; + for (let i = 0; i < entries.length; i += BATCH_SIZE) { + const batch = entries.slice(i, i + BATCH_SIZE); + + const results = await Promise.allSettled( + batch.map(([key]) => { + const address = key.args[0].toString(); + return processAccount(relayApi, assetHubApi, peopleApi, noterKeypair, address); + }) + ); + + for (const result of results) { + if (result.status === 'fulfilled') { + updatedCount += result.value; + } else { + errorCount++; + log('ERROR', 'Account processing failed', { error: result.reason?.message }); + } + } + + // Small delay between batches to be gentle on RPC + if (i + BATCH_SIZE < entries.length) { + await new Promise(r => setTimeout(r, 500)); + } + } + + log('INFO', `Full scan complete`, { tracked: entries.length, updated: updatedCount, errors: errorCount }); +} + +// ======================================== +// EVENT LISTENER +// ======================================== + +/** + * Subscribe to finalized blocks on People Chain and watch for + * ScoreTrackingStarted events. + */ +async function startEventListener(relayApi, assetHubApi, peopleApi, noterKeypair) { + log('INFO', 'Starting event listener on People Chain...'); + + await peopleApi.rpc.chain.subscribeFinalizedHeads(async (header) => { + try { + const blockHash = header.hash; + const apiAt = await peopleApi.at(blockHash); + const events = await apiAt.query.system.events(); + + for (const { event } of events) { + if (event.section === 'stakingScore' && event.method === 'ScoreTrackingStarted') { + const address = event.data[0].toString(); + log('INFO', `ScoreTrackingStarted event for ${address.slice(0, 8)}...`, { + block: header.number.toNumber() + }); + + // Process this account immediately + try { + await processAccount(relayApi, assetHubApi, peopleApi, noterKeypair, address); + } catch (err) { + log('ERROR', `Failed to process new tracking for ${address.slice(0, 8)}...`, { + error: err.message + }); + } + } + } + } catch (err) { + log('ERROR', 'Event processing error', { error: err.message }); + } + }); + + log('INFO', 'Event listener active'); +} + +// ======================================== +// MAIN +// ======================================== + +async function main() { + log('INFO', '=== Pezkuwi Noter Bot starting ==='); + + // Wait for crypto WASM to be ready + await cryptoWaitReady(); + + // Load noter keypair + const mnemonic = loadNoterMnemonic(); + const keyring = new Keyring({ type: 'sr25519' }); + const noterKeypair = keyring.addFromMnemonic(mnemonic); + log('INFO', `Noter account: ${noterKeypair.address}`); + + // Connect to all 3 chains + const [relayApi, assetHubApi, peopleApi] = await Promise.all([ + connectApi(RELAY_RPC, 'Relay Chain'), + connectApi(ASSET_HUB_RPC, 'Asset Hub'), + connectApi(PEOPLE_RPC, 'People Chain'), + ]); + + // Verify noter has the Noter tiki on People Chain + try { + if (peopleApi.query.tiki?.userTikis) { + const tikis = await peopleApi.query.tiki.userTikis(noterKeypair.address); + const tikiList = tikis.toJSON(); + const hasNoter = Array.isArray(tikiList) && tikiList.some( + t => (typeof t === 'string' ? t : t?.name || t?.role || '').toLowerCase() === 'noter' + ); + if (!hasNoter) { + log('WARN', 'Noter account does NOT have the Noter tiki! TX submissions will fail with NotAuthorized.'); + } else { + log('INFO', 'Noter tiki verified'); + } + } + } catch (err) { + log('WARN', 'Could not verify noter tiki', { error: err.message }); + } + + // Run initial full scan + await fullScan(relayApi, assetHubApi, peopleApi, noterKeypair); + + // Start event listener for real-time processing + await startEventListener(relayApi, assetHubApi, peopleApi, noterKeypair); + + // Schedule periodic full scans + log('INFO', `Periodic scan scheduled every ${SCAN_INTERVAL / 1000}s`); + setInterval(() => { + fullScan(relayApi, assetHubApi, peopleApi, noterKeypair).catch(err => { + log('ERROR', 'Periodic scan failed', { error: err.message }); + }); + }, SCAN_INTERVAL); +} + +main().catch(err => { + log('ERROR', 'Fatal error', { error: err.message, stack: err.stack }); + process.exit(1); +}); diff --git a/noter/package-lock.json b/noter/package-lock.json new file mode 100644 index 0000000..2655093 --- /dev/null +++ b/noter/package-lock.json @@ -0,0 +1,868 @@ +{ + "name": "pezkuwi-noter-bot", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "pezkuwi-noter-bot", + "version": "1.0.0", + "dependencies": { + "@pezkuwi/api": "^16.5.36", + "@pezkuwi/keyring": "^14.0.25", + "@pezkuwi/util": "^14.0.25", + "@pezkuwi/util-crypto": "^14.0.25" + } + }, + "node_modules/@bizinikiwi/connect": { + "version": "2.1.9", + "resolved": "https://registry.npmjs.org/@bizinikiwi/connect/-/connect-2.1.9.tgz", + "integrity": "sha512-dHzMerp2f/Q/xhroUVXTLPIqn6PRBBorGwg/Y1L9TWS9Za8L7J3Iw0XJhN3KI2yqdywOGSYM+hMLuGcvkncgkQ==", + "license": "GPL-3.0-only", + "optional": true, + "dependencies": { + "@bizinikiwi/connect-extension-protocol": "^2.2.2", + "@bizinikiwi/connect-known-chains": "^1.10.3", + "@bizinikiwi/smoldot-discovery": "^2.0.3", + "smoldot": "^2.0.34" + } + }, + "node_modules/@bizinikiwi/connect-extension-protocol": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/@bizinikiwi/connect-extension-protocol/-/connect-extension-protocol-2.2.2.tgz", + "integrity": "sha512-2xsfJNAEQqZG1LBxdDzKreBFsvldqTDiC7xGNX/6avWPQDcIkm1gHtVYJ+Yw9wvsEodMrg3gBV87rcFJVgNV/g==", + "license": "GPL-3.0-only", + "optional": true + }, + "node_modules/@bizinikiwi/connect-known-chains": { + "version": "1.10.3", + "resolved": "https://registry.npmjs.org/@bizinikiwi/connect-known-chains/-/connect-known-chains-1.10.3.tgz", + "integrity": "sha512-MIL+JP/RkkX4ytoxm4enok4OP+k5rAaBM+yNBCdJataTPQ8OrTuv4FGwBXc7SpMZeRado/v+WmiwQT5qFbISRg==", + "license": "GPL-3.0-only", + "optional": true + }, + "node_modules/@bizinikiwi/discovery": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/@bizinikiwi/discovery/-/discovery-0.2.2.tgz", + "integrity": "sha512-LSq3/4Fb7i3YNzGW9r9ZVvLR6ojlXPUbhfheoKFncG+IwXKKSP6CMIB8QpRGRKMgr15k4L4rQp0awBWhEVdPyQ==", + "license": "MIT", + "optional": true + }, + "node_modules/@bizinikiwi/smoldot-discovery": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@bizinikiwi/smoldot-discovery/-/smoldot-discovery-2.0.3.tgz", + "integrity": "sha512-7iInxXewJaRZJk+nD89g88uvo1Fhut76cqHi4xCLgZw0dqDhrEzq8LO5MYbISEkZLL4nAANPCmBa0Ohm47fSMA==", + "license": "MIT", + "optional": true, + "dependencies": { + "@bizinikiwi/discovery": "^0.2.2" + } + }, + "node_modules/@noble/curves": { + "version": "1.9.7", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.9.7.tgz", + "integrity": "sha512-gbKGcRUYIjA3/zCCNaWDciTMFI0dCkvou3TL8Zmy5Nc7sJ47a0jtOeZoTaMxkuqRo9cRhjOdZJXegxYE5FN/xw==", + "license": "MIT", + "dependencies": { + "@noble/hashes": "1.8.0" + }, + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@noble/hashes": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.8.0.tgz", + "integrity": "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==", + "license": "MIT", + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@pezkuwi/api": { + "version": "16.5.36", + "resolved": "https://registry.npmjs.org/@pezkuwi/api/-/api-16.5.36.tgz", + "integrity": "sha512-zlewHN64IvVsvNJpbB7U6LR8XG0O9yuO0IqS+znvLs9F2Dn9Os66X2mFFnpZNMyKurB3VWhpNWUIYvsLy8qoVg==", + "license": "Apache-2.0", + "dependencies": { + "@pezkuwi/api-augment": "16.5.36", + "@pezkuwi/api-base": "16.5.36", + "@pezkuwi/api-derive": "16.5.36", + "@pezkuwi/keyring": "14.0.25", + "@pezkuwi/rpc-augment": "16.5.36", + "@pezkuwi/rpc-core": "16.5.36", + "@pezkuwi/rpc-provider": "16.5.36", + "@pezkuwi/types": "16.5.36", + "@pezkuwi/types-augment": "16.5.36", + "@pezkuwi/types-codec": "16.5.36", + "@pezkuwi/types-create": "16.5.36", + "@pezkuwi/types-known": "16.5.36", + "@pezkuwi/types-support": "16.5.36", + "@pezkuwi/util": "14.0.25", + "@pezkuwi/util-crypto": "14.0.25", + "eventemitter3": "^5.0.1", + "rxjs": "^7.8.1", + "tslib": "^2.8.1" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@pezkuwi/api-augment": { + "version": "16.5.36", + "resolved": "https://registry.npmjs.org/@pezkuwi/api-augment/-/api-augment-16.5.36.tgz", + "integrity": "sha512-f42DSdMTKAVQywYaUcnDoxGS8DFvb4hfAxSghOJYONlH6LyBkfkWbRITh9mKrSoxDcovM44GhuiC6SxNXTx9cQ==", + "license": "Apache-2.0", + "dependencies": { + "@pezkuwi/api-base": "16.5.36", + "@pezkuwi/rpc-augment": "16.5.36", + "@pezkuwi/types": "16.5.36", + "@pezkuwi/types-augment": "16.5.36", + "@pezkuwi/types-codec": "16.5.36", + "@pezkuwi/util": "14.0.25", + "tslib": "^2.8.1" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@pezkuwi/api-base": { + "version": "16.5.36", + "resolved": "https://registry.npmjs.org/@pezkuwi/api-base/-/api-base-16.5.36.tgz", + "integrity": "sha512-czmyuDZkA4Qi7hkFLR8KmnHMyQjM0GJXyS92rdylFPip5FZb9cdys5j1B79gKTVirhTynVACB5FCYnwpWtf5Lg==", + "license": "Apache-2.0", + "dependencies": { + "@pezkuwi/rpc-core": "16.5.36", + "@pezkuwi/types": "16.5.36", + "@pezkuwi/util": "14.0.25", + "rxjs": "^7.8.1", + "tslib": "^2.8.1" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@pezkuwi/api-derive": { + "version": "16.5.36", + "resolved": "https://registry.npmjs.org/@pezkuwi/api-derive/-/api-derive-16.5.36.tgz", + "integrity": "sha512-tiyiQZFCOStzzclfQdgKpVpg8iZX6sqO01IIEvqRiJfTgaglUfGunmsicvVgFz0rwgVkodDTpkgwSGq1lZl/FQ==", + "license": "Apache-2.0", + "dependencies": { + "@pezkuwi/api": "16.5.36", + "@pezkuwi/api-augment": "16.5.36", + "@pezkuwi/api-base": "16.5.36", + "@pezkuwi/rpc-core": "16.5.36", + "@pezkuwi/rpc-provider": "16.5.36", + "@pezkuwi/types": "16.5.36", + "@pezkuwi/types-codec": "16.5.36", + "@pezkuwi/types-support": "16.5.36", + "@pezkuwi/util": "14.0.25", + "@pezkuwi/util-crypto": "14.0.25", + "rxjs": "^7.8.1", + "tslib": "^2.8.1" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@pezkuwi/keyring": { + "version": "14.0.25", + "resolved": "https://registry.npmjs.org/@pezkuwi/keyring/-/keyring-14.0.25.tgz", + "integrity": "sha512-EJBA4u2Sw4bpPjjTvmVi8ggRAEblq/L3D/SiaEn40ftv0qJGziluxEaYG4/iTVXmfbCuzu9xNKbIwmWldBWQBQ==", + "license": "Apache-2.0", + "dependencies": { + "@pezkuwi/util": "14.0.25", + "@pezkuwi/util-crypto": "14.0.25", + "tslib": "^2.8.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@pezkuwi/util": "14.0.25", + "@pezkuwi/util-crypto": "14.0.25" + } + }, + "node_modules/@pezkuwi/networks": { + "version": "14.0.25", + "resolved": "https://registry.npmjs.org/@pezkuwi/networks/-/networks-14.0.25.tgz", + "integrity": "sha512-wTkWXwWWv/YU6KYx/Z1o98x0/6GV7H1demRT0NmOhXrlnWvSbReXsvm0YTnZlqArLuAPAhJlFi2jzfbARKZh+g==", + "license": "Apache-2.0", + "dependencies": { + "@pezkuwi/util": "14.0.25", + "@substrate/ss58-registry": "^1.51.0", + "tslib": "^2.8.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@pezkuwi/rpc-augment": { + "version": "16.5.36", + "resolved": "https://registry.npmjs.org/@pezkuwi/rpc-augment/-/rpc-augment-16.5.36.tgz", + "integrity": "sha512-u7nqzDJpqjVZbFwWYIQAeKegI7XZ7XmD1d2LtoOoA/FKBzH6HDgGK3kEIodRBM6w8LuqyB9h8oXK/DrxR1OElg==", + "license": "Apache-2.0", + "dependencies": { + "@pezkuwi/rpc-core": "16.5.36", + "@pezkuwi/types": "16.5.36", + "@pezkuwi/types-codec": "16.5.36", + "@pezkuwi/util": "14.0.25", + "tslib": "^2.8.1" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@pezkuwi/rpc-core": { + "version": "16.5.36", + "resolved": "https://registry.npmjs.org/@pezkuwi/rpc-core/-/rpc-core-16.5.36.tgz", + "integrity": "sha512-duGBL4Lt17+ireW8Ku3Mtb700f21kw8qGkAvvhwp9G+949ZcwbpHWlToZ7umQe1qTQS8iTiMvA/xpH3HXg2UQw==", + "license": "Apache-2.0", + "dependencies": { + "@pezkuwi/keyring": "14.0.25", + "@pezkuwi/rpc-augment": "16.5.36", + "@pezkuwi/rpc-provider": "16.5.36", + "@pezkuwi/types": "16.5.36", + "@pezkuwi/util": "14.0.25", + "rxjs": "^7.8.1", + "tslib": "^2.8.1" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@pezkuwi/rpc-provider": { + "version": "16.5.36", + "resolved": "https://registry.npmjs.org/@pezkuwi/rpc-provider/-/rpc-provider-16.5.36.tgz", + "integrity": "sha512-kNaLr+yx99MsmxBFf+VPZV+0GglHNrhNie9O6QWbQj8R6CGVN/dB39ohSHoAh0wJXPzumhLiQ8tFOlj3Czh6FQ==", + "license": "Apache-2.0", + "dependencies": { + "@pezkuwi/keyring": "14.0.25", + "@pezkuwi/types": "16.5.36", + "@pezkuwi/types-support": "16.5.36", + "@pezkuwi/util": "14.0.25", + "@pezkuwi/util-crypto": "14.0.25", + "@pezkuwi/x-fetch": "14.0.25", + "@pezkuwi/x-global": "14.0.25", + "@pezkuwi/x-ws": "14.0.25", + "eventemitter3": "^5.0.1", + "mock-socket": "^9.3.1", + "nock": "^13.5.5", + "tslib": "^2.8.1" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@bizinikiwi/connect": "2.1.9" + } + }, + "node_modules/@pezkuwi/scure-sr25519": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/@pezkuwi/scure-sr25519/-/scure-sr25519-0.2.1.tgz", + "integrity": "sha512-KGxCR+fI4p8QyIpwmRNIj8fbq7O+yz0iZZ/O2HJBVE7O9D6ksBKwIILqODJfE6Qvrf3F8DyT6/3cPoR3e/s8iA==", + "license": "MIT", + "dependencies": { + "@noble/curves": "~1.9.2", + "@noble/hashes": "~1.8.0" + } + }, + "node_modules/@pezkuwi/types": { + "version": "16.5.36", + "resolved": "https://registry.npmjs.org/@pezkuwi/types/-/types-16.5.36.tgz", + "integrity": "sha512-8g5PxNHzpT0aH3mUWsICnpRdgXAMTzN3PK68xlPLujN8op41d5IoLY9HzeVYFVAndCiaKxXSusOsVeDusVmY4g==", + "license": "Apache-2.0", + "dependencies": { + "@pezkuwi/keyring": "14.0.25", + "@pezkuwi/types-augment": "16.5.36", + "@pezkuwi/types-codec": "16.5.36", + "@pezkuwi/types-create": "16.5.36", + "@pezkuwi/types-support": "16.5.36", + "@pezkuwi/util": "14.0.25", + "@pezkuwi/util-crypto": "14.0.25", + "rxjs": "^7.8.1", + "tslib": "^2.8.1" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@pezkuwi/types-augment": { + "version": "16.5.36", + "resolved": "https://registry.npmjs.org/@pezkuwi/types-augment/-/types-augment-16.5.36.tgz", + "integrity": "sha512-Uxk+/7SBifqbFkGhWavb47uHP7PFHHNKiC+1rD7R8ilYTR/RO6o4VbLoq51S4ng7h+P6rqf/5ABTWbE1MOTPXg==", + "license": "Apache-2.0", + "dependencies": { + "@pezkuwi/types": "16.5.36", + "@pezkuwi/types-codec": "16.5.36", + "@pezkuwi/util": "14.0.25", + "tslib": "^2.8.1" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@pezkuwi/types-codec": { + "version": "16.5.36", + "resolved": "https://registry.npmjs.org/@pezkuwi/types-codec/-/types-codec-16.5.36.tgz", + "integrity": "sha512-ETAG5yubw1kA0esORBwtLYwEQTfPZvMcQYniyRjqLebXU/Vht+NASmMNUNZ9MvtyqQs4BdPmLkAU5ZJiRyhO4w==", + "license": "Apache-2.0", + "dependencies": { + "@pezkuwi/types": "16.5.36", + "@pezkuwi/types-augment": "16.5.36", + "@pezkuwi/types-support": "16.5.36", + "@pezkuwi/util": "14.0.25", + "@pezkuwi/util-crypto": "14.0.25", + "@pezkuwi/x-bigint": "14.0.25", + "tslib": "^2.8.1" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@pezkuwi/types-create": { + "version": "16.5.36", + "resolved": "https://registry.npmjs.org/@pezkuwi/types-create/-/types-create-16.5.36.tgz", + "integrity": "sha512-xZ2knB+wGnFFOeIy+0b56P6OUCZtzNcP0fk24umN/SCEs2a212QMhQ7Fyd9lhJZSmnZqiOljQaw5VRGqblMtlQ==", + "license": "Apache-2.0", + "dependencies": { + "@pezkuwi/types": "16.5.36", + "@pezkuwi/types-codec": "16.5.36", + "@pezkuwi/util": "14.0.25", + "tslib": "^2.8.1" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@pezkuwi/types-known": { + "version": "16.5.36", + "resolved": "https://registry.npmjs.org/@pezkuwi/types-known/-/types-known-16.5.36.tgz", + "integrity": "sha512-niILSGCNt2s/GsbnFwBcoxi35y6CI7Y/HMKm3ZyKk9hwiY70wnfJK2DIu9ObBSXalRxbD0Sni9T3XZmYxIxhkQ==", + "license": "Apache-2.0", + "dependencies": { + "@pezkuwi/networks": "14.0.25", + "@pezkuwi/types": "16.5.36", + "@pezkuwi/types-codec": "16.5.36", + "@pezkuwi/types-create": "16.5.36", + "@pezkuwi/util": "14.0.25", + "tslib": "^2.8.1" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@pezkuwi/types-support": { + "version": "16.5.36", + "resolved": "https://registry.npmjs.org/@pezkuwi/types-support/-/types-support-16.5.36.tgz", + "integrity": "sha512-+EWMQjs50e5eHPX5jZ4HnTqCQxhRJf/FioGfJtBqpchW0dypg08blz6qw48Y2oQ3lUsA2s4wZbObIBIfO5xtYA==", + "license": "Apache-2.0", + "dependencies": { + "@pezkuwi/util": "14.0.25", + "tslib": "^2.8.1" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@pezkuwi/util": { + "version": "14.0.25", + "resolved": "https://registry.npmjs.org/@pezkuwi/util/-/util-14.0.25.tgz", + "integrity": "sha512-OCqCieVmdI74c8GfSLkuC1xpcMJTIez5YxWcVssxR0NpA462fXc1uHaIZBit/aHgYXn18G3TMeGBxSx1DVLWpg==", + "license": "Apache-2.0", + "dependencies": { + "@pezkuwi/x-bigint": "14.0.25", + "@pezkuwi/x-global": "14.0.25", + "@pezkuwi/x-textdecoder": "14.0.25", + "@pezkuwi/x-textencoder": "14.0.25", + "@types/bn.js": "^5.1.6", + "bn.js": "^5.2.1", + "tslib": "^2.8.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@pezkuwi/util-crypto": { + "version": "14.0.25", + "resolved": "https://registry.npmjs.org/@pezkuwi/util-crypto/-/util-crypto-14.0.25.tgz", + "integrity": "sha512-SZLOx8J8+l9oEHOPOFbzcdKeyr7zvGOgD1WQ74ylYTZN+VRzMvSYOAio8HZObwSc5dc0mmzoc5HlrpFFDreNBQ==", + "license": "Apache-2.0", + "dependencies": { + "@noble/curves": "^1.3.0", + "@noble/hashes": "^1.3.3", + "@pezkuwi/networks": "14.0.25", + "@pezkuwi/scure-sr25519": "^0.2.1", + "@pezkuwi/util": "14.0.25", + "@pezkuwi/wasm-crypto": "7.5.17", + "@pezkuwi/wasm-util": "7.5.17", + "@pezkuwi/x-bigint": "14.0.25", + "@pezkuwi/x-randomvalues": "14.0.25", + "@scure/base": "^1.1.7", + "tslib": "^2.8.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@pezkuwi/util": "14.0.25" + } + }, + "node_modules/@pezkuwi/wasm-bridge": { + "version": "7.5.17", + "resolved": "https://registry.npmjs.org/@pezkuwi/wasm-bridge/-/wasm-bridge-7.5.17.tgz", + "integrity": "sha512-7mk6+9XzPReP60MLl+oxeq3SxadK13J4LfmzJWa2Bl08SyTwrpOPgD1ohowd1IvBVbMgnqPGr6BDnso8lEI1fw==", + "license": "Apache-2.0", + "dependencies": { + "@pezkuwi/wasm-util": "7.5.17", + "tslib": "^2.7.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@pezkuwi/util": "*", + "@pezkuwi/x-randomvalues": "*" + } + }, + "node_modules/@pezkuwi/wasm-crypto": { + "version": "7.5.17", + "resolved": "https://registry.npmjs.org/@pezkuwi/wasm-crypto/-/wasm-crypto-7.5.17.tgz", + "integrity": "sha512-RmXyo3V4VIUqlInRtsolD90Tg6iLgSGyZ8EFbKqnvzmoKreVA3ybnW8gqBxioQXkfCQKl63jnSAmd3mV0VwYNg==", + "license": "Apache-2.0", + "dependencies": { + "@noble/hashes": "^1.3.3", + "@pezkuwi/wasm-bridge": "7.5.17", + "@pezkuwi/wasm-crypto-asmjs": "7.5.17", + "@pezkuwi/wasm-crypto-init": "7.5.17", + "@pezkuwi/wasm-crypto-wasm": "7.5.17", + "@pezkuwi/wasm-util": "7.5.17", + "tslib": "^2.7.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@pezkuwi/util": "*", + "@pezkuwi/x-randomvalues": "*" + } + }, + "node_modules/@pezkuwi/wasm-crypto-asmjs": { + "version": "7.5.17", + "resolved": "https://registry.npmjs.org/@pezkuwi/wasm-crypto-asmjs/-/wasm-crypto-asmjs-7.5.17.tgz", + "integrity": "sha512-akM7/goSqYenoQXQYYiMP2esxka6IaqhcidKB54FAucvtIO5O2LtbAfCeNN+e5xyiAeTcTUXbSrVzDOd4+3czA==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.7.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@pezkuwi/util": "*" + } + }, + "node_modules/@pezkuwi/wasm-crypto-init": { + "version": "7.5.17", + "resolved": "https://registry.npmjs.org/@pezkuwi/wasm-crypto-init/-/wasm-crypto-init-7.5.17.tgz", + "integrity": "sha512-q/T6sj8bFL2JPeTmSGbwd8E4LpK+hKdAhDR86jrZ/rKMNuLnYMSYuiR7GraymYFqlG2yLZoJihKn5b8J40YjaQ==", + "license": "Apache-2.0", + "dependencies": { + "@pezkuwi/wasm-bridge": "7.5.17", + "@pezkuwi/wasm-crypto-asmjs": "7.5.17", + "@pezkuwi/wasm-crypto-wasm": "7.5.17", + "@pezkuwi/wasm-util": "7.5.17", + "tslib": "^2.7.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@pezkuwi/util": "*", + "@pezkuwi/x-randomvalues": "*" + } + }, + "node_modules/@pezkuwi/wasm-crypto-wasm": { + "version": "7.5.17", + "resolved": "https://registry.npmjs.org/@pezkuwi/wasm-crypto-wasm/-/wasm-crypto-wasm-7.5.17.tgz", + "integrity": "sha512-yg9/ldrHSUaIJ+db7vuPkU6DBw/SAuU4kK2L05LEbFeC093SfRS4f0qnIwNhlgjEJVsAfSWjZXOGBAM1Mc8aHg==", + "license": "Apache-2.0", + "dependencies": { + "@pezkuwi/wasm-util": "7.5.17", + "tslib": "^2.7.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@pezkuwi/util": "*" + } + }, + "node_modules/@pezkuwi/wasm-util": { + "version": "7.5.17", + "resolved": "https://registry.npmjs.org/@pezkuwi/wasm-util/-/wasm-util-7.5.17.tgz", + "integrity": "sha512-MHodOmAuldNmmkTwZgGmSvCvUbhgR79N6biG6QVXrUtwVGUK37IUx/195T1cG0IZaSjLsWwz3olhksto5z54Lw==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.7.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@pezkuwi/util": "*" + } + }, + "node_modules/@pezkuwi/x-bigint": { + "version": "14.0.25", + "resolved": "https://registry.npmjs.org/@pezkuwi/x-bigint/-/x-bigint-14.0.25.tgz", + "integrity": "sha512-9CG28jPK0EUuXTn8QWnsYjXycfHBVQCR5QGJ17hgRenzRRDzoIB5unhC0XklcIh5U/KO88TPRVZKKiwSfQXlKg==", + "license": "Apache-2.0", + "dependencies": { + "@pezkuwi/x-global": "14.0.25", + "tslib": "^2.8.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@pezkuwi/x-fetch": { + "version": "14.0.25", + "resolved": "https://registry.npmjs.org/@pezkuwi/x-fetch/-/x-fetch-14.0.25.tgz", + "integrity": "sha512-fiNYdYMq0OdYsSUwVBA68eKieeQ+PJYniEeCRNvkMUN1LUWMzdv9zTTPRtsGUEGm12y9uUgymgD92eo4PSoJog==", + "license": "Apache-2.0", + "dependencies": { + "@pezkuwi/x-global": "14.0.25", + "node-fetch": "^3.3.2", + "tslib": "^2.8.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@pezkuwi/x-global": { + "version": "14.0.25", + "resolved": "https://registry.npmjs.org/@pezkuwi/x-global/-/x-global-14.0.25.tgz", + "integrity": "sha512-WxY0dCOWFfqqd2jtLNX8BmJMCR5NTlc9QBuL3u4TwF6yAc4jKqlq3F1J1vAMESnBwnR1jUepKgn+2dpGuspJYw==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.8.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@pezkuwi/x-randomvalues": { + "version": "14.0.25", + "resolved": "https://registry.npmjs.org/@pezkuwi/x-randomvalues/-/x-randomvalues-14.0.25.tgz", + "integrity": "sha512-Kkbkdv8e2XZEnhwJHaqM27wKn25fc/Dt6neGy3x150AVuf4EjWnM0Q9pNVC4WQKbThvDQ8SvzCdfZos4Lae8sA==", + "license": "Apache-2.0", + "dependencies": { + "@pezkuwi/x-global": "14.0.25", + "tslib": "^2.8.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@pezkuwi/util": "14.0.25", + "@pezkuwi/wasm-util": "7.5.17" + } + }, + "node_modules/@pezkuwi/x-textdecoder": { + "version": "14.0.25", + "resolved": "https://registry.npmjs.org/@pezkuwi/x-textdecoder/-/x-textdecoder-14.0.25.tgz", + "integrity": "sha512-ecse2X9BKG164BfCesCZfL3lZU+XAdLjaOKzLqPB+hlTshHVnnSAvUvZNaw4zq9ztBVhhktxZ9K27S1w8ZANMg==", + "license": "Apache-2.0", + "dependencies": { + "@pezkuwi/x-global": "14.0.25", + "tslib": "^2.8.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@pezkuwi/x-textencoder": { + "version": "14.0.25", + "resolved": "https://registry.npmjs.org/@pezkuwi/x-textencoder/-/x-textencoder-14.0.25.tgz", + "integrity": "sha512-0R25a5V8ykoHCHwl2zYsW6FxQlGdPgHiaGUUqY4wfnNAyUsolsm1YU772vfNfARdLN6K+jiRdQ6I6RW114LtgQ==", + "license": "Apache-2.0", + "dependencies": { + "@pezkuwi/x-global": "14.0.25", + "tslib": "^2.8.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@pezkuwi/x-ws": { + "version": "14.0.25", + "resolved": "https://registry.npmjs.org/@pezkuwi/x-ws/-/x-ws-14.0.25.tgz", + "integrity": "sha512-YwbnTl+EF3Gtp2qrs/23Qo2FkpPB2y+0HGa4XovyfbDk7iAXJuIAAw0sq2StxVF1NsSm0DZIyX1GJU+nyM/5Pw==", + "license": "Apache-2.0", + "dependencies": { + "@pezkuwi/x-global": "14.0.25", + "tslib": "^2.8.0", + "ws": "^8.18.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@scure/base": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.2.6.tgz", + "integrity": "sha512-g/nm5FgUa//MCj1gV09zTJTaM6KBAHqLN907YVQqf7zC49+DcO4B1so4ZX07Ef10Twr6nuqYEH9GEggFXA4Fmg==", + "license": "MIT", + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@substrate/ss58-registry": { + "version": "1.51.0", + "resolved": "https://registry.npmjs.org/@substrate/ss58-registry/-/ss58-registry-1.51.0.tgz", + "integrity": "sha512-TWDurLiPxndFgKjVavCniytBIw+t4ViOi7TYp9h/D0NMmkEc9klFTo+827eyEJ0lELpqO207Ey7uGxUa+BS1jQ==", + "license": "Apache-2.0" + }, + "node_modules/@types/bn.js": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@types/bn.js/-/bn.js-5.2.0.tgz", + "integrity": "sha512-DLbJ1BPqxvQhIGbeu8VbUC1DiAiahHtAYvA0ZEAa4P31F7IaArc8z3C3BRQdWX4mtLQuABG4yzp76ZrS02Ui1Q==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/node": { + "version": "25.2.3", + "resolved": "https://registry.npmjs.org/@types/node/-/node-25.2.3.tgz", + "integrity": "sha512-m0jEgYlYz+mDJZ2+F4v8D1AyQb+QzsNqRuI7xg1VQX/KlKS0qT9r1Mo16yo5F/MtifXFgaofIFsdFMox2SxIbQ==", + "license": "MIT", + "dependencies": { + "undici-types": "~7.16.0" + } + }, + "node_modules/bn.js": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.2.tgz", + "integrity": "sha512-v2YAxEmKaBLahNwE1mjp4WON6huMNeuDvagFZW+ASCuA/ku0bXR9hSMw0XpiqMoA3+rmnyck/tPRSFQkoC9Cuw==", + "license": "MIT" + }, + "node_modules/data-uri-to-buffer": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", + "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==", + "license": "MIT", + "engines": { + "node": ">= 12" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/eventemitter3": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.4.tgz", + "integrity": "sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==", + "license": "MIT" + }, + "node_modules/fetch-blob": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz", + "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "paypal", + "url": "https://paypal.me/jimmywarting" + } + ], + "license": "MIT", + "dependencies": { + "node-domexception": "^1.0.0", + "web-streams-polyfill": "^3.0.3" + }, + "engines": { + "node": "^12.20 || >= 14.13" + } + }, + "node_modules/formdata-polyfill": { + "version": "4.0.10", + "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", + "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==", + "license": "MIT", + "dependencies": { + "fetch-blob": "^3.1.2" + }, + "engines": { + "node": ">=12.20.0" + } + }, + "node_modules/json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==", + "license": "ISC" + }, + "node_modules/mock-socket": { + "version": "9.3.1", + "resolved": "https://registry.npmjs.org/mock-socket/-/mock-socket-9.3.1.tgz", + "integrity": "sha512-qxBgB7Qa2sEQgHFjj0dSigq7fX4k6Saisd5Nelwp2q8mlbAFh5dHV9JTTlF8viYJLSSWgMCZFUom8PJcMNBoJw==", + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/nock": { + "version": "13.5.6", + "resolved": "https://registry.npmjs.org/nock/-/nock-13.5.6.tgz", + "integrity": "sha512-o2zOYiCpzRqSzPj0Zt/dQ/DqZeYoaQ7TUonc/xUPjCGl9WeHpNbxgVvOquXYAaJzI0M9BXV3HTzG0p8IUAbBTQ==", + "license": "MIT", + "dependencies": { + "debug": "^4.1.0", + "json-stringify-safe": "^5.0.1", + "propagate": "^2.0.0" + }, + "engines": { + "node": ">= 10.13" + } + }, + "node_modules/node-domexception": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", + "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", + "deprecated": "Use your platform's native DOMException instead", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "github", + "url": "https://paypal.me/jimmywarting" + } + ], + "license": "MIT", + "engines": { + "node": ">=10.5.0" + } + }, + "node_modules/node-fetch": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz", + "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==", + "license": "MIT", + "dependencies": { + "data-uri-to-buffer": "^4.0.0", + "fetch-blob": "^3.1.4", + "formdata-polyfill": "^4.0.10" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/node-fetch" + } + }, + "node_modules/propagate": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/propagate/-/propagate-2.0.1.tgz", + "integrity": "sha512-vGrhOavPSTz4QVNuBNdcNXePNdNMaO1xj9yBeH1ScQPjk/rhg9sSlCXPhMkFuaNNW/syTvYqsnbIJxMBfRbbag==", + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/rxjs": { + "version": "7.8.2", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz", + "integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/smoldot": { + "version": "2.0.40", + "resolved": "https://registry.npmjs.org/smoldot/-/smoldot-2.0.40.tgz", + "integrity": "sha512-h6XC/kKDLdZBBTI0X8y4ZxmaZ2KYVVB0+5isCQm6j26ljeNjHZUDOV+hf8VyoE23+jg00wrxNJ2IVcIAURxwtg==", + "license": "GPL-3.0-or-later WITH Classpath-exception-2.0", + "optional": true, + "dependencies": { + "ws": "^8.8.1" + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" + }, + "node_modules/undici-types": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz", + "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==", + "license": "MIT" + }, + "node_modules/web-streams-polyfill": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz", + "integrity": "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==", + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/ws": { + "version": "8.19.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.19.0.tgz", + "integrity": "sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + } + } +} diff --git a/noter/package.json b/noter/package.json new file mode 100644 index 0000000..ce50ff5 --- /dev/null +++ b/noter/package.json @@ -0,0 +1,16 @@ +{ + "name": "pezkuwi-noter-bot", + "version": "1.0.0", + "description": "Noter bot: collects staking data from Relay Chain / Asset Hub and submits to People Chain", + "type": "module", + "scripts": { + "start": "node bot.js", + "dev": "node --watch bot.js" + }, + "dependencies": { + "@pezkuwi/api": "^16.5.36", + "@pezkuwi/keyring": "^14.0.25", + "@pezkuwi/util": "^14.0.25", + "@pezkuwi/util-crypto": "^14.0.25" + } +}