Skip to content

Conversation

@lrsaturnino
Copy link
Member

Add comprehensive wallet-operator mapping toolset for beta staker consolidation analysis. Enables identification of wallets containing deprecated operators and BTC distribution calculations.

Core functionality:

  • query-dkg-events.js: Extracts operator membership from on-chain DKG events
  • analyze-per-operator.js: Calculates BTC distribution by provider
  • validate-operator-list.js: Verifies operator list completeness

Configuration:

  • operators.json: Defines KEEP (4 active) vs DISABLE (16 deprecated) operators
  • Contract ABIs for Bridge and WalletRegistry interactions
  • Archive node RPC support for historical event queries

Documentation:

  • README: Usage guide and integration points
  • Manual sweep procedures and execution scripts
  • Operator consolidation communication guidelines

Integration:

  • Provides data source for monitoring dashboard
  • Supports draining progress assessment
  • Enables manual sweep decision-making

Technical details:

  • Uses threshold cryptography (51/100 signatures)
  • Queries sortition pool for operator address resolution
  • Classifies operators by provider (STAKED, P2P, BOAR, NUCO)

Add comprehensive wallet-operator mapping toolset for beta staker
consolidation analysis. Enables identification of wallets containing
deprecated operators and BTC distribution calculations.

Core functionality:
- query-dkg-events.js: Extracts operator membership from on-chain DKG events
- analyze-per-operator.js: Calculates BTC distribution by provider
- validate-operator-list.js: Verifies operator list completeness

Configuration:
- operators.json: Defines KEEP (4 active) vs DISABLE (16 deprecated) operators
- Contract ABIs for Bridge and WalletRegistry interactions
- Archive node RPC support for historical event queries

Documentation:
- README: Usage guide and integration points
- Manual sweep procedures and execution scripts
- Operator consolidation communication guidelines

Integration:
- Provides data source for monitoring dashboard
- Supports draining progress assessment
- Enables manual sweep decision-making

Technical details:
- Uses threshold cryptography (51/100 signatures)
- Queries sortition pool for operator address resolution
- Classifies operators by provider (STAKED, P2P, BOAR, NUCO)
const path = require('path');

const MAPPING_FILE = path.join(__dirname, 'wallet-operator-mapping.json');
const CSV_PATH = '/Users/leonardosaturnino/Documents/GitHub/memory-bank/20250809-beta-staker-consolidation/knowledge/threshold_stakers_may_2025.csv';
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we commit this file to the repo?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in commit hash 6461451

}

// File paths
const PROOF_OF_FUNDS_PATH = '/Users/leonardosaturnino/Documents/GitHub/memory-bank/20250809-beta-staker-consolidation/knowledge/20251006-tbtc-proof-of-funds.json';
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we commit this file to the repo?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in commit hash 6461451

if (providerShares[data.provider]) {
if (data.status === 'KEEP') {
providerShares[data.provider].keep += data.totalShare;
providerShares[data.provider].keepWallets = data.walletCount;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are we sure this is = and not +=?

Suggested change
providerShares[data.provider].keepWallets = data.walletCount;
providerShares[data.provider].keepWallets += data.walletCount;

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in commit hash 6461451

providerShares[data.provider].keepWallets = data.walletCount;
} else {
providerShares[data.provider].disable += data.totalShare;
providerShares[data.provider].disableWallets = data.walletCount;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ditto

Suggested change
providerShares[data.provider].disableWallets = data.walletCount;
providerShares[data.provider].disableWallets += data.walletCount;

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in commit hash 6461451

Fix critical bugs and configuration issues identified in code review:

Bug Fixes:
- Fix wallet count aggregation in analyze-per-operator.js
  - Changed assignment operator from = to += on lines 122, 125
  - Now correctly sums wallet counts across all operators per provider
  - Previously only recorded last operator's count, causing incorrect analysis

Configuration:
- Externalize hard-coded file paths to environment variables
  - query-dkg-events.js: Use PROOF_OF_FUNDS_PATH with ./data/ fallback
  - validate-operator-list.js: Use THRESHOLD_STAKERS_CSV_PATH with ./data/ fallback
  - Scripts now portable across team members and environments

Documentation:
- Add data file setup section to README.md
- Document two setup options: default directory and env variables
- Create data/README.md with file requirements and sources
- Update .env.example with new configuration variables
- Add data/ directory to .gitignore

All review comments from piotr-roslaniec addressed.
Add gitignore rules for wallet-operator-mapper script working files:
- .env for local configuration
- data/ directory for analysis outputs
- JSON mapping files generated during execution
- package-lock.json for npm dependency lock

These files are runtime artifacts that should not be tracked.
@jose-blockchain
Copy link
Contributor

Looks solid overall! Since these queries archive nodes for historical DKG events, have you run into any RPC rate limting issues? scanning large block ranges can sometimes be flaky depending on the provider.

As a nice to have in the future, might be worth adding some retry logic or at least documenting the expected runtime and which RPC providers work well (I'm guessing this needs archive node access, so not all Infura/Alchemy tiers will work).

Also curious... what's the typical execution time for a full analysis run?

Remove single-purpose investigation scripts and add general-purpose
query utilities for ongoing operator management.

Removed:
- calculate-all-beta-staker-weights.js (governance task complete)
- calculate-allowlist-weights.js (superseded)
- generate-allowlist-weights-final.js (output saved)
- check-current-pool-weights.js (investigation complete)
- check-sortition-pool-divisor.js (findings incorporated)
- investigate-unknown-operator.js (one-time investigation)
- verify-missing-wallets.js (specific verification done)

Added utility scripts:
- query-proof-of-funds.js: Generate proof-of-funds reports
- query-sortition-pool.js: Check operator pool status
- query-all-pool-operators.js: Discover all pool operators
- query-all-stakers.js: Verify staker documentation completeness

Updated README to document all remaining scripts in Main and
Utility sections.
Copy link
Collaborator

@piotr-roslaniec piotr-roslaniec left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, just a couple of questions

console.log(`\nTotal unique staking providers: ${allStakingProviders.size}\n`);

// Load our known list
const stakersJson = require('/Users/leonardosaturnino/Documents/GitHub/memory-bank/20250809-beta-staker-consolidation/knowledge/threshold_stakers_may_2025.json');
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's add this JSON to repo or use a permalink to fetch it

);
const walletRegistry = new ethers.Contract(WALLET_REGISTRY_ADDRESS, walletRegistryAbi, provider);

for (const provider of unknownProviders) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nitpick: We are shadowing const provider = new ethers.JsonRpcProvider(...) from before

Suggested change
for (const provider of unknownProviders) {
for (const stakingProvider of unknownProviders) {

totalBalance += BigInt(balanceSats);

// Convert satoshis to BTC as integer string (truncated, no decimals)
const balanceBTCInt = Math.floor(balanceSats / 100000000);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure about whether or not this will lead to some significant loss in precision

Suggested change
const balanceBTCInt = Math.floor(balanceSats / 100000000);
const balanceBTCInt = (balanceSats / 100000000).toFixed(8);

providers.forEach(provider => {
if (summary.byProvider[provider]) {
summary.byProvider[provider].wallets++;
summary.byProvider[provider].btc += wallet.btcBalance;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What happens if wallet has operators from multiple deprecated providers? Is that possible? If yes, is it going to be counted multiple times?

Suggested change
summary.byProvider[provider].btc += wallet.btcBalance;
summary.byProvider[provider].btc += wallet.btcBalance / providers.size

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants